Pārlūkot izejas kodu

Using latest love-android branch (e263d91d136d)

fysx 11 gadi atpakaļ
vecāks
revīzija
e96eef4435
87 mainītis faili ar 1068 papildinājumiem un 395 dzēšanām
  1. 5 2
      jni/love/src/common/Data.h
  2. 6 2
      jni/love/src/common/Memoizer.cpp
  3. 17 7
      jni/love/src/common/Reference.cpp
  4. 17 1
      jni/love/src/common/Reference.h
  5. 1 1
      jni/love/src/common/Vector.cpp
  6. 1 1
      jni/love/src/common/b64.h
  7. 21 0
      jni/love/src/common/utf8.cpp
  8. 8 1
      jni/love/src/common/utf8.h
  9. 2 2
      jni/love/src/common/wrap_Data.cpp
  10. 16 15
      jni/love/src/libraries/ddsparse/ddsparse.cpp
  11. 1 1
      jni/love/src/libraries/ddsparse/ddsparse.h
  12. 1 5
      jni/love/src/libraries/enet/enet.cpp
  13. 6 0
      jni/love/src/libraries/enet/libenet/ChangeLog
  14. 1 1
      jni/love/src/libraries/enet/libenet/include/enet/enet.h
  15. 2 2
      jni/love/src/libraries/enet/libenet/include/enet/protocol.h
  16. 1 1
      jni/love/src/libraries/enet/libenet/include/enet/unix.h
  17. 1 1
      jni/love/src/libraries/enet/libenet/include/enet/win32.h
  18. 3 2
      jni/love/src/libraries/enet/libenet/protocol.c
  19. 1 1
      jni/love/src/modules/audio/Audio.h
  20. 2 2
      jni/love/src/modules/audio/openal/Source.cpp
  21. 17 1
      jni/love/src/modules/event/sdl/Event.cpp
  22. 6 11
      jni/love/src/modules/filesystem/FileData.cpp
  23. 1 3
      jni/love/src/modules/filesystem/FileData.h
  24. 21 0
      jni/love/src/modules/filesystem/physfs/Filesystem.cpp
  25. 5 0
      jni/love/src/modules/filesystem/physfs/Filesystem.h
  26. 25 3
      jni/love/src/modules/filesystem/physfs/wrap_Filesystem.cpp
  27. 1 1
      jni/love/src/modules/font/Font.h
  28. 3 3
      jni/love/src/modules/font/GlyphData.cpp
  29. 1 1
      jni/love/src/modules/font/GlyphData.h
  30. 1 1
      jni/love/src/modules/font/ImageRasterizer.h
  31. 1 1
      jni/love/src/modules/font/Rasterizer.cpp
  32. 1 1
      jni/love/src/modules/font/Rasterizer.h
  33. 20 11
      jni/love/src/modules/font/freetype/TrueTypeRasterizer.cpp
  34. 1 0
      jni/love/src/modules/graphics/Graphics.cpp
  35. 1 0
      jni/love/src/modules/graphics/Graphics.h
  36. 47 12
      jni/love/src/modules/graphics/opengl/Canvas.cpp
  37. 1 1
      jni/love/src/modules/graphics/opengl/Font.h
  38. 23 8
      jni/love/src/modules/graphics/opengl/Graphics.cpp
  39. 2 0
      jni/love/src/modules/graphics/opengl/Graphics.h
  40. 101 21
      jni/love/src/modules/graphics/opengl/Mesh.cpp
  41. 5 4
      jni/love/src/modules/graphics/opengl/Mesh.h
  42. 1 1
      jni/love/src/modules/graphics/opengl/ParticleSystem.h
  43. 2 2
      jni/love/src/modules/graphics/opengl/wrap_Graphics.cpp
  44. 18 13
      jni/love/src/modules/graphics/opengl/wrap_Mesh.cpp
  45. 4 4
      jni/love/src/modules/image/CompressedData.cpp
  46. 2 2
      jni/love/src/modules/image/CompressedData.h
  47. 2 2
      jni/love/src/modules/image/Image.h
  48. 2 2
      jni/love/src/modules/image/ImageData.cpp
  49. 1 1
      jni/love/src/modules/image/ImageData.h
  50. 14 18
      jni/love/src/modules/image/magpie/DevilHandler.cpp
  51. 12 7
      jni/love/src/modules/image/magpie/DevilHandler.h
  52. 62 0
      jni/love/src/modules/image/magpie/FormatHandler.cpp
  53. 18 10
      jni/love/src/modules/image/magpie/FormatHandler.h
  54. 8 5
      jni/love/src/modules/image/magpie/Image.cpp
  55. 9 0
      jni/love/src/modules/image/magpie/Image.h
  56. 41 14
      jni/love/src/modules/image/magpie/ImageData.cpp
  57. 10 3
      jni/love/src/modules/image/magpie/ImageData.h
  58. 11 0
      jni/love/src/modules/keyboard/Keyboard.cpp
  59. 11 0
      jni/love/src/modules/keyboard/Keyboard.h
  60. 11 0
      jni/love/src/modules/keyboard/sdl/Keyboard.cpp
  61. 13 13
      jni/love/src/modules/math/MathModule.cpp
  62. 2 2
      jni/love/src/modules/math/wrap_Math.cpp
  63. 1 1
      jni/love/src/modules/mouse/Mouse.h
  64. 2 2
      jni/love/src/modules/mouse/wrap_Cursor.cpp
  65. 43 1
      jni/love/src/modules/physics/box2d/Body.cpp
  66. 26 1
      jni/love/src/modules/physics/box2d/Body.h
  67. 16 16
      jni/love/src/modules/physics/box2d/Fixture.cpp
  68. 0 3
      jni/love/src/modules/physics/box2d/Fixture.h
  69. 16 0
      jni/love/src/modules/physics/box2d/wrap_Body.cpp
  70. 2 0
      jni/love/src/modules/physics/box2d/wrap_Body.h
  71. 1 1
      jni/love/src/modules/physics/box2d/wrap_MotorJoint.cpp
  72. 9 3
      jni/love/src/modules/physics/box2d/wrap_World.cpp
  73. 1 1
      jni/love/src/modules/sound/Decoder.h
  74. 29 25
      jni/love/src/modules/sound/SoundData.cpp
  75. 5 4
      jni/love/src/modules/sound/SoundData.h
  76. 1 1
      jni/love/src/modules/sound/lullaby/FLACDecoder.cpp
  77. 1 1
      jni/love/src/modules/sound/lullaby/GmeDecoder.cpp
  78. 86 2
      jni/love/src/modules/system/System.cpp
  79. 10 0
      jni/love/src/modules/system/System.h
  80. 9 1
      jni/love/src/modules/system/wrap_System.cpp
  81. 1 0
      jni/love/src/modules/system/wrap_System.h
  82. 19 15
      jni/love/src/modules/window/sdl/Window.cpp
  83. 2 1
      jni/love/src/scripts/auto.lua
  84. 26 12
      jni/love/src/scripts/boot.lua
  85. 61 27
      jni/love/src/scripts/boot.lua.h
  86. 15 14
      jni/love/src/scripts/graphics.lua
  87. 35 33
      jni/love/src/scripts/graphics.lua.h

+ 5 - 2
jni/love/src/common/Data.h

@@ -25,6 +25,9 @@
 #include "config.h"
 #include "Object.h"
 
+// C
+#include <stddef.h>
+
 namespace love
 {
 
@@ -38,7 +41,7 @@ public:
 	/**
 	 * Destructor.
 	 **/
-	virtual ~Data() {};
+	virtual ~Data() {}
 
 	/**
 	 * Gets a pointer to the data. This pointer will obviously not
@@ -49,7 +52,7 @@ public:
 	/**
 	 * Gets the size of the Data in bytes.
 	 **/
-	virtual int getSize() const = 0;
+	virtual size_t getSize() const = 0;
 
 }; // Data
 

+ 6 - 2
jni/love/src/common/Memoizer.cpp

@@ -38,8 +38,12 @@ void Memoizer::remove(void *key)
 
 void *Memoizer::find(void *key)
 {
-	if (objectMap.count(key)) return objectMap[key];
-	return NULL;
+	auto it = objectMap.find(key);
+
+	if (it != objectMap.end())
+		return it->second;
+	else
+		return nullptr;
 }
 
 } // love

+ 17 - 7
jni/love/src/common/Reference.cpp

@@ -26,7 +26,7 @@ namespace love
 const char REFERENCE_TABLE_NAME[] = "love-references";
 
 Reference::Reference()
-	: L(0)
+	: L(nullptr)
 	, idx(LUA_REFNIL)
 {
 }
@@ -64,21 +64,31 @@ void Reference::unref()
 	}
 }
 
-void Reference::push()
+void Reference::push(lua_State *newL)
 {
 	if (idx != LUA_REFNIL)
 	{
-		luax_insist(L, LUA_REGISTRYINDEX, REFERENCE_TABLE_NAME);
-		lua_rawgeti(L, -1, idx);
-		lua_remove(L, -2);
+		luax_insist(newL, LUA_REGISTRYINDEX, REFERENCE_TABLE_NAME);
+		lua_rawgeti(newL, -1, idx);
+		lua_remove(newL, -2);
 	}
 	else
-		lua_pushnil(L);
+		lua_pushnil(newL);
 }
 
-lua_State *Reference::getL()
+void Reference::push()
+{
+	push(L);
+}
+
+lua_State *Reference::getL() const
 {
 	return L;
 }
 
+void Reference::setL(lua_State *newL)
+{
+	L = newL;
+}
+
 } // love

+ 17 - 1
jni/love/src/common/Reference.h

@@ -63,6 +63,14 @@ public:
 	 **/
 	void unref();
 
+	/**
+	 * Pushes the referred value onto the stack of a different coroutine
+	 * in the same main Lua state.
+	 * THIS SHOULD NOT BE USED FOR DIFFERENT LUA STATES (created with
+	 * luaL_newstate)! Only with different coroutines!
+	 **/
+	void push(lua_State *newL);
+
 	/**
 	 * Pushes the referred value onto the stack.
 	 **/
@@ -72,7 +80,15 @@ public:
 	 * Gets the Lua state associated with this
 	 * reference.
 	 **/
-	lua_State *getL();
+	lua_State *getL() const;
+
+	/**
+	 * Associates a new Lua state with this reference.
+	 * THIS IS DANGEROUS! It is only designed to be
+	 * used with different coroutines from the same
+	 * main Lua state!
+	 **/
+	void setL(lua_State *newL);
 
 private:
 

+ 1 - 1
jni/love/src/common/Vector.cpp

@@ -23,4 +23,4 @@
 namespace love
 {
 // Implementation in header.
-}
+}

+ 1 - 1
jni/love/src/common/b64.h

@@ -38,4 +38,4 @@ char *b64_decode(const char *src, int slen, int &size);
 
 } // love
 
-#endif // LOVE_B64_H
+#endif // LOVE_B64_H

+ 21 - 0
jni/love/src/common/utf8.cpp

@@ -45,6 +45,27 @@ std::string to_utf8(LPCWSTR wstr)
 	return ret;
 }
 
