Bart van Strien avatar Bart van Strien committed 7c7332b Merge

Merge in default

Comments (0)

Files changed (50)

platform/macosx/love.xcodeproj/project.pbxproj

 
 /* Begin PBXBuildFile section */
 		8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
+		A5474CEF1624903B00C8EEAC /* math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5474CEE1624903B00C8EEAC /* math.cpp */; };
 		A901B882143B65C500D77063 /* DrawQable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A901B880143B65C400D77063 /* DrawQable.cpp */; };
 		A901B885143B661400D77063 /* Quad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A901B883143B661300D77063 /* Quad.cpp */; };
+		A911D2DB15DFECC8005B7EB8 /* Module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A911D2DA15DFECC8005B7EB8 /* Module.cpp */; };
+		A911D3C815DFF24D005B7EB8 /* Game_Music_Emu.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A911D3C715DFF24D005B7EB8 /* Game_Music_Emu.framework */; };
+		A911D3C915DFF25D005B7EB8 /* Game_Music_Emu.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A911D3C715DFF24D005B7EB8 /* Game_Music_Emu.framework */; };
 		A9255DD11043183600BA1496 /* FreeType.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E4810420B4A007D418B /* FreeType.framework */; };
 		A9255DD21043183600BA1496 /* SDL.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E5210420B57007D418B /* SDL.framework */; };
 		A9255DD31043183600BA1496 /* Lua.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E5310420B57007D418B /* Lua.framework */; };
 				A9255DD11043183600BA1496 /* FreeType.framework in Copy Frameworks */,
 				A9255DD21043183600BA1496 /* SDL.framework in Copy Frameworks */,
 				A9255DD31043183600BA1496 /* Lua.framework in Copy Frameworks */,
+				A911D3C915DFF25D005B7EB8 /* Game_Music_Emu.framework in Copy Frameworks */,
 			);
 			name = "Copy Frameworks";
 			runOnlyForDeploymentPostprocessing = 0;
 /* Begin PBXFileReference section */
 		1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
 		8D1107320486CEB800E47090 /* love.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = love.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		A5474CEE1624903B00C8EEAC /* math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = math.cpp; sourceTree = "<group>"; };
 		A901B880143B65C400D77063 /* DrawQable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DrawQable.cpp; sourceTree = "<group>"; };
 		A901B881143B65C400D77063 /* DrawQable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DrawQable.h; sourceTree = "<group>"; };
 		A901B883143B661300D77063 /* Quad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Quad.cpp; sourceTree = "<group>"; };
 		A901B884143B661300D77063 /* Quad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Quad.h; sourceTree = "<group>"; };
+		A911D2DA15DFECC8005B7EB8 /* Module.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Module.cpp; sourceTree = "<group>"; };
+		A911D3C715DFF24D005B7EB8 /* Game_Music_Emu.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Game_Music_Emu.framework; path = /Library/Frameworks/Game_Music_Emu.framework; sourceTree = "<absolute>"; };
 		A9255DEA1043188D00BA1496 /* SDLMain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLMain.m; sourceTree = "<group>"; };
 		A9255DEB1043188D00BA1496 /* SDLMain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLMain.h; sourceTree = "<group>"; };
 		A9255E021043195A00BA1496 /* Vorbis.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Vorbis.framework; path = /Library/Frameworks/Vorbis.framework; sourceTree = "<absolute>"; };
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				A9255F461043247300BA1496 /* IL.framework in Frameworks */,
-				A9255EE810431BD000BA1496 /* Vorbis.framework in Frameworks */,
 				8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
 				A93E6E4910420B4A007D418B /* OpenAL.framework in Frameworks */,
 				A93E6E4A10420B4A007D418B /* OpenGL.framework in Frameworks */,
+				A9255F461043247300BA1496 /* IL.framework in Frameworks */,
+				A9255EE810431BD000BA1496 /* Vorbis.framework in Frameworks */,
 				A93E6E4B10420B4A007D418B /* FreeType.framework in Frameworks */,
 				A93E6E5410420B57007D418B /* SDL.framework in Frameworks */,
 				A93E6E5510420B57007D418B /* Lua.framework in Frameworks */,
 				A9D307EA106635C3004FEDF8 /* physfs.framework in Frameworks */,
 				A9F16927109E7BAD00FC83D1 /* libmodplug.framework in Frameworks */,
 				A9F169A7109E824900FC83D1 /* mpg123.framework in Frameworks */,
+				A911D3C815DFF24D005B7EB8 /* Game_Music_Emu.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				A911D3C715DFF24D005B7EB8 /* Game_Music_Emu.framework */,
 				A9F169A6109E824900FC83D1 /* mpg123.framework */,
 				A9F16926109E7BAD00FC83D1 /* libmodplug.framework */,
 				A9D307E9106635C3004FEDF8 /* physfs.framework */,
 				A93E69E010420ABF007D418B /* Exception.cpp */,
 				A93E69E110420ABF007D418B /* Exception.h */,
 				A9A5BE4C14A2D2D000D9931C /* int.h */,
+				A5474CEE1624903B00C8EEAC /* math.cpp */,
 				A93E69E210420ABF007D418B /* math.h */,
 				A93E69E310420ABF007D418B /* Matrix.cpp */,
 				A93E69E410420ABF007D418B /* Matrix.h */,
 				A9D5C47C142E32ED0044ECF7 /* Memoizer.cpp */,
 				A9D5C47B142E31350044ECF7 /* Memoizer.h */,
+				A911D2DA15DFECC8005B7EB8 /* Module.cpp */,
 				A93E69E710420ABF007D418B /* Module.h */,
 				A93E69E810420ABF007D418B /* Object.cpp */,
 				A93E69E910420ABF007D418B /* Object.h */,
 				A9642D7514D1A66000CE0B02 /* OpenGL.cpp in Sources */,
 				A9F6E6AE15A1080D00C86200 /* love.cpp in Sources */,
 				A9F6E6B115A1099C00C86200 /* GmeDecoder.cpp in Sources */,
