Commits

Alex Szpakowski committed 448da0a

changed PixelEffect name to ShaderEffect, added lua-side support for vert/frag shader combinations with love.graphics.newShaderEffect, added tentative support for single-file vertex+fragment shaders

Comments (0)

Files changed (22)

platform/macosx/love.xcodeproj/project.pbxproj

 		A96F41891412B36D0067FE9A /* wrap_WheelJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A96F41871412B35B0067FE9A /* wrap_WheelJoint.cpp */; };
 		A96F418C1412B3AD0067FE9A /* WheelJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A96F418A1412B3A30067FE9A /* WheelJoint.cpp */; };
 		A96F41921412BBEE0067FE9A /* Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A96F41901412BBEE0067FE9A /* Canvas.cpp */; };
-		A96F41951412BBF80067FE9A /* PixelEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A96F41931412BBF80067FE9A /* PixelEffect.cpp */; };
 		A96F41981412BC000067FE9A /* VertexBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A96F41961412BC000067FE9A /* VertexBuffer.cpp */; };
 		A96F419B1412BC070067FE9A /* wrap_Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A96F41991412BC070067FE9A /* wrap_Canvas.cpp */; };
-		A96F419E1412BC0E0067FE9A /* wrap_PixelEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A96F419C1412BC0E0067FE9A /* wrap_PixelEffect.cpp */; };
 		A96F41A41412C91F0067FE9A /* EdgeShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A96F41A21412C91E0067FE9A /* EdgeShape.cpp */; };
 		A96F41A71412C92B0067FE9A /* wrap_EdgeShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A96F41A51412C92B0067FE9A /* wrap_EdgeShape.cpp */; };
 		A97E632514604BC200020E43 /* wrap_Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A97E632314604BC200020E43 /* wrap_Keyboard.cpp */; };
 		A9F2D09114BA85EC0035D2A5 /* Audio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F2D09014BA85EC0035D2A5 /* Audio.cpp */; };
 		A9F6E6AE15A1080D00C86200 /* love.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F6E6AC15A1080D00C86200 /* love.cpp */; };
 		A9F6E6B115A1099C00C86200 /* GmeDecoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9F6E6AF15A1099C00C86200 /* GmeDecoder.cpp */; };
+		FADB91451683F5C600D84B22 /* ShaderEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADB91431683F5C600D84B22 /* ShaderEffect.cpp */; };
+		FADB91481683F5FA00D84B22 /* wrap_ShaderEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADB91461683F5F900D84B22 /* wrap_ShaderEffect.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
 		A93E69EB10420ABF007D418B /* Reference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reference.h; sourceTree = "<group>"; };
 		A93E69EC10420ABF007D418B /* runtime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = runtime.cpp; sourceTree = "<group>"; };
 		A93E69ED10420ABF007D418B /* runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = runtime.h; sourceTree = "<group>"; };
-		A93E69EE10420ABF007D418B /* types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = types.h; sourceTree = "<group>"; };
+		A93E69EE10420ABF007D418B /* types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = types.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
 		A93E69EF10420ABF007D418B /* Vector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Vector.cpp; sourceTree = "<group>"; };
 		A93E69F010420ABF007D418B /* Vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Vector.h; sourceTree = "<group>"; };
 		A93E69F110420ABF007D418B /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; };
 		A93E6A8010420AC2007D418B /* wrap_Rasterizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Rasterizer.h; sourceTree = "<group>"; };
 		A93E6A8210420AC2007D418B /* Drawable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Drawable.cpp; sourceTree = "<group>"; };
 		A93E6A8310420AC2007D418B /* Drawable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Drawable.h; sourceTree = "<group>"; };
-		A93E6A8410420AC2007D418B /* Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Graphics.h; sourceTree = "<group>"; };
+		A93E6A8410420AC2007D418B /* Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Graphics.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
 		A93E6A8510420AC2007D418B /* Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Image.h; sourceTree = "<group>"; };
 		A93E6A8710420AC2007D418B /* Font.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Font.cpp; sourceTree = "<group>"; };
 		A93E6A8810420AC2007D418B /* Font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Font.h; sourceTree = "<group>"; };
 		A93E6A8910420AC2007D418B /* GLee.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = GLee.c; sourceTree = "<group>"; };
 		A93E6A8A10420AC2007D418B /* GLee.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLee.h; sourceTree = "<group>"; };
-		A93E6A8D10420AC2007D418B /* Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Graphics.cpp; sourceTree = "<group>"; };
-		A93E6A8E10420AC2007D418B /* Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Graphics.h; sourceTree = "<group>"; };
+		A93E6A8D10420AC2007D418B /* Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Graphics.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+		A93E6A8E10420AC2007D418B /* Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Graphics.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
 		A93E6A8F10420AC2007D418B /* Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Image.cpp; sourceTree = "<group>"; };
 		A93E6A9010420AC2007D418B /* Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Image.h; sourceTree = "<group>"; };
 		A93E6A9310420AC2007D418B /* Quad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Quad.cpp; sourceTree = "<group>"; };
 		A93E6A9610420AC2007D418B /* SpriteBatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpriteBatch.h; sourceTree = "<group>"; };
 		A93E6A9910420AC2007D418B /* wrap_Font.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Font.cpp; sourceTree = "<group>"; };
 		A93E6A9A10420AC2007D418B /* wrap_Font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Font.h; sourceTree = "<group>"; };
-		A93E6A9D10420AC3007D418B /* wrap_Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Graphics.cpp; sourceTree = "<group>"; };
-		A93E6A9E10420AC3007D418B /* wrap_Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Graphics.h; sourceTree = "<group>"; };
+		A93E6A9D10420AC3007D418B /* wrap_Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = wrap_Graphics.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+		A93E6A9E10420AC3007D418B /* wrap_Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = wrap_Graphics.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
 		A93E6A9F10420AC3007D418B /* wrap_Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Image.cpp; sourceTree = "<group>"; };
 		A93E6AA010420AC3007D418B /* wrap_Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Image.h; sourceTree = "<group>"; };
 		A93E6AA110420AC3007D418B /* wrap_Quad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Quad.cpp; sourceTree = "<group>"; };
 		A93E6B9010420ACC007D418B /* Timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Timer.h; sourceTree = "<group>"; };
 		A93E6B9710420ACC007D418B /* boot.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lua; path = boot.lua; sourceTree = "<group>"; };
 		A93E6B9810420ACC007D418B /* boot.lua.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = boot.lua.h; sourceTree = "<group>"; };
-		A93E6B9910420ACC007D418B /* graphics.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lua; path = graphics.lua; sourceTree = "<group>"; };
+		A93E6B9910420ACC007D418B /* graphics.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lua; lineEnding = 0; path = graphics.lua; sourceTree = "<group>"; };
 		A93E6B9A10420ACC007D418B /* graphics.lua.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = graphics.lua.h; sourceTree = "<group>"; };
 		A93E6E4610420B4A007D418B /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; };
 		A93E6E4710420B4A007D418B /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
 		A968F0C71083A07C00A895AA /* StringMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringMap.h; sourceTree = "<group>"; };
 		A968F0CE1083A9A900A895AA /* Event.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Event.cpp; sourceTree = "<group>"; };
 		A968F0D01083A9B900A895AA /* File.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = File.cpp; sourceTree = "<group>"; };
-		A968F0D21083A9D400A895AA /* Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Graphics.cpp; sourceTree = "<group>"; };
+		A968F0D21083A9D400A895AA /* Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Graphics.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
 		A968F0D41083A9E700A895AA /* Joystick.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Joystick.cpp; sourceTree = "<group>"; };
 		A968F0D61083A9F200A895AA /* Keyboard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Keyboard.cpp; sourceTree = "<group>"; };
 		A968F0D81083A9FC00A895AA /* Mouse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mouse.cpp; sourceTree = "<group>"; };
 		A96F418A1412B3A30067FE9A /* WheelJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WheelJoint.cpp; sourceTree = "<group>"; };
 		A96F418B1412B3A80067FE9A /* WheelJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WheelJoint.h; sourceTree = "<group>"; };
 		A96F41901412BBEE0067FE9A /* Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Canvas.cpp; sourceTree = "<group>"; };
-		A96F41911412BBEE0067FE9A /* Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Canvas.h; sourceTree = "<group>"; };
-		A96F41931412BBF80067FE9A /* PixelEffect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PixelEffect.cpp; sourceTree = "<group>"; };
-		A96F41941412BBF80067FE9A /* PixelEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PixelEffect.h; sourceTree = "<group>"; };
+		A96F41911412BBEE0067FE9A /* Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Canvas.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
 		A96F41961412BC000067FE9A /* VertexBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VertexBuffer.cpp; sourceTree = "<group>"; };
 		A96F41971412BC000067FE9A /* VertexBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VertexBuffer.h; sourceTree = "<group>"; };
 		A96F41991412BC070067FE9A /* wrap_Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Canvas.cpp; sourceTree = "<group>"; };
 		A96F419A1412BC070067FE9A /* wrap_Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Canvas.h; sourceTree = "<group>"; };
-		A96F419C1412BC0E0067FE9A /* wrap_PixelEffect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_PixelEffect.cpp; sourceTree = "<group>"; };
-		A96F419D1412BC0E0067FE9A /* wrap_PixelEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_PixelEffect.h; sourceTree = "<group>"; };
 		A96F41A21412C91E0067FE9A /* EdgeShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EdgeShape.cpp; sourceTree = "<group>"; };
 		A96F41A31412C91E0067FE9A /* EdgeShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EdgeShape.h; sourceTree = "<group>"; };
 		A96F41A51412C92B0067FE9A /* wrap_EdgeShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_EdgeShape.cpp; sourceTree = "<group>"; };
 		A9F6E6B015A1099C00C86200 /* GmeDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GmeDecoder.h; sourceTree = "<group>"; };
 		A9F8833511163C8C00831E98 /* audio.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lua; path = audio.lua; sourceTree = "<group>"; };
 		A9F8833611163C8C00831E98 /* audio.lua.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio.lua.h; sourceTree = "<group>"; };
+		FADB91431683F5C600D84B22 /* ShaderEffect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ShaderEffect.cpp; sourceTree = "<group>"; };
+		FADB91441683F5C600D84B22 /* ShaderEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShaderEffect.h; sourceTree = "<group>"; };
+		FADB91461683F5F900D84B22 /* wrap_ShaderEffect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_ShaderEffect.cpp; sourceTree = "<group>"; };
+		FADB91471683F5FA00D84B22 /* wrap_ShaderEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_ShaderEffect.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
 				A9642D7414D1A66000CE0B02 /* OpenGL.h */,
 				A9B4BA9A1045937F001DBC80 /* ParticleSystem.cpp */,
 				A9B4BA981045937F001DBC80 /* ParticleSystem.h */,