+std::wstring to_widestr(const std::string &str)
+{
+	if (str.empty())
+		return std::wstring();
+
+	int wide_size = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int) str.length(), nullptr, 0);
+
+	if (wide_size == 0)
+		return std::wstring();
+
+	std::wstring widestr;
+	widestr.resize(wide_size);
+
+	int ok = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int) str.length(), &widestr[0], widestr.length());
+
+	if (!ok)
+		return std::wstring();
+
+	return widestr;
+}
+
 void replace_char(std::string &str, char find, char replace)
 {
 	int length = str.length();

+ 8 - 1
jni/love/src/common/utf8.h

@@ -35,6 +35,13 @@ namespace love
  **/
 std::string to_utf8(LPCWSTR wstr);
 
+/**
+ * Convert a UTF-8 encoded string to a wide string.
+ * @param str The UTF-8 string.
+ * @return A wide string.
+**/
+std::wstring to_widestr(const std::string &str);
+
 /**
  * Replace all occurences of 'find' with 'replace' in a string.
  * @param str The string to modify.
@@ -45,4 +52,4 @@ void replace_char(std::string &str, char find, char replace);
 
 } // love
 
-#endif // LOVE_WINDOWS
+#endif // LOVE_WINDOWS

+ 2 - 2
jni/love/src/common/wrap_Data.cpp

@@ -31,7 +31,7 @@ Data *luax_checkdata(lua_State *L, int idx)
 int w_Data_getString(lua_State *L)
 {
 	Data *t = luax_checkdata(L, 1);
-	lua_pushlstring(L, (const char *) t->getData(), (size_t) t->getSize());
+	lua_pushlstring(L, (const char *) t->getData(), t->getSize());
 	return 1;
 }
 
@@ -45,7 +45,7 @@ int w_Data_getPointer(lua_State *L)
 int w_Data_getSize(lua_State *L)
 {
 	Data *t = luax_checkdata(L, 1);
-	lua_pushinteger(L, t->getSize());
+	lua_pushnumber(L, (lua_Number) t->getSize());
 	return 1;
 }
 

+ 16 - 15
jni/love/src/libraries/ddsparse/ddsparse.cpp

@@ -237,36 +237,37 @@ size_t Parser::getMipmapCount() const
 
 size_t Parser::parseImageSize(Format fmt, int width, int height) const
 {
-	size_t size = 0;
+	size_t numBlocksWide = 0;
+	size_t numBlocksHigh = 0;
+	size_t numBytesPerBlock = 0;
 
 	switch (fmt)
 	{
 	case FORMAT_DXT1:
+	case FORMAT_BC4:
+	case FORMAT_BC4s:
+		numBytesPerBlock = 8;
+		break;
 	case FORMAT_DXT3:
 	case FORMAT_DXT5:
 	case FORMAT_BC5s:
 	case FORMAT_BC5:
+	case FORMAT_BC6H:
 	case FORMAT_BC7:
 	case FORMAT_BC7srgb:
-		{
-			int numBlocksWide = 0;
-			if (width > 0)
-				numBlocksWide = std::max(1, (width + 3) / 4);
-
-			int numBlocksHigh = 0;
-			if (height > 0)
-				numBlocksHigh = std::max(1, (height + 3) / 4);
-
-			int numBytesPerBlock = (fmt == FORMAT_DXT1 ? 8 : 16);
-
-			size = numBlocksWide * numBytesPerBlock * numBlocksHigh;
-		}
+		numBytesPerBlock = 16;
 		break;
 	default:
 		break;
 	}
 
-	return size;
+	if (width > 0)
+		numBlocksWide = std::max(1, (width + 3) / 4);
+
+	if (height > 0)
+		numBlocksHigh = std::max(1, (height + 3) / 4);
+
+	return numBlocksWide * numBytesPerBlock * numBlocksHigh;
 }
 
 bool Parser::parseTexData(const uint8_t *data, size_t dataSize, Format fmt, int w, int h, int mips)

+ 1 - 1
jni/love/src/libraries/ddsparse/ddsparse.h

@@ -60,7 +60,7 @@ struct Image
 	const uint8_t *data;
 
 	Image() : width(0), height(0), dataSize(0), data(0)
-	{};
+	{}
 };
 
 /**

+ 1 - 5
jni/love/src/libraries/enet/enet.cpp

@@ -89,7 +89,7 @@ static void parse_address(lua_State *l, const char *addr_str, ENetAddress *addre
 /**
  * Find the index of a given peer for which we only have the pointer.
  */
-size_t find_peer_index (lua_State *l, ENetHost *enet_host, ENetPeer *peer) {
+static size_t find_peer_index(lua_State *l, ENetHost *enet_host, ENetPeer *peer) {
 	size_t peer_index;
 	for (peer_index = 0; peer_index < enet_host->peerCount; peer_index++) {
 		if (peer == &(enet_host->peers[peer_index]))
@@ -716,10 +716,6 @@ static const struct luaL_Reg enet_peer_funcs [] = {
 	{NULL, NULL}
 };
 
-static const struct luaL_Reg enet_event_funcs [] = {
-	{NULL, NULL}
-};
-
 int luaopen_enet(lua_State *l) {
 	enet_initialize();
 	atexit(enet_deinitialize);

+ 6 - 0
jni/love/src/libraries/enet/libenet/ChangeLog

@@ -1,3 +1,9 @@
+ENet 1.3.11 (December 26, 2013):
+
+* allow an ENetHost to connect to itself
+* fixed possible bug with disconnect notifications during connect attempts
+* fixed some preprocessor definition bugs
+
 ENet 1.3.10 (October 23, 2013);
 
 * doubled maximum reliable window size

+ 1 - 1
jni/love/src/libraries/enet/libenet/include/enet/enet.h

@@ -25,7 +25,7 @@ extern "C"
 
 #define ENET_VERSION_MAJOR 1
 #define ENET_VERSION_MINOR 3
-#define ENET_VERSION_PATCH 10
+#define ENET_VERSION_PATCH 11
 #define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch))
 #define ENET_VERSION_GET_MAJOR(version) (((version)>>16)&0xFF)
 #define ENET_VERSION_GET_MINOR(version) (((version)>>8)&0xFF)

+ 2 - 2
jni/love/src/libraries/enet/libenet/include/enet/protocol.h

@@ -54,7 +54,7 @@ typedef enum _ENetProtocolFlag
    ENET_PROTOCOL_HEADER_SESSION_SHIFT   = 12
 } ENetProtocolFlag;
 
-#ifdef _MSC_VER_
+#ifdef _MSC_VER
 #pragma pack(push, 1)
 #define ENET_PACKED
 #elif defined(__GNUC__) || defined(__clang__)
@@ -191,7 +191,7 @@ typedef union _ENetProtocol
    ENetProtocolThrottleConfigure throttleConfigure;
 } ENET_PACKED ENetProtocol;
 
-#ifdef _MSC_VER_
+#ifdef _MSC_VER
 #pragma pack(pop)
 #endif
 

+ 1 - 1
jni/love/src/libraries/enet/libenet/include/enet/unix.h

@@ -40,7 +40,7 @@ typedef fd_set ENetSocketSet;
 
 #define ENET_SOCKETSET_EMPTY(sockset)          FD_ZERO (& (sockset))
 #define ENET_SOCKETSET_ADD(sockset, socket)    FD_SET (socket, & (sockset))
-#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLEAR (socket, & (sockset))
+#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset))
 #define ENET_SOCKETSET_CHECK(sockset, socket)  FD_ISSET (socket, & (sockset))
     
 #endif /* __ENET_UNIX_H__ */

+ 1 - 1
jni/love/src/libraries/enet/libenet/include/enet/win32.h

@@ -50,7 +50,7 @@ typedef fd_set ENetSocketSet;
 
 #define ENET_SOCKETSET_EMPTY(sockset)          FD_ZERO (& (sockset))
 #define ENET_SOCKETSET_ADD(sockset, socket)    FD_SET (socket, & (sockset))
-#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLEAR (socket, & (sockset))
+#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset))
 #define ENET_SOCKETSET_CHECK(sockset, socket)  FD_ISSET (socket, & (sockset))
 
 #endif /* __ENET_WIN32_H__ */

+ 3 - 2
jni/love/src/libraries/enet/libenet/protocol.c

@@ -297,7 +297,8 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
               peer = currentPeer;
         }
         else 
-        if (currentPeer -> address.host == host -> receivedAddress.host)
+        if (currentPeer -> state != ENET_PEER_STATE_CONNECTING &&
+            currentPeer -> address.host == host -> receivedAddress.host)
         {
             if (currentPeer -> address.port == host -> receivedAddress.port &&
                 currentPeer -> connectID == command -> connect.connectID)
@@ -819,7 +820,7 @@ enet_protocol_handle_disconnect (ENetHost * host, ENetPeer * peer, const ENetPro
 
     enet_peer_reset_queues (peer);
 
-    if (peer -> state == ENET_PEER_STATE_CONNECTION_SUCCEEDED || peer -> state == ENET_PEER_STATE_DISCONNECTING)
+    if (peer -> state == ENET_PEER_STATE_CONNECTION_SUCCEEDED || peer -> state == ENET_PEER_STATE_DISCONNECTING || peer -> state == ENET_PEER_STATE_CONNECTING)
         enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE);
     else
     if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)

+ 1 - 1
jni/love/src/modules/audio/Audio.h

@@ -67,7 +67,7 @@ public:
 	/**
 	 * Destructor.
 	 **/
-	virtual ~Audio() {};
+	virtual ~Audio() {}
 
 	virtual Source *newSource(love::sound::Decoder *decoder) = 0;
 	virtual Source *newSource(love::sound::SoundData *soundData) = 0;

+ 2 - 2
jni/love/src/modules/audio/openal/Source.cpp

@@ -468,8 +468,8 @@ void Source::getDirection(float *v) const
 
 void Source::setCone(float innerAngle, float outerAngle, float outerVolume)
 {
-	cone.innerAngle = LOVE_TODEG(innerAngle);
-	cone.outerAngle = LOVE_TODEG(outerAngle);
+	cone.innerAngle = (int) LOVE_TODEG(innerAngle);
+	cone.outerAngle = (int) LOVE_TODEG(outerAngle);
 	cone.outerVolume = outerVolume;
 
 	if (valid)

+ 17 - 1
jni/love/src/modules/event/sdl/Event.cpp

@@ -28,6 +28,7 @@
 #include "window/Window.h"
 #include "common/Exception.h"
 #include "audio/Audio.h"
+#include "common/config.h"
 
 #include <cmath>
 
@@ -254,6 +255,9 @@ Message *Event::convert(const SDL_Event &e) const
 	case SDL_QUIT:
 		msg = new Message("quit");
 		break;
+	case SDL_APP_LOWMEMORY:
+		msg = new Message("lowmemory");
+		break;
 	default:
 		break;
 	}
@@ -446,7 +450,8 @@ Message *Event::convertWindowEvent(const SDL_Event &e) const
 			int px_w = e.window.data1;
 			int px_h = e.window.data2;
 
-#if SDL_VERSION_ATLEAST(2,0,1)
+			// FIXME: disabled in Linux for runtime SDL 2.0.0 compatibility.
+#if SDL_VERSION_ATLEAST(2,0,1) && !defined(LOVE_LINUX)
 			SDL_Window *sdlwin = SDL_GetWindowFromID(e.window.windowID);
 			if (sdlwin)
 				SDL_GL_GetDrawableSize(sdlwin, &px_w, &px_h);
@@ -682,6 +687,17 @@ std::map<SDL_Keycode, love::keyboard::Keyboard::Key> Event::createKeyMap()
 	k[SDLK_AUDIOPLAY] = Keyboard::KEY_AUDIOPLAY;
 	k[SDLK_AUDIOMUTE] = Keyboard::KEY_AUDIOMUTE;
 	k[SDLK_MEDIASELECT] = Keyboard::KEY_MEDIASELECT;
+	k[SDLK_WWW] = Keyboard::KEY_WWW;
+	k[SDLK_MAIL] = Keyboard::KEY_MAIL;
+	k[SDLK_CALCULATOR] = Keyboard::KEY_CALCULATOR;
+	k[SDLK_COMPUTER] = Keyboard::KEY_COMPUTER;
+	k[SDLK_AC_SEARCH] = Keyboard::KEY_APP_SEARCH;
+	k[SDLK_AC_HOME] = Keyboard::KEY_APP_HOME;
+	k[SDLK_AC_BACK] = Keyboard::KEY_APP_BACK;
+	k[SDLK_AC_FORWARD] = Keyboard::KEY_APP_FORWARD;
+	k[SDLK_AC_STOP] = Keyboard::KEY_APP_STOP;
+	k[SDLK_AC_REFRESH] = Keyboard::KEY_APP_REFRESH;
+	k[SDLK_AC_BOOKMARKS] = Keyboard::KEY_APP_BOOKMARKS;
 
 	k[SDLK_BRIGHTNESSDOWN] = Keyboard::KEY_BRIGHTNESSDOWN;
 	k[SDLK_BRIGHTNESSUP] = Keyboard::KEY_BRIGHTNESSUP;

+ 6 - 11
jni/love/src/modules/filesystem/FileData.cpp

@@ -20,9 +20,9 @@
 
 #include "FileData.h"
 
-// STD
+// C++
 #include <iostream>
-#include <climits>
+#include <limits>
 
 namespace love
 {
@@ -31,7 +31,7 @@ namespace filesystem
 
 FileData::FileData(uint64 size, const std::string &filename)
 	: data(new char[(size_t) size])
-	, size(size)
+	, size((size_t) size)
 	, filename(filename)
 {
 	if (filename.rfind('.') != std::string::npos)
@@ -48,15 +48,10 @@ void *FileData::getData() const
 	return (void *)data;
 }
 
-// TODO: Enable this
-/*uint64 FileData::getSize() const
+size_t FileData::getSize() const
 {
-	return size;
-}*/
-
-int FileData::getSize() const
-{
-	return size > INT_MAX ? INT_MAX : (int) size;
+	size_t sizemax = std::numeric_limits<size_t>::max();
+	return size > sizemax ? sizemax : (size_t) size;
 }
 
 const std::string &FileData::getFilename() const

+ 1 - 3
jni/love/src/modules/filesystem/FileData.h

@@ -49,9 +49,7 @@ public:
 
 	// Implements Data.
 	void *getData() const;
-	//TODO: Enable this
-	//uint64 getSize() const;
-	int getSize() const;
+	size_t getSize() const;
 
 	const std::string &getFilename() const;
 	const std::string &getExtension() const;

+ 21 - 0
jni/love/src/modules/filesystem/physfs/Filesystem.cpp

@@ -575,6 +575,16 @@ std::string Filesystem::getSourceBaseDirectory() const
 	return game_source.substr(0, base_end_pos);
 }
 
+std::string Filesystem::getRealDirectory(const char *filename) const
+{
+	const char *dir = PHYSFS_getRealDir(filename);
+
+	if (dir == nullptr)
+		throw love::Exception("File does not exist.");
+
+	return std::string(dir);
+}
+
 bool Filesystem::exists(const char *file) const
 {
 	return PHYSFS_exists(file);
@@ -645,6 +655,10 @@ void Filesystem::append(const char *filename, const void *data, int64 size) cons
 int Filesystem::getDirectoryItems(lua_State *L)
 {
 	const char *dir = luaL_checkstring(L, 1);
+	bool hascallback = !lua_isnoneornil(L, 2);
+
+	if (hascallback)
+		luaL_checktype(L, 2, LUA_TFUNCTION);
 
 	char **rc = PHYSFS_enumerateFiles(dir);
 	int index = 1;
@@ -653,6 +667,13 @@ int Filesystem::getDirectoryItems(lua_State *L)
 
 	for (char **i = rc; *i != 0; i++)
 	{
+		if (hascallback)
+		{
+			lua_pushvalue(L, 2);
+			lua_pushstring(L, *i);
+			lua_call(L, 1, 0);
+		}
+
 		lua_pushstring(L, *i);
 		lua_rawseti(L, -2, index);
 		index++;

+ 5 - 0
jni/love/src/modules/filesystem/physfs/Filesystem.h

@@ -166,6 +166,11 @@ public:
 	 **/
 	std::string getSourceBaseDirectory() const;
 
+	/**
+	 * Gets the real directory path containing the file.
+	 **/
+	std::string getRealDirectory(const char *filename) const;
+
 	/**
 	 * Checks whether a file exists in the current search path
 	 * or not.

+ 25 - 3
jni/love/src/modules/filesystem/physfs/wrap_Filesystem.cpp

@@ -526,9 +526,31 @@ int extloader(lua_State *L)
 
 	tokenized_name += library_extension();
 
-	void *handle = SDL_LoadObject((std::string(instance->getAppdataDirectory()) + LOVE_PATH_SEPARATOR LOVE_APPDATA_FOLDER LOVE_PATH_SEPARATOR + tokenized_name).c_str());
-	if (!handle && instance->isFused())
-		handle = SDL_LoadObject((std::string(instance->getSaveDirectory()) + LOVE_PATH_SEPARATOR + tokenized_name).c_str());
+	void *handle = nullptr;
+
+	// If the game is fused, try looking for the DLL in the game's read paths.
+	if (instance->isFused())
+	{
+		try
+		{
+			std::string dir = instance->getRealDirectory(tokenized_name.c_str());
+
+			// We don't want to look in the game's source, because it can be a
+			// zip sometimes and a folder other times.
+			if (dir.find(instance->getSource()) == std::string::npos)
+				handle = SDL_LoadObject((dir + LOVE_PATH_SEPARATOR + tokenized_name).c_str());
+		}
+		catch (love::Exception &)
+		{
+			// Nothing...
+		}
+	}
+
+	if (!handle)
+	{
+		std::string path = std::string(instance->getAppdataDirectory()) + LOVE_PATH_SEPARATOR LOVE_APPDATA_FOLDER LOVE_PATH_SEPARATOR + tokenized_name;
+		handle = SDL_LoadObject(path.c_str());
+	}
 
 	if (!handle)
 	{

+ 1 - 1
jni/love/src/modules/font/Font.h

@@ -54,4 +54,4 @@ public:
 } // font
 } // love
 
-#endif // LOVE_FONT_FONT_H
+#endif // LOVE_FONT_FONT_H

+ 3 - 3
jni/love/src/modules/font/GlyphData.cpp

@@ -64,16 +64,16 @@ void *GlyphData::getData() const
 	return (void *) data;
 }
 
-int GlyphData::getSize() const
+size_t GlyphData::getSize() const
 {
 	switch (format)
 	{
 	case GlyphData::FORMAT_LUMINANCE_ALPHA:
-		return getWidth() * getHeight() * 2;
+		return size_t(getWidth() * getHeight() * 2);
 		break;
 	case GlyphData::FORMAT_RGBA:
 	default:
-		return getWidth() * getHeight() * 4;
+		return size_t(getWidth() * getHeight() * 4);
 		break;
 	}
 

+ 1 - 1
jni/love/src/modules/font/GlyphData.h

@@ -67,7 +67,7 @@ public:
 
 	// Implements Data.
 	void *getData() const;
-	int getSize() const;
+	size_t getSize() const;
 
 	/**
 	 * Gets the height of the glyph.

+ 1 - 1
jni/love/src/modules/font/ImageRasterizer.h

@@ -79,4 +79,4 @@ private:
 } // font
 } // love
 
-#endif // LOVE_FONT_IMAGE_RASTERIZER_H
+#endif // LOVE_FONT_IMAGE_RASTERIZER_H

+ 1 - 1
jni/love/src/modules/font/Rasterizer.cpp

@@ -96,4 +96,4 @@ bool Rasterizer::hasGlyphs(const std::string &text) const
 }
 
 } // font
-} // love
+} // love

+ 1 - 1
jni/love/src/modules/font/Rasterizer.h

@@ -114,4 +114,4 @@ protected:
 } // font
 } // love
 
-#endif // LOVE_FONT_RASTERIZER_H
+#endif // LOVE_FONT_RASTERIZER_H

+ 20 - 11
jni/love/src/modules/font/freetype/TrueTypeRasterizer.cpp

@@ -33,12 +33,15 @@ namespace freetype
 TrueTypeRasterizer::TrueTypeRasterizer(FT_Library library, Data *data, int size)
 	: data(data)
 {
-	if (FT_New_Memory_Face(library,
-	                      (const FT_Byte *)data->getData(), /* first byte in memory */
-	                      data->getSize(),                  /* size in bytes        */
-	                      0,                                /* face_index           */
-	                      &face))
-		throw love::Exception("TrueTypeFont Loading error: FT_New_Face failed (there is probably a problem with your font file)");
+	FT_Error err = FT_Err_Ok;
+	err = FT_New_Memory_Face(library,
+	                         (const FT_Byte *)data->getData(), /* first byte in memory */
+	                         data->getSize(),                  /* size in bytes        */
+	                         0,                                /* face_index           */
+	                         &face);
+
+	if (err != FT_Err_Ok)
+		throw love::Exception("TrueType Font Loading error: FT_New_Face failed: 0x%x (problem with font file?)", err);
 
 	FT_Set_Pixel_Sizes(face, size, size);
 
@@ -68,12 +71,18 @@ GlyphData *TrueTypeRasterizer::getGlyphData(uint32 glyph) const
 	love::font::GlyphMetrics glyphMetrics = {};
 	FT_Glyph ftglyph;
 
+	FT_Error err = FT_Err_Ok;
+
 	// Initialize
-	if (FT_Load_Glyph(face, FT_Get_Char_Index(face, glyph), FT_LOAD_DEFAULT))
-		throw love::Exception("TrueTypeFont Loading error: FT_Load_Glyph failed");
+	err = FT_Load_Glyph(face, FT_Get_Char_Index(face, glyph), FT_LOAD_DEFAULT);
+
+	if (err != FT_Err_Ok)
+		throw love::Exception("TrueType Font Loading error: FT_Load_Glyph failed (0x%x)", err);
+
+	err = FT_Get_Glyph(face->glyph, &ftglyph);
 
-	if (FT_Get_Glyph(face->glyph, &ftglyph))
-		throw love::Exception("TrueTypeFont Loading error: FT_Get_Glyph failed");
+	if (err != FT_Err_Ok)
+		throw love::Exception("TrueType Font Loading error: FT_Get_Glyph failed (0x%x)", err);
 
 	FT_Glyph_To_Bitmap(&ftglyph, FT_RENDER_MODE_NORMAL, 0, 1);
 
@@ -146,4 +155,4 @@ bool TrueTypeRasterizer::hasGlyph(uint32 glyph) const
 
 } // freetype
 } // font
-} // love
+} // love