+				A911D2DB15DFECC8005B7EB8 /* Module.cpp in Sources */,
+				A5474CEF1624903B00C8EEAC /* math.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 				GCC_PREFIX_HEADER = love_Prefix.pch;
 				INSTALL_PATH = "$(HOME)/Applications";
+				OTHER_CFLAGS = "-DLOVE_SUPPORT_GME=1";
 				PRODUCT_NAME = love;
 			};
 			name = Debug;
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 				GCC_PREFIX_HEADER = love_Prefix.pch;
 				INSTALL_PATH = "$(HOME)/Applications";
+				OTHER_CFLAGS = "-DLOVE_SUPPORT_GME=1";
 				PRODUCT_NAME = love;
 			};
 			name = Release;

platform/msvc2010/liblove.vcxproj

     <ClCompile Include="..\..\src\common\b64.cpp" />
     <ClCompile Include="..\..\src\common\delay.cpp" />
     <ClCompile Include="..\..\src\common\Exception.cpp" />
+    <ClCompile Include="..\..\src\common\math.cpp" />
     <ClCompile Include="..\..\src\common\Matrix.cpp" />
     <ClCompile Include="..\..\src\common\Memoizer.cpp" />
+    <ClCompile Include="..\..\src\common\Module.cpp" />
     <ClCompile Include="..\..\src\common\Object.cpp" />
     <ClCompile Include="..\..\src\common\Reference.cpp" />
     <ClCompile Include="..\..\src\common\runtime.cpp" />

platform/msvc2010/liblove.vcxproj.filters

     <ClCompile Include="..\..\src\modules\love\love.cpp">
       <Filter>modules\love</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\common\Module.cpp">
+      <Filter>common</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\common\math.cpp">
+      <Filter>common</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="..\..\src\scripts\boot.lua">

platform/msvc2010/love.sln

 
 Microsoft Visual Studio Solution File, Format Version 11.00
 # Visual C++ Express 2010
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "love", "love.vcxproj", "{0078B97A-F6DB-E014-BED9-BE378D93CEA4}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "love", "love.vcxproj", "{B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}"
 	ProjectSection(ProjectDependencies) = postProject
 		{A3FCC735-3E18-4D6B-9DA9-01D9E910B7F8} = {A3FCC735-3E18-4D6B-9DA9-01D9E910B7F8}
 	EndProjectSection
 		Release Static|x64 = Release Static|x64
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Debug Dynamic|Win32.ActiveCfg = Debug Dynamic|Win32
-		{0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Debug Dynamic|Win32.Build.0 = Debug Dynamic|Win32
-		{0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Debug Dynamic|x64.ActiveCfg = Debug Dynamic|x64
-		{0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Dynamic|Win32.ActiveCfg = Release Dynamic|Win32
-		{0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Dynamic|Win32.Build.0 = Release Dynamic|Win32
-		{0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Dynamic|x64.ActiveCfg = Release Dynamic|x64
-		{0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Dynamic|x64.Build.0 = Release Dynamic|x64
-		{0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Static|Win32.ActiveCfg = Release Static|Win32
-		{0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Static|Win32.Build.0 = Release Static|Win32
-		{0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Static|x64.ActiveCfg = Release Static|x64
-		{0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Static|x64.Build.0 = Release Static|x64
+		{B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Debug Dynamic|Win32.ActiveCfg = Debug Dynamic|Win32
+		{B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Debug Dynamic|Win32.Build.0 = Debug Dynamic|Win32
+		{B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Debug Dynamic|x64.ActiveCfg = Debug Dynamic|x64
+		{B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Dynamic|Win32.ActiveCfg = Release Dynamic|Win32
+		{B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Dynamic|Win32.Build.0 = Release Dynamic|Win32
+		{B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Dynamic|x64.ActiveCfg = Release Dynamic|x64
+		{B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Dynamic|x64.Build.0 = Release Dynamic|x64
+		{B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Static|Win32.ActiveCfg = Release Static|Win32
+		{B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Static|Win32.Build.0 = Release Static|Win32
+		{B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Static|x64.ActiveCfg = Release Static|x64
+		{B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Static|x64.Build.0 = Release Static|x64
 		{A3FCC735-3E18-4D6B-9DA9-01D9E910B7F8}.Debug Dynamic|Win32.ActiveCfg = Debug Dynamic|Win32
 		{A3FCC735-3E18-4D6B-9DA9-01D9E910B7F8}.Debug Dynamic|Win32.Build.0 = Debug Dynamic|Win32
 		{A3FCC735-3E18-4D6B-9DA9-01D9E910B7F8}.Debug Dynamic|x64.ActiveCfg = Debug Dynamic|x64

platform/msvc2010/love.vcxproj

       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
       <Optimization>Disabled</Optimization>
-      <AdditionalIncludeDirectories>include\SDL;..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>include;include\SDL;..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>
       </MultiProcessorCompilation>
       <MinimalRebuild>false</MinimalRebuild>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
       <Optimization>Disabled</Optimization>
-      <AdditionalIncludeDirectories>include\SDL;..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>include;include\SDL;..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>
       </MultiProcessorCompilation>
       <MinimalRebuild>false</MinimalRebuild>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <WarningLevel>Level1</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
-      <AdditionalIncludeDirectories>include\SDL;..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>include;include\SDL;..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <OmitFramePointers>true</OmitFramePointers>
       <StringPooling>true</StringPooling>
       <BufferSecurityCheck>false</BufferSecurityCheck>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <WarningLevel>Level1</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
-      <AdditionalIncludeDirectories>include\SDL;..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>include;include\SDL;..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <OmitFramePointers>true</OmitFramePointers>
       <StringPooling>true</StringPooling>
       <BufferSecurityCheck>false</BufferSecurityCheck>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release Static|Win32'">
     <ClCompile>
-      <AdditionalIncludeDirectories>include\SDL;..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>include;include\SDL;..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <OmitFramePointers>true</OmitFramePointers>
       <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <StringPooling>true</StringPooling>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release Static|x64'">
     <ClCompile>
-      <AdditionalIncludeDirectories>include\SDL;..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>include;include\SDL;..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <OmitFramePointers>true</OmitFramePointers>
       <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <StringPooling>true</StringPooling>

platform/unix/automagic

 [[ -x ${AUTOMAKE} ]]   || die "Could not find automake."
 
 automagic() {
-	cp platform/unix/configure.in .
+	cp platform/unix/configure.ac .
 	cp platform/unix/Makefile.am .
 
 	if ! sh platform/unix/gen-makefile; then

platform/unix/configure.ac

+AC_INIT([love], [HEAD])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_AUX_DIR([platform/unix])
+AC_CONFIG_MACRO_DIR([platform/unix/m4])
+AC_CONFIG_SRCDIR([src/love.cpp])
+AM_INIT_AUTOMAKE([foreign -Wall foreign tar-ustar silent-rules])
+AM_SILENT_RULES
+AC_PREFIX_DEFAULT([/usr])
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+AC_PROG_LIBTOOL
+AC_PROG_CC
+AC_PROG_CXX
+AC_C_BIGENDIAN
+AC_SEARCH_LIBS([sqrt], [m], [], AC_MSG_ERROR([Can't LÖVE without C math library]))
+AC_SEARCH_LIBS([SDL_Init], [SDL], [], AC_MSG_ERROR([Can't LÖVE without SDL]))
+AC_SEARCH_LIBS([glLoadIdentity], [GL], [], AC_MSG_ERROR([Can't LÖVE without OpenGL]))
+#AC_SEARCH_LIBS([gluOrtho2D], [GLU], [], AC_MSG_ERROR([Can't LÖVE without OpenGL Utility Library]))
+AC_SEARCH_LIBS([alSourcePlay], [openal], [], AC_MSG_ERROR([Can't LÖVE without OpenAL]))
+lua=lua
+AC_ARG_WITH([luajit],
+	    [AS_HELP_STRING([--with-luajit], [Use LuaJIT instead of lua and llvm-lua])],
+	    [lua=luajit],
+	    [])
+AC_ARG_WITH([llvm-lua],
+	    [AS_HELP_STRING([--with-llvm-lua], [Use llvm-lua instead of lua and LuaJIT])],
+	    [lua=llvm-lua],
+	    [])
+
+AS_IF([test "$lua" = "lua"],
+	AC_SEARCH_LIBS(
+		[lua_pcall],
+		[lua lua5.1],
+		if test "$ac_cv_search_lua_pcall" = "-llua5.1"; then
+			AC_SUBST([INCLUDE_LUA], [-I/usr/include/lua5.1])
+		fi,
+		AC_MSG_ERROR([Can't LÖVE without Lua])
+	)
+      )
+AS_IF([test "$lua" = "luajit"],
+	AC_SEARCH_LIBS(
+		[lua_pcall],
+		[luajit luajit-5.1],
+		AC_SUBST([INCLUDE_LUA], [-I/usr/include/luajit-2.0]),
+		AC_MSG_ERROR([Can't LÖVE without LuaJIT])
+	)
+      )
+AS_IF([test "$lua" = "llvm-lua"],
+	AC_SEARCH_LIBS(
+		[lua_pcall],
+		[llvm-lua],
+		[],
+		AC_MSG_ERROR([Can't LÖVE without llvm-lua])
+	)
+      )
+
+AC_SEARCH_LIBS([ilInit], [IL], [], AC_MSG_ERROR([Can't LÖVE without DevIL]))
+AC_SEARCH_LIBS([FT_Load_Glyph], [freetype], [], AC_MSG_ERROR([Can't LÖVE without FreeType]))
+AC_SEARCH_LIBS([PHYSFS_init], [physfs], [], AC_MSG_ERROR([Can't LÖVE without PhysicsFS]))
+AC_SEARCH_LIBS([ModPlug_Load], [modplug], [], AC_MSG_ERROR([Can't LÖVE without ModPlug]))
+AC_SEARCH_LIBS([ov_open], [vorbisfile], [], AC_MSG_ERROR([Can't LÖVE without VorbisFile]))
+
+AC_ARG_ENABLE([mpg123], AC_HELP_STRING([--disable-mpg123], [Disable mp3 support, for patent-free builds]), [], [enable_mpg123=yes])
+AS_IF([test "x$enable_mpg123" != xno],
+	AC_SEARCH_LIBS([mpg123_open_feed], [mpg123], [], AC_MSG_ERROR([Can't LÖVE without Mpg123])),
+	AC_DEFINE([LOVE_NOMPG123], [], [Build without mpg123]))
+AS_IF([test "x$enable_mpg123" != xno],
+	AC_SEARCH_LIBS([mpg123_seek_64], [mpg123], AC_SUBST([FILE_OFFSET],[-D_FILE_OFFSET_BITS=64]), AC_SUBST([FILE_OFFSET],[])))
+
+AC_ARG_ENABLE([exe], AC_HELP_STRING([--disable-exe], [Disable building of executable launcher]), [], [enable_exe=yes])
+AS_IF([test "x$enable_exe" != xno],
+	  AC_DEFINE([LOVE_BUILD_EXE], [], [Don't build launcher]))
+AM_CONDITIONAL([LOVE_BUILD_EXE], [test "x$enable_exe" != xno])
+
+AC_ARG_ENABLE([gme], AC_HELP_STRING([--enable-gme], [Enable GME support, for more chiptuney goodness]), [], [enable_gme=no])
+AS_IF([test "x$enable_gme" == xyes],
+	  AC_SEARCH_LIBS([gme_open_data], [gme], [], AC_MSG_ERROR([Can't LÖVE without gme])))
+AS_IF([test "x$enable_gme" == xyes],
+	  AC_DEFINE([LOVE_SUPPORT_GME], [], [Enable gme]))
+
+AC_CONFIG_FILES([
+	Makefile
+	src/Makefile
+])
+AC_OUTPUT

platform/unix/configure.in

-AC_INIT([love], [HEAD])
-AC_CONFIG_HEADERS([config.h])
-AC_CONFIG_AUX_DIR([platform/unix])
-AC_CONFIG_MACRO_DIR([platform/unix/m4])
-AC_CONFIG_SRCDIR([src/love.cpp])
-AM_INIT_AUTOMAKE([foreign -Wall foreign tar-ustar silent-rules])
-AM_SILENT_RULES
-AC_PREFIX_DEFAULT([/usr])
-AM_PROG_AR
-AC_PROG_LIBTOOL
-AC_PROG_CC
-AC_PROG_CXX
-AC_C_BIGENDIAN
-AC_SEARCH_LIBS([sqrt], [m], [], AC_MSG_ERROR([Can't LÖVE without C math library]))
-AC_SEARCH_LIBS([SDL_Init], [SDL], [], AC_MSG_ERROR([Can't LÖVE without SDL]))
-AC_SEARCH_LIBS([glLoadIdentity], [GL], [], AC_MSG_ERROR([Can't LÖVE without OpenGL]))
-#AC_SEARCH_LIBS([gluOrtho2D], [GLU], [], AC_MSG_ERROR([Can't LÖVE without OpenGL Utility Library]))
-AC_SEARCH_LIBS([alSourcePlay], [openal], [], AC_MSG_ERROR([Can't LÖVE without OpenAL]))
-lua=lua
-AC_ARG_WITH([luajit],
-	    [AS_HELP_STRING([--with-luajit], [Use LuaJIT instead of lua and llvm-lua])],
-	    [lua=luajit],
-	    [])
-AC_ARG_WITH([llvm-lua],
-	    [AS_HELP_STRING([--with-llvm-lua], [Use llvm-lua instead of lua and LuaJIT])],
-	    [lua=llvm-lua],
-	    [])
-
-AS_IF([test "$lua" = "lua"],
-	AC_SEARCH_LIBS(
-		[lua_pcall],
-		[lua lua5.1],
-		if test "$ac_cv_search_lua_pcall" = "-llua5.1"; then
-			AC_SUBST([INCLUDE_LUA], [-I/usr/include/lua5.1])
-		fi,
-		AC_MSG_ERROR([Can't LÖVE without Lua])
-	)
-      )
-AS_IF([test "$lua" = "luajit"],
-	AC_SEARCH_LIBS(
-		[lua_pcall],
-		[luajit luajit-5.1],
-		AC_SUBST([INCLUDE_LUA], [-I/usr/include/luajit-2.0]),
-		AC_MSG_ERROR([Can't LÖVE without LuaJIT])
-	)
-      )
-AS_IF([test "$lua" = "llvm-lua"],
-	AC_SEARCH_LIBS(
-		[lua_pcall],
-		[llvm-lua],
-		[],
-		AC_MSG_ERROR([Can't LÖVE without llvm-lua])
-	)
-      )
-
-AC_SEARCH_LIBS([ilInit], [IL], [], AC_MSG_ERROR([Can't LÖVE without DevIL]))
-AC_SEARCH_LIBS([FT_Load_Glyph], [freetype], [], AC_MSG_ERROR([Can't LÖVE without FreeType]))
-AC_SEARCH_LIBS([PHYSFS_init], [physfs], [], AC_MSG_ERROR([Can't LÖVE without PhysicsFS]))
-AC_SEARCH_LIBS([ModPlug_Load], [modplug], [], AC_MSG_ERROR([Can't LÖVE without ModPlug]))
-AC_SEARCH_LIBS([ov_open], [vorbisfile], [], AC_MSG_ERROR([Can't LÖVE without VorbisFile]))
-
-AC_ARG_ENABLE([mpg123], AC_HELP_STRING([--disable-mpg123], [Disable mp3 support, for patent-free builds]), [], [enable_mpg123=yes])
-AS_IF([test "x$enable_mpg123" != xno],
-	AC_SEARCH_LIBS([mpg123_open_feed], [mpg123], [], AC_MSG_ERROR([Can't LÖVE without Mpg123])),
-	AC_DEFINE([LOVE_NOMPG123], [], [Build without mpg123]))
-AS_IF([test "x$enable_mpg123" != xno],
-	AC_SEARCH_LIBS([mpg123_seek_64], [mpg123], AC_SUBST([FILE_OFFSET],[-D_FILE_OFFSET_BITS=64]), AC_SUBST([FILE_OFFSET],[])))
-
-AC_ARG_ENABLE([exe], AC_HELP_STRING([--disable-exe], [Disable building of executable launcher]), [], [enable_exe=yes])
-AS_IF([test "x$enable_exe" != xno],
-	  AC_DEFINE([LOVE_BUILD_EXE], [], [Don't build launcher]))
-AM_CONDITIONAL([LOVE_BUILD_EXE], [test "x$enable_exe" != xno])
-
-AC_ARG_ENABLE([gme], AC_HELP_STRING([--enable-gme], [Enable GME support, for more chiptuney goodness]), [], [enable_gme=no])
-AS_IF([test "x$enable_gme" == xyes],
-	  AC_SEARCH_LIBS([gme_open_data], [gme], [], AC_MSG_ERROR([Can't LÖVE without gme])))
-AS_IF([test "x$enable_gme" == xyes],
-	  AC_DEFINE([LOVE_SUPPORT_GME], [], [Enable gme]))
-
-AC_CONFIG_FILES([
-	Makefile
-	src/Makefile
-])
-AC_OUTPUT

src/common/Module.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.
+ **/
+
+// LOVE
+#include "Module.h"
+#include "Exception.h"
+
+// std
+#include <map>
+#include <utility>
+#include <string>
+
+namespace
+{
+	std::map<std::string, love::Module*> registry;
+} // anonymous namespace
+
+namespace love
+{
+	void Module::registerInstance(Module *instance)
+	{
+		if (instance == NULL)
+			throw Exception("Module instance is NULL");
+
+		std::string name(instance->getName());
+
+		std::map<std::string, Module*>::iterator it = registry.find(name);
+
+		if (registry.end() != it)
+		{
+			if (it->second == instance)
+				return;
+			throw Exception("Module %s already registered!", instance->getName());
+		}
+
+		registry.insert(make_pair(name, instance));
+	}
+
+	Module *Module::getInstance(const char *name)
+	{
+		std::map<std::string, Module*>::iterator it = registry.find(std::string(name));
+
+		if (registry.end() == it)
+			return NULL;
+
+		return it->second;
+	}
+} // namespace love