-				A96F41931412BBF80067FE9A /* PixelEffect.cpp */,
-				A96F41941412BBF80067FE9A /* PixelEffect.h */,
 				A93E6A9310420AC2007D418B /* Quad.cpp */,
 				A93E6A9410420AC2007D418B /* Quad.h */,
+				FADB91431683F5C600D84B22 /* ShaderEffect.cpp */,
+				FADB91441683F5C600D84B22 /* ShaderEffect.h */,
 				A93E6A9510420AC2007D418B /* SpriteBatch.cpp */,
 				A93E6A9610420AC2007D418B /* SpriteBatch.h */,
 				A96F41961412BC000067FE9A /* VertexBuffer.cpp */,
 				A93E6AA010420AC3007D418B /* wrap_Image.h */,
 				A9B4BA9B1045937F001DBC80 /* wrap_ParticleSystem.cpp */,
 				A9B4BA991045937F001DBC80 /* wrap_ParticleSystem.h */,
-				A96F419C1412BC0E0067FE9A /* wrap_PixelEffect.cpp */,
-				A96F419D1412BC0E0067FE9A /* wrap_PixelEffect.h */,
 				A93E6AA110420AC3007D418B /* wrap_Quad.cpp */,
 				A93E6AA210420AC3007D418B /* wrap_Quad.h */,
+				FADB91461683F5F900D84B22 /* wrap_ShaderEffect.cpp */,
+				FADB91471683F5FA00D84B22 /* wrap_ShaderEffect.h */,
 				A93E6AA310420AC3007D418B /* wrap_SpriteBatch.cpp */,
 				A93E6AA410420AC3007D418B /* wrap_SpriteBatch.h */,
 			);
 				A96E254F13B9892100456DEA /* threads.cpp in Sources */,
 				A96E255113B9892100456DEA /* wrap_Thread.cpp in Sources */,
 				A96F41921412BBEE0067FE9A /* Canvas.cpp in Sources */,
-				A96F41951412BBF80067FE9A /* PixelEffect.cpp in Sources */,
 				A96F41981412BC000067FE9A /* VertexBuffer.cpp in Sources */,
 				A96F419B1412BC070067FE9A /* wrap_Canvas.cpp in Sources */,
-				A96F419E1412BC0E0067FE9A /* wrap_PixelEffect.cpp in Sources */,
 				A901B882143B65C500D77063 /* DrawQable.cpp in Sources */,
 				A901B885143B661400D77063 /* Quad.cpp in Sources */,
 				A986ECAF132CEBB000F048C8 /* Fixture.cpp in Sources */,
 				A9F6E6B115A1099C00C86200 /* GmeDecoder.cpp in Sources */,
 				A911D2DB15DFECC8005B7EB8 /* Module.cpp in Sources */,
 				A5474CEF1624903B00C8EEAC /* math.cpp in Sources */,