+ 1 - 0
jni/love/src/modules/graphics/Graphics.cpp

@@ -134,6 +134,7 @@ StringMap<Graphics::BlendMode, Graphics::BLEND_MAX_ENUM>::Entry Graphics::blendM
 	{ "subtractive", Graphics::BLEND_SUBTRACTIVE },
 	{ "multiplicative", Graphics::BLEND_MULTIPLICATIVE },
 	{ "premultiplied", Graphics::BLEND_PREMULTIPLIED },
+	{ "screen", Graphics::BLEND_SCREEN },
 	{ "replace", Graphics::BLEND_REPLACE },
 };
 

+ 1 - 0
jni/love/src/modules/graphics/Graphics.h

@@ -57,6 +57,7 @@ public:
 		BLEND_SUBTRACTIVE,
 		BLEND_MULTIPLICATIVE,
 		BLEND_PREMULTIPLIED,
+		BLEND_SCREEN,
 		BLEND_REPLACE,
 		BLEND_MAX_ENUM
 	};

+ 47 - 12
jni/love/src/modules/graphics/opengl/Canvas.cpp

@@ -55,10 +55,11 @@ struct FramebufferStrategy
 	/**
 	 * @param[in]  width   Width of the stencil buffer
 	 * @param[in]  height  Height of the stencil buffer
+	 * @param[in]  samples Number of samples to use
 	 * @param[out] stencil Name for stencil buffer
 	 * @return Whether the stencil buffer was successfully created
 	 **/
-	virtual bool createStencil(int, int, GLuint &)
+	virtual bool createStencil(int, int, int, GLuint &)
 	{
 		return false;
 	}
@@ -121,13 +122,17 @@ struct FramebufferStrategyCore : public FramebufferStrategy
 		return status;
 	}
 
-	virtual bool createStencil(int width, int height, GLuint &stencil)
+	virtual bool createStencil(int width, int height, int samples, GLuint &stencil)
 	{
 		// create stencil buffer
 		glDeleteRenderbuffers(1, &stencil);
 		glGenRenderbuffers(1, &stencil);
 		glBindRenderbuffer(GL_RENDERBUFFER, stencil);
-		glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
+
+		if (samples > 1)
+			glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_STENCIL_INDEX8, width, height);
+		else
+			glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
 
 		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
 								  GL_RENDERBUFFER, stencil);
@@ -217,13 +222,17 @@ struct FramebufferStrategyCore : public FramebufferStrategy
 
 struct FramebufferStrategyCorePacked : public FramebufferStrategyCore
 {
-	virtual bool createStencil(int width, int height, GLuint &stencil)
+	virtual bool createStencil(int width, int height, int samples, GLuint &stencil)
 	{
 		// create combined depth/stencil buffer
 		glDeleteRenderbuffers(1, &stencil);
 		glGenRenderbuffers(1, &stencil);
 		glBindRenderbuffer(GL_RENDERBUFFER, stencil);
-		glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height);
+
+		if (samples > 1)
+			glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH_STENCIL, width, height);
+		else
+			glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height);
 
 		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
 								  GL_RENDERBUFFER, stencil);
@@ -257,14 +266,24 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy
 		return status;
 	}
 
-	virtual bool createStencil(int width, int height, GLuint &stencil)
+	virtual bool createStencil(int width, int height, int samples, GLuint &stencil)
 	{
 		// create combined depth/stencil buffer
 		glDeleteRenderbuffersEXT(1, &stencil);
 		glGenRenderbuffersEXT(1, &stencil);
 		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil);
-		glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT,
-								 width, height);
+
+		if (samples > 1)
+		{
+			glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples,
+			                                    GL_DEPTH_STENCIL, width, height);
+		}
+		else
+		{
+			glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT,
+			                         width, height);
+		}
+
 		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
 									 GL_RENDERBUFFER_EXT, stencil);
 
@@ -356,14 +375,24 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy
 
 struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT
 {
-	virtual bool createStencil(int width, int height, GLuint &stencil)
+	virtual bool createStencil(int width, int height, int samples, GLuint &stencil)
 	{
 		// create stencil buffer
 		glDeleteRenderbuffersEXT(1, &stencil);
 		glGenRenderbuffersEXT(1, &stencil);
 		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil);
-		glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX,
-								 width, height);
+
+		if (samples > 1)
+		{
+			glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples,
+			                                    GL_STENCIL_INDEX, width, height);
+		}
+		else
+		{
+			glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX,
+			                         width, height);
+		}
+
 		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
 									 GL_RENDERBUFFER_EXT, stencil);
 
@@ -589,6 +618,9 @@ bool Canvas::loadVolatile()
 		return false;
 
 	clear(Color(0, 0, 0, 0));
+
+	fsaa_dirty = (fsaa_buffer != 0);
+
 	return true;
 }
 
@@ -865,6 +897,9 @@ void Canvas::clear(Color c)
 
 	if (current != this)
 		strategy->bindFBO(previous);
+
+	if (fsaa_buffer != 0)
+		fsaa_dirty = true;
 }
 
 bool Canvas::checkCreateStencil()
@@ -876,7 +911,7 @@ bool Canvas::checkCreateStencil()
 	if (current != this)
 		strategy->bindFBO(fbo);
 
-	bool success = strategy->createStencil(width, height, depth_stencil);
+	bool success = strategy->createStencil(width, height, fsaa_samples, depth_stencil);
 
 	if (current && current != this)
 		strategy->bindFBO(current->fbo);

+ 1 - 1
jni/love/src/modules/graphics/opengl/Font.h

@@ -175,7 +175,7 @@ private:
 				return texture < other.texture;
 			else
 				return startvertex < other.startvertex;
-		};
+		}
 	};
 
 	bool initializeTexture(GLenum format);

+ 23 - 8
jni/love/src/modules/graphics/opengl/Graphics.cpp

@@ -52,6 +52,7 @@ Graphics::Graphics()
 	, width(0)
 	, height(0)
 	, created(false)
+	, activeStencil(false)
 	, savedState()
 {
 	currentWindow = love::window::sdl::Window::createSingleton();
@@ -266,17 +267,19 @@ bool Graphics::setMode(int width, int height, bool &sRGB)
 
 void Graphics::unSetMode()
 {
+	if (!isCreated())
+		return;
+
 	// Window re-creation may destroy the GL context, so we must save the state.
-	if (isCreated())
-	{
-		savedState = saveState();
+	savedState = saveState();
 
-		// Unload all volatile objects. These must be reloaded after the display
-		// mode change.
-		Volatile::unloadAll();
+	// Unload all volatile objects. These must be reloaded after the display
+	// mode change.
+	Volatile::unloadAll();
 
-		gl.deInitContext();
-	}
+	gl.deInitContext();
+
+	created = false;
 }
 
 static void APIENTRY debugCB(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /*len*/, const GLchar *msg, const GLvoid* /*usr*/)
@@ -439,6 +442,8 @@ void Graphics::defineStencil()
 	glEnable(GL_STENCIL_TEST);
 	glStencilFunc(GL_ALWAYS, 1, 1);
 	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+
+	activeStencil = true;
 }
 
 void Graphics::useStencil(bool invert)
@@ -450,8 +455,12 @@ void Graphics::useStencil(bool invert)
 
 void Graphics::discardStencil()
 {
+	if (!activeStencil)
+		return;
+
 	setColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
 	glDisable(GL_STENCIL_TEST);
+	activeStencil = false;
 }
 
 Image *Graphics::newImage(love::image::ImageData *data, Texture::Format format)
@@ -691,6 +700,10 @@ void Graphics::setBlendMode(Graphics::BlendMode mode)
 		state.srcRGB = state.srcA = GL_SRC_ALPHA;
 		state.dstRGB = state.dstA = GL_ONE;
 		break;
+	case BLEND_SCREEN:
+		state.srcRGB = state.srcA = GL_ONE;
+		state.dstRGB = state.dstA = GL_ONE_MINUS_SRC_COLOR;
+		break;
 	case BLEND_REPLACE:
 	default:
 		state.srcRGB = state.srcA = GL_ONE;
@@ -718,6 +731,8 @@ Graphics::BlendMode Graphics::getBlendMode() const
 			return BLEND_MULTIPLICATIVE;
 		else if (state.srcRGB == GL_ONE && state.dstRGB == GL_ONE_MINUS_SRC_ALPHA)
 			return BLEND_PREMULTIPLIED;
+		else if (state.srcRGB == GL_ONE && state.dstRGB == GL_ONE_MINUS_SRC_COLOR)
+			return BLEND_SCREEN;
 		else if (state.srcRGB == GL_ONE && state.dstRGB == GL_ZERO)
 			return BLEND_REPLACE;
 	}

+ 2 - 0
jni/love/src/modules/graphics/opengl/Graphics.h

@@ -481,6 +481,8 @@ private:
 	int height;
 	bool created;
 
+	bool activeStencil;
+
 	DisplayState savedState;
 
 }; // Graphics

+ 101 - 21
jni/love/src/modules/graphics/opengl/Mesh.cpp

@@ -38,6 +38,7 @@ Mesh::Mesh(const std::vector<Vertex> &verts, Mesh::DrawMode mode)
 	, vertex_count(0)
 	, ibo(nullptr)
 	, element_count(0)
+	, element_data_type(getGLDataTypeFromMax(verts.size()))
 	, instance_count(1)
 	, draw_mode(mode)
 	, range_min(-1)
@@ -53,6 +54,7 @@ Mesh::Mesh(int vertexcount, Mesh::DrawMode mode)
 	, vertex_count(0)
 	, ibo(nullptr)
 	, element_count(0)
+	, element_data_type(getGLDataTypeFromMax(vertexcount))
 	, draw_mode(mode)
 	, range_min(-1)
 	, range_max(-1)
@@ -151,15 +153,42 @@ size_t Mesh::getVertexCount() const
 	return vertex_count;
 }
 
-void Mesh::setVertexMap(const std::vector<uint32> &map)
+/**
+ * Copies index data from a vector to a mapped index buffer.
+ **/
+template <typename T>
+static void copyToIndexBuffer(const std::vector<uint32> &indices, VertexBuffer::Mapper &buffermap, size_t maxval)
 {
-	for (size_t i = 0; i < map.size(); i++)
+	T *elems = (T *) buffermap.get();
+
+	for (size_t i = 0; i < indices.size(); i++)
 	{
-		if (map[i] >= vertex_count)
-			throw love::Exception("Invalid vertex map value: %d", map[i] + 1);
+		if (indices[i] >= maxval)
+			throw love::Exception("Invalid vertex map value: %d", indices[i] + 1);
+
+		elems[i] = (T) indices[i];
 	}
+}
 