src/common/Module.h

 	 **/
 	virtual const char *getName() const = 0;
 
+	/**
+	 * Add module to internal registry. To be used /only/ in
+	 * runtime.cpp:luax_register_module()
+	 * @param instance The module instance.
+	 */
+	static void registerInstance(Module *instance);
+
+	/**
+	 * Retrieve module instance from internal registry. May return NULL
+	 * if module not registered.
+	 * @param name The full name of the module.
+	 * @returns Module instance of NULL if the module is not registered.
+	 */
+	static Module *getInstance(const char *name);
+
 }; // Module
 
 } // love

src/common/math.cpp

+#include "math.h"
+#include <limits>
+#include <cmath>
+
+namespace
+{
+	// The Box–Muller transform generates two random numbers, one of which we
+	// cache here. A value of +infinity is used to signal the cache is invalid
+	// and that new numbers have to be generated.
+	float last_randnormal = std::numeric_limits<float>::infinity();
+}
+
+namespace love
+{
+
+float random_normal(float o)
+{
+	// number in cache?
+	if (last_randnormal != std::numeric_limits<float>::infinity())
+	{
+		float r = last_randnormal;
+		last_randnormal = std::numeric_limits<float>::infinity();
+		return r * o;
+	}
+
+	// else: generate numbers using the Box-Muller transform
+	float a = sqrt(-2.0f * log(random()));
+	float b = float(LOVE_M_PI) * 2.0f * random();
+	last_randnormal = a * cos(b);
+	return a * sin(b) * o;
+}
+
+} // namespace love

src/common/math.h

 #define LOVE_MATH_H
 
 #include <climits> // for CHAR_BIT