+				FADB91451683F5C600D84B22 /* ShaderEffect.cpp in Sources */,
+				FADB91481683F5FA00D84B22 /* wrap_ShaderEffect.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

src/common/types.h

 	GRAPHICS_PARTICLE_SYSTEM_ID,
 	GRAPHICS_SPRITE_BATCH_ID,
 	GRAPHICS_CANVAS_ID,
-	GRAPHICS_PIXELEFFECT_ID,
+	GRAPHICS_SHADEREFFECT_ID,
 
 	// Image
 	IMAGE_IMAGE_DATA_ID,
 const bits GRAPHICS_PARTICLE_SYSTEM_T = (bits(1) << GRAPHICS_PARTICLE_SYSTEM_ID) | GRAPHICS_DRAWABLE_T;
 const bits GRAPHICS_SPRITE_BATCH_T = (bits(1) << GRAPHICS_SPRITE_BATCH_ID) | GRAPHICS_DRAWABLE_T;
 const bits GRAPHICS_CANVAS_T = (bits(1) << GRAPHICS_CANVAS_ID) | GRAPHICS_DRAWQABLE_T;
-const bits GRAPHICS_PIXELEFFECT_T = (bits(1) << GRAPHICS_PIXELEFFECT_ID) | OBJECT_T;
+const bits GRAPHICS_SHADEREFFECT_T = (bits(1) << GRAPHICS_SHADEREFFECT_ID) | OBJECT_T;
 
 // Image.
 const bits IMAGE_IMAGE_DATA_T = (bits(1) << IMAGE_IMAGE_DATA_ID) | DATA_T;

src/modules/graphics/Graphics.cpp

 {
 	{ "canvas", Graphics::SUPPORT_CANVAS },
 	{ "hdrcanvas", Graphics::SUPPORT_HDR_CANVAS },
-	{ "pixeleffect", Graphics::SUPPORT_PIXELEFFECT },
+	{ "shadereffect", Graphics::SUPPORT_SHADEREFFECT },
 	{ "npot", Graphics::SUPPORT_NPOT },
 	{ "subtractive", Graphics::SUPPORT_SUBTRACTIVE },
 };

src/modules/graphics/Graphics.h

 	{
 		SUPPORT_CANVAS = 1,
 		SUPPORT_HDR_CANVAS,
-		SUPPORT_PIXELEFFECT,
+		SUPPORT_SHADEREFFECT,
 		SUPPORT_NPOT,
 		SUPPORT_SUBTRACTIVE,
 		SUPPORT_MAX_ENUM

src/modules/graphics/opengl/Canvas.h

 	static void bindDefaultCanvas();
 
 private:
-	friend class PixelEffect;
+	friend class ShaderEffect;
 	GLuint getTextureName() const
 	{
 		return img;

src/modules/graphics/opengl/Graphics.cpp

 	DisplayState s;
 	discardStencil();
 	Canvas::bindDefaultCanvas();
-	PixelEffect::detach();
+	ShaderEffect::detach();
 	restoreState(s);
 }
 
 	return NULL; // never reached
 }
 
-PixelEffect *Graphics::newPixelEffect(const std::string &code)
+ShaderEffect *Graphics::newShaderEffect(const std::string &vertcode, const std::string &fragcode)
 {
-	PixelEffect *effect = NULL;
+	ShaderEffect *effect = NULL;
 	try
 	{
-		effect = new PixelEffect("", code);
+		effect = new ShaderEffect(vertcode, fragcode);
 	}
 	catch(love::Exception &e)
 	{

src/modules/graphics/opengl/Graphics.h

 #include "SpriteBatch.h"
 #include "ParticleSystem.h"
 #include "Canvas.h"
-#include "PixelEffect.h"
+#include "ShaderEffect.h"
 
 namespace love
 {
 
 	Canvas *newCanvas(int width, int height, Canvas::TextureType texture_type = Canvas::TYPE_NORMAL);
 
-	PixelEffect *newPixelEffect(const std::string &code);
+	ShaderEffect *newShaderEffect(const std::string &vertcode, const std::string &fragcode);
 
 	/**
 	 * Sets the foreground color.

src/modules/graphics/opengl/Image.h

 
 	void drawv(const Matrix &t, const vertex *v) const;
 
-	friend class PixelEffect;
+	friend class ShaderEffect;
 	GLuint getTextureName() const
 	{
 		return texture;

src/modules/graphics/opengl/PixelEffect.cpp

-/**
- * Copyright (c) 2006-2012 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#include "PixelEffect.h"
-#include "GLee.h"
-#include "Graphics.h"
-
-namespace
-{
-// temporarily attaches a shader program (for setting uniforms, etc)
-// reattaches the originally active program when destroyed
-struct TemporaryAttacher
-{
-	TemporaryAttacher(love::graphics::opengl::PixelEffect *sp) : s(sp)
-	{
-		glGetIntegerv(GL_CURRENT_PROGRAM, &activeProgram);
-		s->attach();
-	}
-	~TemporaryAttacher()
-	{
-		glUseProgram(activeProgram);
-	}
-	love::graphics::opengl::PixelEffect *s;
-	GLint activeProgram;
-};
-} // anonymous namespace
-
-namespace love
-{
-namespace graphics
-{
-namespace opengl
-{
-
-PixelEffect *PixelEffect::current = NULL;
-
-std::map<std::string, GLint> PixelEffect::_texture_unit_pool;
-GLint PixelEffect::_current_texture_unit = 0;
-GLint PixelEffect::_max_texture_units = 0;
-
-GLint PixelEffect::getTextureUnit(const std::string &name)
-{
-	std::map<std::string, GLint>::const_iterator it = _texture_unit_pool.find(name);
-
-	if (it != _texture_unit_pool.end())
-		return it->second;
-
-	if (++_current_texture_unit >= _max_texture_units)
-		throw love::Exception("No more texture units available");
-
-	_texture_unit_pool[name] = _current_texture_unit;
-	return _current_texture_unit;
-}
-
-	PixelEffect::PixelEffect(const std::string &vertcode, const std::string &fragcode)
-	: _program(0)
-	, _vertcode(vertcode)
-	, _fragcode(fragcode)
-{
-	glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &_max_texture_units);
-	loadVolatile();
-}
-
-GLuint PixelEffect::createShader(GLenum type, const std::string &code)
-{
-	const char *shadertypename = NULL;
-	switch (type)
-	{
-	case GL_VERTEX_SHADER:
-		shadertypename = "vertex";
-		break;
-	case GL_GEOMETRY_SHADER_ARB:
-		shadertypename = "geometry";
-	case GL_FRAGMENT_SHADER:
-	default:
-		shadertypename = "fragment";
-		break;
-	}
-	
-	GLuint shader = glCreateShader(type);
-	if (shader == 0) // should only fail when called between glBegin() and glEnd()
-		throw love::Exception("Cannot create %s shader object.", shadertypename);
-	
-	const char *src = code.c_str();
-	size_t srclen = code.length();
-	glShaderSource(shader, 1, (const GLchar **)&src, (GLint *)&srclen);
-	
-	glCompileShader(shader);
-	
-	GLint compile_status;
-	glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
-	if (compile_status == GL_FALSE)
-	{
-		GLint infologlen;
-		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologlen);
-		
-		GLchar *errorlog = new GLchar[infologlen + 1];
-		glGetShaderInfoLog(shader, infologlen, NULL, errorlog);
-		
-		std::string tmp(errorlog);
-		
-		delete[] errorlog;
-		glDeleteShader(shader);
-		
-		throw love::Exception("Cannot compile %s shader:\n%s", shadertypename, tmp.c_str());
-	}
-	
-	return shader;
-}
-
-GLuint PixelEffect::createProgram(const std::vector<GLuint> &shaders)
-{
-	GLuint program = glCreateProgram();
-	if (program == 0) // should only fail when called between glBegin() and glEnd()
-		throw love::Exception("Cannot create shader program object.");
-	
-	std::vector<GLuint>::const_iterator it;
-	for (it = shaders.begin(); it != shaders.end(); ++it)
-		glAttachShader(program, *it);
-	
-	glLinkProgram(program);
-	
-	for (it = shaders.begin(); it != shaders.end(); ++it)
-		glDetachShader(program, *it);
-	
-	GLint link_ok;
-	glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
-	if (link_ok == GL_FALSE)
-	{
-		GLint strlen, nullpos;
-		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &strlen);
-		
-		char *temp_str = new char[strlen+1];
-		// be extra sure that the error string will be 0-terminated
-		memset(temp_str, '\0', strlen+1);
-		glGetProgramInfoLog(program, strlen, &nullpos, temp_str);
-		temp_str[nullpos] = '\0';
-		
-		std::string warnings(temp_str);
-		delete[] temp_str;
-
-		glDeleteProgram(program);
-		
-		throw love::Exception("Cannot link shader program object:\n%s", warnings.c_str());
-	}
-	
-	return program;
-}
-
-bool PixelEffect::loadVolatile()
-{	
-	std::vector<GLuint> shaders;
-	
-	if (_vertcode.length() > 0)
-		shaders.push_back(createShader(GL_VERTEX_SHADER, _vertcode));
-	
-	if (_fragcode.length() > 0)
-		shaders.push_back(createShader(GL_FRAGMENT_SHADER, _fragcode));
-	
-	if (shaders.size() == 0)
-		throw love::Exception("Cannot create PixelEffect: no source code!");
-	
-	try
-	{
-		_program = createProgram(shaders);
-	}
-	catch (love::Exception &e)
-	{
-		std::vector<GLuint>::iterator it;
-		for (it = shaders.begin(); it != shaders.end(); ++it)
-			glDeleteShader(*it);
-		
-		throw;
-	}
-	
-	std::vector<GLuint>::iterator it;
-	for (it = shaders.begin(); it != shaders.end(); ++it)
-		glDeleteShader(*it);
-
-	return true;
-}
-
-PixelEffect::~PixelEffect()
-{
-	unloadVolatile();
-}
-
-void PixelEffect::unloadVolatile()
-{
-	if (_program != 0)
-		glDeleteProgram(_program);
-}
-
-std::string PixelEffect::getGLSLVersion()
-{
-	// GL_SHADING_LANGUAGE_VERSION may not be available in OpenGL < 2.0.
-	const char *tmp = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
-	if (NULL == tmp)
-		return "0.0";
-
-	// the version string always begins with a version number of the format
-	//   major_number.minor_number
-	// or
-	//   major_number.minor_number.release_number
-	// we can keep release_number, since it does not affect the check below.
-	std::string versionString(tmp);
-	size_t minorEndPos = versionString.find(' ');
-	return versionString.substr(0, minorEndPos);
-}
-
-
-bool PixelEffect::isSupported()
-{
-	return GLEE_VERSION_2_0 && getGLSLVersion() >= "1.2";
-}
-
-std::string PixelEffect::getWarnings() const
-{
-	GLint strlen, nullpos;
-	glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &strlen);
-	char *temp_str = new char[strlen+1];
-	// be extra sure that the error string will be 0-terminated
-	memset(temp_str, '\0', strlen+1);
-	glGetProgramInfoLog(_program, strlen, &nullpos, temp_str);
-	temp_str[nullpos] = '\0';
-
-	std::string warnings(temp_str);
-	delete[] temp_str;
-	return warnings;
-}
-
-void PixelEffect::attach()
-{
-	glUseProgram(_program);
-	current = this;
-}
-
-void PixelEffect::detach()
-{
-	glUseProgram(0);
-	current = NULL;
-}
-
-void PixelEffect::sendFloat(const std::string &name, int size, const GLfloat *vec, int count)
-{
-	TemporaryAttacher attacher(this);
-	GLint location = getUniformLocation(name);
-
-	if (size < 1 || size > 4)
-	{
-		throw love::Exception("Invalid variable size: %d (expected 1-4).", size);
-	}
-
-	switch (size)
-	{
-	case 4:
-		glUniform4fv(location, count, vec);
-		break;
-	case 3:
-		glUniform3fv(location, count, vec);
-		break;
-	case 2:
-		glUniform2fv(location, count, vec);
-		break;
-	case 1:
-	default:
-		glUniform1fv(location, count, vec);
-		break;
-	}
-
-	// throw error if needed
-	checkSetUniformError();
-}
-
-void PixelEffect::sendMatrix(const std::string &name, int size, const GLfloat *m, int count)
-{
-	TemporaryAttacher attacher(this);
-	GLint location = getUniformLocation(name);
-
-	if (size < 2 || size > 4)
-	{
-		throw love::Exception("Invalid matrix size: %dx%d "
-							  "(can only set 2x2, 3x3 or 4x4 matrices).", size,size);
-	}
-
-	switch (size)
-	{
-	case 4:
-		glUniformMatrix4fv(location, count, GL_FALSE, m);
-		break;
-	case 3:
-		glUniformMatrix3fv(location, count, GL_FALSE, m);
-		break;
-	case 2:
-	default:
-		glUniformMatrix2fv(location, count, GL_FALSE, m);
-		break;
-	}
-
-	// throw error if needed
-	checkSetUniformError();
-}
-
-void PixelEffect::sendImage(const std::string &name, const Image &image)
-{
-	GLint texture_unit = getTextureUnit(name);
-
-	TemporaryAttacher attacher(this);
-	GLint location = getUniformLocation(name);
-
-	glActiveTexture(GL_TEXTURE0 + texture_unit);
-	bindTexture(image.getTextureName(), true); // guarantee it gets bound
-	glUniform1i(location, texture_unit);
-
-	// reset texture unit
-	glActiveTexture(GL_TEXTURE0);
-
-	// throw error if needed
-	checkSetUniformError();
-}
-
-void PixelEffect::sendCanvas(const std::string &name, const Canvas &canvas)
-{
-	GLint texture_unit = getTextureUnit(name);
-
-	TemporaryAttacher attacher(this);
-	GLint location = getUniformLocation(name);
-
-	glActiveTexture(GL_TEXTURE0 + texture_unit);
-	bindTexture(canvas.getTextureName(), true); // guarantee it gets bound
-	glUniform1i(location, texture_unit);
-
-	// reset texture unit
-	glActiveTexture(GL_TEXTURE0);
-
-	// throw error if needed
-	checkSetUniformError();
-}
-
-GLint PixelEffect::getUniformLocation(const std::string &name)
-{
-	std::map<std::string, GLint>::const_iterator it = _uniforms.find(name);
-	if (it != _uniforms.end())
-		return it->second;
-
-	GLint location = glGetUniformLocation(_program, name.c_str());
-	if (location == -1)
-	{
-		throw love::Exception(
-			"Cannot get location of shader variable `%s'.\n"
-			"A common error is to define but not use the variable.", name.c_str());
-	}
-
-	_uniforms[name] = location;
-	return location;
-}
-
-void PixelEffect::checkSetUniformError()
-{
-	GLenum error_code = glGetError();
-	if (GL_INVALID_OPERATION == error_code)
-	{
-		throw love::Exception(
-			"Invalid operation:\n"
-			"- Trying to send the wrong value type to shader variable, or\n"
-			"- Trying to send array values with wrong dimension, or\n"
-			"- Invalid variable name.");
-	}
-}
-
-} // opengl
-} // graphics
-} // love

src/modules/graphics/opengl/PixelEffect.h

-/**
- * Copyright (c) 2006-2012 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#ifndef LOVE_GRAPHICS_EFFECT_H
-#define LOVE_GRAPHICS_EFFECT_H
-
-#include "common/Object.h"
-#include <string>
-#include <map>
-#include <vector>
-#include "OpenGL.h"
-#include "Image.h"
-#include "Canvas.h"
-
-namespace love
-{
-namespace graphics
-{
-namespace opengl
-{
-// A fragment shader
-class PixelEffect : public Object, public Volatile
-{
-public:
-	PixelEffect(const std::string &vertcode, const std::string &fragcode);
-	virtual ~PixelEffect();
-	std::string getWarnings() const;
-
-	virtual bool loadVolatile();
-	virtual void unloadVolatile();
-
-	void attach();
-	static void detach();
-	static std::string getGLSLVersion();
-	static bool isSupported();
-
-	static PixelEffect *current;
-
-	void sendFloat(const std::string &name, int size, const GLfloat *vec, int count);
-	void sendMatrix(const std::string &name, int size, const GLfloat *m, int count);
-	void sendImage(const std::string &name, const Image &image);
-	void sendCanvas(const std::string &name, const Canvas &canvas);
-
-private:
-	GLint getUniformLocation(const std::string &name);
-	void checkSetUniformError();
-	GLuint createShader(GLenum type, const std::string &code);
-	GLuint createProgram(const std::vector<GLuint> &shaders);
-	
-	GLuint _program;
-	std::string _vertcode;
-	std::string _fragcode; // volatile and stuff
-
-	// uniform location buffer
-	std::map<std::string, GLint> _uniforms;
-
-	// texture unit pool for setting images
-	static std::map<std::string, GLint> _texture_unit_pool;
-	static GLint _current_texture_unit;
-	static GLint _max_texture_units;
-	static GLint getTextureUnit(const std::string &name);
-};
-
-} // opengl
-} // graphics
-} // love
-
-#endif // LOVE_GRAPHICS_EFFECT_H

src/modules/graphics/opengl/ShaderEffect.cpp

+/**
+ * Copyright (c) 2006-2012 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "ShaderEffect.h"
+#include "GLee.h"
+#include "Graphics.h"
+
+namespace
+{
+// temporarily attaches a shader program (for setting uniforms, etc)
+// reattaches the originally active program when destroyed
+struct TemporaryAttacher
+{
+	TemporaryAttacher(love::graphics::opengl::ShaderEffect *sp) : s(sp)
+	{
+		glGetIntegerv(GL_CURRENT_PROGRAM, &activeProgram);
+		s->attach();
+	}
+	~TemporaryAttacher()
+	{
+		glUseProgram(activeProgram);
+	}
+	love::graphics::opengl::ShaderEffect *s;
+	GLint activeProgram;
+};
+} // anonymous namespace
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+
+ShaderEffect *ShaderEffect::current = NULL;
+
+std::map<std::string, GLint> ShaderEffect::_texture_unit_pool;
+GLint ShaderEffect::_current_texture_unit = 0;
+GLint ShaderEffect::_max_texture_units = 0;
+
+GLint ShaderEffect::getTextureUnit(const std::string &name)
+{
+	std::map<std::string, GLint>::const_iterator it = _texture_unit_pool.find(name);
+
+	if (it != _texture_unit_pool.end())
+		return it->second;
+
+	if (++_current_texture_unit >= _max_texture_units)
+		throw love::Exception("No more texture units available");
+
+	_texture_unit_pool[name] = _current_texture_unit;
+	return _current_texture_unit;
+}
+
+ShaderEffect::ShaderEffect(const std::string &vertcode, const std::string &fragcode)
+	: _program(0)
+	, _vertcode(vertcode)
+	, _fragcode(fragcode)
+{
+	glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &_max_texture_units);
+	loadVolatile();
+}
+
+GLuint ShaderEffect::createShader(GLenum type, const std::string &code)
+{
+	const char *shadertypename = NULL;
+	switch (type)
+	{
+	case GL_VERTEX_SHADER:
+		shadertypename = "vertex";
+		break;
+	case GL_GEOMETRY_SHADER_ARB:
+		shadertypename = "geometry";
+	case GL_FRAGMENT_SHADER:
+	default:
+		shadertypename = "fragment";
+		break;
+	}
+	
+	GLuint shader = glCreateShader(type);
+	if (shader == 0) // should only fail when called between glBegin() and glEnd()
+		throw love::Exception("Cannot create %s shader object.", shadertypename);
+	
+	const char *src = code.c_str();
+	size_t srclen = code.length();
+	glShaderSource(shader, 1, (const GLchar **)&src, (GLint *)&srclen);
+	
+	glCompileShader(shader);
+	
+	GLint compile_status;
+	glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
+	if (compile_status == GL_FALSE)
+	{
+		GLint infologlen;
+		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologlen);
+		
+		GLchar *errorlog = new GLchar[infologlen + 1];
+		glGetShaderInfoLog(shader, infologlen, NULL, errorlog);
+		
+		std::string tmp(errorlog);
+		
+		delete[] errorlog;
+		glDeleteShader(shader);
+		
+		throw love::Exception("Cannot compile %s shader:\n%s", shadertypename, tmp.c_str());
+	}
+	
+	return shader;
+}
+
+void ShaderEffect::createProgram(const std::vector<GLuint> &shaders)
+{
+	_program = glCreateProgram();
+	if (_program == 0) // should only fail when called between glBegin() and glEnd()
+		throw love::Exception("Cannot create shader program object.");
+	
+	std::vector<GLuint>::const_iterator it;
+	for (it = shaders.begin(); it != shaders.end(); ++it)
+		glAttachShader(_program, *it);
+	
+	glLinkProgram(_program);
+	
+	for (it = shaders.begin(); it != shaders.end(); ++it)
+		glDetachShader(_program, *it);
+	
+	GLint link_ok;
+	glGetProgramiv(_program, GL_LINK_STATUS, &link_ok);
+	if (link_ok == GL_FALSE)
+	{
+		const std::string warnings = getWarnings();
+		glDeleteProgram(_program);
+		
+		throw love::Exception("Cannot link shader program object:\n%s", warnings.c_str());
+	}
+}
+
+bool ShaderEffect::loadVolatile()
+{	
+	std::vector<GLuint> shaders;
+	
+	if (_vertcode.length() > 0)
+		shaders.push_back(createShader(GL_VERTEX_SHADER, _vertcode));
+	
+	if (_fragcode.length() > 0)
+		shaders.push_back(createShader(GL_FRAGMENT_SHADER, _fragcode));
+	
+	if (shaders.size() == 0)
+		throw love::Exception("Cannot create ShaderEffect: no source code!");
+	
+	try
+	{
+		createProgram(shaders);
+	}
+	catch (love::Exception &e)
+	{
+		std::vector<GLuint>::iterator it;
+		for (it = shaders.begin(); it != shaders.end(); ++it)
+			glDeleteShader(*it);
+		
+		throw;
+	}
+	
+	std::vector<GLuint>::iterator it;
+	for (it = shaders.begin(); it != shaders.end(); ++it)
+		glDeleteShader(*it);
+
+	return true;
+}
+
+ShaderEffect::~ShaderEffect()
+{
+	unloadVolatile();
+}
+
+void ShaderEffect::unloadVolatile()
+{
+	if (_program != 0)
+		glDeleteProgram(_program);
+}
+
+std::string ShaderEffect::getGLSLVersion()
+{
+	// GL_SHADING_LANGUAGE_VERSION may not be available in OpenGL < 2.0.
+	const char *tmp = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
+	if (NULL == tmp)
+		return "0.0";
+
+	// the version string always begins with a version number of the format
+	//   major_number.minor_number
+	// or
+	//   major_number.minor_number.release_number
+	// we can keep release_number, since it does not affect the check below.
+	std::string versionString(tmp);
+	size_t minorEndPos = versionString.find(' ');
+	return versionString.substr(0, minorEndPos);
+}
+
+
+bool ShaderEffect::isSupported()
+{
+	return GLEE_VERSION_2_0 && getGLSLVersion() >= "1.2";
+}
+
+std::string ShaderEffect::getWarnings() const
+{
+	GLint strlen, nullpos;
+	glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &strlen);
+	char *temp_str = new char[strlen+1];
+	// be extra sure that the error string will be 0-terminated
+	memset(temp_str, '\0', strlen+1);
+	glGetProgramInfoLog(_program, strlen, &nullpos, temp_str);
+	temp_str[nullpos] = '\0';
+
+	std::string warnings(temp_str);
+	delete[] temp_str;
+	return warnings;
+}
+
+void ShaderEffect::attach()
+{
+	glUseProgram(_program);
+	current = this;
+}
+
+void ShaderEffect::detach()
+{
+	glUseProgram(0);
+	current = NULL;
+}
+
+void ShaderEffect::sendFloat(const std::string &name, int size, const GLfloat *vec, int count)
+{
+	TemporaryAttacher attacher(this);
+	GLint location = getUniformLocation(name);
+
+	if (size < 1 || size > 4)
+	{
+		throw love::Exception("Invalid variable size: %d (expected 1-4).", size);
+	}
+
+	switch (size)
+	{
+	case 4:
+		glUniform4fv(location, count, vec);
+		break;
+	case 3:
+		glUniform3fv(location, count, vec);
+		break;
+	case 2:
+		glUniform2fv(location, count, vec);
+		break;
+	case 1:
+	default:
+		glUniform1fv(location, count, vec);
+		break;
+	}
+
+	// throw error if needed
+	checkSetUniformError();
+}
+
+void ShaderEffect::sendMatrix(const std::string &name, int size, const GLfloat *m, int count)
+{
+	TemporaryAttacher attacher(this);
+	GLint location = getUniformLocation(name);
+
+	if (size < 2 || size > 4)
+	{
+		throw love::Exception("Invalid matrix size: %dx%d "
+							  "(can only set 2x2, 3x3 or 4x4 matrices).", size,size);
+	}
+
+	switch (size)
+	{
+	case 4:
+		glUniformMatrix4fv(location, count, GL_FALSE, m);
+		break;
+	case 3:
+		glUniformMatrix3fv(location, count, GL_FALSE, m);
+		break;
+	case 2:
+	default:
+		glUniformMatrix2fv(location, count, GL_FALSE, m);
+		break;
+	}
+
+	// throw error if needed
+	checkSetUniformError();
+}
+
+void ShaderEffect::sendImage(const std::string &name, const Image &image)
+{
+	GLint texture_unit = getTextureUnit(name);
+
+	TemporaryAttacher attacher(this);
+	GLint location = getUniformLocation(name);
+
+	glActiveTexture(GL_TEXTURE0 + texture_unit);
+	bindTexture(image.getTextureName(), true); // guarantee it gets bound
+	glUniform1i(location, texture_unit);
+
+	// reset texture unit
+	glActiveTexture(GL_TEXTURE0);
+
+	// throw error if needed
+	checkSetUniformError();
+}
+
+void ShaderEffect::sendCanvas(const std::string &name, const Canvas &canvas)
+{
+	GLint texture_unit = getTextureUnit(name);
+
+	TemporaryAttacher attacher(this);
+	GLint location = getUniformLocation(name);
+
+	glActiveTexture(GL_TEXTURE0 + texture_unit);
+	bindTexture(canvas.getTextureName(), true); // guarantee it gets bound
+	glUniform1i(location, texture_unit);
+
+	// reset texture unit
+	glActiveTexture(GL_TEXTURE0);
+
+	// throw error if needed
+	checkSetUniformError();
+}
+
+GLint ShaderEffect::getUniformLocation(const std::string &name)
+{
+	std::map<std::string, GLint>::const_iterator it = _uniforms.find(name);
+	if (it != _uniforms.end())
+		return it->second;
+
+	GLint location = glGetUniformLocation(_program, name.c_str());
+	if (location == -1)
+	{
+		throw love::Exception(
+			"Cannot get location of shader variable `%s'.\n"
+			"A common error is to define but not use the variable.", name.c_str());
+	}
+
+	_uniforms[name] = location;
+	return location;
+}
+
+void ShaderEffect::checkSetUniformError()
+{
+	GLenum error_code = glGetError();
+	if (GL_INVALID_OPERATION == error_code)
+	{
+		throw love::Exception(
+			"Invalid operation:\n"
+			"- Trying to send the wrong value type to shader variable, or\n"
+			"- Trying to send array values with wrong dimension, or\n"
+			"- Invalid variable name.");
+	}
+}
+
+} // opengl
+} // graphics
+} // love

src/modules/graphics/opengl/ShaderEffect.h

+/**
+ * Copyright (c) 2006-2012 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_GRAPHICS_EFFECT_H
+#define LOVE_GRAPHICS_EFFECT_H
+
+#include "common/Object.h"
+#include <string>
+#include <map>
+#include <vector>
+#include "OpenGL.h"
+#include "Image.h"
+#include "Canvas.h"
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+// A fragment shader
+class ShaderEffect : public Object, public Volatile
+{
+public:
+	ShaderEffect(const std::string &vertcode, const std::string &fragcode);
+	virtual ~ShaderEffect();
+	std::string getWarnings() const;
+
+	virtual bool loadVolatile();
+	virtual void unloadVolatile();
+
+	void attach();
+	static void detach();
+	static std::string getGLSLVersion();
+	static bool isSupported();
+
+	static ShaderEffect *current;
+
+	void sendFloat(const std::string &name, int size, const GLfloat *vec, int count);
+	void sendMatrix(const std::string &name, int size, const GLfloat *m, int count);
+	void sendImage(const std::string &name, const Image &image);
+	void sendCanvas(const std::string &name, const Canvas &canvas);
+
+private:
+	GLint getUniformLocation(const std::string &name);
+	void checkSetUniformError();
+	GLuint createShader(GLenum type, const std::string &code);
+	void createProgram(const std::vector<GLuint> &shaders);
+	
+	GLuint _program;
+	std::string _vertcode;
+	std::string _fragcode; // volatile and stuff
+
+	// uniform location buffer
+	std::map<std::string, GLint> _uniforms;
+
+	// texture unit pool for setting images
+	static std::map<std::string, GLint> _texture_unit_pool;
+	static GLint _current_texture_unit;
+	static GLint _max_texture_units;
+	static GLint getTextureUnit(const std::string &name);
+};
+
+} // opengl
+} // graphics
+} // love
+
+#endif // LOVE_GRAPHICS_EFFECT_H

src/modules/graphics/opengl/wrap_Graphics.cpp

 	return 1;
 }
 
-int w_newPixelEffect(lua_State *L)
+int w_newShaderEffect(lua_State *L)
 {
-	if (!PixelEffect::isSupported())
+	if (!ShaderEffect::isSupported())
 		return luaL_error(L, "Sorry, your graphics card does not support pixel effects.");
 
 	try
 	{
-		luaL_checkstring(L, 1);
+		// clamp stack to 2 elements
+		lua_settop(L, 2);
 
 		luax_getfunction(L, "graphics", "_effectCodeToGLSL");
+		
+		// push vertcode and fragcode strings to the top of the stack so they become arguments for the function
 		lua_pushvalue(L, 1);
-		lua_pcall(L, 1, 1, 0);
-
-		const char *code = lua_tostring(L, -1);
-		PixelEffect *effect = instance->newPixelEffect(code);
-		luax_newtype(L, "PixelEffect", GRAPHICS_PIXELEFFECT_T, (void *)effect);
+		lua_pushvalue(L, 2);
+		
+		// call effectCodeToGLSL
+		lua_pcall(L, 2, 2, 0);
+		
+		// get returned values from the top of the stack
+		const char *vertcode = luaL_optstring(L, -2, "");
+		const char *fragcode = luaL_optstring(L, -1, "");
+		
+		ShaderEffect *effect = instance->newShaderEffect(vertcode, fragcode);
+		luax_newtype(L, "ShaderEffect", GRAPHICS_SHADEREFFECT_T, (void *)effect);
 	}
 	catch(const love::Exception &e)
 	{
-		// memory is freed in Graphics::newPixelEffect
+		// memory is freed in Graphics::newShaderEffect
 		luax_getfunction(L, "graphics", "_transformGLSLErrorMessages");
 		lua_pushstring(L, e.what());
-		lua_pcall(L, 1,1, 0);
+		lua_pcall(L, 1, 1, 0);
 		const char *err = lua_tostring(L, -1);
 		return luaL_error(L, "%s", err);
 	}
 	return 1;
 }
 
-int w_setPixelEffect(lua_State *L)
+int w_setShaderEffect(lua_State *L)
 {
 	if (lua_isnoneornil(L,1))
 	{
-		PixelEffect::detach();
+		ShaderEffect::detach();
 		return 0;
 	}
 
-	PixelEffect *effect = luax_checkpixeleffect(L, 1);
+	ShaderEffect *effect = luax_checkshadereffect(L, 1);
 	effect->attach();
 	return 0;
 }
 
-int w_getPixelEffect(lua_State *L)
+int w_getShaderEffect(lua_State *L)
 {
-	PixelEffect *effect = PixelEffect::current;
+	ShaderEffect *effect = ShaderEffect::current;
 	if (effect)
 	{
 		effect->retain();
-		luax_newtype(L, "PixelEffect", GRAPHICS_PIXELEFFECT_T, (void *) effect);
+		luax_newtype(L, "ShaderEffect", GRAPHICS_SHADEREFFECT_T, (void *) effect);
 	}
 	else
 		lua_pushnil(L);
 			if (!Canvas::isHdrSupported())
 				supported = false;
 			break;
-		case Graphics::SUPPORT_PIXELEFFECT:
-			if (!PixelEffect::isSupported())
+		case Graphics::SUPPORT_SHADEREFFECT:
+			if (!ShaderEffect::isSupported())
 				supported = false;
 			break;
 		case Graphics::SUPPORT_NPOT:
 	{ "newSpriteBatch", w_newSpriteBatch },
 	{ "newParticleSystem", w_newParticleSystem },
 	{ "newCanvas", w_newCanvas },
-	{ "newPixelEffect", w_newPixelEffect },
+	{ "newShaderEffect", w_newShaderEffect },
 
 	{ "setColor", w_setColor },
 	{ "getColor", w_getColor },
 	{ "setCanvas", w_setCanvas },
 	{ "getCanvas", w_getCanvas },
 
-	{ "setPixelEffect", w_setPixelEffect },
-	{ "getPixelEffect", w_getPixelEffect },
+	{ "setShaderEffect", w_setShaderEffect },
+	{ "getShaderEffect", w_getShaderEffect },
 
 	{ "isSupported", w_isSupported },
 
 	luaopen_spritebatch,
 	luaopen_particlesystem,
 	luaopen_canvas,
-	luaopen_pixeleffect,
+	luaopen_shadereffect,
 	0
 };
 

src/modules/graphics/opengl/wrap_Graphics.h

 #include "wrap_SpriteBatch.h"
 #include "wrap_ParticleSystem.h"
 #include "wrap_Canvas.h"
-#include "wrap_PixelEffect.h"
+#include "wrap_ShaderEffect.h"
 #include "Graphics.h"
 
 namespace love
 int w_newSpriteBatch(lua_State *L);
 int w_newParticleSystem(lua_State *L);
 int w_newCanvas(lua_State *L);  // comments in function
-int w_newPixelEffect(lua_State *L);
+int w_newShaderEffect(lua_State *L);
 int w_setColor(lua_State *L);
 int w_getColor(lua_State *L);
 int w_setBackgroundColor(lua_State *L);
 int w_newScreenshot(lua_State *L);
 int w_setCanvas(lua_State *L);
 int w_getCanvas(lua_State *L);
-int w_setPixelEffect(lua_State *L);
+int w_setShaderEffect(lua_State *L);
+int w_getShaderEffect(lua_State *L);
 int w_isSupported(lua_State *L);
 int w_draw(lua_State *L);
 int w_drawq(lua_State *L);

src/modules/graphics/opengl/wrap_PixelEffect.cpp

-/**
- * Copyright (c) 2006-2012 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#include "wrap_PixelEffect.h"
-#include "wrap_Image.h"
-#include "wrap_Canvas.h"
-#include <string>
-#include <iostream>
-using namespace std;
-
-namespace love
-{
-namespace graphics
-{
-namespace opengl
-{
-
-PixelEffect *luax_checkpixeleffect(lua_State *L, int idx)
-{
-	return luax_checktype<PixelEffect>(L, idx, "PixelEffect", GRAPHICS_PIXELEFFECT_T);
-}
-
-int w_PixelEffect_getWarnings(lua_State *L)
-{
-	PixelEffect *effect = luax_checkpixeleffect(L, 1);
-	lua_pushstring(L, effect->getWarnings().c_str());
-	return 1;
-}
-
-static int _sendScalars(lua_State *L, PixelEffect *effect, const char *name, int count)
-{
-	float *values = new float[count];
-	for (int i = 0; i < count; ++i)
-	{
-		if (!lua_isnumber(L, 3 + i))
-		{
-			delete[] values;
-			return luaL_typerror(L, 3 + i, "number");
-		}
-		values[i] = (float)lua_tonumber(L, 3 + i);
-	}
-
-	try
-	{
-		effect->sendFloat(name, 1, values, count);
-	}
-	catch(love::Exception &e)
-	{
-		delete[] values;
-		return luaL_error(L, e.what());
-	}
-
-	delete[] values;
-	return 0;
-}
-
-static int _sendVectors(lua_State *L, PixelEffect *effect, const char *name, int count)
-{
-	size_t dimension = lua_objlen(L, 3);
-	float *values = new float[count * dimension];
-
-	for (int i = 0; i < count; ++i)
-	{
-		if (!lua_istable(L, 3 + i))
-		{
-			delete[] values;
-			return luaL_typerror(L, 3 + i, "table");
-		}
-		if (lua_objlen(L, 3 + i) != dimension)
-		{
-			delete[] values;
-			return luaL_error(L, "Error in argument %d: Expected table size %d, got %d.",
-							  3+i, dimension, lua_objlen(L, 3+i));
-		}
-
-		for (size_t k = 1; k <= dimension; ++k)
-		{
-			lua_rawgeti(L, 3 + i, k);
-			values[i * dimension + k - 1] = (float)lua_tonumber(L, -1);
-		}
-		lua_pop(L, int(dimension));
-	}
-
-	try
-	{
-		effect->sendFloat(name, dimension, values, count);
-	}
-	catch(love::Exception &e)
-	{
-		delete[] values;
-		return luaL_error(L, e.what());
-	}
-
-	delete[] values;
-	return 0;
-}
-
-int w_PixelEffect_sendFloat(lua_State *L)
-{
-	PixelEffect *effect = luax_checkpixeleffect(L, 1);
-	const char *name = luaL_checkstring(L, 2);
-	int count = lua_gettop(L) - 2;
-
-	if (count < 1)
-		return luaL_error(L, "No variable to send.");
-
-	if (lua_isnumber(L, 3))
-		return _sendScalars(L, effect, name, count);
-	else if (lua_istable(L, 3))
-		return _sendVectors(L, effect, name, count);
-
-	return luaL_typerror(L, 3, "number or table");
-}
-
-int w_PixelEffect_sendMatrix(lua_State *L)
-{
-	int count = lua_gettop(L) - 2;
-	PixelEffect *effect = luax_checkpixeleffect(L, 1);
-	const char *name = luaL_checkstring(L, 2);
-
-	if (!lua_istable(L, 3))
-		return luaL_typerror(L, 3, "matrix table");
-
-	lua_getfield(L, 3, "dimension");
-	int dimension = lua_tointeger(L, -1);
-	lua_pop(L, 1);
-
-	if (dimension < 2 || dimension > 4)
-		return luaL_error(L, "Invalid matrix size: %dx%d (only 2x2, 3x3 and 4x4 matrices are supported).",
-						  count, count);
-
-	float *values = new float[dimension * dimension * count];
-	for (int i = 0; i < count; ++i)
-	{
-		lua_getfield(L, 3+i, "dimension");
-		if (lua_tointeger(L, -1) != dimension)
-		{
-			// You unlock this door with the key of imagination. Beyond it is
-			// another dimension: a dimension of sound, a dimension of sight,
-			// a dimension of mind. You're moving into a land of both shadow
-			// and substance, of things and ideas. You've just crossed over
-			// into... the Twilight Zone.
-			int other_dimension = lua_tointeger(L, -1);
-			delete[] values;
-			return luaL_error(L, "Invalid matrix size at argument %d: Expected size %dx%d, got %dx%d.",
-							  3+i, dimension, dimension, other_dimension, other_dimension);
-		}
-
-		for (int k = 1; k <= dimension*dimension; ++k)
-		{
-			lua_rawgeti(L, 3+i, k);
-			values[i * dimension * dimension + k - 1] = (float)lua_tonumber(L, -1);
-		}
-
-		lua_pop(L, 1 + dimension);
-	}
-
-	try
-	{
-		effect->sendMatrix(name, dimension, values, count);
-	}
-	catch(love::Exception &e)
-	{
-		delete[] values;
-		return luaL_error(L, e.what());
-	}
-
-	delete[] values;
-	return 0;
-}
-
-int w_PixelEffect_sendImage(lua_State *L)
-{
-	PixelEffect *effect = luax_checkpixeleffect(L, 1);
-	const char *name = luaL_checkstring(L, 2);
-	Image *img = luax_checkimage(L, 3);
-
-	try
-	{
-		effect->sendImage(name, *img);
-	}
-	catch(love::Exception &e)
-	{
-		luaL_error(L, e.what());
-	}
-
-	return 0;
-}
-
-int w_PixelEffect_sendCanvas(lua_State *L)
-{
-	PixelEffect *effect = luax_checkpixeleffect(L, 1);
-	const char *name = luaL_checkstring(L, 2);
-	Canvas *canvas = luax_checkcanvas(L, 3);
-
-	try
-	{
-		effect->sendCanvas(name, *canvas);
-	}
-	catch(love::Exception &e)
-	{
-		luaL_error(L, e.what());
-	}
-
-	return 0;
-}
-
-
-static const luaL_Reg functions[] =
-{
-	{ "getWarnings", w_PixelEffect_getWarnings },
-	{ "sendFloat",   w_PixelEffect_sendFloat },
-	{ "sendMatrix",  w_PixelEffect_sendMatrix },
-	{ "sendImage",   w_PixelEffect_sendImage },
-	{ "sendCanvas",  w_PixelEffect_sendCanvas },
-	{ 0, 0 }
-};
-
-extern "C" int luaopen_pixeleffect(lua_State *L)
-{
-	return luax_register_type(L, "PixelEffect", functions);
-}
-
-} // opengl
-} // graphics
-} // love
-

src/modules/graphics/opengl/wrap_PixelEffect.h

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

src/modules/graphics/opengl/wrap_ShaderEffect.cpp

+/**
+ * Copyright (c) 2006-2012 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "wrap_ShaderEffect.h"
+#include "wrap_Image.h"
+#include "wrap_Canvas.h"
+#include <string>
+#include <iostream>
+using namespace std;
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+
+ShaderEffect *luax_checkshadereffect(lua_State *L, int idx)
+{
+	return luax_checktype<ShaderEffect>(L, idx, "ShaderEffect", GRAPHICS_SHADEREFFECT_T);
+}
+
+int w_ShaderEffect_getWarnings(lua_State *L)
+{
+	ShaderEffect *effect = luax_checkshadereffect(L, 1);
+	lua_pushstring(L, effect->getWarnings().c_str());
+	return 1;
+}
+
+static int _sendScalars(lua_State *L, ShaderEffect *effect, const char *name, int count)
+{
+	float *values = new float[count];
+	for (int i = 0; i < count; ++i)
+	{
+		if (!lua_isnumber(L, 3 + i))
+		{
+			delete[] values;
+			return luaL_typerror(L, 3 + i, "number");
+		}
+		values[i] = (float)lua_tonumber(L, 3 + i);
+	}
+
+	try
+	{
+		effect->sendFloat(name, 1, values, count);
+	}
+	catch(love::Exception &e)
+	{
+		delete[] values;
+		return luaL_error(L, e.what());
+	}
+
+	delete[] values;
+	return 0;
+}
+
+static int _sendVectors(lua_State *L, ShaderEffect *effect, const char *name, int count)
+{
+	size_t dimension = lua_objlen(L, 3);
+	float *values = new float[count * dimension];
+
+	for (int i = 0; i < count; ++i)
+	{
+		if (!lua_istable(L, 3 + i))
+		{
+			delete[] values;
+			return luaL_typerror(L, 3 + i, "table");
+		}
+		if (lua_objlen(L, 3 + i) != dimension)
+		{
+			delete[] values;
+			return luaL_error(L, "Error in argument %d: Expected table size %d, got %d.",
+							  3+i, dimension, lua_objlen(L, 3+i));
+		}
+
+		for (size_t k = 1; k <= dimension; ++k)
+		{
+			lua_rawgeti(L, 3 + i, k);
+			values[i * dimension + k - 1] = (float)lua_tonumber(L, -1);
+		}
+		lua_pop(L, int(dimension));
+	}
+
+	try
+	{
+		effect->sendFloat(name, dimension, values, count);
+	}
+	catch(love::Exception &e)
+	{
+		delete[] values;
+		return luaL_error(L, e.what());
+	}
+
+	delete[] values;
+	return 0;
+}
+
+int w_ShaderEffect_sendFloat(lua_State *L)
+{
+	ShaderEffect *effect = luax_checkshadereffect(L, 1);
+	const char *name = luaL_checkstring(L, 2);
+	int count = lua_gettop(L) - 2;
+
+	if (count < 1)
+		return luaL_error(L, "No variable to send.");
+
+	if (lua_isnumber(L, 3))
+		return _sendScalars(L, effect, name, count);
+	else if (lua_istable(L, 3))
+		return _sendVectors(L, effect, name, count);
+
+	return luaL_typerror(L, 3, "number or table");
+}
+
+int w_ShaderEffect_sendMatrix(lua_State *L)
+{
+	int count = lua_gettop(L) - 2;
+	ShaderEffect *effect = luax_checkshadereffect(L, 1);
+	const char *name = luaL_checkstring(L, 2);
+
+	if (!lua_istable(L, 3))
+		return luaL_typerror(L, 3, "matrix table");
+
+	lua_getfield(L, 3, "dimension");
+	int dimension = lua_tointeger(L, -1);
+	lua_pop(L, 1);
+
+	if (dimension < 2 || dimension > 4)
+		return luaL_error(L, "Invalid matrix size: %dx%d (only 2x2, 3x3 and 4x4 matrices are supported).",
+						  count, count);
+
+	float *values = new float[dimension * dimension * count];
+	for (int i = 0; i < count; ++i)
+	{
+		lua_getfield(L, 3+i, "dimension");
+		if (lua_tointeger(L, -1) != dimension)
+		{
+			// You unlock this door with the key of imagination. Beyond it is
+			// another dimension: a dimension of sound, a dimension of sight,
+			// a dimension of mind. You're moving into a land of both shadow
+			// and substance, of things and ideas. You've just crossed over
+			// into... the Twilight Zone.
+			int other_dimension = lua_tointeger(L, -1);
+			delete[] values;
+			return luaL_error(L, "Invalid matrix size at argument %d: Expected size %dx%d, got %dx%d.",
+							  3+i, dimension, dimension, other_dimension, other_dimension);
+		}
+
+		for (int k = 1; k <= dimension*dimension; ++k)
+		{
+			lua_rawgeti(L, 3+i, k);
+			values[i * dimension * dimension + k - 1] = (float)lua_tonumber(L, -1);
+		}
+
+		lua_pop(L, 1 + dimension);
+	}
+
+	try
+	{
+		effect->sendMatrix(name, dimension, values, count);
+	}
+	catch(love::Exception &e)
+	{
+		delete[] values;
+		return luaL_error(L, e.what());
+	}
+
+	delete[] values;
+	return 0;
+}
+
+int w_ShaderEffect_sendImage(lua_State *L)
+{
+	ShaderEffect *effect = luax_checkshadereffect(L, 1);
+	const char *name = luaL_checkstring(L, 2);
+	Image *img = luax_checkimage(L, 3);
+
+	try
+	{
+		effect->sendImage(name, *img);
+	}
+	catch(love::Exception &e)
+	{
+		luaL_error(L, e.what());
+	}
+
+	return 0;
+}
+
+int w_ShaderEffect_sendCanvas(lua_State *L)
+{
+	ShaderEffect *effect = luax_checkshadereffect(L, 1);
+	const char *name = luaL_checkstring(L, 2);
+	Canvas *canvas = luax_checkcanvas(L, 3);
+
+	try
+	{
+		effect->sendCanvas(name, *canvas);
+	}
+	catch(love::Exception &e)
+	{
+		luaL_error(L, e.what());
+	}
+
+	return 0;
+}
+
+
+static const luaL_Reg functions[] =
+{
+	{ "getWarnings", w_ShaderEffect_getWarnings },
+	{ "sendFloat",   w_ShaderEffect_sendFloat },
+	{ "sendMatrix",  w_ShaderEffect_sendMatrix },
+	{ "sendImage",   w_ShaderEffect_sendImage },
+	{ "sendCanvas",  w_ShaderEffect_sendCanvas },
+	{ 0, 0 }
+};
+
+extern "C" int luaopen_shadereffect(lua_State *L)
+{
+	return luax_register_type(L, "ShaderEffect", functions);
+}
+
+} // opengl
+} // graphics
+} // love
+

src/modules/graphics/opengl/wrap_ShaderEffect.h

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

src/scripts/boot.lua

 	end
 
 	love.graphics.setCanvas()
-	love.graphics.setPixelEffect()
+	love.graphics.setShaderEffect()
 
 	-- Load.
 	if love.audio then love.audio.stop() end

src/scripts/boot.lua.h

 	0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 
 	0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x28, 0x29, 0x0a,
 	0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 
-	0x50, 0x69, 0x78, 0x65, 0x6c, 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x28, 0x29, 0x0a,
+	0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x28, 0x29, 0x0a,
 	0x09, 0x2d, 0x2d, 0x20, 0x4c, 0x6f, 0x61, 0x64, 0x2e, 0x0a,
 	0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x74, 0x68, 0x65, 
 	0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x74, 0x6f, 0x70, 0x28, 

src/scripts/graphics.lua

 	end
 
 	-- PIXEL EFFECTS
-	local GLSL_HEADER_LINE_COUNT = 6
-	local GLSL_HEADER = [[#version 120