-	size_t size = sizeof(uint32) * map.size();
+void Mesh::setVertexMap(const std::vector<uint32> &map)
+{
+	GLenum datatype = getGLDataTypeFromMax(vertex_count);
+
+	// Calculate the size in bytes of the index buffer data.
+	size_t size = map.size();
+	switch (datatype)
+	{
+	case GL_UNSIGNED_BYTE:
+		size *= sizeof(uint8);
+		break;
+	case GL_UNSIGNED_SHORT:
+		size *= sizeof(uint16);
+		break;
+	case GL_UNSIGNED_INT:
+	default:
+		size *= sizeof(uint32);
+		break;
+	}
 
 	if (ibo && size > ibo->getSize())
 	{
@@ -175,27 +204,68 @@ void Mesh::setVertexMap(const std::vector<uint32> &map)
 
 	element_count = map.size();
 
-	if (ibo && element_count > 0)
-	{
-		VertexBuffer::Bind ibo_bind(*ibo);
-		VertexBuffer::Mapper ibo_map(*ibo);
+	if (!ibo || element_count == 0)
+		return;
 
-		// Fill the buffer.
-		memcpy(ibo_map.get(), &map[0], size);
+	VertexBuffer::Bind ibo_bind(*ibo);
+	VertexBuffer::Mapper ibo_map(*ibo);
+
+	// Fill the buffer with the index values from the vector.
+	switch (datatype)
+	{
+	case GL_UNSIGNED_BYTE:
+		copyToIndexBuffer<uint8>(map, ibo_map, vertex_count);
+		break;
+	case GL_UNSIGNED_SHORT:
+		copyToIndexBuffer<uint16>(map, ibo_map, vertex_count);
+		break;
+	case GL_UNSIGNED_INT:
+	default:
+		copyToIndexBuffer<uint32>(map, ibo_map, vertex_count);
+		break;
 	}
+
+	element_data_type = datatype;
 }
 
-const uint32 *Mesh::getVertexMap() const
+/**
+ * Copies index data from a mapped buffer to a vector.
+ **/
+template <typename T>
+static void copyFromIndexBuffer(void *buffer, std::vector<uint32> &indices, size_t maxval)
 {
-	if (ibo && element_count > 0)
-	{
-		VertexBuffer::Bind ibo_bind(*ibo);
+	T *elems = (T *) buffer;
+	for (size_t i = 0; i < maxval; i++)
+		indices.push_back((uint32) elems[i]);
+}
 
-		// We unmap the buffer in Mesh::draw and Mesh::setVertexMap.
-		return (uint32 *) ibo->map();
-	}
+void Mesh::getVertexMap(std::vector<uint32> &map) const
+{
+	if (!ibo || element_count == 0)
+		return;
 
-	return nullptr;
+	map.clear();
+	map.reserve(element_count);
+
+	VertexBuffer::Bind ibo_bind(*ibo);
+
+	// We unmap the buffer in Mesh::draw and Mesh::setVertexMap.
+	void *buffer = ibo->map();
+
+	// Fill the vector from the buffer.
+	switch (element_data_type)
+	{
+	case GL_UNSIGNED_BYTE:
+		copyFromIndexBuffer<uint8>(buffer, map, vertex_count);
+		break;
+	case GL_UNSIGNED_SHORT:
+		copyFromIndexBuffer<uint16>(buffer, map, vertex_count);
+		break;
+	case GL_UNSIGNED_INT:
+	default:
+		copyFromIndexBuffer<uint32>(buffer, map, vertex_count);
+		break;
+	}
 }
 
 size_t Mesh::getVertexMapCount() const
@@ -335,7 +405,7 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
 			min = std::min(std::max(range_min, 0), max);
 
 		const void *indices = ibo->getPointer(min * sizeof(uint32));
-		GLenum type = GL_UNSIGNED_INT;
+		GLenum type = element_data_type;
 
 		if (instance_count > 1)
 			gl.drawElementsInstanced(mode, max - min + 1, type, indices, instance_count);
@@ -375,7 +445,7 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
 		texture->postdraw();
 }
 
-GLenum Mesh::getGLDrawMode(Mesh::DrawMode mode) const
+GLenum Mesh::getGLDrawMode(DrawMode mode) const
 {
 	switch (mode)
 	{
@@ -394,6 +464,16 @@ GLenum Mesh::getGLDrawMode(Mesh::DrawMode mode) const
 	return GL_TRIANGLES;
 }
 
+GLenum Mesh::getGLDataTypeFromMax(size_t maxvalue) const
+{
+	if (maxvalue > LOVE_UINT16_MAX)
+		return GL_UNSIGNED_INT;
+	else if (maxvalue > LOVE_UINT8_MAX)
+		return GL_UNSIGNED_SHORT;
+	else
+		return GL_UNSIGNED_BYTE;
+}
+
 bool Mesh::getConstant(const char *in, Mesh::DrawMode &out)
 {
 	return drawModes.find(in, out);

+ 5 - 4
jni/love/src/modules/graphics/opengl/Mesh.h

@@ -109,11 +109,10 @@ public:
 	void setVertexMap(const std::vector<uint32> &map);
 
 	/**
-	 * Gets a pointer to the vertex map array. The pointer is only valid until
-	 * the next function call in the graphics module.
-	 * May return null if the vertex map is empty.
+	 * Fills the uint32 vector passed into the method with the previously set
+	 * vertex map (index buffer) values.
 	 **/
-	const uint32 *getVertexMap() const;
+	void getVertexMap(std::vector<uint32> &map) const;
 
 	/**
 	 * Gets the total number of elements in the vertex map array.
@@ -171,6 +170,7 @@ public:
 private:
 
 	GLenum getGLDrawMode(DrawMode mode) const;
+	GLenum getGLDataTypeFromMax(size_t maxvalue) const;
 
 	// Vertex buffer.
 	VertexBuffer *vbo;
@@ -179,6 +179,7 @@ private:
 	// Element (vertex index) buffer, for the vertex map.
 	VertexBuffer *ibo;
 	size_t element_count;
+	GLenum element_data_type;
 
 	int instance_count;
 

+ 1 - 1
jni/love/src/modules/graphics/opengl/ParticleSystem.h

@@ -66,7 +66,7 @@ public:
 		INSERT_MODE_TOP,
 		INSERT_MODE_BOTTOM,
 		INSERT_MODE_RANDOM,
-		INSERT_MODE_MAX_ENUM,
+		INSERT_MODE_MAX_ENUM
 	};
 
 	/**

+ 2 - 2
jni/love/src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -494,8 +494,8 @@ int w_newMesh(lua_State *L)
 			v.x = (float) luaL_checknumber(L, -8);
 			v.y = (float) luaL_checknumber(L, -7);
 
-			v.s = (float) luaL_checknumber(L, -6);
-			v.t = (float) luaL_checknumber(L, -5);
+			v.s = (float) luaL_optnumber(L, -6, 0.0);
+			v.t = (float) luaL_optnumber(L, -5, 0.0);
 
 			v.r = (unsigned char) luaL_optinteger(L, -4, 255);
 			v.g = (unsigned char) luaL_optinteger(L, -3, 255);

+ 18 - 13
jni/love/src/modules/graphics/opengl/wrap_Mesh.cpp

@@ -53,8 +53,8 @@ int w_Mesh_setVertex(lua_State *L)
 
 		v.x = luaL_checknumber(L, -8);
 		v.y = luaL_checknumber(L, -7);
-		v.s = luaL_checknumber(L, -6);
-		v.t = luaL_checknumber(L, -5);
+		v.s = luaL_optnumber(L, -6, 0.0);
+		v.t = luaL_optnumber(L, -5, 0.0);
 		v.r = luaL_optinteger(L, -4, 255);
 		v.g = luaL_optinteger(L, -3, 255);
 		v.b = luaL_optinteger(L, -2, 255);
@@ -66,8 +66,8 @@ int w_Mesh_setVertex(lua_State *L)
 	{
 		v.x = luaL_checknumber(L, 3);
 		v.y = luaL_checknumber(L, 4);
-		v.s = luaL_checknumber(L, 5);
-		v.t = luaL_checknumber(L, 6);
+		v.s = luaL_optnumber(L, 5, 0.0);
+		v.t = luaL_optnumber(L, 6, 0.0);
 		v.r = luaL_optinteger(L,  7, 255);
 		v.g = luaL_optinteger(L,  8, 255);
 		v.b = luaL_optinteger(L,  9, 255);
@@ -122,8 +122,8 @@ int w_Mesh_setVertices(lua_State *L)
 		v.x = (float) luaL_checknumber(L, -8);
 		v.y = (float) luaL_checknumber(L, -7);
 
-		v.s = (float) luaL_checknumber(L, -6);
-		v.t = (float) luaL_checknumber(L, -5);
+		v.s = (float) luaL_optnumber(L, -6, 0.0);
+		v.t = (float) luaL_optnumber(L, -5, 0.0);
 
 		v.r = (unsigned char) luaL_optinteger(L, -4, 255);
 		v.g = (unsigned char) luaL_optinteger(L, -3, 255);
@@ -220,14 +220,15 @@ int w_Mesh_setVertexMap(lua_State *L)
 int w_Mesh_getVertexMap(lua_State *L)
 {
 	Mesh *t = luax_checkmesh(L, 1);
-	const uint32 *vertex_map = 0;
 
-	EXCEPT_GUARD(vertex_map = t->getVertexMap();)
-	size_t elements = t->getVertexMapCount();
+	std::vector<uint32> vertex_map;
+	EXCEPT_GUARD(t->getVertexMap(vertex_map);)
 
-	lua_createtable(L, elements, 0);
+	size_t element_count = vertex_map.size();
 
-	for (size_t i = 0; i < elements; i++)
+	lua_createtable(L, element_count, 0);
+
+	for (size_t i = 0; i < element_count; i++)
 	{
 		lua_pushinteger(L, lua_Integer(vertex_map[i]) + 1);
 		lua_rawseti(L, -2, i + 1);
@@ -370,8 +371,12 @@ static const luaL_Reg functions[] =
 	{ "getVertexCount", w_Mesh_getVertexCount },
 	{ "setVertexMap", w_Mesh_setVertexMap },
 	{ "getVertexMap", w_Mesh_getVertexMap },
-	{ "setInstanceCount", w_Mesh_setInstanceCount },
-	{ "getInstanceCount", w_Mesh_getInstanceCount },
+
+	// Disabled for now, since implementation is incomplete and might change
+	// if/when VertexBuffers / custom vertex attributes are added.
+	// { "setInstanceCount", w_Mesh_setInstanceCount },
+	// { "getInstanceCount", w_Mesh_getInstanceCount },
+
 	{ "setTexture", w_Mesh_setTexture },
 	{ "getTexture", w_Mesh_getTexture },
 	{ "setDrawMode", w_Mesh_setDrawMode },

+ 4 - 4
jni/love/src/modules/image/CompressedData.cpp

@@ -36,9 +36,9 @@ CompressedData::~CompressedData()
 {
 }
 
-int CompressedData::getSize() const
+size_t CompressedData::getSize() const
 {
-	return int(dataSize);
+	return dataSize;
 }
 
 void *CompressedData::getData() const
@@ -51,11 +51,11 @@ int CompressedData::getMipmapCount() const
 	return dataImages.size();
 }
 
-int CompressedData::getSize(int miplevel) const
+size_t CompressedData::getSize(int miplevel) const
 {
 	checkMipmapLevelExists(miplevel);
 
-	return int(dataImages[miplevel].size);
+	return dataImages[miplevel].size;
 }
 
 void *CompressedData::getData(int miplevel) const

+ 2 - 2
jni/love/src/modules/image/CompressedData.h

@@ -71,7 +71,7 @@ public:
 
 	// Implements Data.
 	virtual void *getData() const;
-	virtual int getSize() const;
+	virtual size_t getSize() const;
 
 	/**
 	 * Gets the number of mipmaps in this Compressed Image Data.
@@ -82,7 +82,7 @@ public:
 	/**
 	 * Gets the size in bytes of a sub-image at the specified mipmap level.
 	 **/
-	int getSize(int miplevel) const;
+	size_t getSize(int miplevel) const;
 
 	/**
 	 * Gets the byte data of a sub-image at the specified mipmap level.

+ 2 - 2
jni/love/src/modules/image/Image.h

@@ -47,7 +47,7 @@ public:
 	/**
 	 * Destructor.
 	 **/
-	virtual ~Image() {};
+	virtual ~Image() {}
 
 	/**
 	 * Creates new ImageData from FileData.
@@ -93,4 +93,4 @@ public:
 } // image
 } // love
 
-#endif // LOVE_IMAGE_IMAGE_H
+#endif // LOVE_IMAGE_IMAGE_H

+ 2 - 2
jni/love/src/modules/image/ImageData.cpp

@@ -38,9 +38,9 @@ ImageData::~ImageData()
 	delete mutex;
 }
 
-int ImageData::getSize() const
+size_t ImageData::getSize() const
 {
-	return getWidth()*getHeight()*sizeof(pixel);
+	return size_t(getWidth()*getHeight())*sizeof(pixel);
 }
 
 void *ImageData::getData() const

+ 1 - 1
jni/love/src/modules/image/ImageData.h

@@ -130,7 +130,7 @@ public:
 
 	// Implements Data.
 	virtual void *getData() const;
-	virtual int getSize() const;
+	virtual size_t getSize() const;
 
 protected:
 

+ 14 - 18
jni/love/src/modules/image/magpie/DevilHandler.cpp

@@ -23,15 +23,10 @@
 // LOVE
 #include "common/Exception.h"
 #include "common/math.h"
-#include "thread/threads.h"
 
 // DevIL
 #include <IL/il.h>
 
-using love::thread::Lock;
-
-static Mutex *devilMutex = 0;
-
 namespace love
 {
 namespace image
@@ -44,21 +39,22 @@ static inline void ilxClearErrors()
 	while (ilGetError() != IL_NO_ERROR);
 }
 
-void DevilHandler::init()
+DevilHandler::DevilHandler()
+	: mutex(nullptr)
 {
+	// There should only ever be one DevilHandler object (owned by the Image
+	// module), so we can use the global initialization function here.
 	ilInit();
 	ilEnable(IL_ORIGIN_SET);
 	ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
 }
 
-void DevilHandler::quit()
+DevilHandler::~DevilHandler()
 {
 	ilShutDown();
-	if (devilMutex)
-	{
-		delete devilMutex;
-		devilMutex = 0;
-	}
+
+	if (mutex)
+		delete mutex;
 }
 
 bool DevilHandler::canDecode(love::filesystem::FileData * /*data*/)
@@ -85,10 +81,10 @@ bool DevilHandler::canEncode(ImageData::Format format)
 
 DevilHandler::DecodedImage DevilHandler::decode(love::filesystem::FileData *data)
 {
-	if (!devilMutex)
-		devilMutex = thread::newMutex();
+	if (!mutex)
+		mutex = love::thread::newMutex();
 
-	Lock lock(devilMutex);
+	love::thread::Lock lock(mutex);
 
 	ILuint image = ilGenImage();
 	ilBindImage(image);
@@ -140,10 +136,10 @@ DevilHandler::DecodedImage DevilHandler::decode(love::filesystem::FileData *data
 
 DevilHandler::EncodedImage DevilHandler::encode(const DecodedImage &img, ImageData::Format format)
 {
-	if (!devilMutex)
-		devilMutex = thread::newMutex();
+	if (!mutex)
+		mutex = love::thread::newMutex();
 
-	Lock lock(devilMutex);
+	love::thread::Lock lock(mutex);
 
 	ILuint tempimage = ilGenImage();
 	ilBindImage(tempimage);

+ 12 - 7
jni/love/src/modules/image/magpie/DevilHandler.h

@@ -24,6 +24,7 @@
 // LOVE
 #include "filesystem/FileData.h"
 #include "FormatHandler.h"
+#include "thread/threads.h"
 
 namespace love
 {
@@ -39,16 +40,20 @@ class DevilHandler : public FormatHandler
 {
 public:
 
-	static void init();
-	static void quit();
-
 	// Implements FormatHandler.
 
-	static bool canDecode(love::filesystem::FileData *data);
-	static bool canEncode(ImageData::Format format);
+	DevilHandler();
+	virtual ~DevilHandler();
+
+	virtual bool canDecode(love::filesystem::FileData *data);
+	virtual bool canEncode(ImageData::Format format);
+
+	virtual DecodedImage decode(love::filesystem::FileData *data);
+	virtual EncodedImage encode(const DecodedImage &img, ImageData::Format format);
+
+private:
 
-	static DecodedImage decode(love::filesystem::FileData *data);
-	static EncodedImage encode(const DecodedImage &img, ImageData::Format format);
+	Mutex *mutex;
 
 }; // DevilHandler
 

+ 62 - 0
jni/love/src/modules/image/magpie/FormatHandler.cpp

@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2006-2014 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 "FormatHandler.h"
+#include "common/Exception.h"
+
+namespace love
+{
+namespace image
+{
+namespace magpie
+{
+
+FormatHandler::FormatHandler()
+{
+}
+
+FormatHandler::~FormatHandler()
+{
+}
+
+bool FormatHandler::canDecode(love::filesystem::FileData* /*data*/)
+{
+	return false;
+}
+
+bool FormatHandler::canEncode(ImageData::Format /*format*/)
+{
+	return false;
+}
+
+FormatHandler::DecodedImage FormatHandler::decode(love::filesystem::FileData* /*data*/)
+{
+	throw love::Exception("Image decoding is not implemented for this format backend.");
+}
+
+FormatHandler::EncodedImage FormatHandler::encode(const DecodedImage& /*img*/, ImageData::Format /*format*/)
+{
+	throw love::Exception("Image encoding is not implemented for this format backend.");
+}
+
+} // magpie
+} // image
+} // love

+ 18 - 10
jni/love/src/modules/image/magpie/FormatHandler.h

@@ -24,6 +24,7 @@
 // LOVE
 #include "image/ImageData.h"
 #include "filesystem/FileData.h"
+#include "common/Object.h"
 
 namespace love
 {
@@ -34,8 +35,9 @@ namespace magpie
 
 /**
  * Base class for all ImageData encoder/decoder library interfaces.
+ * We inherit from love::Object to take advantage of reference counting...
  **/
-class FormatHandler
+class FormatHandler : public love::Object
 {
 public:
 
@@ -56,26 +58,32 @@ public:
 		EncodedImage() : size(0), data(0) {}
 	};
 
-	// Lets pretend we have virtual static methods...
+	/**
+	 * The default constructor is called when the Image module is initialized.
+	 **/
+	FormatHandler();
 
 	/**
-	 * Determines whether a particular FileData can be decoded by this handler.
-	 * @param data The data to decode.
+	 * The destructor is called when the Image module is uninitialized.
 	 **/
-	// virtual static bool canDecode(love::filesystem::FileData *data) = 0;
+	virtual ~FormatHandler();
 
 	/**
-	 * Determines whether this handler can encode to a particular format.
-	 * @param format The format to encode to.
+	 * Whether this format handler can decode a particular FileData.
+	 **/
+	virtual bool canDecode(love::filesystem::FileData *data);
+
+	/**
+	 * Whether this format handler can encode to a particular format.
 	 **/
-	// virtual static bool canEncode(ImageData::Format format) = 0;
+	virtual bool canEncode(ImageData::Format format);
 
 	/**
 	 * Decodes an image from its encoded form into raw pixel data.
 	 * @param data The encoded data to decode.
 	 * @return The decoded pixel data.
 	 **/
-	// virtual static DecodedImage decode(love::filesystem::FileData *data) = 0;
+	virtual DecodedImage decode(love::filesystem::FileData *data);
 
 	/**
 	 * Encodes an image from raw pixel data into a particular format.
@@ -83,7 +91,7 @@ public:
 	 * @param format The format to encode to.
 	 * @return The encoded image data.
 	 **/
-	// virtual static EncodedImage encode(const DecodedImage &img, ImageData::Format format) = 0;
+	virtual EncodedImage encode(const DecodedImage &img, ImageData::Format format);
 
 }; // FormatHandler
 

+ 8 - 5
jni/love/src/modules/image/magpie/Image.cpp

@@ -34,12 +34,15 @@ namespace magpie
 
 Image::Image()
 {
-	DevilHandler::init();
+	formatHandlers.push_back(new DevilHandler);
 }
 
 Image::~Image()
 {
-	DevilHandler::quit();
+	// ImageData objects reference the FormatHandlers in our list, so we should
+	// release them instead of deleting them completely here.
+	for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it)
+		(*it)->release();
 }
 
 const char *Image::getName() const
@@ -49,17 +52,17 @@ const char *Image::getName() const
 
 love::image::ImageData *Image::newImageData(love::filesystem::FileData *data)
 {
-	return new ImageData(data);
+	return new ImageData(formatHandlers, data);
 }
 
 love::image::ImageData *Image::newImageData(int width, int height)
 {
-	return new ImageData(width, height);
+	return new ImageData(formatHandlers, width, height);
 }
 
 love::image::ImageData *Image::newImageData(int width, int height, void *data, bool own)
 {
-	return new ImageData(width, height, data, own);
+	return new ImageData(formatHandlers, width, height, data, own);
 }
 
 love::image::CompressedData *Image::newCompressedData(love::filesystem::FileData *data)

+ 9 - 0
jni/love/src/modules/image/magpie/Image.h

@@ -23,6 +23,10 @@
 
 // LOVE
 #include "image/Image.h"
+#include "FormatHandler.h"
+
+// C++
+#include <list>
 
 namespace love
 {
@@ -54,6 +58,11 @@ public:
 
 	bool isCompressed(love::filesystem::FileData *data);
 
+private:
+
+	// Image format handlers we can use for decoding and encoding ImageData.
+	std::list<FormatHandler *> formatHandlers;
+
 }; // Image
 
 } // magpie

+ 41 - 14
jni/love/src/modules/image/magpie/ImageData.cpp

@@ -18,11 +18,9 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
+// LOVE
 #include "ImageData.h"
 
-#include "FormatHandler.h"
-#include "DevilHandler.h"
-
 namespace love
 {
 namespace image
@@ -30,23 +28,36 @@ namespace image
 namespace magpie
 {
 
-ImageData::ImageData(love::filesystem::FileData *data)
+ImageData::ImageData(std::list<FormatHandler *> formats, love::filesystem::FileData *data)
+	: formatHandlers(formats)
 {
+	for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it)
+		(*it)->retain();
+
 	decode(data);
 }
 
-ImageData::ImageData(int width, int height)
+ImageData::ImageData(std::list<FormatHandler *> formats, int width, int height)
+	: formatHandlers(formats)
 {
+	for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it)
+		(*it)->retain();
+
 	this->width = width;
 	this->height = height;
+
 	create(width, height);
 
 	// Set to black/transparency.
 	memset(data, 0, width*height*sizeof(pixel));
 }
 
-ImageData::ImageData(int width, int height, void *data, bool own)
+ImageData::ImageData(std::list<FormatHandler *> formats, int width, int height, void *data, bool own)
+	: formatHandlers(formats)
 {
+	for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it)
+		(*it)->retain();
+
 	this->width = width;
 	this->height = height;
 
@@ -59,6 +70,9 @@ ImageData::ImageData(int width, int height, void *data, bool own)
 ImageData::~ImageData()
 {
 	delete[] data;
+
+	for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it)
+		(*it)->release();
 }
 
 void ImageData::create(int width, int height, void *data)
@@ -80,16 +94,23 @@ void ImageData::decode(love::filesystem::FileData *data)
 {
 	FormatHandler::DecodedImage decodedimage;
 
-	if (DevilHandler::canDecode(data))
-		decodedimage = DevilHandler::decode(data);
-	else
+	for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it)
+	{
+		if ((*it)->canDecode(data))
+		{
+			decodedimage = (*it)->decode(data);
+			break;
+		}
+	}
+
+	if (decodedimage.data == nullptr)
 		throw love::Exception("Could not decode image: unrecognized format.");
 
 	// The decoder *must* output a 32 bits-per-pixel image.
 	if (decodedimage.size != decodedimage.width*decodedimage.height*sizeof(pixel))
 	{
 		delete[] decodedimage.data;
-		throw love::Exception("Coult not convert image!");
+		throw love::Exception("Could not convert image!");
 	}
 
 	if (this->data)
@@ -114,15 +135,21 @@ void ImageData::encode(love::filesystem::File *f, ImageData::Format format)
 		rawimage.size = width*height*sizeof(pixel);
 		rawimage.data = data;
 
-		if (DevilHandler::canEncode(format))
-			encodedimage = DevilHandler::encode(rawimage, format);
-		else
+		for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it)
+		{
+			if ((*it)->canEncode(format))
+			{
+				encodedimage = (*it)->encode(rawimage, format);
+				break;
+			}
+		}
+
+		if (encodedimage.data == nullptr)
 			throw love::Exception("Image format has no suitable encoder.");
 	}
 
 	try
 	{
-		
 		f->open(love::filesystem::File::WRITE);
 		f->write(encodedimage.data, encodedimage.size);
 		f->close();

+ 10 - 3
jni/love/src/modules/image/magpie/ImageData.h

@@ -22,9 +22,13 @@
 #define LOVE_IMAGE_MAGPIE_IMAGE_DATA_H
 
 // LOVE
+#include "FormatHandler.h"
 #include "filesystem/File.h"
 #include "image/ImageData.h"
 
+// C++
+#include <list>
+
 namespace love
 {
 namespace image
@@ -36,9 +40,9 @@ class ImageData : public love::image::ImageData
 {
 public:
 
-	ImageData(love::filesystem::FileData *data);
-	ImageData(int width, int height);
-	ImageData(int width, int height, void *data, bool own);
+	ImageData(std::list<FormatHandler *> formats, love::filesystem::FileData *data);
+	ImageData(std::list<FormatHandler *> formats, int width, int height);
+	ImageData(std::list<FormatHandler *> formats, int width, int height, void *data, bool own);
 	virtual ~ImageData();
 
 	// Implements image::ImageData.
@@ -52,6 +56,9 @@ private:
 	// Decode and load an encoded format.
 	void decode(love::filesystem::FileData *data);
 
+	// Image format handlers we can use for decoding and encoding.
+	std::list<FormatHandler *> formatHandlers;
+
 }; // ImageData
 
 } // magpie

+ 11 - 0
jni/love/src/modules/keyboard/Keyboard.cpp

@@ -221,6 +221,17 @@ StringMap<Keyboard::Key, Keyboard::KEY_MAX_ENUM>::Entry Keyboard::keyEntries[] =
 	{"audioplay", Keyboard::KEY_AUDIOPLAY},
 	{"audiomute", Keyboard::KEY_AUDIOMUTE},
 	{"mediaselect", Keyboard::KEY_MEDIASELECT},
+	{"www", Keyboard::KEY_WWW},
+	{"mail", Keyboard::KEY_MAIL},
+	{"calculator", Keyboard::KEY_CALCULATOR},
+	{"computer", Keyboard::KEY_COMPUTER},
+	{"appsearch", Keyboard::KEY_APP_SEARCH},
+	{"apphome", Keyboard::KEY_APP_HOME},
+	{"appback", Keyboard::KEY_APP_BACK},
+	{"appforward", Keyboard::KEY_APP_FORWARD},
+	{"appstop", Keyboard::KEY_APP_STOP},
+	{"apprefresh", Keyboard::KEY_APP_REFRESH},
+	{"appbookmarks", Keyboard::KEY_APP_BOOKMARKS},
 
 	{"brightnessdown", Keyboard::KEY_BRIGHTNESSDOWN},
 	{"brightnessup", Keyboard::KEY_BRIGHTNESSUP},

+ 11 - 0
jni/love/src/modules/keyboard/Keyboard.h

@@ -221,6 +221,17 @@ public:
 		KEY_AUDIOPLAY,
 		KEY_AUDIOMUTE,
 		KEY_MEDIASELECT,
+		KEY_WWW,
+		KEY_MAIL,
+		KEY_CALCULATOR,
+		KEY_COMPUTER,
+		KEY_APP_SEARCH,
+		KEY_APP_HOME,
+		KEY_APP_BACK,
+		KEY_APP_FORWARD,
+		KEY_APP_STOP,
+		KEY_APP_REFRESH,
+		KEY_APP_BOOKMARKS,
 
 		KEY_BRIGHTNESSDOWN,
 		KEY_BRIGHTNESSUP,

+ 11 - 0
jni/love/src/modules/keyboard/sdl/Keyboard.cpp

@@ -265,6 +265,17 @@ std::map<Keyboard::Key, SDL_Keycode> Keyboard::createKeyMap()
 	k[Keyboard::KEY_AUDIOPLAY] = SDLK_AUDIOPLAY;
 	k[Keyboard::KEY_AUDIOMUTE] = SDLK_AUDIOMUTE;
 	k[Keyboard::KEY_MEDIASELECT] = SDLK_MEDIASELECT;
+	k[Keyboard::KEY_WWW] = SDLK_WWW;
+	k[Keyboard::KEY_MAIL] = SDLK_MAIL;
+	k[Keyboard::KEY_CALCULATOR] = SDLK_CALCULATOR;
+	k[Keyboard::KEY_COMPUTER] = SDLK_COMPUTER;
+	k[Keyboard::KEY_APP_SEARCH] = SDLK_AC_SEARCH;
+	k[Keyboard::KEY_APP_HOME] = SDLK_AC_HOME;
+	k[Keyboard::KEY_APP_BACK] = SDLK_AC_BACK;
+	k[Keyboard::KEY_APP_FORWARD] = SDLK_AC_FORWARD;
+	k[Keyboard::KEY_APP_STOP] = SDLK_AC_STOP;
+	k[Keyboard::KEY_APP_REFRESH] = SDLK_AC_REFRESH;
+	k[Keyboard::KEY_APP_BOOKMARKS] = SDLK_AC_BOOKMARKS;
 
 	k[Keyboard::KEY_BRIGHTNESSDOWN] = SDLK_BRIGHTNESSDOWN;
 	k[Keyboard::KEY_BRIGHTNESSUP] = SDLK_BRIGHTNESSUP;

+ 13 - 13
jni/love/src/modules/math/MathModule.cpp

@@ -198,14 +198,14 @@ bool Math::isConvex(const std::vector<Vertex> &polygon)
  **/
 float Math::gammaToLinear(float c) const
 {
-	if (c > 1.0)
-		return 1.0;
-	else if (c < 0.0)
-		return 0.0;
+	if (c > 1.0f)
+		return 1.0f;
+	else if (c < 0.0f)
+		return 0.0f;
 	else if (c <= 0.04045)
-		return c / 12.92;
+		return c / 12.92f;
 	else
-		return powf((c + 0.055) / 1.055, 2.4);
+		return powf((c + 0.055f) / 1.055f, 2.4f);
 }
 
 /**
@@ -213,14 +213,14 @@ float Math::gammaToLinear(float c) const
  **/
 float Math::linearToGamma(float c) const
 {
-	if (c > 1.0)
-		return 1.0;
-	else if (c < 0.0)
-		return 0.0;
-	else if (c < 0.0031308)
-		return c * 12.92;
+	if (c > 1.0f)
+		return 1.0f;
+	else if (c < 0.0f)
+		return 0.0f;
+	else if (c < 0.0031308f)
+		return c * 12.92f;
 	else
-		return 1.055 * powf(c, 0.41666) - 0.055;
+		return 1.055f * powf(c, 0.41666f) - 0.055f;
 }
 
 } // math

+ 2 - 2
jni/love/src/modules/math/wrap_Math.cpp

@@ -259,7 +259,7 @@ static int getGammaArgs(lua_State *L, float color[4])
 		for (int i = 1; i <= n && i <= 4; i++)
 		{
 			lua_rawgeti(L, 1, i);
-			color[i - 1] = (float) luaL_checknumber(L, -1) / 255.0;
+			color[i - 1] = (float) luaL_checknumber(L, -1) / 255.0f;
 			numcomponents++;
 		}
 
@@ -270,7 +270,7 @@ static int getGammaArgs(lua_State *L, float color[4])
 		int n = lua_gettop(L);
 		for (int i = 1; i <= n && i <= 4; i++)
 		{
-			color[i - 1] = (float) luaL_checknumber(L, i) / 255.0;
+			color[i - 1] = (float) luaL_checknumber(L, i) / 255.0f;
 			numcomponents++;
 		}
 	}