+#include <cstdlib> // for rand() and RAND_MAX
 
 /* Definitions of useful mathematical constants
  * M_E        - e
 	return static_cast<float>(next_p2(static_cast<int>(x)));
 }
 
+/**
+ * Draws a random number from a uniform distribution.
+ * @returns Uniformly distributed random number in [0:1).
+ */
+inline float random()
+{
+	// to satisfy picky compilers...
+	return float(double(rand() % RAND_MAX) / double(RAND_MAX));
+}
+
+/**
+ * Draws a random number from a uniform distribution.
+ * @return Uniformly distributed random number in [0:max).
+ */
+inline float random(float max)
+{
+	return random() * max;
+}
+
+/**
+ * Draws a random number from a uniform distribution.
+ * @return Uniformly distributed random number in [min:max).
+ */
+inline float random(float min, float max)
+{
+	return random(max - min) + min;
+}
+
+/**
+ * Draws a random number from a normal/gaussian distribution.
+ * @param o Standard deviation of the distribution.
+ * @returns Normal distributed random number with mean 0 and variance o^2.
+ */
+float random_normal(float o = 1.);
+#define random_gaussian random_normal
+
 } // love
 
 #endif // LOVE_MATH_H

src/common/runtime.cpp

 	lua_setfield(L, -3, m.name); // love.graphics = table
 	lua_remove(L, -2); // love
 
+	// Register module instance
+	Module::registerInstance(m.module);
+
 	return 1;
 }
 

src/modules/event/sdl/Event.cpp

 	switch (e.type)
 	{
 	case SDL_KEYDOWN:
-		if (keys.find(e.key.keysym.sym, key) && love::event::Event::keys.find(key, txt))
-		{
-			arg1 = new Variant(txt, strlen(txt));
-			arg2 = new Variant((double) e.key.keysym.unicode);
-			msg = new Message("keypressed", arg1, arg2);
-			arg1->release();
-			arg2->release();
-		}
+		if (!keys.find(e.key.keysym.sym, key))
+			key = love::keyboard::Keyboard::KEY_UNKNOWN;
+		if (!love::event::Event::keys.find(key, txt))
+			txt = "unknown";
+		arg1 = new Variant(txt, strlen(txt));
+		arg2 = new Variant((double) e.key.keysym.unicode);
+		msg = new Message("keypressed", arg1, arg2);
+		arg1->release();
+		arg2->release();
 		break;
 	case SDL_KEYUP:
-		if (keys.find(e.key.keysym.sym, key) && love::event::Event::keys.find(key, txt))
-		{
-			arg1 = new Variant(txt, strlen(txt));
-			msg = new Message("keyreleased", arg1);
-			arg1->release();
-		}
+		if (!keys.find(e.key.keysym.sym, key))
+			key = love::keyboard::Keyboard::KEY_UNKNOWN;
+		if (!love::event::Event::keys.find(key, txt))
+			txt = "unknown";
+		arg1 = new Variant(txt, strlen(txt));
+		msg = new Message("keyreleased", arg1);
+		arg1->release();
 		break;
 	case SDL_MOUSEBUTTONDOWN:
 	case SDL_MOUSEBUTTONUP:

src/modules/filesystem/File.h

 #include "common/Object.h"
 #include "common/StringMap.h"
 #include "common/int.h"
+#include "FileData.h"
 
 namespace love
 {
 	 * @param size The number of bytes to attempt reading, or -1 for EOF.
 	 * @return A newly allocated Data object.
 	 **/
-	virtual Data *read(int64 size = ALL) = 0;
+	virtual FileData *read(int64 size = ALL) = 0;
 
 	/**
 	 * Reads data into the destination buffer.

src/modules/filesystem/physfs/File.cpp

 }
 
 
-Data *File::read(int64 size)
+FileData *File::read(int64 size)
 {
 	bool isOpen = (file != 0);
 

src/modules/filesystem/physfs/File.h

 	bool open(Mode mode);
 	bool close();
 	int64 getSize();
-	Data *read(int64 size = ALL);
+	FileData *read(int64 size = ALL);
 	int64 read(void *dst, int64 size);
 	bool write(const void *data, int64 size);
 	bool write(const Data *data, int64 size = ALL);

src/modules/font/ImageRasterizer.cpp

 		widths[c] = (end - start);
 	}
 
+	// Find spacing of last glyph
+	if (length > 0)
+	{
+		start = end;
+		while (start < imgw && equal(pixels[start], spacer))
+			++start;
+
+		spacing[glyphs[length - 1]] = (start > end) ? (start - end) : 0;
+	}
+
 	// Replace spacer color with an empty pixel
 	for (unsigned int i = 0; i < imgs; ++i)
 	{

src/modules/graphics/Graphics.cpp

 StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::supportEntries[] =
 {
 	{ "canvas", Graphics::SUPPORT_CANVAS },
+	{ "hdrcanvas", Graphics::SUPPORT_HDR_CANVAS },
 	{ "pixeleffect", Graphics::SUPPORT_PIXELEFFECT },
 	{ "npot", Graphics::SUPPORT_NPOT },
 	{ "subtractive", Graphics::SUPPORT_SUBTRACTIVE },

src/modules/graphics/Graphics.h

 	enum Support
 	{
 		SUPPORT_CANVAS = 1,
+		SUPPORT_HDR_CANVAS,
 		SUPPORT_PIXELEFFECT,
 		SUPPORT_NPOT,
 		SUPPORT_SUBTRACTIVE,

src/modules/graphics/Quad.h

 	virtual void flip(bool x, bool y) = 0;
 
 	/**
-	 * Mirror texture coordinates around 0.5
-	 */
-	virtual void mirror(bool x, bool y) = 0;
-
-	/**
 	 * Gets a pointer to the vertices.
 	 **/
 	virtual const vertex *getVertices() const = 0;

src/modules/graphics/opengl/Canvas.cpp

 	 * @param[out] img           Texture name
 	 * @param[in]  width         Width of framebuffer
 	 * @param[in]  height        Height of framebuffer
+	 * @param[in]  texture_type  Type of the canvas texture.
 	 * @return Creation status
 	 */
-	virtual GLenum createFBO(GLuint &, GLuint &, GLuint &, int, int)
+	virtual GLenum createFBO(GLuint &, GLuint &, GLuint &, int, int, Canvas::TextureType)
 	{
 		return GL_FRAMEBUFFER_UNSUPPORTED;
 	}
 
 struct FramebufferStrategyGL3 : public FramebufferStrategy
 {
-	virtual GLenum createFBO(GLuint &framebuffer, GLuint &depth_stencil,  GLuint &img, int width, int height)
+	virtual GLenum createFBO(GLuint &framebuffer, GLuint &depth_stencil,  GLuint &img, int width, int height, Canvas::TextureType texture_type)
 	{
 		// get currently bound fbo to reset to it later
 		GLint current_fbo;
 		glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil);
 		glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height);
 		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
-								  GL_RENDERBUFFER, depth_stencil);
+			GL_RENDERBUFFER, depth_stencil);
 		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-								  GL_RENDERBUFFER, depth_stencil);
+			GL_RENDERBUFFER, depth_stencil);
 
 		// generate texture save target
+		GLint internalFormat;
+		GLenum format;
+		switch (texture_type)
+		{
+			case Canvas::TYPE_HDR:
+				internalFormat = GL_RGBA16F;
+				format = GL_FLOAT;
+				break;
+			case Canvas::TYPE_NORMAL:
+			default:
+				internalFormat = GL_RGBA8;
+				format = GL_UNSIGNED_BYTE;
+		}
+
 		glGenTextures(1, &img);
 		bindTexture(img);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height,
-					 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+		glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height,
+			0, GL_RGBA, format, NULL);
 		bindTexture(0);
 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-							   GL_TEXTURE_2D, img, 0);
+			GL_TEXTURE_2D, img, 0);
 
 		// check status
 		GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 
 		// unbind framebuffer
 		glBindRenderbuffer(GL_RENDERBUFFER, 0);
-		glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)current_fbo);
+		glBindFramebuffer(GL_FRAMEBUFFER, (GLuint) current_fbo);
 		return status;
 	}
 	virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil,  GLuint img)
 	}
 };
 
-struct FramebufferStrategyEXT : public FramebufferStrategy
+struct FramebufferStrategyPackedEXT : public FramebufferStrategy
 {
-
-	virtual GLenum createFBO(GLuint &framebuffer, GLuint &depth_stencil, GLuint &img, int width, int height)
+	virtual GLenum createFBO(GLuint &framebuffer, GLuint &depth_stencil, GLuint &img, int width, int height, Canvas::TextureType texture_type)
 	{
 		GLint current_fbo;
 		glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &current_fbo);
 		// create stencil buffer
 		glGenRenderbuffersEXT(1, &depth_stencil);
 		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil);
-		glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, width, height);
+		glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT,
+			width, height);
 		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
-									 GL_RENDERBUFFER_EXT, depth_stencil);
+			GL_RENDERBUFFER_EXT, depth_stencil);
 		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
-									 GL_RENDERBUFFER_EXT, depth_stencil);
+			GL_RENDERBUFFER_EXT, depth_stencil);
 
 		// generate texture save target
+		GLint internalFormat;
+		GLenum format;
+		switch (texture_type)
+		{
+			case Canvas::TYPE_HDR:
+				internalFormat = GL_RGBA16F;
+				format = GL_FLOAT;
+				break;
+			case Canvas::TYPE_NORMAL:
+			default:
+				internalFormat = GL_RGBA8;
+				format = GL_UNSIGNED_BYTE;
+		}
+
 		glGenTextures(1, &img);
 		bindTexture(img);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height,
-					 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+		glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height,
+			0, GL_RGBA, format, NULL);
 		bindTexture(0);
 		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-								  GL_TEXTURE_2D, img, 0);
+			GL_TEXTURE_2D, img, 0);
 
 		// check status
 		GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
 
 		// unbind framebuffer
 		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
-		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint)current_fbo);
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint) current_fbo);
 		return status;
 	}
 
 	}
 };
 
+struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT
+{
+	virtual GLenum createFBO(GLuint &framebuffer, GLuint &stencil, GLuint &img, int width, int height, Canvas::TextureType texture_type)
+	{
+		GLint current_fbo;
+		glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &current_fbo);
+
+		// create framebuffer
+		glGenFramebuffersEXT(1, &framebuffer);
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer);
+
+		// create stencil buffer
+		glGenRenderbuffersEXT(1, &stencil);
+		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil);
+		glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX,
+			width, height);
+		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
+			GL_RENDERBUFFER_EXT, stencil);
+
+		// generate texture save target
+		GLint internalFormat;
+		GLenum format;
+		switch (texture_type)
+		{
+			case Canvas::TYPE_HDR:
+				internalFormat = GL_RGBA16F;
+				format = GL_FLOAT;
+				break;
+			case Canvas::TYPE_NORMAL:
+			default:
+				internalFormat = GL_RGBA8;
+				format = GL_UNSIGNED_BYTE;
+		}
+
+		glGenTextures(1, &img);
+		bindTexture(img);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height,
+			0, GL_RGBA, format, NULL);
+		bindTexture(0);
+		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+			GL_TEXTURE_2D, img, 0);
+
+		// check status
+		GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+
+		// unbind framebuffer
+		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint) current_fbo);
+		return status;
+	}
+
+	bool isSupported()
+	{
+		GLuint fb, stencil, img;
+		GLenum status = createFBO(fb, stencil, img, 2, 2, Canvas::TYPE_NORMAL);
+		deleteFBO(fb, stencil, img);
+		return status == GL_FRAMEBUFFER_COMPLETE;
+	}
+};
+
 FramebufferStrategy *strategy = NULL;
 
 FramebufferStrategy strategyNone;
 
 FramebufferStrategyGL3 strategyGL3;
 
+FramebufferStrategyPackedEXT strategyPackedEXT;
+
 FramebufferStrategyEXT strategyEXT;
 
 Canvas *Canvas::current = NULL;
 
-static void loadStrategy()
+static void getStrategy()
 {
 	if (!strategy)
 	{
 		if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object)
 			strategy = &strategyGL3;
 		else if (GLEE_EXT_framebuffer_object && GLEE_EXT_packed_depth_stencil)
+			strategy = &strategyPackedEXT;
+		else if (GLEE_EXT_framebuffer_object && strategyEXT.isSupported())
 			strategy = &strategyEXT;
 		else
 			strategy = &strategyNone;
 	}
 }
 
-Canvas::Canvas(int width, int height)
+Canvas::Canvas(int width, int height, TextureType texture_type)
 	: width(width)
 	, height(height)
+	, texture_type(texture_type)
 {
 	float w = static_cast<float>(width);
 	float h = static_cast<float>(height);
 
 	// world coordinates
 	vertices[0].x = 0;
-	vertices[0].y = 0;
+	vertices[0].y = h;
 	vertices[1].x = 0;
-	vertices[1].y = h;
+	vertices[1].y = 0;
 	vertices[2].x = w;
-	vertices[2].y = h;
+	vertices[2].y = 0;
 	vertices[3].x = w;
-	vertices[3].y = 0;
+	vertices[3].y = h;
 
 	// texture coordinates
 	vertices[0].s = 0;
 	vertices[3].s = 1;
 	vertices[3].t = 1;
 
-	loadStrategy();
+	getStrategy();
 
 	loadVolatile();
 }
 
 bool Canvas::isSupported()
 {
-	loadStrategy();
+	getStrategy();
 	return (strategy != &strategyNone);
 }
 
+bool Canvas::isHdrSupported()
+{
+	return GLEE_VERSION_3_0 || GLEE_ARB_texture_float;
+}
+
 void Canvas::bindDefaultCanvas()
 {
 	if (current != NULL)
 	glLoadIdentity();
 
 	// Set up orthographic view (no depth)
-	glOrtho(0.0, width, height, 0.0, -1.0, 1.0);
+	glOrtho(0.0, width, 0.0, height, -1.0, 1.0);
 
 	// Switch back to modelview matrix
 	glMatrixMode(GL_MODELVIEW);
 void Canvas::drawq(love::graphics::Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
 {
 	static Matrix t;
-	quad->mirror(false, true);
 	const vertex *v = quad->getVertices();
 
 	t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
 	drawv(t, v);
-	quad->mirror(false, true);
 }
 
 love::image::ImageData *Canvas::getImageData(love::image::Image *image)
 	int row = 4 * width;
 	int size = row * height;
 	GLubyte *pixels = new GLubyte[size];
-	GLubyte *screenshot = new GLubyte[size];
 
 	strategy->bindFBO(fbo);
 	glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 	else
 		strategy->bindFBO(0);
 
-	GLubyte *src = pixels - row;  // second line of source image
-	GLubyte *dst = screenshot + size;  // last row of destination image
+	love::image::ImageData *img = image->newImageData(width, height, (void *)pixels);
 
-	for (int i = 0; i < height; ++i)
-		memcpy(dst -= row, src += row, row);
-
-	love::image::ImageData *img = image->newImageData(width, height, (void *)screenshot);
-
-	delete[] screenshot;
 	delete[] pixels;
 
 	return img;
 
 bool Canvas::loadVolatile()
 {
-	status = strategy->createFBO(fbo, depth_stencil, img, width, height);
+	status = strategy->createFBO(fbo, depth_stencil, img, width, height, texture_type);
 	if (status != GL_FRAMEBUFFER_COMPLETE)
 		return false;
 
 	glPopMatrix();
 }
 
+bool Canvas::getConstant(const char *in, Canvas::TextureType &out)
+{
+	return textureTypes.find(in, out);
+}
+
+bool Canvas::getConstant(Canvas::TextureType in, const char *&out)
+{
+	return textureTypes.find(in, out);
+}
+
+StringMap<Canvas::TextureType, Canvas::TYPE_MAX_ENUM>::Entry Canvas::textureTypeEntries[] =
+{
+	{"normal", Canvas::TYPE_NORMAL},
+	{"hdr",    Canvas::TYPE_HDR},
+};
+StringMap<Canvas::TextureType, Canvas::TYPE_MAX_ENUM> Canvas::textureTypes(Canvas::textureTypeEntries, sizeof(Canvas::textureTypeEntries));
+
 } // opengl
 } // graphics
 } // love

src/modules/graphics/opengl/Canvas.h

 class Canvas : public DrawQable, public Volatile
 {
 public:
-	Canvas(int width, int height);
+	enum TextureType {
+		TYPE_NORMAL,
+		TYPE_HDR,
+		TYPE_MAX_ENUM
+	};
+
+	Canvas(int width, int height, TextureType texture_type = TYPE_NORMAL);
 	virtual ~Canvas();
 
-	static bool isSupported();
-
-	unsigned int getStatus() const
-	{
-		return status;
-	}
-
-	static Canvas *current;
-	static void bindDefaultCanvas();
-
 	void startGrab();
 	void stopGrab();
 
 	int getWidth();
 	int getHeight();
 
+	unsigned int getStatus() const
+	{
+		return status;
+	}
+
+	TextureType getTextureType() const
+	{
+		return texture_type;
+	}
+
 	bool loadVolatile();
 	void unloadVolatile();
 
+	static bool isSupported();
+	static bool isHdrSupported();
+	static bool getConstant(const char *in, TextureType &out);
+	static bool getConstant(TextureType in, const char *&out);
+
+	static Canvas *current;
+	static void bindDefaultCanvas();
+
 private:
 	friend class PixelEffect;
 	GLuint getTextureName() const
 	GLuint depth_stencil;
 	GLuint img;
 
+	TextureType texture_type;
+
 	vertex vertices[4];
 
 	GLenum status;
 	struct
 	{
 		Image::Filter filter;
-		Image::Wrap wrap;
+		Image::Wrap   wrap;
 	} settings;
 
 	void drawv(const Matrix &t, const vertex *v) const;
+
+	static StringMap<TextureType, TYPE_MAX_ENUM>::Entry textureTypeEntries[];
+	static StringMap<TextureType, TYPE_MAX_ENUM> textureTypes;
 };
 
 } // opengl