+ 1 - 1
jni/love/src/modules/mouse/Mouse.h

@@ -49,7 +49,7 @@ public:
 		BUTTON_MAX_ENUM
 	};
 
-	virtual ~Mouse() {};
+	virtual ~Mouse() {}
 
 	virtual Cursor *newCursor(love::image::ImageData *data, int hotx, int hoty) = 0;
 	virtual Cursor *getSystemCursor(Cursor::SystemCursor cursortype) = 0;

+ 2 - 2
jni/love/src/modules/mouse/wrap_Cursor.cpp

@@ -51,7 +51,7 @@ int w_Cursor_getType(lua_State *L)
 
 	lua_pushstring(L, typestr);
 	return 1;
-};
+}
 
 static const luaL_Reg functions[] =
 {
@@ -65,4 +65,4 @@ extern "C" int luaopen_cursor(lua_State *L)
 }
 
 } // mouse
-} // love
+} // love

+ 43 - 1
jni/love/src/modules/physics/box2d/Body.cpp

@@ -37,10 +37,14 @@ namespace box2d
 
 Body::Body(World *world, b2Vec2 p, Body::Type type)
 	: world(world)
+	, udata(nullptr)
 {
+	udata = new bodyudata();
+	udata->ref = nullptr;
 	world->retain();
 	b2BodyDef def;
 	def.position = Physics::scaleDown(p);
+	def.userData = (void *) udata;
 	body = world->world->CreateBody(&def);
 	// Box2D body holds a reference to the love Body.
 	this->retain();
@@ -50,7 +54,9 @@ Body::Body(World *world, b2Vec2 p, Body::Type type)
 
 Body::Body(b2Body *b)
 	: body(b)
+	, udata(nullptr)
 {
+	udata = (bodyudata *) b->GetUserData();
 	world = (World *)Memoizer::find(b->GetWorld());
 	world->retain();
 	// Box2D body holds a reference to the love Body.
@@ -60,8 +66,10 @@ Body::Body(b2Body *b)
 
 Body::~Body()
 {
+	if (udata != nullptr)
+		delete udata->ref;
+	delete udata;
 	world->release();
-	body = 0;
 }
 
 float Body::getX()
@@ -469,6 +477,40 @@ void Body::destroy()
 	this->release();
 }
 
+int Body::setUserData(lua_State *L)
+{
+	love::luax_assert_argc(L, 1, 1);
+
+	if (udata == nullptr)
+	{
+		udata = new bodyudata();
+		body->SetUserData((void *) udata);
+	}
+
+	if (udata->ref != nullptr)
+	{
+		// We set the Reference's lua_State to this one before deleting it, so
+		// it unrefs using the current lua_State's stack. This is necessary
+		// if setUserData is called in a coroutine.
+		udata->ref->setL(L);
+		delete udata->ref;
+	}
+
+	udata->ref = new Reference(L);
+
+	return 0;
+}
+
+int Body::getUserData(lua_State *L)
+{
+	if (udata != nullptr && udata->ref != nullptr)
+		udata->ref->push(L);
+	else
+		lua_pushnil(L);
+
+	return 1;
+}
+
 } // box2d
 } // physics
 } // love