src/modules/graphics/opengl/Graphics.cpp

 	return new ParticleSystem(image, size);
 }
 
-Canvas *Graphics::newCanvas(int width, int height)
+Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_type)
 {
-	Canvas *canvas = new Canvas(width, height);
+	if (texture_type == Canvas::TYPE_HDR && !Canvas::isHdrSupported())
+		throw Exception("HDR Canvases are not supported by your OpenGL implementation");
+
+	while (GL_NO_ERROR != glGetError())
+		/* clear opengl error flag */;
+
+	Canvas *canvas = new Canvas(width, height, texture_type);
 	GLenum err = canvas->getStatus();
 
 	// everything ok, return canvas (early out)
 	if (mode == BLEND_ALPHA)
 		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 	else if (mode == BLEND_MULTIPLICATIVE)
-		glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
+		glBlendFunc(GL_DST_COLOR, GL_ZERO);
 	else if (mode == BLEND_PREMULTIPLIED)
 		glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
 	else // mode == BLEND_ADDITIVE || mode == BLEND_SUBTRACTIVE
 		return BLEND_ADDITIVE;
 	else if (src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA)  // && equation == GL_FUNC_ADD
 		return BLEND_ALPHA;
-	else if (src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA)  // && equation == GL_FUNC_ADD
+	else if (src == GL_DST_COLOR && dst == GL_ZERO)  // && equation == GL_FUNC_ADD
 		return BLEND_MULTIPLICATIVE;
 	else if (src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA)  // && equation == GL_FUNC_ADD
 		return BLEND_PREMULTIPLIED;

src/modules/graphics/opengl/Graphics.h

 
 	ParticleSystem *newParticleSystem(Image *image, int size);
 
-	Canvas *newCanvas(int width, int height);
+	Canvas *newCanvas(int width, int height, Canvas::TextureType texture_type = Canvas::TYPE_NORMAL);
 
 	PixelEffect *newPixelEffect(const std::string &code);
 

src/modules/graphics/opengl/ParticleSystem.cpp

 {
 	float low = inner - (outer/2.0f)*var;
 	float high = inner + (outer/2.0f)*var;
-	float r = (rand() / (float(RAND_MAX)+1));
+	float r = random();
 	return low*(1-r)+high*r;
 }
 
+StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM>::Entry ParticleSystem::distributionsEntries[] = {
+	{ "none",     ParticleSystem::DISTRIBUTION_NONE },
+	{ "uniform",  ParticleSystem::DISTRIBUTION_UNIFORM },
+	{ "normal",   ParticleSystem::DISTRIBUTION_NORMAL },
+};
+
+StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM> ParticleSystem::distributions(ParticleSystem::distributionsEntries, sizeof(ParticleSystem::distributionsEntries));
+
 
 ParticleSystem::ParticleSystem(Image *sprite, unsigned int buffer)
 	: pStart(0)
 	, active(true)
 	, emissionRate(0)
 	, emitCounter(0)
+	, areaSpreadDistribution(DISTRIBUTION_NONE)
 	, lifetime(-1)
 	, life(0)
 	, particleLifeMin(0)
 	if (min == max)
 		pLast->life = min;
 	else
-		pLast->life = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
+		pLast->life = random(min, max);
 	pLast->lifetime = pLast->life;
 
 	pLast->position[0] = position.getX();
 	pLast->position[1] = position.getY();
 
+	switch (areaSpreadDistribution)
+	{
+		case DISTRIBUTION_UNIFORM:
+			pLast->position[0] += random(-areaSpread.getX(), areaSpread.getX());
+			pLast->position[1] += random(-areaSpread.getY(), areaSpread.getY());
+			break;
+		case DISTRIBUTION_NORMAL:
+			pLast->position[0] += random_normal(areaSpread.getX());
+			pLast->position[1] += random_normal(areaSpread.getY());
+			break;
+		case DISTRIBUTION_NONE:
+		default:
+			break;
+	}
+
 	min = direction - spread/2.0f;
 	max = direction + spread/2.0f;
-	pLast->direction = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
+	pLast->direction = random(min, max);
 
 	pLast->origin = position;
 
 	min = speedMin;
 	max = speedMax;
-	float speed = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
+	float speed = random(min, max);
 	pLast->speed = love::Vector(cos(pLast->direction), sin(pLast->direction));
 	pLast->speed *= speed;
 
 	min = gravityMin;
 	max = gravityMax;
-	pLast->gravity = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
+	pLast->gravity = random(min, max);
 
 	min = radialAccelerationMin;
 	max = radialAccelerationMax;
-	pLast->radialAcceleration = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
+	pLast->radialAcceleration = random(min, max);
 
 	min = tangentialAccelerationMin;
 	max = tangentialAccelerationMax;
-	pLast->tangentialAcceleration = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
+	pLast->tangentialAcceleration = random(min, max);
 
-	pLast->sizeOffset       = (rand() / (float(RAND_MAX)+1)) * sizeVariation; // time offset for size change
-	pLast->sizeIntervalSize = (1.0f - (rand() / (float(RAND_MAX)+1)) * sizeVariation) - pLast->sizeOffset;
+	pLast->sizeOffset       = random(sizeVariation); // time offset for size change
+	pLast->sizeIntervalSize = (1.0f - random(sizeVariation)) - pLast->sizeOffset;
 	pLast->size = sizes[(size_t)(pLast->sizeOffset - .5f) * (sizes.size() - 1)];
 
 	min = rotationMin;
 	max = rotationMax;
 	pLast->spinStart = calculate_variation(spinStart, spinEnd, spinVariation);
 	pLast->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation);
-	pLast->rotation = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;;
+	pLast->rotation = random(min, max);
 
 	pLast->color = colors[0];
 
 	position = love::Vector(x, y);
 }
 
+
+void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x, float y)
+{
+	areaSpread = love::Vector(x, y);
+	areaSpreadDistribution = distribution;
+}
+
 void ParticleSystem::setDirection(float direction)
 {
 	this->direction = direction;
 	return position;
 }
 
+ParticleSystem::AreaSpreadDistribution ParticleSystem::getAreaSpreadDistribution() const
+{
+	return areaSpreadDistribution;
+}
+
+const love::Vector &ParticleSystem::getAreaSpreadParameters() const
+{
+	return areaSpread;
+}
+
 float ParticleSystem::getDirection() const
 {
 	return direction;
 	} // while
 }
 
+bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out)
+{
+	return distributions.find(in, out);
+}
+
+bool ParticleSystem::getConstant(AreaSpreadDistribution in, const char *&out)
+{
+	return distributions.find(in, out);
+}
+
 } // opengl
 } // graphics
 } // love

src/modules/graphics/opengl/ParticleSystem.h

 class ParticleSystem : public Drawable
 {
 public:
+	/**
+	 * Type of distribution new particles are drawn from: None, uniform, normal.
+	 */
+	enum AreaSpreadDistribution
+	{
+		DISTRIBUTION_NONE,
+		DISTRIBUTION_UNIFORM,
+		DISTRIBUTION_NORMAL,
+		DISTRIBUTION_MAX_ENUM,
+	};
 
 	/**
 	 * Creates a particle system with the specified buffersize and sprite.
 	void setPosition(float x, float y);
 
 	/**
+	 * Sets the emission area spread parameters and distribution type. The interpretation of
+	 * the parameters depends on the distribution type:
+	 *
+	 * * None:    Parameters are ignored. No area spread.
+	 * * Uniform: Parameters denote maximal (symmetric) displacement from emitter position.
+	 * * Normal:  Parameters denote the standard deviation in x and y direction. x and y are assumed to be uncorrelated.
+	 * @param x First parameter. Interpretation depends on distribution type.
+	 * @param y Second parameter. Interpretation depends on distribution type.
+	 * @param distribution Distribution type
+	 * */
+	void setAreaSpread(AreaSpreadDistribution distribution, float x, float y);
+
+	/**
 	 * Sets the direction and the spread of the particle emitter.
 	 * @param direction The direction (in degrees).
 	 **/
 	const love::Vector &getPosition() const;
 
 	/**
+	 * Returns area spread distribution type.
+	 */
+	AreaSpreadDistribution getAreaSpreadDistribution() const;
+
+	/**
+	 * Returns area spread parameters.
+	 */
+	const love::Vector &getAreaSpreadParameters() const;
+
+	/**
 	 * Returns the direction of the emitter (in degrees).
 	 **/
 	float getDirection() const;
 	 * @param dt Time since last update.
 	 **/
 	void update(float dt);
+
+	static bool getConstant(const char *in, AreaSpreadDistribution &out);
+	static bool getConstant(AreaSpreadDistribution in, const char *&out);
 protected:
 
 	// The max amount of particles.
 	// The relative position of the particle emitter.
 	love::Vector position;
 
+	// Emission area spread.
+	AreaSpreadDistribution areaSpreadDistribution;
+	love::Vector areaSpread;
+
 	// The lifetime of the particle emitter (-1 means infinite) and the life it has left.
 	float lifetime;
 	float life;
 
 	void add();
 	void remove(particle *p);
+
+	static StringMap<AreaSpreadDistribution, DISTRIBUTION_MAX_ENUM>::Entry distributionsEntries[];
+	static StringMap<AreaSpreadDistribution, DISTRIBUTION_MAX_ENUM> distributions;
 };
 
 } // opengl