+ 26 - 1
jni/love/src/modules/physics/box2d/Body.h

@@ -41,6 +41,16 @@ class World;
 class Shape;
 class Fixture;
 
+/**
+ * This struct is stored in a void pointer in the Box2D Body class. For now, all
+ * we need is a Lua reference to arbitrary data, but we might need more later.
+ **/
+struct bodyudata
+{
+	// Reference to arbitrary data.
+	Reference *ref;
+};
+
 /**
  * A Body is an entity which has position and orientation
  * in world space. A Body does have collision geometry
@@ -388,6 +398,18 @@ public:
 	 **/
 	void destroy();
 
+	/**
+	 * This function stores an in-C reference to
+	 * arbitrary Lua data in the Box2D Body object.
+	 **/
+	int setUserData(lua_State *L);
+
+	/**
+	 * Gets the data set with setData. If no
+	 * data is set, nil is returned.
+	 **/
+	int getUserData(lua_State *L);
+
 private:
 
 	/**
@@ -408,7 +430,10 @@ private:
 	// This ensures that a World only can be destroyed
 	// once all bodies have been destroyed too.
 	World *world;
-};
+
+	bodyudata *udata;
+
+}; // Body
 
 } // box2d
 } // physics

+ 16 - 16
jni/love/src/modules/physics/box2d/Fixture.cpp

@@ -39,10 +39,10 @@ namespace box2d
 
 Fixture::Fixture(Body *body, Shape *shape, float density)
 	: body(body)
-	, fixture(NULL)
+	, fixture(nullptr)
 {
 	data = new fixtureudata();
-	data->ref = 0;
+	data->ref = nullptr;
 	b2FixtureDef def;
 	def.shape = shape->shape;
 	def.userData = (void *)data;
@@ -65,13 +65,10 @@ Fixture::Fixture(b2Fixture *f)
 
 Fixture::~Fixture()
 {
-	if (data->ref != 0)
+	if (data != nullptr)
 		delete data->ref;
 
 	delete data;
-	data = NULL;
-
-	fixture = NULL;
 }
 
 Shape::Type Fixture::getType() const
@@ -127,14 +124,14 @@ Body *Fixture::getBody() const
 Shape *Fixture::getShape() const
 {
 	if (!fixture->GetShape())
-		return NULL;
+		return nullptr;
 
 	return new Shape(fixture->GetShape(), false);
 }
 
 bool Fixture::isValid() const
 {
-	return fixture != 0;
+	return fixture != nullptr;
 }
 
 void Fixture::setFilterData(int *v)
@@ -205,7 +202,7 @@ uint16 Fixture::getBits(lua_State *L)
 	{
 		size_t bpos = (size_t)(lua_tointeger(L, i)-1);
 		if (bpos >= 16)
-			return luaL_error(L, "Values must be in range 1-16.");
+			luaL_error(L, "Values must be in range 1-16.");
 		b.set(bpos, true);
 	}
 
@@ -230,21 +227,24 @@ int Fixture::setUserData(lua_State *L)
 {
 	love::luax_assert_argc(L, 1, 1);
 
-	if (data->ref != 0)
+	if (data->ref != nullptr)
 	{
+		// We set the Reference's lua_State to this one before deleting it, so
+		// it unrefs using the current lua_State's stack. This is necessary
+		// if setUserData is called in a coroutine.
+		data->ref->setL(L);
 		delete data->ref;
-		data->ref = 0;
 	}
 
 	data->ref = new Reference(L);
+
 	return 0;
 }
 
 int Fixture::getUserData(lua_State *L)
 {
-	love::luax_assert_argc(L, 0, 0);
-	if (data->ref != 0)
-		data->ref->push();
+	if (data->ref != nullptr)
+		data->ref->push(L);
 	else
 		lua_pushnil(L);
 
@@ -311,10 +311,10 @@ void Fixture::destroy(bool implicit)
 		return;
 	}
 
-	if (!implicit && fixture != 0)
+	if (!implicit && fixture != nullptr)
 		body->body->DestroyFixture(fixture);
 	Memoizer::remove(fixture);
-	fixture = NULL;
+	fixture = nullptr;
 
 	// Box2D fixture destroyed. Release its reference to the love Fixture.
 	this->release();

+ 0 - 3
jni/love/src/modules/physics/box2d/Fixture.h

@@ -123,9 +123,6 @@ public:
 	/**
 	 * This function stores an in-C reference to
 	 * arbitrary Lua data in the Box2D Fixture object.
-	 *
-	 * The data set here will be passed to the collision
-	 * handler when collisions occur.
 	 **/
 	int setUserData(lua_State *L);
 

+ 16 - 0
jni/love/src/modules/physics/box2d/wrap_Body.cpp

@@ -538,6 +538,20 @@ int w_Body_destroy(lua_State *L)
 	return 0;
 }
 
+int w_Body_setUserData(lua_State *L)
+{
+	Body *t = luax_checkbody(L, 1);
+	lua_remove(L, 1);
+	return t->setUserData(L);
+}
+
+int w_Body_getUserData(lua_State *L)
+{
+	Body *t = luax_checkbody(L, 1);
+	lua_remove(L, 1);
+	return t->getUserData(L);
+}
+
 static const luaL_Reg functions[] =
 {
 	{ "getX", w_Body_getX },
@@ -592,6 +606,8 @@ static const luaL_Reg functions[] =
 	{ "isFixedRotation", w_Body_isFixedRotation },
 	{ "getFixtureList", w_Body_getFixtureList },
 	{ "destroy", w_Body_destroy },
+	{ "setUserData", w_Body_setUserData },
+	{ "getUserData", w_Body_getUserData },
 	{ 0, 0 }
 };
 

+ 2 - 0
jni/love/src/modules/physics/box2d/wrap_Body.h

@@ -85,6 +85,8 @@ int w_Body_setFixedRotation(lua_State *L);
 int w_Body_isFixedRotation(lua_State *L);
 int w_Body_getFixtureList(lua_State *L);
 int w_Body_destroy(lua_State *L);
+int w_Body_setUserData(lua_State *L);
+int w_Body_getUserData(lua_State *L);
 extern "C" int luaopen_body(lua_State *L);
 
 } // box2d

+ 1 - 1
jni/love/src/modules/physics/box2d/wrap_MotorJoint.cpp

@@ -140,4 +140,4 @@ extern "C" int luaopen_motorjoint(lua_State *L)
 
 } // box2d
 } // phyics
-} // love
+} // love

+ 9 - 3
jni/love/src/modules/physics/box2d/wrap_World.cpp

@@ -143,21 +143,27 @@ int w_World_getBodyList(lua_State *L)
 {
 	World *t = luax_checkworld(L, 1);
 	lua_remove(L, 1);
-	return t->getBodyList(L);
+	int ret = 0;
+	EXCEPT_GUARD(ret = t->getBodyList(L);)
+	return ret;
 }
 
 int w_World_getJointList(lua_State *L)
 {
 	World *t = luax_checkworld(L, 1);
 	lua_remove(L, 1);
-	return t->getJointList(L);
+	int ret = 0;
+	EXCEPT_GUARD(ret = t->getJointList(L);)
+	return ret;
 }
 
 int w_World_getContactList(lua_State *L)
 {
 	World *t = luax_checkworld(L, 1);
 	lua_remove(L, 1);
-	return t->getContactList(L);
+	int ret = 0;
+	EXCEPT_GUARD(ret = t->getContactList(L);)
+	return ret;
 }
 
 int w_World_queryBoundingBox(lua_State *L)

+ 1 - 1
jni/love/src/modules/sound/Decoder.h

@@ -67,7 +67,7 @@ public:
 	/**
 	 * Destructor. Should free internal buffer.
 	 **/