src/modules/graphics/opengl/PixelEffect.cpp

 
 #include "PixelEffect.h"
 #include "GLee.h"
+#include "Graphics.h"
 
 namespace
 {
 	}
 
 	glDeleteShader(shader);
+
 	return true;
 }
 
 
 std::string PixelEffect::getGLSLVersion()
 {
-	// GL_SHADING_LANGUAGE_VERSION is not available in OpenGL < 2.1.
-	// Be very pessimistic about the GLSL version in that case.
-	if (!GLEE_VERSION_2_1)
+	// 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
-	std::string versionString((const char *)glGetString(GL_SHADING_LANGUAGE_VERSION));
-	size_t minorEndPos = versionString.find(" ");
+	// 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 && GLEE_ARB_shader_objects && GLEE_ARB_fragment_shader && getGLSLVersion() >= "1.2";
+	return GLEE_VERSION_2_0 && getGLSLVersion() >= "1.2";
 }
 
 std::string PixelEffect::getWarnings() const

src/modules/graphics/opengl/Quad.cpp

 	}
 }
 
-void Quad::mirror(bool x, bool y)
-{
-	for (size_t i = 0; i < NUM_VERTICES; ++i)
-	{
-		if (x)
-			vertices[i].s = 1.0f - vertices[i].s;
-		if (y)
-			vertices[i].t = 1.0f - vertices[i].t;
-	}
-}
-
 const vertex *Quad::getVertices() const
 {
 	return vertices;

src/modules/graphics/opengl/Quad.h

 	Viewport getViewport() const;
 
 	void flip(bool x, bool y);
-	void mirror(bool x, bool y);
 
 	/**
 	 * Gets a pointer to the vertices.

src/modules/graphics/opengl/wrap_Canvas.cpp

 	return 1;
 }
 
+int w_Canvas_getType(lua_State *L)
+{
+	Canvas *canvas = luax_checkcanvas(L, 1);
+	Canvas::TextureType type = canvas->getTextureType();
+	const char *str;
+	Canvas::getConstant(type, str);
+	lua_pushstring(L, str);
+	return 1;
+}
+
 static const luaL_Reg functions[] =
 {
 	{ "renderTo", w_Canvas_renderTo },
 	{ "clear", w_Canvas_clear },
 	{ "getWidth", w_Canvas_getWidth },
 	{ "getHeight", w_Canvas_getHeight },
+	{ "getType", w_Canvas_getType },
 	{ 0, 0 }
 };
 

src/modules/graphics/opengl/wrap_Canvas.h

 int w_Canvas_clear(lua_State *L);
 int w_Canvas_getWidth(lua_State *L);
 int w_Canvas_getHeight(lua_State *L);
+int w_Canvas_getType(lua_State *L);
 extern "C" int luaopen_canvas(lua_State *L);
 
 } // opengl

src/modules/graphics/opengl/wrap_Graphics.cpp

 	Image::Filter img_filter;
 	bool setFilter = false;
 
+	// For the filter modes..
+	int startIndex = 2;
+
 	// Convert to ImageData if necessary.
 	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || (luax_istype(L, 1, DATA_T) && !luax_istype(L, 1, IMAGE_IMAGE_DATA_T)))
 		luax_convobj(L, 1, "image", "newImageData");
 	{
 		int idxs[] = {1, 2};
 		luax_convobj(L, idxs, 2, "font", "newRasterizer");
+		startIndex = 3; // There's a glyphs args in there, move up
 	}
 
 	love::font::Rasterizer *rasterizer = luax_checktype<love::font::Rasterizer>(L, 1, "Rasterizer", FONT_RASTERIZER_T);
 
-	if (lua_isstring(L, 2) && lua_isstring(L, 3))
+	if (lua_isstring(L, startIndex) && lua_isstring(L, startIndex+1))
 	{
 		Image::FilterMode min;
 		Image::FilterMode mag;
-		const char *minstr = luaL_checkstring(L, 2);
-		const char *magstr = luaL_checkstring(L, 3);
+		const char *minstr = luaL_checkstring(L, startIndex);
+		const char *magstr = luaL_checkstring(L, startIndex+1);
 		if (!Image::getConstant(minstr, min))
 			return luaL_error(L, "Invalid filter mode: %s", minstr);
 		if (!Image::getConstant(magstr, mag))
 int w_newCanvas(lua_State *L)
 {
 	// check if width and height are given. else default to screen dimensions.
-	int width  = luaL_optint(L, 1, instance->getWidth());
-	int height = luaL_optint(L, 2, instance->getHeight());
-	glGetError(); // clear opengl error flag
+	int width       = luaL_optint(L, 1, instance->getWidth());
+	int height      = luaL_optint(L, 2, instance->getHeight());
+	const char *str = luaL_optstring(L, 3, "normal");
+
+	Canvas::TextureType texture_type;
+	if (!Canvas::getConstant(str, texture_type))
+		return luaL_error(L, "Invalid canvas type: %s", str);
 
 	Canvas *canvas = NULL;
 	try
 	{
-		canvas = instance->newCanvas(width, height);
+		canvas = instance->newCanvas(width, height, texture_type);
 	}
 	catch(Exception &e)
 	{
 			if (!Canvas::isSupported())
 				supported = false;
 			break;
+		case Graphics::SUPPORT_HDR_CANVAS:
+			if (!Canvas::isHdrSupported())
+				supported = false;
+			break;
 		case Graphics::SUPPORT_PIXELEFFECT:
 			if (!PixelEffect::isSupported())
 				supported = false;

src/modules/graphics/opengl/wrap_ParticleSystem.cpp

 	return 0;
 }
 
+int w_ParticleSystem_setAreaSpread(lua_State *L)
+{
+	ParticleSystem *t = luax_checkparticlesystem(L, 1);
+
+	ParticleSystem::AreaSpreadDistribution distribution;
+	const char *str = luaL_checkstring(L, 2);
+	if (!ParticleSystem::getConstant(str, distribution))
+		return luaL_error(L, "Invalid distribution: '%s'", str);
+
+	float x = (float)luaL_checknumber(L, 3);
+	float y = (float)luaL_checknumber(L, 4);
+	if (x < 0.0f || y < 0.0f)
+		return luaL_error(L, "Invalid area spread parameters (must be >= 0)");
+
+	t->setAreaSpread(distribution, x, y);
+	return 0;
+}
+
 int w_ParticleSystem_setDirection(lua_State *L)
 {
 	ParticleSystem *t = luax_checkparticlesystem(L, 1);
 	return 2;
 }
 
+int w_ParticleSystem_getAreaSpread(lua_State *L)
+{
+	ParticleSystem *t = luax_checkparticlesystem(L, 1);
+	ParticleSystem::AreaSpreadDistribution distribution = t-> getAreaSpreadDistribution();
+	const char *str;
+	ParticleSystem::getConstant(distribution, str);
+	const love::Vector &p = t->getAreaSpreadParameters();
+
+	lua_pushstring(L, str);
+	lua_pushnumber(L, p.x);
+	lua_pushnumber(L, p.y);
+
+	return 3;
+}
+
 int w_ParticleSystem_getDirection(lua_State *L)
 {
 	ParticleSystem *t = luax_checkparticlesystem(L, 1);
 	{ "setLifetime", w_ParticleSystem_setLifetime },
 	{ "setParticleLife", w_ParticleSystem_setParticleLife },
 	{ "setPosition", w_ParticleSystem_setPosition },
+	{ "setAreaSpread", w_ParticleSystem_setAreaSpread },
 	{ "setDirection", w_ParticleSystem_setDirection },
 	{ "setSpread", w_ParticleSystem_setSpread },
 	{ "setRelativeDirection", w_ParticleSystem_setRelativeDirection },
 	{ "getX", w_ParticleSystem_getX },
 	{ "getY", w_ParticleSystem_getY },
 	{ "getPosition", w_ParticleSystem_getPosition },
+	{ "getAreaSpread", w_ParticleSystem_getAreaSpread },
 	{ "getDirection", w_ParticleSystem_getDirection },
 	{ "getSpread", w_ParticleSystem_getSpread },
 	{ "getOffsetX", w_ParticleSystem_getOffsetX },

src/modules/graphics/opengl/wrap_SpriteBatch.cpp

 int w_SpriteBatch_setColor(lua_State *L)
 {
 	SpriteBatch *t = luax_checkspritebatch(L, 1);
+	Color c;
 
 	if (lua_gettop(L) <= 1)
+	{
 		t->setColor();
+		return 0;
+	}
+	else if (lua_istable(L, 2))
+	{
+		lua_rawgeti(L, 2, 1);
+		c.r = (unsigned char) luaL_checkint(L, -1);
+		lua_pop(L, 1);
+		lua_rawgeti(L, 2, 2);
+		c.g = (unsigned char) luaL_checkint(L, -1);
+		lua_pop(L, 1);
+		lua_rawgeti(L, 2, 3);
+		c.b = (unsigned char) luaL_checkint(L, -1);
+		lua_pop(L, 1);
+		lua_rawgeti(L, 2, 4);
+		c.a = (unsigned char) luaL_optint(L, -1, 255);
+		lua_pop(L, 1);
+	}
 	else
 	{
-		Color c;
 		c.r = (unsigned char)luaL_checkint(L, 2);
 		c.g = (unsigned char)luaL_checkint(L, 3);
 		c.b = (unsigned char)luaL_checkint(L, 4);
 		c.a = (unsigned char)luaL_optint(L, 5, 255);
-		t->setColor(c);
 	}
 
+	t->setColor(c);
+
 	return 0;
 }
 

src/modules/physics/box2d/Contact.cpp

 
 Contact::~Contact()
 {
-	Memoizer::remove(contact);
+	invalidate();
+}
+
+void Contact::invalidate()
+{
+	if (contact != NULL)
+	{
+		Memoizer::remove(contact);
+		contact = NULL;
+	}
+}
+
+bool Contact::isValid()
+{
+	return contact != NULL ? true : false;
 }
 
 int Contact::getPositions(lua_State *L)

src/modules/physics/box2d/Contact.h

 	virtual ~Contact();
 
 	/**
+	 * Removes the b2Contact pointer from Memoizer and sets it
+	 * to null on the Contact.
+	 **/
+	void invalidate();
+
+	/**
+	 * Returns if the Contact still points to a valid b2Contact.
+	 * @return True if the contact is still valid or false if it has been destroyed.
+	 **/
+	bool isValid();
+
+	/**
 	 * Gets the position of each point of contact.
 	 * @return The position along the x-axis.
 	 * @return The position along the y-axis.

src/modules/physics/box2d/World.cpp

 				throw love::Exception("A fixture has escaped Memoizer!");
 		}
 
-		Contact *c = new Contact(contact);
+		Contact *cobj = (Contact *)Memoizer::find(contact);
+		if (!cobj)
+			cobj = new Contact(contact);
+		else
+			cobj->retain();
 
-		luax_newtype(L, "Contact", (PHYSICS_CONTACT_T), (void *)c);
+		luax_newtype(L, "Contact", (PHYSICS_CONTACT_T), (void *)cobj);
 
 		int args = 3;
 		if (impulse)
 	a->getFilterData(filterA);
 	b->getFilterData(filterB);
 
-	if (filterA[2] != 0 &&  // 0 is the default group, so this does not count
-			filterA[2] == filterB[2]) // if they are in the same group
+	if (filterA[2] != 0 && // 0 is the default group, so this does not count
+		filterA[2] == filterB[2]) // if they are in the same group
 		return filterA[2] > 0; // Negative indexes mean you don't collide
 
 	if ((filterA[1] & filterB[0]) == 0 ||
-			(filterB[1] & filterA[0]) == 0)
+		(filterB[1] & filterA[0]) == 0)
 		return false; // A and B aren't set to collide
 
 	if (ref != 0)
 void World::EndContact(b2Contact *contact)
 {
 	end.process(contact);
+
+	// Letting the Contact know that the b2Contact will be destroyed any second.
+	Contact *c = (Contact *)Memoizer::find(contact);
+	if (c != NULL)
+		c->invalidate();
 }
 
 void World::PreSolve(b2Contact *contact, const b2Manifold *oldManifold)
 	case 4:
 		if (postsolve.ref)
 			delete postsolve.ref;
-		postsolve.ref = luax_refif (L, LUA_TFUNCTION);
+		postsolve.ref = luax_refif(L, LUA_TFUNCTION);
 	case 3:
 		if (presolve.ref)
 			delete presolve.ref;
-		presolve.ref = luax_refif (L, LUA_TFUNCTION);
+		presolve.ref = luax_refif(L, LUA_TFUNCTION);
 	case 2:
 		if (end.ref)
 			delete end.ref;
-		end.ref = luax_refif (L, LUA_TFUNCTION);
+		end.ref = luax_refif(L, LUA_TFUNCTION);
 	case 1:
 		if (begin.ref)
 			delete begin.ref;
-		begin.ref = luax_refif (L, LUA_TFUNCTION);
+		begin.ref = luax_refif(L, LUA_TFUNCTION);
 	}
 
 	return 0;
 	luax_assert_argc(L, 1);
 	if (filter.ref)
 		delete filter.ref;
-	filter.ref = luax_refif (L, LUA_TFUNCTION);
+	filter.ref = luax_refif(L, LUA_TFUNCTION);
 	return 0;
 }
 
 	{
 		if (!c) break;
 		Contact *contact = (Contact *)Memoizer::find(c);
-		if (!contact) throw love::Exception("A contact has escaped Memoizer!");
-		contact->retain();
+		if (!contact)
+			contact = new Contact(c);
+		else
+			contact->retain();
 		luax_newtype(L, "Contact", PHYSICS_CONTACT_T, (void *)contact);
 		lua_rawseti(L, -2, i);
 		i++;
 	box.lowerBound = Physics::scaleDown(b2Vec2(lx, ly));
 	box.upperBound = Physics::scaleDown(b2Vec2(ux, uy));
 	if (query.ref) delete query.ref;
-	query.ref = luax_refif (L, LUA_TFUNCTION);
+	query.ref = luax_refif(L, LUA_TFUNCTION);
 	world->QueryAABB(&query, box);
 	return 0;
 }
 	b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2));
 	if (raycast.ref)
 		delete raycast.ref;
-	raycast.ref = luax_refif (L, LUA_TFUNCTION);
+	raycast.ref = luax_refif(L, LUA_TFUNCTION);
 	world->RayCast(&raycast, v1, v2);
 	return 0;
 }

src/modules/physics/box2d/wrap_Contact.cpp

 
 Contact *luax_checkcontact(lua_State *L, int idx)
 {
-	return luax_checktype<Contact>(L, idx, "Contact", PHYSICS_CONTACT_T);
+	Contact *c = luax_checktype<Contact>(L, idx, "Contact", PHYSICS_CONTACT_T);
+	if (!c->isValid())
+		luaL_error(L, "Attempt to use destroyed contact.");
+	return c;
 }
 
 int w_Contact_getPositions(lua_State *L)

src/modules/physics/box2d/wrap_World.cpp

 {
 	World *t = luax_checkworld(L, 1);
 	float dt = (float)luaL_checknumber(L, 2);
-	t->update(dt);
+	ASSERT_GUARD(t->update(dt);)
 	return 0;
 }
 

src/modules/sound/Sound.h

 	 * @param sampleRate Samples per second, or quality of the audio. 44100 is a good value.
 	 * @return A Decoder object on success, or zero if no decoder could be found.
 	 **/
-	virtual Decoder *newDecoder(filesystem::File *file, int bufferSize) = 0;
+	virtual Decoder *newDecoder(filesystem::FileData *file, int bufferSize) = 0;
 
 }; // Sound
 
 } // sound
 } // love
 
-#endif // LOVE_SOUND_SOUND_H
+#endif // LOVE_SOUND_SOUND_H

src/modules/sound/lullaby/GmeDecoder.cpp

 
 	num_tracks = gme_track_count(emu);
 
-	if (num_tracks <= 0)
-		throw love::Exception("Game music file has no tracks");
+	try
+	{