-	virtual ~Decoder() {};
+	virtual ~Decoder() {}
 
 	/**
 	 * Decodes the next chunk of the music stream, this will usually be

+ 29 - 25
jni/love/src/modules/sound/SoundData.cpp

@@ -21,11 +21,11 @@
 #include "SoundData.h"
 
 // C
-#include <climits>
 #include <cstdlib>
 #include <cstring>
 
-// STL
+// C++
+#include <limits>
 #include <iostream>
 #include <vector>
 
@@ -48,11 +48,11 @@ SoundData::SoundData(Decoder *decoder)
 	{
 		// Expand or allocate buffer. Note that realloc may move
 		// memory to other locations.
-		if (!data || bufferSize < (size_t) size + decoded)
+		if (!data || bufferSize < size + decoded)
 		{
-			while (bufferSize < (size_t) size + decoded)
+			while (bufferSize < size + decoded)
 				bufferSize <<= 1;
-			data = (char *)realloc(data, bufferSize);
+			data = (uint8 *) realloc(data, bufferSize);
 		}
 
 		if (!data)
@@ -61,22 +61,22 @@ SoundData::SoundData(Decoder *decoder)
 		// Copy memory into new part of memory.
 		memcpy(data + size, decoder->getBuffer(), decoded);
 
-		// Keep this up to date.
-		size += decoded;
-
 		// Overflow check.
-		if (size < 0)
+		if (size > std::numeric_limits<size_t>::max() - decoded)
 		{
 			free(data);
 			throw love::Exception("Not enough memory.");
 		}
 
+		// Keep this up to date.
+		size += decoded;
+
 		decoded = decoder->decode();
 	}
 
 	// Shrink buffer if necessary.
-	if (data && bufferSize > (size_t) size)
-		data = (char *) realloc(data, size);
+	if (data && bufferSize > size)
+		data = (uint8 *) realloc(data, size);
 
 	channels = decoder->getChannels();
 	bitDepth = decoder->getBitDepth();
@@ -136,15 +136,17 @@ void SoundData::load(int samples, int sampleRate, int bitDepth, int channels, vo
 
 	double realsize = samples;
 	realsize *= (bitDepth / 8) * channels;
-	if (realsize > INT_MAX)
+	if (realsize > std::numeric_limits<size_t>::max())
 		throw love::Exception("Data is too big!");
 
-	data = (char *)malloc(size);
+	data = (uint8 *) malloc(size);
 	if (!data)
 		throw love::Exception("Not enough memory.");
 
 	if (newData)
 		memcpy(data, newData, size);
+	else
+		memset(data, bitDepth == 8 ? 128 : 0, size);
 }
 
 void *SoundData::getData() const
@@ -152,9 +154,9 @@ void *SoundData::getData() const
 	return (void *)data;
 }
 
-int SoundData::getSize() const
+size_t SoundData::getSize() const
 {
-	return (int)size;
+	return size;
 }
 
 int SoundData::getChannels() const
@@ -185,36 +187,38 @@ float SoundData::getDuration() const
 void SoundData::setSample(int i, float sample)
 {
 	// Check range.
-	if (i < 0 || i >= size/(bitDepth/8))
+	if (i < 0 || (size_t) i >= size/(bitDepth/8))
 		throw love::Exception("Attempt to set out-of-range sample!");
 
 	if (bitDepth == 16)
 	{
-		short *s = (short *)data;
-		s[i] = (short)(sample*(float)SHRT_MAX);
-		return;
+		// 16-bit sample values are signed.
+		int16 *s = (int16 *) data;
+		s[i] = (int16) (sample * (float) LOVE_INT16_MAX);
 	}
 	else
 	{
-		data[i] = (char)(sample*(float)CHAR_MAX);
-		return;
+		// 8-bit sample values are unsigned internally.
+		data[i] = (uint8) ((sample * 127.0f) + 128.0f);
 	}
 }
 
 float SoundData::getSample(int i) const
 {
 	// Check range.
-	if (i < 0 || i >= size/(bitDepth/8))
+	if (i < 0 || (size_t) i >= size/(bitDepth/8))
 		throw love::Exception("Attempt to get out-of-range sample!");
 
 	if (bitDepth == 16)
 	{
-		short *s = (short *)data;
-		return (float)s[i]/(float)SHRT_MAX;
+		// 16-bit sample values are signed.
+		int16 *s = (int16 *) data;
+		return (float) s[i] / (float) LOVE_INT16_MAX;
 	}
 	else
 	{
-		return (float)data[i]/(float)CHAR_MAX;
+		// 8-bit sample values are unsigned internally.
+		return ((float) data[i] - 128.0f) / 127.0f;
 	}
 }
 

+ 5 - 4
jni/love/src/modules/sound/SoundData.h

@@ -23,7 +23,7 @@
 
 // LOVE
 #include "filesystem/File.h"
-
+#include "common/int.h"
 #include "Decoder.h"
 
 namespace love
@@ -43,7 +43,7 @@ public:
 
 	// Implements Data.
 	void *getData() const;
-	int getSize() const;
+	size_t getSize() const;
 
 	virtual int getChannels() const;
 	virtual int getBitDepth() const;
@@ -59,12 +59,13 @@ private:
 
 	void load(int samples, int sampleRate, int bitDepth, int channels, void *newData = 0);
 
-	char *data;
-	int size;
+	uint8 *data;
+	size_t size;
 
 	int sampleRate;
 	int bitDepth;
 	int channels;
+
 }; // SoundData
 
 } // sound

+ 1 - 1
jni/love/src/modules/sound/lullaby/FLACDecoder.cpp

@@ -183,4 +183,4 @@ void FLACDecoder::error_callback(FLAC__StreamDecoderErrorStatus status)
 } // sound
 } // love
 
-#endif // 0
+#endif // 0

+ 1 - 1
jni/love/src/modules/sound/lullaby/GmeDecoder.cpp

@@ -146,4 +146,4 @@ int GmeDecoder::getBitDepth() const
 } // sound
 } // love
 
-#endif // LOVE_SUPPORT_GME
+#endif // LOVE_SUPPORT_GME

+ 86 - 2
jni/love/src/modules/system/System.cpp

@@ -18,8 +18,25 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
+// LOVE
+#include "common/config.h"
 #include "System.h"
 
+#if defined(LOVE_MACOSX)
+#include <CoreServices/CoreServices.h>
+#elif defined(LOVE_ANDROID)
+#include "common/android.h"
+#elif defined(LOVE_LINUX)
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#elif defined(LOVE_WINDOWS)
+#include "common/utf8.h"
+#include <shlobj.h>
+#include <shellapi.h>
+#pragma comment(lib, "shell32.lib")
+#endif
+
 namespace love
 {
 namespace system
@@ -27,9 +44,9 @@ namespace system
 
 std::string System::getOS() const
 {
-#ifdef LOVE_MACOSX
+#if defined(LOVE_MACOSX)
 	return "OS X";
-#elif LOVE_WINDOWS
+#elif defined(LOVE_WINDOWS)
 	return "Windows";
 #elif LOVE_ANDROID
 	return "Android";
@@ -40,6 +57,73 @@ std::string System::getOS() const
 #endif
 }
 
+bool System::openURL(const std::string &url) const
+{
+	bool success = false;
+
+#if defined(LOVE_MACOSX)
+
+	// We could be lazy and use system("open " + url), but this is safer.
+	CFURLRef cfurl = CFURLCreateWithBytes(nullptr,
+	                                      (const UInt8 *) url.c_str(),
+	                                      url.length(),
+	                                      kCFStringEncodingUTF8,
+	                                      nullptr);
+
+	success = LSOpenCFURLRef(cfurl, nullptr) == noErr;
+	CFRelease(cfurl);
+
+#elif defined(LOVE_ANDROID)
+
+	success = love::android::openURL (url);	
+
+#elif defined(LOVE_LINUX)
+
+	// Spawn a child process, which we'll replace with xdg-open.
+	pid_t pid = vfork();
+
+	if (pid == 0) // Child process.
+	{
+		// Replace the child process with xdg-open and pass in the URL.
+		execlp("xdg-open", "xdg-open", url.c_str(), nullptr);
+
+		// exec will only return if it errored, so we should exit with non-zero.
+		_exit(1);
+	}
+	else if (pid > 0) // Parent process.
+	{
+		// Wait for xdg-open to complete (or fail.)
+		int status = 0;
+		if (waitpid(pid, &status, 0) == pid)
+			success = (status == 0);
+		else
+			success = false;
+	}
+	else
+	{
+		// vfork() failed.
+		success = false;
+	}
+
+#elif defined(LOVE_WINDOWS)
+
+	// Unicode-aware WinAPI functions don't accept UTF-8, so we need to convert.
+	std::wstring wurl = to_widestr(url);
+
+	HINSTANCE result = ShellExecuteW(nullptr,
+	                                 L"open",
+	                                 wurl.c_str(),
+	                                 nullptr,
+	                                 nullptr,
+	                                 SW_SHOW);
+
+	success = (int) result > 32;
+
+#endif
+
+	return success;
+}
+
 bool System::getConstant(const char *in, System::PowerState &out)
 {
 	return powerStates.find(in, out);

+ 10 - 0
jni/love/src/modules/system/System.h

@@ -85,6 +85,16 @@ public:
 	 **/
 	virtual PowerState getPowerInfo(int &seconds, int &percent) const = 0;
 
+	/**
+	 * Opens the specified URL with the user's default program to handle that
+	 * particular URL type.
+	 *
+	 * @param url The URL to open.
+	 *
+	 * @return Whether the URL was opened successfully.
+	 **/
+	virtual bool openURL(const std::string &url) const;
+
 	static bool getConstant(const char *in, PowerState &out);
 	static bool getConstant(PowerState in, const char *&out);
 

+ 9 - 1
jni/love/src/modules/system/wrap_System.cpp

@@ -79,6 +79,13 @@ int w_getPowerInfo(lua_State *L)
 	return 3;
 }
 
+int w_openURL(lua_State *L)
+{
+	std::string url = luax_checkstring(L, 1);
+	luax_pushboolean(L, instance->openURL(url));
+	return 1;
+}
+
 static const luaL_Reg functions[] =
 {
 	{ "getOS", w_getOS },
@@ -86,6 +93,7 @@ static const luaL_Reg functions[] =
 	{ "setClipboardText", w_setClipboardText },
 	{ "getClipboardText", w_getClipboardText },
 	{ "getPowerInfo", w_getPowerInfo },
+	{ "openURL", w_openURL },
 	{ 0, 0 }
 };
 
@@ -109,4 +117,4 @@ extern "C" int luaopen_love_system(lua_State *L)
 }
 
 } // system
-} // love
+} // love

+ 1 - 0
jni/love/src/modules/system/wrap_System.h

@@ -35,6 +35,7 @@ int w_getProcessorCount(lua_State *L);
 int w_setClipboardText(lua_State *L);
 int w_getClipboardText(lua_State *L);
 int w_getPowerInfo(lua_State *L);
+int w_openURL(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_system(lua_State *L);
 
 } // system

+ 19 - 15
jni/love/src/modules/window/sdl/Window.cpp

@@ -77,10 +77,6 @@ Window::_currentMode::_currentMode()
 
 bool Window::setWindow(int width, int height, WindowSettings *settings)
 {
-	graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics.");
-	if (gfx != nullptr)
-		gfx->unSetMode();
-
 	WindowSettings f;
 
 	if (settings)
@@ -123,11 +119,16 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
 	if (f.borderless)
 		sdlflags |= SDL_WINDOW_BORDERLESS;
 
-#if SDL_VERSION_ATLEAST(2,0,1)
+	// FIXME: disabled in Linux for runtime SDL 2.0.0 compatibility.
+#if SDL_VERSION_ATLEAST(2,0,1) && !defined(LOVE_LINUX)
 	if (f.highdpi)
 		sdlflags |= SDL_WINDOW_ALLOW_HIGHDPI;
 #endif
 
+	graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics.");
+	if (gfx != nullptr)
+		gfx->unSetMode();
+
 	// Destroy and recreate the window if the dimensions or flags have changed.
 	if (window)
 	{
@@ -137,7 +138,8 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
 		Uint32 testflags = SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN_DESKTOP
 			| SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS;
 
-#if SDL_VERSION_ATLEAST(2,0,1)
+		// FIXME: disabled in Linux for runtime SDL 2.0.0 compatibility.
+#if SDL_VERSION_ATLEAST(2,0,1) && !defined(LOVE_LINUX)
 		testflags |= SDL_WINDOW_ALLOW_HIGHDPI;
 #endif
 
@@ -160,6 +162,8 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
 
 	if (!window)
 	{
+		created = false;
+
 		// In Windows and Linux, some GL attributes are set on window creation.
 		setWindowGLAttributes(f.fsaa, f.sRGB);
 
@@ -212,7 +216,8 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
 		int width = curMode.width;
 		int height = curMode.height;
 
-#if SDL_VERSION_ATLEAST(2,0,1)
+		// FIXME: disabled in Linux for runtime SDL 2.0.0 compatibility.
+#if SDL_VERSION_ATLEAST(2,0,1) && !defined(LOVE_LINUX)
 		SDL_GL_GetDrawableSize(window, &width, &height);
 #endif
 
@@ -411,13 +416,10 @@ void Window::updateSettings(const WindowSettings &newsettings)
 #endif
 
 	// Only minimize on focus loss if the window is in exclusive-fullscreen
-	// mode (mimics behaviour of SDL 2.0.2+).
-	// In OS X we always disable this to prevent dock minimization weirdness.
-#ifndef LOVE_MACOSX
+	// mode.
 	if (curMode.settings.fullscreen && curMode.settings.fstype == FULLSCREEN_TYPE_NORMAL)
 		SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "1");
 	else
-#endif
 		SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
 
 	curMode.settings.sRGB = newsettings.sRGB;
@@ -435,9 +437,9 @@ void Window::displayError(const std::string &title, const std::string &text) con
 
 void Window::getWindow(int &width, int &height, WindowSettings &settings)
 {
-	// Window position may be different from creation - update display index.
+	// The window might have been modified (moved, resized, etc.) by the user.
 	if (window)
-		curMode.settings.display = std::max(SDL_GetWindowDisplayIndex(window), 0);
+		updateSettings(curMode.settings);
 
 	width = curMode.width;
 	height = curMode.height;
@@ -484,7 +486,8 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype)
 			int width = curMode.width;
 			int height = curMode.height;
 
-#if SDL_VERSION_ATLEAST(2,0,1)
+			// FIXME: disabled in Linux for runtime SDL 2.0.0 compatibility.
+#if SDL_VERSION_ATLEAST(2,0,1) && !defined(LOVE_LINUX)
 			SDL_GL_GetDrawableSize(window, &width, &height);
 #endif
 
@@ -688,7 +691,8 @@ double Window::getPixelScale() const
 
 #ifdef LOVE_ANDROID
 	scale = love::android::getScreenScale();
-#elif SDL_VERSION_ATLEAST(2,0,1)
+	// FIXME: disabled in Linux for runtime SDL 2.0.0 compatibility.
+#elif SDL_VERSION_ATLEAST(2,0,1) && !defined(LOVE_LINUX)
 	if (window)
 	{
 		int wheight;

+ 2 - 1
jni/love/src/scripts/auto.lua

@@ -34,7 +34,8 @@ const unsigned char %s[] =
 {
 %s
 }; // [%s]
-} // love]]
+} // love
+]]
 --formatting parameters:
 -- - input file name
 -- - c variable name

+ 26 - 12
jni/love/src/scripts/boot.lua

@@ -227,6 +227,10 @@ function love.createhandlers()
 		resize = function(w, h)
 			if love.resize then return love.resize(w, h) end
 		end,
+		lowmemory = function()
+			collectgarbage("collect")
+			if love.lowmemory then return love.lowmemory() end
+		end,
 	}, {
 		__index = function(self, name)
 			error("Unknown event: " .. name)
@@ -235,15 +239,14 @@ function love.createhandlers()
 
 end
 
-local is_fused_game = false
-local no_game_code = false
-
 local function uridecode(s)
 	return s:gsub("%%%x%x", function(str)
 		return string.char(tonumber(str:sub(2), 16))
 	end)
 end
 
+local no_game_code = false
+
 -- This can't be overriden.
 function love.boot()
 
@@ -260,35 +263,45 @@ function love.boot()
 
 	-- Is this one of those fancy "fused" games?
 	local can_has_game = pcall(love.filesystem.setSource, arg0)
-	is_fused_game = can_has_game
+	local is_fused_game = can_has_game
 	if love.arg.options.fused.set then
 		is_fused_game = true
 	end
 
+	love.filesystem.setFused(is_fused_game)
+
+	local identity = ""
 	if not can_has_game and o.game.set and o.game.arg[1] then
 		local nouri = o.game.arg[1]
 		if nouri:sub(1, 7) == "file://" then
 			nouri = uridecode(nouri:sub(8))
 		end
 		local full_source =  love.path.getfull(nouri)
-		local leaf = love.path.leaf(full_source)
-		leaf = leaf:gsub("^([%.]+)", "") -- strip leading "."'s
-		leaf = leaf:gsub("%.([^%.]+)$", "") -- strip extension
-		leaf = leaf:gsub("%.", "_") -- replace remaining "."'s with "_"
-		love.filesystem.setIdentity(leaf)
 		can_has_game = pcall(love.filesystem.setSource, full_source)
+		
+		-- Use the name of the source .love as the identity for now.
+		identity = love.path.leaf(full_source)
+	else
+		-- Use the name of the exe as the identity for now.
+		identity = love.path.leaf(arg0)
 	end
 
+	identity = identity:gsub("^([%.]+)", "") -- strip leading "."'s
+	identity = identity:gsub("%.([^%.]+)$", "") -- strip extension
+	identity = identity:gsub("%.", "_") -- replace remaining "."'s with "_"
+	identity = #identity > 0 and identity or "lovegame"
+
+	-- When conf.lua is initially loaded, the main source should be checked
+	-- before the save directory (the identity should be appended.)
+	pcall(love.filesystem.setIdentity, identity, true)
+
 	if can_has_game and not (love.filesystem.exists("main.lua") or love.filesystem.exists("conf.lua")) then
 		no_game_code = true
 	end
 
-	love.filesystem.setFused(is_fused_game)
-
 	if not can_has_game then
 		love.nogame()
 	end
-
 end
 
 function love.init()
@@ -473,6 +486,7 @@ function love.run()
 
 	if love.math then
 		love.math.setRandomSeed(os.time())
+		for i=1,3 do love.math.random() end
 	end
 
 	if love.event then

+ 61 - 27
jni/love/src/scripts/boot.lua.h

@@ -427,6 +427,14 @@ const unsigned char boot_lua[] =
 	0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x72, 
 	0x65, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x77, 0x2c, 0x20, 0x68, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
+	0x09, 0x09, 0x6c, 0x6f, 0x77, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 
+	0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x0a,
+	0x09, 0x09, 0x09, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x67, 0x61, 0x72, 0x62, 0x61, 0x67, 0x65, 0x28, 
+	0x22, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x22, 0x29, 0x0a,
+	0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6c, 0x6f, 0x77, 0x6d, 0x65, 0x6d, 0x6f, 
+	0x72, 0x79, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 
+	0x65, 0x2e, 0x6c, 0x6f, 0x77, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
 	0x09, 0x7d, 0x2c, 0x20, 0x7b, 0x0a,
 	0x09, 0x09, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 
 	0x6f, 0x6e, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a,
@@ -435,10 +443,6 @@ const unsigned char boot_lua[] =
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
 	0x09, 0x7d, 0x29, 0x0a,
 	0x65, 0x6e, 0x64, 0x0a,
-	0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 0x61, 0x6d, 
-	0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a,
-	0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x6f, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 
-	0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a,
 	0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x75, 0x72, 0x69, 
 	0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x28, 0x73, 0x29, 0x0a,
 	0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x25, 0x25, 
@@ -449,6 +453,8 @@ const unsigned char boot_lua[] =
 	0x62, 0x28, 0x32, 0x29, 0x2c, 0x20, 0x31, 0x36, 0x29, 0x29, 0x0a,
 	0x09, 0x65, 0x6e, 0x64, 0x29, 0x0a,
 	0x65, 0x6e, 0x64, 0x0a,
+	0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x6f, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 
+	0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a,
 	0x2d, 0x2d, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x63, 0x61, 0x6e, 0x27, 0x74, 0x20, 0x62, 0x65, 0x20, 0x6f, 
 	0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x6e, 0x2e, 0x0a,
 	0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 
@@ -473,13 +479,18 @@ const unsigned char boot_lua[] =
 	0x65, 0x20, 0x3d, 0x20, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 
 	0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, 0x65, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2c, 
 	0x20, 0x61, 0x72, 0x67, 0x30, 0x29, 0x0a,
-	0x09, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x63, 
-	0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x0a,
+	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 0x61, 
+	0x6d, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x0a,
 	0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 
 	0x6e, 0x73, 0x2e, 0x66, 0x75, 0x73, 0x65, 0x64, 0x2e, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
 	0x09, 0x09, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 
 	0x74, 0x72, 0x75, 0x65, 0x0a,
 	0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, 
+	0x65, 0x74, 0x46, 0x75, 0x73, 0x65, 0x64, 0x28, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 
+	0x61, 0x6d, 0x65, 0x29, 0x0a,
+	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 
+	0x22, 0x22, 0x0a,
 	0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 
 	0x6d, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x20, 
 	0x61, 0x6e, 0x64, 0x20, 0x6f, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x5b, 0x31, 0x5d, 0x20, 
@@ -495,28 +506,51 @@ const unsigned char boot_lua[] =
 	0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 
 	0x65, 0x20, 0x3d, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x67, 0x65, 0x74, 
 	0x66, 0x75, 0x6c, 0x6c, 0x28, 0x6e, 0x6f, 0x75, 0x72, 0x69, 0x29, 0x0a,
-	0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 
-	0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x6c, 0x65, 0x61, 0x66, 0x28, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x73, 
-	0x6f, 0x75, 0x72, 0x63, 0x65, 0x29, 0x0a,
-	0x09, 0x09, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x3d, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x3a, 0x67, 0x73, 0x75, 0x62, 
-	0x28, 0x22, 0x5e, 0x28, 0x5b, 0x25, 0x2e, 0x5d, 0x2b, 0x29, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x20, 0x2d, 
-	0x2d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x6c, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x22, 0x2e, 
-	0x22, 0x27, 0x73, 0x0a,
-	0x09, 0x09, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x3d, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x3a, 0x67, 0x73, 0x75, 0x62, 
-	0x28, 0x22, 0x25, 0x2e, 0x28, 0x5b, 0x5e, 0x25, 0x2e, 0x5d, 0x2b, 0x29, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22, 
-	0x29, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 
-	0x6f, 0x6e, 0x0a,
-	0x09, 0x09, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x3d, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x3a, 0x67, 0x73, 0x75, 0x62, 
-	0x28, 0x22, 0x25, 0x2e, 0x22, 0x2c, 0x20, 0x22, 0x5f, 0x22, 0x29, 0x20, 0x2d, 0x2d, 0x20, 0x72, 0x65, 0x70, 
-	0x6c, 0x61, 0x63, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x22, 0x2e, 0x22, 
-	0x27, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x22, 0x5f, 0x22, 0x0a,
-	0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 
-	0x73, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x28, 0x6c, 0x65, 0x61, 0x66, 0x29, 0x0a,
 	0x09, 0x09, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x70, 
 	0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 
 	0x65, 0x6d, 0x2e, 0x73, 0x65, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2c, 0x20, 0x66, 0x75, 0x6c, 0x6c, 
 	0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x29, 0x0a,
+	0x09, 0x09, 0x0a,
+	0x09, 0x09, 0x2d, 0x2d, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 
+	0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x2e, 0x6c, 0x6f, 0x76, 
+	0x65, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 
+	0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x77, 0x2e, 0x0a,
+	0x09, 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 
+	0x70, 0x61, 0x74, 0x68, 0x2e, 0x6c, 0x65, 0x61, 0x66, 0x28, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 
+	0x72, 0x63, 0x65, 0x29, 0x0a,
+	0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a,
+	0x09, 0x09, 0x2d, 0x2d, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 
+	0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x65, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 
+	0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x77, 0x2e, 0x0a,
+	0x09, 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 
+	0x70, 0x61, 0x74, 0x68, 0x2e, 0x6c, 0x65, 0x61, 0x66, 0x28, 0x61, 0x72, 0x67, 0x30, 0x29, 0x0a,
 	0x09, 0x65, 0x6e, 0x64, 0x0a,
+	0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 
+	0x74, 0x79, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x5e, 0x28, 0x5b, 0x25, 0x2e, 0x5d, 0x2b, 0x29, 0x22, 
+	0x2c, 0x20, 0x22, 0x22, 0x29, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x6c, 0x65, 0x61, 
+	0x64, 0x69, 0x6e, 0x67, 0x20, 0x22, 0x2e, 0x22, 0x27, 0x73, 0x0a,
+	0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 
+	0x74, 0x79, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x25, 0x2e, 0x28, 0x5b, 0x5e, 0x25, 0x2e, 0x5d, 0x2b, 
+	0x29, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 
+	0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x0a,
+	0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 
+	0x74, 0x79, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x25, 0x2e, 0x22, 0x2c, 0x20, 0x22, 0x5f, 0x22, 0x29, 
+	0x20, 0x2d, 0x2d, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 
+	0x69, 0x6e, 0x67, 0x20, 0x22, 0x2e, 0x22, 0x27, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x22, 0x5f, 0x22, 0x0a,
+	0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x23, 0x69, 0x64, 0x65, 0x6e, 0x74, 
+	0x69, 0x74, 0x79, 0x20, 0x3e, 0x20, 0x30, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 
+	0x74, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x6c, 0x6f, 0x76, 0x65, 0x67, 0x61, 0x6d, 0x65, 0x22, 0x0a,
+	0x09, 0x2d, 0x2d, 0x20, 0x57, 0x68, 0x65, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x6c, 0x75, 0x61, 0x20, 
+	0x69, 0x73, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 
+	0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 
+	0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x0a,
+	0x09, 0x2d, 0x2d, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x76, 
+	0x65, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x28, 0x74, 0x68, 0x65, 0x20, 0x69, 
+	0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 
+	0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x2e, 0x29, 0x0a,
+	0x09, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 
+	0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2c, 0x20, 
+	0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2c, 0x20, 0x74, 0x72, 0x75, 0x65, 0x29, 0x0a,
 	0x09, 0x69, 0x66, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x61, 
 	0x6e, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 
 	0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x28, 0x22, 0x6d, 0x61, 0x69, 0x6e, 
@@ -526,9 +560,6 @@ const unsigned char boot_lua[] =
 	0x09, 0x09, 0x6e, 0x6f, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x74, 
 	0x72, 0x75, 0x65, 0x0a,
 	0x09, 0x65, 0x6e, 0x64, 0x0a,
-	0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, 
-	0x65, 0x74, 0x46, 0x75, 0x73, 0x65, 0x64, 0x28, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 
-	0x61, 0x6d, 0x65, 0x29, 0x0a,
 	0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 
 	0x6d, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
 	0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6e, 0x6f, 0x67, 0x61, 0x6d, 0x65, 0x28, 0x29, 0x0a,
@@ -846,6 +877,9 @@ const unsigned char boot_lua[] =
 	0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x61, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
 	0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x73, 0x65, 0x74, 0x52, 0x61, 0x6e, 
 	0x64, 0x6f, 0x6d, 0x53, 0x65, 0x65, 0x64, 0x28, 0x6f, 0x73, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x28, 0x29, 0x29, 0x0a,
+	0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x33, 0x20, 0x64, 0x6f, 0x20, 0x6c, 0x6f, 0x76, 
+	0x65, 0x2e, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x28, 0x29, 0x20, 0x65, 0x6e, 
+	0x64, 0x0a,
 	0x09, 0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x65, 
 	0x6e, 0x0a,
@@ -5398,4 +5432,4 @@ const unsigned char boot_lua[] =
 	0x65, 0x74, 0x76, 0x61, 0x6c, 0x29, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x0a,
 	0x65, 0x6e, 0x64, 0x0a,
 }; // [boot.lua]
-} // love
+} // love

+ 15 - 14
jni/love/src/scripts/graphics.lua

@@ -1332,13 +1332,14 @@ uniform vec4 love_ScreenSize;]]
 #define VaryingTexCoord gl_TexCoord[0]
 #define VaryingColor gl_FrontColor
 
-#if defined(GL_ARB_draw_instanced)
-	#extension GL_ARB_draw_instanced : enable
-	#define love_InstanceID gl_InstanceIDARB
-#else
-	attribute float love_PseudoInstanceID;
-	int love_InstanceID = int(love_PseudoInstanceID);
-#endif]],
+// #if defined(GL_ARB_draw_instanced)
+//	#extension GL_ARB_draw_instanced : enable
+//	#define love_InstanceID gl_InstanceIDARB
+// #else
+//	attribute float love_PseudoInstanceID;
+//	int love_InstanceID = int(love_PseudoInstanceID);
+// #endif
+]],
 
 		FOOTER = [[
 void main() {
@@ -1359,13 +1360,13 @@ attribute vec4 VertexColor;
 varying vec4 VaryingTexCoord;
 varying lowp vec4 VaryingColor;
 
-#if defined(GL_EXT_draw_instanced)
-	#extension GL_EXT_draw_instanced : enable
-	#define love_InstanceID gl_InstanceIDEXT
-#else
-	attribute float love_PseudoInstanceID;
-	int love_InstanceID = int(love_PseudoInstanceID);
-#endif
+//#if defined(GL_EXT_draw_instanced)
+//	#extension GL_EXT_draw_instanced : enable
+//	#define love_InstanceID gl_InstanceIDEXT
+//#else
+//	attribute float love_PseudoInstanceID;
+//	int love_InstanceID = int(love_PseudoInstanceID);
+//#endif
 ]],
 
 		FOOTER = [[

+ 35 - 33
jni/love/src/scripts/graphics.lua.h

@@ -6333,22 +6333,24 @@ const unsigned char graphics_lua[] =
 	0x30, 0x5d, 0x0a,
 	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 
 	0x6f, 0x72, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x0a,
-	0x23, 0x69, 0x66, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x28, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 
-	0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x29, 0x0a,
-	0x09, 0x23, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 
-	0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x20, 0x3a, 0x20, 
-	0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x0a,
-	0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 0x73, 0x74, 
-	0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x20, 0x67, 0x6c, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 
-	0x49, 0x44, 0x41, 0x52, 0x42, 0x0a,
-	0x23, 0x65, 0x6c, 0x73, 0x65, 0x0a,
-	0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x6c, 
-	0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 
-	0x49, 0x44, 0x3b, 0x0a,
-	0x09, 0x69, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 
-	0x49, 0x44, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 0x65, 0x75, 
-	0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x29, 0x3b, 0x0a,
-	0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x5d, 0x5d, 0x2c, 0x0a,
+	0x2f, 0x2f, 0x20, 0x23, 0x69, 0x66, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x28, 0x47, 0x4c, 0x5f, 
+	0x41, 0x52, 0x42, 0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 
+	0x29, 0x0a,
+	0x2f, 0x2f, 0x09, 0x23, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x47, 0x4c, 0x5f, 0x41, 
+	0x52, 0x42, 0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x20, 
+	0x3a, 0x20, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x0a,
+	0x2f, 0x2f, 0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 
+	0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x20, 0x67, 0x6c, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 
+	0x63, 0x65, 0x49, 0x44, 0x41, 0x52, 0x42, 0x0a,
+	0x2f, 0x2f, 0x20, 0x23, 0x65, 0x6c, 0x73, 0x65, 0x0a,
+	0x2f, 0x2f, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 
+	0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 
+	0x63, 0x65, 0x49, 0x44, 0x3b, 0x0a,
+	0x2f, 0x2f, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 
+	0x63, 0x65, 0x49, 0x44, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 
+	0x65, 0x75, 0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x29, 0x3b, 0x0a,
+	0x2f, 0x2f, 0x20, 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a,
+	0x5d, 0x5d, 0x2c, 0x0a,
 	0x09, 0x09, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a,
 	0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a,
 	0x09, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x3d, 
@@ -6375,22 +6377,22 @@ const unsigned char graphics_lua[] =
 	0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a,
 	0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x6f, 0x77, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 
 	0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a,
-	0x23, 0x69, 0x66, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x28, 0x47, 0x4c, 0x5f, 0x45, 0x58, 0x54, 
-	0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x29, 0x0a,
-	0x09, 0x23, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x47, 0x4c, 0x5f, 0x45, 0x58, 0x54, 
-	0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x20, 0x3a, 0x20, 
-	0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x0a,
-	0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 0x73, 0x74, 
-	0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x20, 0x67, 0x6c, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 
-	0x49, 0x44, 0x45, 0x58, 0x54, 0x0a,
-	0x23, 0x65, 0x6c, 0x73, 0x65, 0x0a,
-	0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x6c, 
-	0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 
-	0x49, 0x44, 0x3b, 0x0a,
-	0x09, 0x69, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 
-	0x49, 0x44, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 0x65, 0x75, 
-	0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x29, 0x3b, 0x0a,
-	0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a,
+	0x2f, 0x2f, 0x23, 0x69, 0x66, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x28, 0x47, 0x4c, 0x5f, 0x45, 
+	0x58, 0x54, 0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x29, 0x0a,
+	0x2f, 0x2f, 0x09, 0x23, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x47, 0x4c, 0x5f, 0x45, 
+	0x58, 0x54, 0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x20, 
+	0x3a, 0x20, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x0a,
+	0x2f, 0x2f, 0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 
+	0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x20, 0x67, 0x6c, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 
+	0x63, 0x65, 0x49, 0x44, 0x45, 0x58, 0x54, 0x0a,
+	0x2f, 0x2f, 0x23, 0x65, 0x6c, 0x73, 0x65, 0x0a,
+	0x2f, 0x2f, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 
+	0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 
+	0x63, 0x65, 0x49, 0x44, 0x3b, 0x0a,
+	0x2f, 0x2f, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 
+	0x63, 0x65, 0x49, 0x44, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 
+	0x65, 0x75, 0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x29, 0x3b, 0x0a,
+	0x2f, 0x2f, 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a,
 	0x5d, 0x5d, 0x2c, 0x0a,
 	0x09, 0x09, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a,
 	0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a,
@@ -6757,4 +6759,4 @@ const unsigned char graphics_lua[] =
 	0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x29, 0x0a,
 	0x65, 0x6e, 0x64, 0x0a,
 }; // [graphics.lua]
-} // love
+} // love