Explorar o código

Using latest android branch of LÖVE (6d14516b05c9) that now syncs with default (woooo!)

fysx %!s(int64=10) %!d(string=hai) anos
pai
achega
357a7237a4
Modificáronse 100 ficheiros con 9016 adicións e 3476 borrados
  1. 1 0
      jni/love/Android.mk
  2. 5 1
      jni/love/src/common/Exception.cpp
  3. 1 1
      jni/love/src/common/Exception.h
  4. 121 47
      jni/love/src/common/Matrix.cpp
  5. 103 12
      jni/love/src/common/Matrix.h
  6. 63 0
      jni/love/src/common/OSX.h
  7. 95 0
      jni/love/src/common/OSX.mm
  8. 14 5
      jni/love/src/common/Object.cpp
  9. 5 9
      jni/love/src/common/Object.h
  10. 3 8
      jni/love/src/common/Variant.cpp
  11. 0 1
      jni/love/src/common/Variant.h
  12. 4 4
      jni/love/src/common/Vector.h
  13. 21 6
      jni/love/src/common/config.h
  14. 66 0
      jni/love/src/common/iOS.h
  15. 327 0
      jni/love/src/common/iOS.mm
  16. 0 2
      jni/love/src/common/int.h
  17. 87 147
      jni/love/src/common/runtime.cpp
  18. 66 42
      jni/love/src/common/runtime.h
  19. 219 0
      jni/love/src/common/types.cpp
  20. 11 82
      jni/love/src/common/types.h
  21. 7 7
      jni/love/src/common/version.h
  22. 2 2
      jni/love/src/common/wrap_Data.cpp
  23. 32 28
      jni/love/src/libraries/enet/enet.cpp
  24. 151 258
      jni/love/src/libraries/glad/glad.cpp
  25. 377 461
      jni/love/src/libraries/glad/glad.hpp
  26. 243 572
      jni/love/src/libraries/glad/gladfuncs.hpp
  27. 206 175
      jni/love/src/libraries/lodepng/lodepng.cpp
  28. 83 91
      jni/love/src/libraries/lodepng/lodepng.h
  29. 3 1
      jni/love/src/libraries/luasocket/libluasocket/except.c
  30. 3 1
      jni/love/src/libraries/luasocket/libluasocket/inet.c
  31. 4 2
      jni/love/src/libraries/luasocket/libluasocket/luasocket.c
  32. 4 2
      jni/love/src/libraries/luasocket/libluasocket/mime.c
  33. 3 1
      jni/love/src/libraries/luasocket/libluasocket/select.c
  34. 3 1
      jni/love/src/libraries/luasocket/libluasocket/tcp.c
  35. 3 1
      jni/love/src/libraries/luasocket/libluasocket/timeout.c
  36. 3 1
      jni/love/src/libraries/luasocket/libluasocket/udp.c
  37. 10 3
      jni/love/src/libraries/luasocket/libluasocket/unix.c
  38. 27 1
      jni/love/src/libraries/luautf8/lutf8lib.c
  39. 1516 0
      jni/love/src/libraries/lz4/lz4.c
  40. 360 0
      jni/love/src/libraries/lz4/lz4.h
  41. 730 0
      jni/love/src/libraries/lz4/lz4hc.c
  42. 189 0
      jni/love/src/libraries/lz4/lz4hc.h
  43. 528 0
      jni/love/src/libraries/noise1234/noise1234.cpp
  44. 57 0
      jni/love/src/libraries/noise1234/noise1234.h
  45. 3 263
      jni/love/src/libraries/noise1234/simplexnoise1234.cpp
  46. 4 13
      jni/love/src/libraries/noise1234/simplexnoise1234.h
  47. 573 134
      jni/love/src/libraries/stb/stb_image.h
  48. 41 6
      jni/love/src/love.cpp
  49. 3 3
      jni/love/src/modules/audio/Audio.cpp
  50. 5 0
      jni/love/src/modules/audio/Source.cpp
  51. 2 1
      jni/love/src/modules/audio/Source.h
  52. 0 5
      jni/love/src/modules/audio/null/Source.cpp
  53. 0 1
      jni/love/src/modules/audio/null/Source.h
  54. 6 1
      jni/love/src/modules/audio/openal/Audio.h
  55. 4 1
      jni/love/src/modules/audio/openal/Pool.cpp
  56. 8 1
      jni/love/src/modules/audio/openal/Pool.h
  57. 96 44
      jni/love/src/modules/audio/openal/Source.cpp
  58. 9 11
      jni/love/src/modules/audio/openal/Source.h
  59. 10 10
      jni/love/src/modules/audio/wrap_Audio.cpp
  60. 37 27
      jni/love/src/modules/audio/wrap_Source.cpp
  61. 1 1
      jni/love/src/modules/audio/wrap_Source.h
  62. 3 4
      jni/love/src/modules/event/Event.h
  63. 186 128
      jni/love/src/modules/event/sdl/Event.cpp
  64. 0 5
      jni/love/src/modules/event/sdl/Event.h
  65. 8 12
      jni/love/src/modules/event/wrap_Event.cpp
  66. 3 6
      jni/love/src/modules/event/wrap_Event.h
  67. 256 0
      jni/love/src/modules/filesystem/DroppedFile.cpp
  68. 83 0
      jni/love/src/modules/filesystem/DroppedFile.h
  69. 66 4
      jni/love/src/modules/filesystem/File.cpp
  70. 10 10
      jni/love/src/modules/filesystem/File.h
  71. 105 0
      jni/love/src/modules/filesystem/Filesystem.cpp
  72. 265 0
      jni/love/src/modules/filesystem/Filesystem.h
  73. 32 99
      jni/love/src/modules/filesystem/physfs/File.cpp
  74. 17 18
      jni/love/src/modules/filesystem/physfs/File.h
  75. 80 164
      jni/love/src/modules/filesystem/physfs/Filesystem.cpp
  76. 14 182
      jni/love/src/modules/filesystem/physfs/Filesystem.h
  77. 62 0
      jni/love/src/modules/filesystem/wrap_DroppedFile.cpp
  78. 39 0
      jni/love/src/modules/filesystem/wrap_DroppedFile.h
  79. 131 15
      jni/love/src/modules/filesystem/wrap_File.cpp
  80. 4 1
      jni/love/src/modules/filesystem/wrap_File.h
  81. 2 2
      jni/love/src/modules/filesystem/wrap_FileData.cpp
  82. 92 61
      jni/love/src/modules/filesystem/wrap_Filesystem.cpp
  83. 3 1
      jni/love/src/modules/filesystem/wrap_Filesystem.h
  84. 338 0
      jni/love/src/modules/font/BMFontRasterizer.cpp
  85. 90 0
      jni/love/src/modules/font/BMFontRasterizer.h
  86. 105 0
      jni/love/src/modules/font/Font.cpp
  87. 17 10
      jni/love/src/modules/font/Font.h
  88. 1 1
      jni/love/src/modules/font/GlyphData.cpp
  89. 4 18
      jni/love/src/modules/font/ImageRasterizer.cpp
  90. 10 8
      jni/love/src/modules/font/ImageRasterizer.h
  91. 5 0
      jni/love/src/modules/font/Rasterizer.cpp
  92. 5 0
      jni/love/src/modules/font/Rasterizer.h
  93. 49 0
      jni/love/src/modules/font/TrueTypeRasterizer.cpp
  94. 62 0
      jni/love/src/modules/font/TrueTypeRasterizer.h
  95. 9 67
      jni/love/src/modules/font/freetype/Font.cpp
  96. 3 14
      jni/love/src/modules/font/freetype/Font.h
  97. 47 9
      jni/love/src/modules/font/freetype/TrueTypeRasterizer.cpp
  98. 17 8
      jni/love/src/modules/font/freetype/TrueTypeRasterizer.h
  99. 0 132
      jni/love/src/modules/font/freetype/wrap_Font.cpp
  100. 235 0
      jni/love/src/modules/font/wrap_Font.cpp

+ 1 - 0
jni/love/Android.mk

@@ -93,6 +93,7 @@ LOCAL_SRC_FILES := \
   $(wildcard ${LOCAL_PATH}/src/libraries/noise1234/*.cpp) \
   $(wildcard ${LOCAL_PATH}/src/libraries/Wuff/*.c) \
   $(wildcard ${LOCAL_PATH}/src/libraries/lodepng/*.cpp) \
+  $(wildcard ${LOCAL_PATH}/src/libraries/lz4/*.c) \
   ))
 
 LOCAL_CXXFLAGS := -std=c++0x

+ 5 - 1
jni/love/src/common/Exception.cpp

@@ -18,8 +18,8 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
-#include "Exception.h"
 #include "common/config.h"
+#include "Exception.h"
 
 #include <iostream>
 
@@ -60,4 +60,8 @@ Exception::Exception(const char *fmt, ...)
 	delete[] buffer;
 }
 
+Exception::~Exception() throw()
+{
+}
+
 }

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

@@ -45,7 +45,7 @@ public:
 	 * @param fmt The format string (see printf).
 	 **/
 	Exception(const char *fmt, ...);
-	virtual ~Exception() throw() {}
+	virtual ~Exception() throw();
 
 	/**
 	 * Returns a string containing reason for the exception.

+ 121 - 47
jni/love/src/common/Matrix.cpp

@@ -32,17 +32,17 @@ namespace love
 // | e2 e6 e10 e14 |
 // | e3 e7 e11 e15 |
 
-Matrix::Matrix()
+Matrix4::Matrix4()
 {
 	setIdentity();
 }
 
-Matrix::Matrix(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
+Matrix4::Matrix4(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
 {
 	setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
 }
 
-Matrix::~Matrix()
+Matrix4::~Matrix4()
 {
 }
 
@@ -55,9 +55,9 @@ Matrix::~Matrix()
 // | e2 e6 e10 e14 |
 // | e3 e7 e11 e15 |
 
-Matrix Matrix::operator * (const Matrix &m) const
+Matrix4 Matrix4::operator * (const Matrix4 &m) const
 {
-	Matrix t;
+	Matrix4 t;
 
 	t.e[0] = (e[0]*m.e[0]) + (e[4]*m.e[1]) + (e[8]*m.e[2]) + (e[12]*m.e[3]);
 	t.e[4] = (e[0]*m.e[4]) + (e[4]*m.e[5]) + (e[8]*m.e[6]) + (e[12]*m.e[7]);
@@ -82,31 +82,31 @@ Matrix Matrix::operator * (const Matrix &m) const
 	return t;
 }
 
-void Matrix::operator *= (const Matrix &m)
+void Matrix4::operator *= (const Matrix4 &m)
 {
-	Matrix t = (*this) * m;
-	memcpy((void *)this->e, (void *)t.e, sizeof(float)*16);
+	Matrix4 t = (*this) * m;
+	memcpy(this->e, t.e, sizeof(float)*16);
 }
 
-const float *Matrix::getElements() const
+const float *Matrix4::getElements() const
 {
 	return e;
 }
 
-void Matrix::setIdentity()
+void Matrix4::setIdentity()
 {
 	memset(e, 0, sizeof(float)*16);
 	e[0] = e[5] = e[10] = e[15] = 1;
 }
 
-void Matrix::setTranslation(float x, float y)
+void Matrix4::setTranslation(float x, float y)
 {
 	setIdentity();
 	e[12] = x;
 	e[13] = y;
 }
 
-void Matrix::setRotation(float rad)
+void Matrix4::setRotation(float rad)
 {
 	setIdentity();
 	float c = cosf(rad), s = sinf(rad);
@@ -116,21 +116,21 @@ void Matrix::setRotation(float rad)
 	e[5] = c;
 }
 
-void Matrix::setScale(float sx, float sy)
+void Matrix4::setScale(float sx, float sy)
 {
 	setIdentity();
 	e[0] = sx;
 	e[5] = sy;
 }
 
-void Matrix::setShear(float kx, float ky)
+void Matrix4::setShear(float kx, float ky)
 {
 	setIdentity();
 	e[1] = ky;
 	e[4] = kx;
 }
 
-void Matrix::setTransformation(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
+void Matrix4::setTransformation(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
 {
 	memset(e, 0, sizeof(float)*16); // zero out matrix
 	float c = cosf(angle), s = sinf(angle);
@@ -149,59 +149,37 @@ void Matrix::setTransformation(float x, float y, float angle, float sx, float sy
 	e[13] = y - ox * e[1] - oy * e[5];
 }
 
-void Matrix::translate(float x, float y)
+void Matrix4::translate(float x, float y)
 {
-	Matrix t;
+	Matrix4 t;
 	t.setTranslation(x, y);
 	this->operator *=(t);
 }
 
-void Matrix::rotate(float rad)
+void Matrix4::rotate(float rad)
 {
-	Matrix t;
+	Matrix4 t;
 	t.setRotation(rad);
 	this->operator *=(t);
 }
 
-void Matrix::scale(float sx, float sy)
+void Matrix4::scale(float sx, float sy)
 {
-	Matrix t;
+	Matrix4 t;
 	t.setScale(sx, sy);
 	this->operator *=(t);
 }
 
-void Matrix::shear(float kx, float ky)
+void Matrix4::shear(float kx, float ky)
 {
-	Matrix t;
+	Matrix4 t;
 	t.setShear(kx,ky);
 	this->operator *=(t);
 }
 
-//                 | x |
-//                 | y |
-//                 | 0 |
-//                 | 1 |
-// | e0 e4 e8  e12 |
-// | e1 e5 e9  e13 |
-// | e2 e6 e10 e14 |
-// | e3 e7 e11 e15 |
-
-void Matrix::transform(Vertex *dst, const Vertex *src, int size) const
-{
-	for (int i = 0; i<size; i++)
-	{
-		// Store in temp variables in case src = dst
-		float x = (e[0]*src[i].x) + (e[4]*src[i].y) + (0) + (e[12]);
-		float y = (e[1]*src[i].x) + (e[5]*src[i].y) + (0) + (e[13]);
-
-		dst[i].x = x;
-		dst[i].y = y;
-	}
-}
-
-Matrix Matrix::ortho(float left, float right, float bottom, float top)
+Matrix4 Matrix4::ortho(float left, float right, float bottom, float top)
 {
-	Matrix m;
+	Matrix4 m;
 
 	m.e[0] = 2.0f / (right - left);
 	m.e[5] = 2.0f / (top - bottom);
@@ -213,5 +191,101 @@ Matrix Matrix::ortho(float left, float right, float bottom, float top)
 	return m;
 }
 
+/**
+ * | e0 e3 e6 |
+ * | e1 e4 e7 |
+ * | e2 e5 e8 |
+ **/
+Matrix3::Matrix3()
+{
+	setIdentity();
+}
+
+Matrix3::Matrix3(const Matrix4 &mat4)
+{
+	const float *mat4elems = mat4.getElements();
+
+	// Column 0.
+	e[0] = mat4elems[0];
+	e[1] = mat4elems[1];
+	e[2] = mat4elems[2];
+
+	// Column 1.
+	e[3] = mat4elems[4];
+	e[4] = mat4elems[5];
+	e[5] = mat4elems[6];
+
+	// Column 2.
+	e[6] = mat4elems[8];
+	e[7] = mat4elems[9];
+	e[8] = mat4elems[10];
+}
+
+Matrix3::~Matrix3()
+{
+}
+
+void Matrix3::setIdentity()
+{
+	memset(e, 0, sizeof(float) * 9);
+	e[8] = e[4] = e[0] = 1.0f;
+}
+
+Matrix3 Matrix3::operator * (const love::Matrix3 &m) const
+{
+	Matrix3 t;
+
+	t.e[0] = (e[0]*m.e[0]) + (e[3]*m.e[1]) + (e[6]*m.e[2]);
+	t.e[3] = (e[0]*m.e[3]) + (e[3]*m.e[4]) + (e[6]*m.e[5]);
+	t.e[6] = (e[0]*m.e[6]) + (e[3]*m.e[7]) + (e[6]*m.e[8]);
+
+	t.e[1] = (e[1]*m.e[0]) + (e[4]*m.e[1]) + (e[7]*m.e[2]);
+	t.e[4] = (e[1]*m.e[3]) + (e[4]*m.e[4]) + (e[7]*m.e[5]);
+	t.e[7] = (e[1]*m.e[6]) + (e[4]*m.e[7]) + (e[7]*m.e[8]);
+
+	t.e[2] = (e[2]*m.e[0]) + (e[5]*m.e[1]) + (e[8]*m.e[2]);
+	t.e[5] = (e[2]*m.e[3]) + (e[5]*m.e[4]) + (e[8]*m.e[5]);
+	t.e[8] = (e[2]*m.e[6]) + (e[5]*m.e[7]) + (e[8]*m.e[8]);
+
+	return t;
+}
+
+void Matrix3::operator *= (const Matrix3 &m)
+{
+	Matrix3 t = (*this) * m;
+	memcpy(e, t.e, sizeof(float) * 9);
+}
+
+const float *Matrix3::getElements() const
+{
+	return e;
+}
+
+Matrix3 Matrix3::transposedInverse() const
+{
+	// e0 e3 e6
+	// e1 e4 e7
+	// e2 e5 e8
+
+	float det = e[0] * (e[4]*e[8] - e[7]*e[5])
+	          - e[1] * (e[3]*e[8] - e[5]*e[6])
+	          + e[2] * (e[3]*e[7] - e[4]*e[6]);
+
+	float invdet = 1.0f / det;
+
+	Matrix3 m;
+
+	m.e[0] =  invdet * (e[4]*e[8] - e[7]*e[5]);
+	m.e[3] = -invdet * (e[1]*e[8] - e[2]*e[7]);
+	m.e[6] =  invdet * (e[1]*e[5] - e[2]*e[4]);
+	m.e[1] = -invdet * (e[3]*e[8] - e[5]*e[6]);
+	m.e[4] =  invdet * (e[0]*e[8] - e[2]*e[6]);
+	m.e[7] = -invdet * (e[0]*e[5] - e[3]*e[2]);
+	m.e[2] =  invdet * (e[3]*e[7] - e[6]*e[4]);
+	m.e[5] = -invdet * (e[0]*e[7] - e[6]*e[1]);
+	m.e[8] =  invdet * (e[0]*e[4] - e[3]*e[1]);
+
+	return m;
+}
 
 } // love

+ 103 - 12
jni/love/src/common/Matrix.h

@@ -28,41 +28,41 @@ namespace love
 {
 
 /**
- * This class is the basis for all transformations in LOVE. Althought not
- * really needed for 2D, it contains 4x4 elements to be compatible with
- * OpenGL without conversions.
+ * This class is the basis for all transformations in LOVE. Although not really
+ * needed for 2D, it contains 4x4 elements to be compatible with OpenGL without
+ * conversions.
  **/
-class Matrix
+class Matrix4
 {
 public:
 
 	/**
 	 * Creates a new identity matrix.
 	 **/
-	Matrix();
+	Matrix4();
 
 	/**
 	 * Creates a new matrix set to a transformation.
 	 **/
-	Matrix(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
+	Matrix4(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
 
 	/**
 	 * Destructor.
 	 **/
-	~Matrix();
+	~Matrix4();
 
 	/**
 	 * Multiplies this Matrix with another Matrix, changing neither.
 	 * @param m The Matrix to multiply with this Matrix.
 	 * @return The combined matrix.
 	 **/
-	Matrix operator * (const Matrix &m) const;
+	Matrix4 operator * (const Matrix4 &m) const;
 
 	/**
 	 * Multiplies a Matrix into this Matrix.
 	 * @param m The Matrix to combine into this Matrix.
 	 **/
-	void operator *= (const Matrix &m);
+	void operator *= (const Matrix4 &m);
 
 	/**
 	 * Gets a pointer to the 16 array elements.
@@ -153,13 +153,14 @@ public:
 	 * @param src The source vertices.
 	 * @param size The number of vertices.
 	 **/
-	void transform(Vertex *dst, const Vertex *src, int size) const;
+	template <typename V>
+	void transform(V *dst, const V *src, int size) const;
 
 	/**
 	 * Creates a new orthographic projection matrix with depth in the range of
 	 * [-1, 1].
 	 **/
-	static Matrix ortho(float left, float right, float bottom, float top);
+	static Matrix4 ortho(float left, float right, float bottom, float top);
 
 private:
 
@@ -171,7 +172,97 @@ private:
 	 **/
 	float e[16];
 
-}; // Matrix
+}; // Matrix4
+
+class Matrix3
+{
+public:
+
+	Matrix3();
+
+	/**
+	 * Constructs a 3x3 matrix from the upper left section of a 4x4 matrix.
+	 **/
+	Matrix3(const Matrix4 &mat4);
+
+	~Matrix3();
+
+	/**
+	 * Resets this matrix to the identity matrix.
+	 **/
+	void setIdentity();
+
+	Matrix3 operator * (const Matrix3 &m) const;
+	void operator *= (const Matrix3 &m);
+
+	/**
+	 * Gets a pointer to the 9 array elements.
+	 **/
+	const float *getElements() const;
+
+	/**
+	 * Calculates the inverse of the transpose of this matrix.
+	 **/
+	Matrix3 transposedInverse() const;
+
+	/**
+	 * Transforms an array of vertices by this matrix.
+	 **/
+	template <typename V>
+	void transform(V *dst, const V *src, int size) const;
+
+private:
+
+	/**
+	 * | e0 e3 e6
+	 * | e1 e4 e7
+	 * | e2 e5 e8
+	 **/
+	float e[9];
+
+}; // Matrix3
+
+//                 | x |
+//                 | y |
+//                 | 0 |
+//                 | 1 |
+// | e0 e4 e8  e12 |
+// | e1 e5 e9  e13 |
+// | e2 e6 e10 e14 |
+// | e3 e7 e11 e15 |
+
+template <typename V>
+void Matrix4::transform(V *dst, const V *src, int size) const
+{
+	for (int i = 0; i < size; i++)
+	{
+		// Store in temp variables in case src = dst
+		float x = (e[0]*src[i].x) + (e[4]*src[i].y) + (0) + (e[12]);
+		float y = (e[1]*src[i].x) + (e[5]*src[i].y) + (0) + (e[13]);
+
+		dst[i].x = x;
+		dst[i].y = y;
+	}
+}
+
+//            | x |
+//            | y |
+//            | 1 |
+// | e0 e3 e6 |
+// | e1 e4 e7 |
+// | e2 e5 e8 |
+template <typename V>
+void Matrix3::transform(V *dst, const V *src, int size) const
+{
+	for (int i = 0; i < size; i++)
+	{
+		float x = (e[0]*src[i].x) + (e[3]*src[i].y) + (e[6]);
+		float y = (e[1]*src[i].x) + (e[4]*src[i].y) + (e[7]);
+
+		dst[i].x = x;
+		dst[i].y = y;
+	}
+}
 
 } //love
 

+ 63 - 0
jni/love/src/common/OSX.h

@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_OSX_H
+#define LOVE_OSX_H
+
+#include "config.h"
+
+#ifdef LOVE_MACOSX
+
+#include <string>
+
+namespace love
+{
+namespace osx
+{
+
+/**
+ * Returns the filepath of the first detected love file in the Resources folder
+ * in the main bundle (love.app.)
+ * Returns an empty string if no love file is found.
+ **/
+std::string getLoveInResources();
+
+/**
+ * Checks for drop-file events. Returns the filepath if an event occurred, or
+ * an empty string otherwise.
+ **/
+std::string checkDropEvents();
+
+/**
+ * Returns the full path to the executable.
+ **/
+std::string getExecutablePath();
+
+/**
+ * Bounce the dock icon, if the app isn't in the foreground.
+ **/
+void requestAttention(bool continuous);
+
+} // osx
+} // love
+
+#endif // LOVE_MACOSX
+
+#endif // LOVE_OSX_H

+ 95 - 0
jni/love/src/common/OSX.mm

@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "OSX.h"
+
+#ifdef LOVE_MACOSX
+
+#import <Foundation/Foundation.h>
+#import <Cocoa/Cocoa.h>
+
+#include <SDL2/SDL.h>
+
+namespace love
+{
+namespace osx
+{
+
+std::string getLoveInResources()
+{
+	std::string path;
+
+	@autoreleasepool
+	{
+		// Check to see if there are any .love files in Resources.
+		NSString *lovepath = [[NSBundle mainBundle] pathForResource:nil ofType:@"love"];
+
+		if (lovepath != nil)
+			path = lovepath.UTF8String;
+	}
+
+	return path;
+}
+
+std::string checkDropEvents()
+{
+	std::string dropstr;
+	SDL_Event event;
+
+	SDL_InitSubSystem(SDL_INIT_VIDEO);
+
+	SDL_PumpEvents();
+	if (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_DROPFILE, SDL_DROPFILE) > 0)
+	{
+		if (event.type == SDL_DROPFILE)
+		{
+			dropstr = std::string(event.drop.file);
+			SDL_free(event.drop.file);
+		}
+	}
+
+	SDL_QuitSubSystem(SDL_INIT_VIDEO);
+
+	return dropstr;
+}
+
+std::string getExecutablePath()
+{
+	@autoreleasepool
+	{
+		return std::string([NSBundle mainBundle].executablePath.UTF8String);
+	}
+}
+
+void requestAttention(bool continuous)
+{
+	@autoreleasepool
+	{
+		if (continuous)
+			[NSApp requestUserAttention:NSCriticalRequest];
+		else
+			[NSApp requestUserAttention:NSInformationalRequest];
+	}
+}
+
+} // osx
+} // love
+
+#endif // LOVE_MACOSX

+ 14 - 5
jni/love/src/common/Object.cpp

@@ -25,28 +25,37 @@ namespace love
 {
 
 Object::Object()
+	: count(1)
+{
+}
+
+Object::Object(const Object & /*other*/)
+	: count(1) // Always start with a reference count of 1.
 {
-	count.value = 1;
 }
 
 Object::~Object()
 {
 }
 
-int Object::getReferenceCount()
+int Object::getReferenceCount() const
 {
-	return SDL_AtomicGet(&count);
+	return count;
 }
 
 void Object::retain()
 {
-	SDL_AtomicIncRef(&count);
+	count.fetch_add(1, std::memory_order_relaxed);
 }
 
 void Object::release()
 {
-	if (SDL_AtomicDecRef(&count))
+	// http://www.boost.org/doc/libs/1_56_0/doc/html/atomic/usage_examples.html
+	if (count.fetch_sub(1, std::memory_order_release) == 1)
+	{
+		std::atomic_thread_fence(std::memory_order_acquire);
 		delete this;
+	}
 }
 
 } // love

+ 5 - 9
jni/love/src/common/Object.h

@@ -21,12 +21,7 @@
 #ifndef LOVE_OBJECT_H
 #define LOVE_OBJECT_H
 
-/**
- * NOTE: the fact that an SDL header is included in such a widely used header
- * file is only temporary - in the LOVE 0.10+ codebase we use atomics from
- * C++11's standard library.
- **/
-#include <SDL_atomic.h>
+#include <atomic>
 
 namespace love
 {
@@ -47,6 +42,7 @@ public:
 	 * Constructor. Sets reference count to one.
 	 **/
 	Object();
+	Object(const Object &other);
 
 	/**
 	 * Destructor.
@@ -57,7 +53,7 @@ public:
 	 * Gets the reference count of this Object.
 	 * @returns The reference count.
 	 **/
-	int getReferenceCount();
+	int getReferenceCount() const;
 
 	/**
 	 * Retains the Object, i.e. increases the
@@ -75,7 +71,7 @@ public:
 private:
 
 	// The reference count.
-	SDL_atomic_t count;
+	std::atomic<int> count;
 
 }; // Object
 
@@ -136,7 +132,7 @@ public:
 private:
 
 	T *object;
-	
+
 }; // StrongRef
 
 } // love

+ 3 - 8
jni/love/src/common/Variant.cpp

@@ -101,9 +101,8 @@ Variant::Variant(love::Type udatatype, void *userdata)
 	if (udatatype != INVALID_ID)
 	{
 		Proxy *p = (Proxy *) userdata;
-		flags = p->flags;
-		data.userdata = p->data;
-		((love::Object *) data.userdata)->retain();
+		data.userdata = p->object;
+		p->object->retain();
 	}
 	else
 		data.userdata = userdata;
@@ -223,11 +222,7 @@ void Variant::toLua(lua_State *L)
 		break;
 	case FUSERDATA:
 		if (udatatype != INVALID_ID)
-		{
-			const char *name = NULL;
-			love::types.find(udatatype, name);
-			luax_pushtype(L, name, flags, (love::Object *) data.userdata);
-		}
+			luax_pushtype(L, udatatype, (love::Object *) data.userdata);
 		else
 			lua_pushlightuserdata(L, data.userdata);
 		// I know this is not the same

+ 0 - 1
jni/love/src/common/Variant.h

@@ -76,7 +76,6 @@ public:
 
 private:
 	love::Type udatatype;
-	bits flags;
 
 }; // Variant
 } // love

+ 4 - 4
jni/love/src/common/Vector.h

@@ -216,15 +216,15 @@ inline float Vector::normalize(float length)
  **/
 
 inline Vector::Vector()
+	: x(0.0f)
+	, y(0.0f)
 {
-	x = 1;
-	y = 1;
 }
 
 inline Vector::Vector(float x, float y)
+	: x(x)
+	, y(y)
 {
-	this->x = x;
-	this->y = y;
 }
 
 inline Vector Vector::operator + (const Vector &v) const

+ 21 - 6
jni/love/src/common/config.h

@@ -32,16 +32,23 @@
 #  define LOVE_ANDROID 1
 #endif
 #if defined(__APPLE__)
-#	define LOVE_MACOSX 1
-#	include <AvailabilityMacros.h>
+#	include <TargetConditionals.h>
+#	if TARGET_OS_IPHONE
+#		define LOVE_IOS 1
+#	elif TARGET_OS_MAC
+#		define LOVE_MACOSX 1
+#	endif
+#endif
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+// I know it's not linux, but it seems most "linux-only" code is bsd-compatible
+#	define LOVE_LINUX 1
 #endif
 
 // Endianness.
-#if defined(__i386__) || defined(__i386)
-#	define LOVE_LITTLE_ENDIAN 1
-#endif
 #if defined(__ppc__) || defined(__ppc) || defined(__powerpc__) || defined(__powerpc)
 #	define LOVE_BIG_ENDIAN 1
+#else
+#	define LOVE_LITTLE_ENDIAN 1
 #endif
 
 // Warnings.
@@ -74,7 +81,7 @@
 #	define NOMINMAX
 #endif
 
-#if defined(LOVE_MACOSX)
+#if defined(LOVE_MACOSX) || defined(LOVE_IOS)
 #	define LOVE_LEGENDARY_APP_ARGV_HACK
 #endif
 
@@ -139,4 +146,12 @@
 #	define LOVE_ENABLE_WUFF
 #endif
 
+// Check we have a sane configuration
+#if !defined(LOVE_WINDOWS) && !defined(LOVE_LINUX) && !defined(LOVE_IOS) && !defined(LOVE_MACOSX)
+#	error Could not detect target platform
+#endif
+#if !defined(LOVE_LITTLE_ENDIAN) && !defined(LOVE_BIG_ENDIAN)
+#	error Could not detect endianness
+#endif
+
 #endif // LOVE_CONFIG_H

+ 66 - 0
jni/love/src/common/iOS.h

@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_IOS_H
+#define LOVE_IOS_H
+
+#include "config.h"
+
+#ifdef LOVE_IOS
+
+#include <string>
+
+namespace love
+{
+namespace ios
+{
+
+/**
+ * Gets the filepath of the first detected love file. The main .app Bundle is
+ * searched first, and then the app's Documents folder.
+ **/
+std::string getLoveInResources(bool &fused);
+
+/**
+ * Gets the directory path where files should be stored.
+ **/
+std::string getAppdataDirectory();
+
+/**
+ * Get the home directory (on iOS, this really means the app's sandbox dir.)
+ **/
+std::string getHomeDirectory();
+
+/**
+ * Opens the specified URL with the default program associated with the URL's
+ * scheme.
+ **/
+bool openURL(const std::string &url);
+
+/**
+ * Returns the full path to the executable.
+ **/
+std::string getExecutablePath();
+
+} // ios
+} // love
+
+#endif // LOVE_IOS
+#endif // LOVE_IOS_H

+ 327 - 0
jni/love/src/common/iOS.mm

@@ -0,0 +1,327 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "iOS.h"
+
+#ifdef LOVE_IOS
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+#include <vector>
+
+#include <SDL_events.h>
+
+static NSArray *getLovesInDocuments();
+static bool deleteFileInDocuments(NSString *filename);
+
+@interface LOVETableViewController : UITableViewController
+
+- (instancetype)initWithGameList:(NSArray *)list;
+
+@property (nonatomic) NSMutableArray *gameList;
+@property (nonatomic, readonly, copy) NSString *selectedGame;
+
+@end
+
+@implementation LOVETableViewController
+
+- (instancetype)initWithGameList:(NSArray *)list
+{
+	if ((self = [super init]))
+	{
+		_gameList = [[NSMutableArray alloc] initWithArray:list copyItems:YES];
+
+		self.title = @"LÖVE Games";
+		self.navigationItem.rightBarButtonItem = self.editButtonItem;
+	}
+
+	return self;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
+{
+	#pragma unused(tableView)
+	#pragma unused(section)
+	// We want to list all games plus the no-game screen.
+	return self.gameList.count + 1;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+	static NSString *cellIdentifier = @"LOVETableCell";
+
+	UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
+	if (cell == nil)
+		cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
+
+	if (indexPath.row < (NSInteger) self.gameList.count)
+		cell.textLabel.text = self.gameList[indexPath.row];
+	else
+		cell.textLabel.text = @"No-game screen";
+
+	return cell;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
+{
+	#pragma unused(tableView)
+	if (indexPath.row < (NSInteger) self.gameList.count)
+		_selectedGame = [(NSString *)(self.gameList[indexPath.row]) copy];
+	else
+	{
+		// We test against nil to check if a game has been selected, so we'll
+		// just use an empty string instead to represent the no-game screen.
+		_selectedGame = @"";
+	}
+}
+
+- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
+{
+	if (editingStyle != UITableViewCellEditingStyleDelete)
+		return;
+
+	if (indexPath.row >= (NSInteger) self.gameList.count)
+		return;
+
+	NSString *filename = self.gameList[indexPath.row];
+
+	// Delete the file.
+	if (deleteFileInDocuments(filename))
+	{
+		[self.gameList removeObjectAtIndex:indexPath.row];
+		[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
+	}
+}
+
+- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;
+{
+	#pragma unused(tableView)
+	// The no-game screen isn't removable.
+	return indexPath.row < (NSInteger) self.gameList.count;
+}
+
+@end
+
+static NSString *getDocumentsDirectory()
+{
+	NSArray *docdirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+	return docdirs[0];
+}
+
+static NSArray *getLovesInDocuments()
+{
+	NSString *documents = getDocumentsDirectory();
+	NSArray *filepaths = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documents error:nil];
+	return [filepaths pathsMatchingExtensions:@[@"love"]];
+}
+
+static bool deleteFileInDocuments(NSString *filename)
+{
+	NSString *documents = getDocumentsDirectory();
+
+	NSString *file = [documents stringByAppendingPathComponent:filename];
+	bool success = [[NSFileManager defaultManager] removeItemAtPath:file error:nil];
+
+	if (success)
+		NSLog(@"Deleted file %@ in Documents folder.", filename);
+
+	return success;
+}
+
+static int dropFileEventFilter(void *userdata, SDL_Event *event)
+{
+	@autoreleasepool
+	{
+		if (event->type != SDL_DROPFILE)
+			return 1;
+
+		NSString *fname = @(event->drop.file);
+		NSFileManager *fmanager = [NSFileManager defaultManager];
+
+		if ([fmanager fileExistsAtPath:fname] && [fname.pathExtension isEqual:@"love"])
+		{
+			NSString *documents = getDocumentsDirectory();
+
+			documents = documents.stringByStandardizingPath.stringByResolvingSymlinksInPath;
+			fname = fname.stringByStandardizingPath.stringByResolvingSymlinksInPath;
+
+			// Is the file inside the Documents directory?
+			if ([fname hasPrefix:documents])
+			{
+				LOVETableViewController *vc = (__bridge LOVETableViewController *) userdata;
+
+				// Update the game list.
+				NSArray *games = getLovesInDocuments();
+				vc.gameList = [[NSMutableArray alloc] initWithArray:games copyItems:YES];
+				[vc.tableView reloadData];
+
+				SDL_free(event->drop.file);
+				return 0;
+			}
+		}
+
+		return 1;
+	}
+}
+
+namespace love
+{
+namespace ios
+{
+
+/**
+ * Displays a full-screen list of available LOVE games for the user to choose.
+ * Returns the index of the selected game from the list. The list of games
+ * includes the no-game screen, and the function will return an index outside
+ * of the array's range if that is selected.
+ **/
+static NSString *showGameList(NSArray *filenames)
+{
+	// Game list view controller.
+	LOVETableViewController *tablecontroller = [[LOVETableViewController alloc] initWithGameList:filenames];
+
+	// Navigation view controller (only used for the header bar right now.)
+	// Contains the game list view/controller.
+	UINavigationController *navcontroller = [[UINavigationController alloc] initWithRootViewController:tablecontroller];
+
+	UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
+	window.rootViewController = navcontroller;
+
+	SDL_EventFilter oldfilter = nullptr;
+	void *oldudata = nullptr;
+	SDL_GetEventFilter(&oldfilter, &oldudata);
+
+	// Manually retain the table VC and use it for the event filter userdata.
+	// We need to set a custom event filter to update the table when .love files
+	// are opened by the user.
+	void *tableudata = (void *) CFBridgingRetain(tablecontroller);
+	SDL_SetEventFilter(dropFileEventFilter, tableudata);
+
+	[window makeKeyAndVisible];
+
+	// Process events until a game in the list is selected.
+	NSRunLoop *runloop = [NSRunLoop currentRunLoop];
+	while (tablecontroller.selectedGame == nil)
+	{
+		[runloop runMode:NSDefaultRunLoopMode  beforeDate:[NSDate distantPast]];
+		[runloop runMode:UITrackingRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0/60.0]];
+	}
+
+	// The window will get released and cleaned up once we go out of scope.
+	window.hidden = YES;
+
+	SDL_SetEventFilter(oldfilter, oldudata);
+	CFBridgingRelease(tableudata);
+
+	return tablecontroller.selectedGame;
+}
+
+std::string getLoveInResources(bool &fused)
+{
+	fused = false;
+	std::string path;
+
+	@autoreleasepool
+	{
+		// Start by looking in the main bundle (.app) folder for .love files.
+		NSArray *bundlepaths = [[NSBundle mainBundle] pathsForResourcesOfType:@"love" inDirectory:nil];
+
+		if (bundlepaths.count > 0)
+		{
+			// The game should be fused if we have something here.
+			fused = true;
+			return [bundlepaths[0] UTF8String];
+		}
+
+		// Otherwise look in the app's Documents directory. The game won't be
+		// fused.
+		NSArray *filepaths = getLovesInDocuments();
+
+		// Let the user select a game from the un-fused list.
+		NSString *selectedfile = showGameList(filepaths);
+
+		// The string length might be 0 if the no-game screen was selected.
+		if (selectedfile != nil && selectedfile.length > 0)
+		{
+			NSString *documents = getDocumentsDirectory();
+			path = [documents stringByAppendingPathComponent:selectedfile].UTF8String;
+		}
+	}
+
+	return path;
+}
+
+std::string getAppdataDirectory()
+{
+	NSSearchPathDirectory searchdir = NSApplicationSupportDirectory;
+	std::string path;
+
+	@autoreleasepool
+	{
+		NSArray *dirs = NSSearchPathForDirectoriesInDomains(searchdir, NSUserDomainMask, YES);
+
+		if (dirs.count > 0)
+			path = [dirs[0] UTF8String];
+	}
+
+	return path;
+}
+
+std::string getHomeDirectory()
+{
+	std::string path;
+
+	@autoreleasepool
+	{
+		path = [NSHomeDirectory() UTF8String];
+	}
+
+	return path;
+}
+
+bool openURL(const std::string &url)
+{
+	bool success = false;
+
+	@autoreleasepool
+	{
+		UIApplication *app = [UIApplication sharedApplication];
+		NSURL *nsurl = [NSURL URLWithString:@(url.c_str())];
+
+		if ([app canOpenURL:nsurl])
+			success = [app openURL:nsurl];
+	}
+
+	return success;
+}
+
+std::string getExecutablePath()
+{
+	@autoreleasepool
+	{
+		return std::string([NSBundle mainBundle].executablePath.UTF8String);
+	}
+}
+
+} // ios
+} // love
+
+#endif // LOVE_IOS

+ 0 - 2
jni/love/src/common/int.h

@@ -31,8 +31,6 @@
 #endif
 
 // C standard sized integer types.
-// This header was added to Visual studio in VS 2012, which is LOVE's current
-// minimum supported VS version (as of this comment's commit date.)
 #include <stdint.h>
 
 #define LOVE_INT8_MAX   0x7F

+ 87 - 147
jni/love/src/common/runtime.cpp

@@ -26,7 +26,6 @@
 #include "Object.h"
 #include "Reference.h"
 #include "StringMap.h"
-#include <thread/threads.h>
 
 // C++
 #include <algorithm>
@@ -36,24 +35,14 @@
 namespace love
 {
 
-static thread::Mutex *gcmutex = nullptr;
-
 /**
  * Called when an object is collected. The object is released
  * once in this function, possibly deleting it.
  **/
 static int w__gc(lua_State *L)
 {
-	if (!gcmutex)
-		gcmutex = thread::newMutex();
-
 	Proxy *p = (Proxy *) lua_touserdata(L, 1);
-	Object *object = (Object *) p->data;
-
-	thread::Lock lock(gcmutex);
-
-	object->release();
-
+	p->object->release();
 	return 0;
 }
 
@@ -67,7 +56,7 @@ static int w__typeOf(lua_State *L)
 {
 	Proxy *p = (Proxy *)lua_touserdata(L, 1);
 	Type t = luax_type(L, 2);
-	luax_pushboolean(L, p->flags[t]);
+	luax_pushboolean(L, typeFlags[p->type][t]);
 	return 1;
 }
 
@@ -75,13 +64,13 @@ static int w__eq(lua_State *L)
 {
 	Proxy *p1 = (Proxy *)lua_touserdata(L, 1);
 	Proxy *p2 = (Proxy *)lua_touserdata(L, 2);
-	luax_pushboolean(L, p1->data == p2->data);
+	luax_pushboolean(L, p1->object == p2->object);
 	return 1;
 }
 
 Reference *luax_refif(lua_State *L, int type)
 {
-	Reference *r = 0;
+	Reference *r = nullptr;
 
 	// Create a reference only if the test succeeds.
 	if (lua_type(L, -1) == type)
@@ -95,9 +84,7 @@ Reference *luax_refif(lua_State *L, int type)
 void luax_printstack(lua_State *L)
 {
 	for (int i = 1; i<=lua_gettop(L); i++)
-	{
 		std::cout << i << " - " << luaL_typename(L, i) << std::endl;
-	}
 }
 
 bool luax_toboolean(lua_State *L, int idx)
@@ -144,7 +131,7 @@ bool luax_boolflag(lua_State *L, int table_index, const char *key, bool defaultV
 	if (lua_isnoneornil(L, -1))
 		retval = defaultValue;
 	else
-		retval = lua_toboolean(L, -1);
+		retval = lua_toboolean(L, -1) != 0;
 
 	lua_pop(L, 1);
 	return retval;
@@ -201,24 +188,32 @@ int luax_assert_nilerror(lua_State *L, int idx)
 
 void luax_setfuncs(lua_State *L, const luaL_Reg *l)
 {
-	if (l == 0)
+	if (l == nullptr)
 		return;
 
-	for (; l->name != 0; l++)
+	for (; l->name != nullptr; l++)
 	{
 		lua_pushcfunction(L, l->func);
 		lua_setfield(L, -2, l->name);
 	}
 }
 
+int luax_require(lua_State *L, const char *name)
+{
+	lua_getglobal(L, "require");
+	lua_pushstring(L, name);
+	lua_call(L, 1, 1);
+	return 1;
+}
+
 int luax_register_module(lua_State *L, const WrappedModule &m)
 {
 	// Put a reference to the C++ module in Lua.
 	luax_insistregistry(L, REGISTRY_MODULES);
 
 	Proxy *p = (Proxy *)lua_newuserdata(L, sizeof(Proxy));
-	p->data = m.module;
-	p->flags = m.flags;
+	p->object = m.module;
+	p->type = m.type;
 
 	luaL_newmetatable(L, m.module->getName());
 	lua_pushvalue(L, -1);
@@ -237,13 +232,15 @@ int luax_register_module(lua_State *L, const WrappedModule &m)
 	lua_newtable(L);
 
 	// Register all the functions.
-	if (m.functions != 0)
+	if (m.functions != nullptr)
 		luax_setfuncs(L, m.functions);
 
 	// Register types.
-	if (m.types != 0)
-		for (const lua_CFunction *t = m.types; *t != 0; t++)
+	if (m.types != nullptr)
+	{
+		for (const lua_CFunction *t = m.types; *t != nullptr; t++)
 			(*t)(L);
+	}
 
 	lua_pushvalue(L, -1);
 	lua_setfield(L, -3, m.name); // love.graphics = table
@@ -265,17 +262,17 @@ int luax_preload(lua_State *L, lua_CFunction f, const char *name)
 	return 0;
 }
 
-int luax_register_type(lua_State *L, const char *tname, const luaL_Reg *f)
+int luax_register_type(lua_State *L, love::Type type, const luaL_Reg *f, bool pushmetatable)
 {
 	// Verify that this type name has a matching Type ID and type name mapping.
-	love::Type ltype;
-	if (!love::getType(tname, ltype))
-		printf("Missing type entry for type name: %s\n", tname);
+	const char *tname = "Invalid";
+	if (!love::getType(type, tname))
+		printf("Missing type name entry for type ID %d\n", type);
 
 	// Get the place for storing and re-using instantiated love types.
-	luax_getregistry(L, REGISTRY_TYPES);
+	luax_getregistry(L, REGISTRY_OBJECTS);
 
-	// Create registry._lovetypes if it doesn't exist yet.
+	// Create registry._loveobjects if it doesn't exist yet.
 	if (!lua_istable(L, -1))
 	{
 		lua_newtable(L);
@@ -291,8 +288,8 @@ int luax_register_type(lua_State *L, const char *tname, const luaL_Reg *f)
 		// setmetatable(newtable, metatable)
 		lua_setmetatable(L, -2);
 
-		// registry._lovetypes = newtable
-		lua_setfield(L, LUA_REGISTRYINDEX, "_lovetypes");
+		// registry._loveobjects = newtable
+		lua_setfield(L, LUA_REGISTRYINDEX, "_loveobjects");
 	}
 	else
 		lua_pop(L, 1);
@@ -325,9 +322,12 @@ int luax_register_type(lua_State *L, const char *tname, const luaL_Reg *f)
 	lua_pushcfunction(L, w__typeOf);
 	lua_setfield(L, -2, "typeOf");
 
-	if (f != 0)
+	if (f != nullptr)
 		luax_setfuncs(L, f);
 
+	if (pushmetatable)
+		return 1; // leave the metatable on the stack.
+
 	lua_pop(L, 1); // Pops metatable.
 	return 0;
 }
@@ -338,19 +338,22 @@ int luax_table_insert(lua_State *L, int tindex, int vindex, int pos)
 		tindex = lua_gettop(L)+1+tindex;
 	if (vindex < 0)
 		vindex = lua_gettop(L)+1+vindex;
+
 	if (pos == -1)
 	{
 		lua_pushvalue(L, vindex);
-		lua_rawseti(L, tindex, lua_objlen(L, tindex)+1);
+		lua_rawseti(L, tindex, (int) luax_objlen(L, tindex)+1);
 		return 0;
 	}
 	else if (pos < 0)
-		pos = lua_objlen(L, tindex)+1+pos;
-	for (int i = lua_objlen(L, tindex)+1; i > pos; i--)
+		pos = (int) luax_objlen(L, tindex)+1+pos;
+
+	for (int i = (int) luax_objlen(L, tindex)+1; i > pos; i--)
 	{
 		lua_rawgeti(L, tindex, i-1);
 		lua_rawseti(L, tindex, i);
 	}
+
 	lua_pushvalue(L, vindex);
 	lua_rawseti(L, tindex, pos);
 	return 0;
@@ -382,20 +385,23 @@ int luax_register_searcher(lua_State *L, lua_CFunction f, int pos)
 	return 0;
 }
 
-void luax_rawnewtype(lua_State *L, const char *name, bits flags, love::Object *object)
+void luax_rawnewtype(lua_State *L, love::Type type, love::Object *object)
 {
 	Proxy *u = (Proxy *)lua_newuserdata(L, sizeof(Proxy));
 
 	object->retain();
 
-	u->data = (void *) object;
-	u->flags = flags;
+	u->object = object;
+	u->type = type;
+
+	const char *name = "Invalid";
+	getType(type, name);
 
 	luaL_newmetatable(L, name);
 	lua_setmetatable(L, -2);
 }
 
-void luax_pushtype(lua_State *L, const char *name, bits flags, love::Object *object)
+void luax_pushtype(lua_State *L, love::Type type, love::Object *object)
 {
 	if (object == nullptr)
 	{
@@ -403,18 +409,18 @@ void luax_pushtype(lua_State *L, const char *name, bits flags, love::Object *obj
 		return;
 	}
 
-	// Fetch the registry table of instantiated types.
-	luax_getregistry(L, REGISTRY_TYPES);
+	// Fetch the registry table of instantiated objects.
+	luax_getregistry(L, REGISTRY_OBJECTS);
 
 	// The table might not exist - it should be insisted in luax_register_type.
 	if (!lua_istable(L, -1))
 	{
 		lua_pop(L, 1);
-		return luax_rawnewtype(L, name, flags, object);
+		return luax_rawnewtype(L, type, object);
 	}
 
-	// Get the value of lovetypes[object] on the stack.
-	lua_pushlightuserdata(L, (void *) object);
+	// Get the value of loveobjects[object] on the stack.
+	lua_pushlightuserdata(L, object);
 	lua_gettable(L, -2);
 
 	// If the Proxy userdata isn't in the instantiated types table yet, add it.
@@ -422,27 +428,28 @@ void luax_pushtype(lua_State *L, const char *name, bits flags, love::Object *obj
 	{
 		lua_pop(L, 1);
 
-		luax_rawnewtype(L, name, flags, object);
+		luax_rawnewtype(L, type, object);
 
-		lua_pushlightuserdata(L, (void *) object);
+		lua_pushlightuserdata(L, object);
 		lua_pushvalue(L, -2);
 
-		// lovetypes[object] = Proxy.
+		// loveobjects[object] = Proxy.
 		lua_settable(L, -4);
 	}
 
-	// Remove the lovetypes table from the stack.
+	// Remove the loveobjects table from the stack.
 	lua_remove(L, -2);
 
 	// Keep the Proxy userdata on the stack.
 }
 
-bool luax_istype(lua_State *L, int idx, love::bits type)
+bool luax_istype(lua_State *L, int idx, love::Type type)
 {
 	if (lua_type(L, idx) != LUA_TUSERDATA)
 		return false;
 
-	return ((((Proxy *)lua_touserdata(L, idx))->flags & type) == type);
+	Proxy *p = (Proxy *) lua_touserdata(L, idx);
+	return typeFlags[p->type][type];
 }
 
 int luax_getfunction(lua_State *L, const char *mod, const char *fn)
@@ -485,7 +492,8 @@ int luax_convobj(lua_State *L, int idxs[], int n, const char *mod, const char *f
 	lua_call(L, n, 2); // Call the function, n args, one return value (plus optional errstring.)
 	luax_assert_nilerror(L, -2); // Make sure the function returned something.
 	lua_pop(L, 1); // Pop the second return value now that we don't need it.
-	lua_replace(L, idxs[0]); // Replace the initial argument with the new object.
+	if (n > 0)
+		lua_replace(L, idxs[0]); // Replace the initial argument with the new object.
 	return 0;
 }
 
@@ -548,6 +556,11 @@ int luax_insistglobal(lua_State *L, const char *k)
 	return 1;
 }
 
+int luax_c_insistglobal(lua_State *L, const char *k)
+{
+	return luax_insistglobal(L, k);
+}
+
 int luax_insistlove(lua_State *L, const char *k)
 {
 	luax_insistglobal(L, "love");
@@ -581,8 +594,8 @@ int luax_insistregistry(lua_State *L, Registry r)
 		return luax_insistlove(L, "_gc");
 	case REGISTRY_MODULES:
 		return luax_insistlove(L, "_modules");
-	case REGISTRY_TYPES:
-		return luax_insist(L, LUA_REGISTRYINDEX, "_lovetypes");
+	case REGISTRY_OBJECTS:
+		return luax_insist(L, LUA_REGISTRYINDEX, "_loveobjects");
 	default:
 		return luaL_error(L, "Attempted to use invalid registry.");
 	}
@@ -596,8 +609,8 @@ int luax_getregistry(lua_State *L, Registry r)
 		return luax_getlove(L, "_gc");
 	case REGISTRY_MODULES:
 		return luax_getlove(L, "_modules");
-	case REGISTRY_TYPES:
-		lua_getfield(L, LUA_REGISTRYINDEX, "_lovetypes");
+	case REGISTRY_OBJECTS:
+		lua_getfield(L, LUA_REGISTRYINDEX, "_loveobjects");
 		return 1;
 	default:
 		return luaL_error(L, "Attempted to use invalid registry.");
@@ -632,105 +645,32 @@ extern "C" int luax_typerror(lua_State *L, int narg, const char *tname)
 	return luaL_argerror(L, narg, msg);
 }
 
-StringMap<Type, TYPE_MAX_ENUM>::Entry typeEntries[] =
+size_t luax_objlen(lua_State *L, int ndx)
 {
-	{"Invalid", INVALID_ID},
-
-	{"Object", OBJECT_ID},
-	{"Data", DATA_ID},
-	{"Module", MODULE_ID},
-
-	// Filesystem
-	{"File", FILESYSTEM_FILE_ID},
-	{"FileData", FILESYSTEM_FILE_DATA_ID},
-
-	// Font
-	{"GlyphData", FONT_GLYPH_DATA_ID},
-	{"Rasterizer", FONT_RASTERIZER_ID},
-
-	// Graphics
-	{"Drawable", GRAPHICS_DRAWABLE_ID},
-	{"Texture", GRAPHICS_TEXTURE_ID},
-	{"Image", GRAPHICS_IMAGE_ID},
-	{"Quad", GRAPHICS_QUAD_ID},
-	{"Font", GRAPHICS_FONT_ID},
-	{"ParticleSystem", GRAPHICS_PARTICLE_SYSTEM_ID},
-	{"SpriteBatch", GRAPHICS_SPRITE_BATCH_ID},
-	{"Canvas", GRAPHICS_CANVAS_ID},
-	{"Shader", GRAPHICS_SHADER_ID},
-	{"Mesh", GRAPHICS_MESH_ID},
-
-	// Image
-	{"ImageData", IMAGE_IMAGE_DATA_ID},
-	{"CompressedData", IMAGE_COMPRESSED_DATA_ID},
-
-	// Joystick
-	{"Joystick", JOYSTICK_JOYSTICK_ID},
-
-	// Math
-	{"RandomGenerator", MATH_RANDOM_GENERATOR_ID},
-	{"BezierCurve", MATH_BEZIER_CURVE_ID},
-
-	// Audio
-	{"Source", AUDIO_SOURCE_ID},
-
-	// Sound
-	{"SoundData", SOUND_SOUND_DATA_ID},
-	{"Decoder", SOUND_DECODER_ID},
-
-	// Mouse
-	{"Cursor", MOUSE_CURSOR_ID},
-
-	// Physics
-	{"World", PHYSICS_WORLD_ID},
-	{"Contact", PHYSICS_CONTACT_ID},
-	{"Body", PHYSICS_BODY_ID},
-	{"Fixture", PHYSICS_FIXTURE_ID},
-	{"Shape", PHYSICS_SHAPE_ID},
-	{"CircleShape", PHYSICS_CIRCLE_SHAPE_ID},
-	{"PolygonShape", PHYSICS_POLYGON_SHAPE_ID},
-	{"EdgeShape", PHYSICS_EDGE_SHAPE_ID},
-	{"ChainShape", PHYSICS_CHAIN_SHAPE_ID},
-	{"Joint", PHYSICS_JOINT_ID},
-	{"MouseJoint", PHYSICS_MOUSE_JOINT_ID},
-	{"DistanceJoint", PHYSICS_DISTANCE_JOINT_ID},
-	{"PrismaticJoint", PHYSICS_PRISMATIC_JOINT_ID},
-	{"RevoluteJoint", PHYSICS_REVOLUTE_JOINT_ID},
-	{"PulleyJoint", PHYSICS_PULLEY_JOINT_ID},
-	{"GearJoint", PHYSICS_GEAR_JOINT_ID},
-	{"FrictionJoint", PHYSICS_FRICTION_JOINT_ID},
-	{"WeldJoint", PHYSICS_WELD_JOINT_ID},
-	{"RopeJoint", PHYSICS_ROPE_JOINT_ID},
-	{"WheelJoint", PHYSICS_WHEEL_JOINT_ID},
-	{"MotorJoint", PHYSICS_MOTOR_JOINT_ID},
-
-	// Thread
-	{"Thread", THREAD_THREAD_ID},
-	{"Channel", THREAD_CHANNEL_ID},
-
-	// The modules themselves. Only add abstracted modules here.
-	{"filesystem", MODULE_FILESYSTEM_ID},
-	{"graphics", MODULE_GRAPHICS_ID},
-	{"image", MODULE_IMAGE_ID},
-	{"sound", MODULE_SOUND_ID},
-};
-
-StringMap<Type, TYPE_MAX_ENUM> types(typeEntries, sizeof(typeEntries));
-
-bool getType(const char *in, love::Type &out)
-{
-	return types.find(in, out);
+#if LUA_VERSION_NUM == 501
+	return lua_objlen(L, ndx);
+#else
+	return lua_rawlen(L, ndx);
+#endif
 }
 
-bool getType(love::Type in, const char *&out)
+void luax_register(lua_State *L, const char *name, const luaL_Reg *l)
 {
-	return types.find(in, out);
+	if (name)
+		lua_newtable(L);
+
+	luax_setfuncs(L, l);
+	if (name)
+	{
+		lua_pushvalue(L, -1);
+		lua_setglobal(L, name);
+	}
 }
 
 Type luax_type(lua_State *L, int idx)
 {
 	Type t = INVALID_ID;
-	types.find(luaL_checkstring(L, idx), t);
+	getType(luaL_checkstring(L, idx), t);
 	return t;
 }
 

+ 66 - 42
jni/love/src/common/runtime.h

@@ -51,7 +51,7 @@ enum Registry
 {
 	REGISTRY_GC,
 	REGISTRY_MODULES,
-	REGISTRY_TYPES
+	REGISTRY_OBJECTS
 };
 
 /**
@@ -63,10 +63,10 @@ enum Registry
 struct Proxy
 {
 	// Holds type information (see types.h).
-	bits flags;
+	Type type;
 
-	// The light userdata (pointer to the love::Object).
-	void *data;
+	// Pointer to the actual object.
+	Object *object;
 };
 
 /**
@@ -80,15 +80,14 @@ struct WrappedModule
 	// The name for the table to put the functions in, without the 'love'-prefix.
 	const char *name;
 
-	// The type flags of this module.
-	love::bits flags;
+	// The type of this module.
+	love::Type type;
 
 	// The functions of the module (last element {0,0}).
 	const luaL_Reg *functions;
 
 	// A list of functions which expose the types of the modules (last element 0).
 	const lua_CFunction *types;
-
 };
 
 /**
@@ -223,6 +222,13 @@ int luax_assert_nilerror(lua_State *L, int idx);
  **/
 void luax_setfuncs(lua_State *L, const luaL_Reg *l);
 
+/**
+ * Loads a Lua module using the 'require' function. Leaves the return result on
+ * the stack.
+ * @param name The name of the module to require.
+ **/
+int luax_require(lua_State *L, const char *name);
+
 /**
  * Register a module in the love table. The love table will be created if it does not exist.
  * NOTE: The module-object is expected to have a +1 reference count before calling
@@ -241,11 +247,11 @@ int luax_preload(lua_State *L, lua_CFunction f, const char *name);
 
 /**
  * Register a new type.
- * @param tname The name of the type. This must not conflict with other type names,
- * even from other modules.
+ * @param type The type.
  * @param f The list of member functions for the type.
+ * @param pushmetatable Whether to push the type's metatable to the stack.
  **/
-int luax_register_type(lua_State *L, const char *tname, const luaL_Reg *f = 0);
+int luax_register_type(lua_State *L, love::Type type, const luaL_Reg *f = nullptr, bool pushmetatable = false);
 
 /**
  * Do a table.insert from C
@@ -270,11 +276,10 @@ int luax_register_searcher(lua_State *L, lua_CFunction f, int pos = -1);
  * storing the Lua representation in a weak table if it doesn't exist yet.
  * NOTE: The object will be retained by Lua and released upon garbage collection.
  * @param L The Lua state.
- * @param name The name of the type. This must match the name used with luax_register_type.
- * @param flags The type information of the object.
+ * @param type The type information of the object.
  * @param object The pointer to the actual object.
  **/
-void luax_pushtype(lua_State *L, const char *name, bits flags, love::Object *object);
+void luax_pushtype(lua_State *L, const love::Type type, love::Object *object);
 
 /**
  * Creates a new Lua representation of the given object *without* checking if it
@@ -284,11 +289,10 @@ void luax_pushtype(lua_State *L, const char *name, bits flags, love::Object *obj
  * Lua-side objects from working in some cases when used as keys in tables.
  * NOTE: The object will be retained by Lua and released upon garbage collection.
  * @param L The Lua state.
- * @param name The name of the type. This must match the name used with luax_register_type.
- * @param flags The type information of the object.
+ * @param type The type information of the object.
  * @param object The pointer to the actual object.
  **/
-void luax_rawnewtype(lua_State *L, const char *name, bits flags, love::Object *object);
+void luax_rawnewtype(lua_State *L, love::Type type, love::Object *object);
 
 /**
  * Checks whether the value at idx is a certain type.
@@ -297,7 +301,7 @@ void luax_rawnewtype(lua_State *L, const char *name, bits flags, love::Object *o
  * @param type The type to check for.
  * @return True if the value is Proxy of the specified type, false otherwise.
  **/
-bool luax_istype(lua_State *L, int idx, love::bits type);
+bool luax_istype(lua_State *L, int idx, love::Type type);
 
 /**
  * Gets the function love.module.function and puts it on top of the stack (alone). If the
@@ -390,52 +394,75 @@ extern "C" { // Also called from luasocket
 	int luax_typerror(lua_State *L, int narg, const char *tname);
 }
 
+/**
+ * Calls luax_objlen/lua_rawlen depending on version
+ **/
+size_t luax_objlen(lua_State *L, int ndx);
+
+extern "C" { // Called by enet and luasocket
+	void luax_register(lua_State *L, const char *name, const luaL_Reg *l);
+	int luax_c_insistglobal(lua_State *L, const char *k);
+}
+
 /**
  * Like luax_totype, but causes an error if the value at idx is not Proxy,
  * or is not the specified type.
  * @param L The Lua state.
  * @param idx The index on the stack.
- * @param name The name of the type.
  * @param type The type bit.
  **/
 template <typename T>
-T *luax_checktype(lua_State *L, int idx, const char *name, love::bits type)
+T *luax_checktype(lua_State *L, int idx, love::Type type)
 {
 	if (lua_type(L, idx) != LUA_TUSERDATA)
+	{
+		const char *name = "Invalid";
+		getType(type, name);
 		luax_typerror(L, idx, name);
+	}
 
 	Proxy *u = (Proxy *)lua_touserdata(L, idx);
 
-	if ((u->flags & type) != type)
+	if (!typeFlags[u->type][type])
+	{
+		const char *name = "Invalid";
+		getType(type, name);
 		luax_typerror(L, idx, name);
+	}
 
-	return (T *)u->data;
+	return (T *)u->object;
 }
 
 template <typename T>
-T *luax_getmodule(lua_State *L, const char *k, love::bits type)
+T *luax_getmodule(lua_State *L, love::Type type)
 {
+	const char *name = "Invalid";
+	getType(type, name);
+
 	luax_insistregistry(L, REGISTRY_MODULES);
-	lua_getfield(L, -1, k);
+	lua_getfield(L, -1, name);
 
 	if (!lua_isuserdata(L, -1))
-		luaL_error(L, "Tried to get nonexistant module %s.", k);
+		luaL_error(L, "Tried to get nonexistant module %s.", name);
 
 	Proxy *u = (Proxy *)lua_touserdata(L, -1);
 
-	if ((u->flags & type) != type)
-		luaL_error(L, "Incorrect module %s", k);
+	if (!typeFlags[u->type][type])
+		luaL_error(L, "Incorrect module %s", name);
 
 	lua_pop(L, 2);
 
-	return (T *)u->data;
+	return (T *)u->object;
 }
 
 template <typename T>
-T *luax_optmodule(lua_State *L, const char *k, love::bits type)
+T *luax_optmodule(lua_State *L, love::Type type)
 {
+	const char *name = "Invalid";
+	getType(type, name);
+
 	luax_insistregistry(L, REGISTRY_MODULES);
-	lua_getfield(L, -1, k);
+	lua_getfield(L, -1, name);
 
 	if (!lua_isuserdata(L, -1))
 	{
@@ -445,12 +472,12 @@ T *luax_optmodule(lua_State *L, const char *k, love::bits type)
 
 	Proxy *u = (Proxy *)lua_touserdata(L, -1);
 
-	if ((u->flags & type) != type)
-		luaL_error(L, "Incorrect module %s", k);
-	
+	if (!typeFlags[u->type][type])
+		luaL_error(L, "Incorrect module %s", name);
+
 	lua_pop(L, 2);
-	
-	return (T *) u->data;
+
+	return (T *) u->object;
 }
 
 /**
@@ -459,13 +486,12 @@ T *luax_optmodule(lua_State *L, const char *k, love::bits type)
  * luax_istype, then this can be safely used. Otherwise, use luax_checktype.
  * @param L The Lua state.
  * @param idx The index on the stack.
- * @param name The name of the type.
- * @param type The type bit.
+ * @param type The type of the object.
  **/
 template <typename T>
-T *luax_totype(lua_State *L, int idx, const char * /* name */, love::bits /* type */)
+T *luax_totype(lua_State *L, int idx, love::Type /*type*/)
 {
-	return (T *)(((Proxy *)lua_touserdata(L, idx))->data);
+	return (T *)(((Proxy *)lua_touserdata(L, idx))->object);
 }
 
 Type luax_type(lua_State *L, int idx);
@@ -495,7 +521,6 @@ int luax_catchexcept(lua_State *L, const T& func)
 		return luaL_error(L, "%s", lua_tostring(L, -1));
 
 	return 0;
-
 }
 
 template <typename T, typename F>
@@ -513,13 +538,12 @@ int luax_catchexcept(lua_State *L, const T& func, const F& finallyfunc)
 		lua_pushstring(L, e.what());
 	}
 
-	finallyfunc();
+	finallyfunc(should_error);
 
 	if (should_error)
 		return luaL_error(L, "%s", lua_tostring(L, -1));
-	
+
 	return 0;
-	
 }
 
 } // love

+ 219 - 0
jni/love/src/common/types.cpp

@@ -0,0 +1,219 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "types.h"
+#include "StringMap.h"
+
+namespace love
+{
+
+static const TypeBits *createTypeFlags()
+{
+	static TypeBits b[TYPE_MAX_ENUM];
+	TypeBits one = TypeBits(1);
+
+	b[INVALID_ID] = one << INVALID_ID;
+
+	b[OBJECT_ID] = one << OBJECT_ID;
+	b[DATA_ID] = (one << DATA_ID) | b[OBJECT_ID];
+	b[MODULE_ID] = (one << MODULE_ID) | b[OBJECT_ID];
+
+	// Filesystem.
+	b[FILESYSTEM_FILE_ID] = (one << FILESYSTEM_FILE_ID) | b[OBJECT_ID];
+	b[FILESYSTEM_DROPPED_FILE_ID] = (one << FILESYSTEM_DROPPED_FILE_ID) | b[FILESYSTEM_FILE_ID];
+	b[FILESYSTEM_FILE_DATA_ID] = (one << FILESYSTEM_FILE_DATA_ID) | b[DATA_ID];
+
+	b[FONT_GLYPH_DATA_ID] = (one << FONT_GLYPH_DATA_ID) | b[DATA_ID];
+	b[FONT_RASTERIZER_ID] = (one << FONT_RASTERIZER_ID) | b[OBJECT_ID];
+
+	// Graphics.
+	b[GRAPHICS_DRAWABLE_ID] = (one << GRAPHICS_DRAWABLE_ID) | b[OBJECT_ID];
+	b[GRAPHICS_TEXTURE_ID] = (one << GRAPHICS_TEXTURE_ID) | b[GRAPHICS_DRAWABLE_ID];
+	b[GRAPHICS_IMAGE_ID] = (one << GRAPHICS_IMAGE_ID) | b[GRAPHICS_TEXTURE_ID];
+	b[GRAPHICS_QUAD_ID] = (one << GRAPHICS_QUAD_ID) | b[OBJECT_ID];
+	b[GRAPHICS_FONT_ID] = (one << GRAPHICS_FONT_ID) | b[OBJECT_ID];
+	b[GRAPHICS_PARTICLE_SYSTEM_ID] = (one << GRAPHICS_PARTICLE_SYSTEM_ID) | b[GRAPHICS_DRAWABLE_ID];
+	b[GRAPHICS_SPRITE_BATCH_ID] = (one << GRAPHICS_SPRITE_BATCH_ID) | b[GRAPHICS_DRAWABLE_ID];
+	b[GRAPHICS_CANVAS_ID] = (one << GRAPHICS_CANVAS_ID) | b[GRAPHICS_TEXTURE_ID];
+	b[GRAPHICS_SHADER_ID] = (one << GRAPHICS_SHADER_ID) | b[OBJECT_ID];
+	b[GRAPHICS_MESH_ID] = (one << GRAPHICS_MESH_ID) | b[GRAPHICS_DRAWABLE_ID];
+	b[GRAPHICS_TEXT_ID] = (one << GRAPHICS_TEXT_ID) | b[GRAPHICS_DRAWABLE_ID];
+
+	// Image.
+	b[IMAGE_IMAGE_DATA_ID] = (one << IMAGE_IMAGE_DATA_ID) | b[DATA_ID];
+	b[IMAGE_COMPRESSED_IMAGE_DATA_ID] = (one << IMAGE_COMPRESSED_IMAGE_DATA_ID) | b[DATA_ID];
+
+	// Joystick.
+	b[JOYSTICK_JOYSTICK_ID] = (one << JOYSTICK_JOYSTICK_ID) | b[OBJECT_ID];
+
+	// Math.
+	b[MATH_RANDOM_GENERATOR_ID] = (one << MATH_RANDOM_GENERATOR_ID) | b[OBJECT_ID];
+	b[MATH_BEZIER_CURVE_ID] = (one << MATH_BEZIER_CURVE_ID) | b[OBJECT_ID];
+	b[MATH_COMPRESSED_DATA_ID] = (one <<MATH_COMPRESSED_DATA_ID) | b[DATA_ID];
+
+	// Audio.
+	b[AUDIO_SOURCE_ID] = (one << AUDIO_SOURCE_ID) | b[OBJECT_ID];
+
+	// Sound.
+	b[SOUND_SOUND_DATA_ID] = (one << SOUND_SOUND_DATA_ID) | b[DATA_ID];
+	b[SOUND_DECODER_ID] = one << SOUND_DECODER_ID;
+
+	// Mouse.
+	b[MOUSE_CURSOR_ID] = (one << MOUSE_CURSOR_ID) | b[OBJECT_ID];
+
+	// Physics.
+	b[PHYSICS_WORLD_ID] = (one << PHYSICS_WORLD_ID) | b[OBJECT_ID];
+	b[PHYSICS_CONTACT_ID] = (one << PHYSICS_CONTACT_ID) | b[OBJECT_ID];
+	b[PHYSICS_BODY_ID] = (one << PHYSICS_BODY_ID) | b[OBJECT_ID];
+	b[PHYSICS_FIXTURE_ID] = (one << PHYSICS_FIXTURE_ID) | b[OBJECT_ID];
+	b[PHYSICS_SHAPE_ID] = (one << PHYSICS_SHAPE_ID) | b[OBJECT_ID];
+	b[PHYSICS_CIRCLE_SHAPE_ID] = (one << PHYSICS_CIRCLE_SHAPE_ID) | b[PHYSICS_SHAPE_ID];
+	b[PHYSICS_POLYGON_SHAPE_ID] = (one << PHYSICS_POLYGON_SHAPE_ID) | b[PHYSICS_SHAPE_ID];
+	b[PHYSICS_EDGE_SHAPE_ID] = (one << PHYSICS_EDGE_SHAPE_ID) | b[PHYSICS_SHAPE_ID];
+	b[PHYSICS_CHAIN_SHAPE_ID] = (one << PHYSICS_CHAIN_SHAPE_ID) | b[PHYSICS_SHAPE_ID];
+	b[PHYSICS_JOINT_ID] = (one << PHYSICS_JOINT_ID) | b[OBJECT_ID];
+	b[PHYSICS_MOUSE_JOINT_ID] = (one << PHYSICS_MOUSE_JOINT_ID) | b[PHYSICS_JOINT_ID];
+	b[PHYSICS_DISTANCE_JOINT_ID] = (one << PHYSICS_DISTANCE_JOINT_ID) | b[PHYSICS_JOINT_ID];
+	b[PHYSICS_PRISMATIC_JOINT_ID] = (one << PHYSICS_PRISMATIC_JOINT_ID) | b[PHYSICS_JOINT_ID];
+	b[PHYSICS_REVOLUTE_JOINT_ID] = (one << PHYSICS_REVOLUTE_JOINT_ID) | b[PHYSICS_JOINT_ID];
+	b[PHYSICS_PULLEY_JOINT_ID] = (one << PHYSICS_PULLEY_JOINT_ID) | b[PHYSICS_JOINT_ID];
+	b[PHYSICS_GEAR_JOINT_ID] = (one << PHYSICS_GEAR_JOINT_ID) | b[PHYSICS_JOINT_ID];
+	b[PHYSICS_FRICTION_JOINT_ID] = (one << PHYSICS_FRICTION_JOINT_ID) | b[PHYSICS_JOINT_ID];
+	b[PHYSICS_WELD_JOINT_ID] = (one << PHYSICS_WELD_JOINT_ID) | b[PHYSICS_JOINT_ID];
+	b[PHYSICS_ROPE_JOINT_ID] = (one << PHYSICS_ROPE_JOINT_ID) | b[PHYSICS_JOINT_ID];
+	b[PHYSICS_WHEEL_JOINT_ID] = (one << PHYSICS_WHEEL_JOINT_ID) | b[PHYSICS_JOINT_ID];
+	b[PHYSICS_MOTOR_JOINT_ID] = (one << PHYSICS_MOTOR_JOINT_ID) | b[PHYSICS_JOINT_ID];
+
+	// Thread.
+	b[THREAD_THREAD_ID] = (one << THREAD_THREAD_ID) | b[OBJECT_ID];
+	b[THREAD_CHANNEL_ID] = (one << THREAD_CHANNEL_ID) | b[OBJECT_ID];
+
+	// Modules.
+	b[MODULE_FILESYSTEM_ID] = (one << MODULE_FILESYSTEM_ID) | b[MODULE_ID];
+	b[MODULE_GRAPHICS_ID] = (one << MODULE_GRAPHICS_ID) | b[MODULE_ID];
+	b[MODULE_IMAGE_ID] = (one << MODULE_IMAGE_ID) | b[MODULE_ID];
+	b[MODULE_SOUND_ID] = (one << MODULE_SOUND_ID) | b[MODULE_ID];
+
+	return b;
+}
+
+const TypeBits *typeFlags = createTypeFlags();
+
+StringMap<Type, TYPE_MAX_ENUM>::Entry typeEntries[] =
+{
+	{"Invalid", INVALID_ID},
+
+	{"Object", OBJECT_ID},
+	{"Data", DATA_ID},
+	{"Module", MODULE_ID},
+
+	// Filesystem
+	{"File", FILESYSTEM_FILE_ID},
+	{"DroppedFile", FILESYSTEM_DROPPED_FILE_ID},
+	{"FileData", FILESYSTEM_FILE_DATA_ID},
+
+	// Font
+	{"GlyphData", FONT_GLYPH_DATA_ID},
+	{"Rasterizer", FONT_RASTERIZER_ID},
+
+	// Graphics
+	{"Drawable", GRAPHICS_DRAWABLE_ID},
+	{"Texture", GRAPHICS_TEXTURE_ID},
+	{"Image", GRAPHICS_IMAGE_ID},
+	{"Quad", GRAPHICS_QUAD_ID},
+	{"Font", GRAPHICS_FONT_ID},
+	{"ParticleSystem", GRAPHICS_PARTICLE_SYSTEM_ID},
+	{"SpriteBatch", GRAPHICS_SPRITE_BATCH_ID},
+	{"Canvas", GRAPHICS_CANVAS_ID},
+	{"Shader", GRAPHICS_SHADER_ID},
+	{"Mesh", GRAPHICS_MESH_ID},
+	{"Text", GRAPHICS_TEXT_ID},
+
+	// Image
+	{"ImageData", IMAGE_IMAGE_DATA_ID},
+	{"CompressedImageData", IMAGE_COMPRESSED_IMAGE_DATA_ID},
+
+	// Joystick
+	{"Joystick", JOYSTICK_JOYSTICK_ID},
+
+	// Math
+	{"RandomGenerator", MATH_RANDOM_GENERATOR_ID},
+	{"BezierCurve", MATH_BEZIER_CURVE_ID},
+	{"CompressedData", MATH_COMPRESSED_DATA_ID},
+
+	// Audio
+	{"Source", AUDIO_SOURCE_ID},
+
+	// Sound
+	{"SoundData", SOUND_SOUND_DATA_ID},
+	{"Decoder", SOUND_DECODER_ID},
+
+	// Mouse
+	{"Cursor", MOUSE_CURSOR_ID},
+
+	// Physics
+	{"World", PHYSICS_WORLD_ID},
+	{"Contact", PHYSICS_CONTACT_ID},
+	{"Body", PHYSICS_BODY_ID},
+	{"Fixture", PHYSICS_FIXTURE_ID},
+	{"Shape", PHYSICS_SHAPE_ID},
+	{"CircleShape", PHYSICS_CIRCLE_SHAPE_ID},
+	{"PolygonShape", PHYSICS_POLYGON_SHAPE_ID},
+	{"EdgeShape", PHYSICS_EDGE_SHAPE_ID},
+	{"ChainShape", PHYSICS_CHAIN_SHAPE_ID},
+	{"Joint", PHYSICS_JOINT_ID},
+	{"MouseJoint", PHYSICS_MOUSE_JOINT_ID},
+	{"DistanceJoint", PHYSICS_DISTANCE_JOINT_ID},
+	{"PrismaticJoint", PHYSICS_PRISMATIC_JOINT_ID},
+	{"RevoluteJoint", PHYSICS_REVOLUTE_JOINT_ID},
+	{"PulleyJoint", PHYSICS_PULLEY_JOINT_ID},
+	{"GearJoint", PHYSICS_GEAR_JOINT_ID},
+	{"FrictionJoint", PHYSICS_FRICTION_JOINT_ID},
+	{"WeldJoint", PHYSICS_WELD_JOINT_ID},
+	{"RopeJoint", PHYSICS_ROPE_JOINT_ID},
+	{"WheelJoint", PHYSICS_WHEEL_JOINT_ID},
+	{"MotorJoint", PHYSICS_MOTOR_JOINT_ID},
+
+	// Thread
+	{"Thread", THREAD_THREAD_ID},
+	{"Channel", THREAD_CHANNEL_ID},
+
+	// The modules themselves. Only add abstracted modules here.
+	{"filesystem", MODULE_FILESYSTEM_ID},
+	{"graphics", MODULE_GRAPHICS_ID},
+	{"image", MODULE_IMAGE_ID},
+	{"sound", MODULE_SOUND_ID},
+};
+
+StringMap<Type, TYPE_MAX_ENUM> types(typeEntries, sizeof(typeEntries));
+
+static_assert((sizeof(typeEntries) / sizeof(typeEntries[0])) == TYPE_MAX_ENUM, "Type name array size doesn't match the total number of type IDs!");
+
+bool getType(const char *in, love::Type &out)
+{
+	return types.find(in, out);
+}
+
+bool getType(love::Type in, const char *&out)
+{
+	return types.find(in, out);
+}
+
+} // love

+ 11 - 82
jni/love/src/common/types.h

@@ -37,6 +37,7 @@ enum Type
 
 	// Filesystem.
 	FILESYSTEM_FILE_ID,
+	FILESYSTEM_DROPPED_FILE_ID,
 	FILESYSTEM_FILE_DATA_ID,
 
 	// Font
@@ -54,10 +55,11 @@ enum Type
 	GRAPHICS_CANVAS_ID,
 	GRAPHICS_SHADER_ID,
 	GRAPHICS_MESH_ID,
+	GRAPHICS_TEXT_ID,
 
 	// Image
 	IMAGE_IMAGE_DATA_ID,
-	IMAGE_COMPRESSED_DATA_ID,
+	IMAGE_COMPRESSED_IMAGE_DATA_ID,
 
 	// Joystick
 	JOYSTICK_JOYSTICK_ID,
@@ -65,6 +67,7 @@ enum Type
 	// Math
 	MATH_RANDOM_GENERATOR_ID,
 	MATH_BEZIER_CURVE_ID,
+	MATH_COMPRESSED_DATA_ID,
 
 	// Audio
 	AUDIO_SOURCE_ID,
@@ -113,89 +116,15 @@ enum Type
 	TYPE_MAX_ENUM
 };
 
-typedef std::bitset<TYPE_MAX_ENUM> bits;
-
-const bits INVALID_T = bits(1) << INVALID_ID;
-
-const bits OBJECT_T = bits(1) << OBJECT_ID;
-const bits DATA_T = (bits(1) << DATA_ID) | OBJECT_T;
-const bits MODULE_T = (bits(1) << MODULE_ID) | OBJECT_T;
-
-// Filesystem.
-const bits FILESYSTEM_FILE_T = (bits(1) << FILESYSTEM_FILE_ID) | OBJECT_T;
-const bits FILESYSTEM_FILE_DATA_T = (bits(1) << FILESYSTEM_FILE_DATA_ID) | DATA_T;
-
-const bits FONT_GLYPH_DATA_T = (bits(1) << FONT_GLYPH_DATA_ID) | DATA_T;
-const bits FONT_RASTERIZER_T = (bits(1) << FONT_RASTERIZER_ID) | OBJECT_T;
-
-// Graphics.
-const bits GRAPHICS_DRAWABLE_T = (bits(1) << GRAPHICS_DRAWABLE_ID) | OBJECT_T;
-const bits GRAPHICS_TEXTURE_T = (bits(1) << GRAPHICS_TEXTURE_ID) | GRAPHICS_DRAWABLE_T;
-const bits GRAPHICS_IMAGE_T = (bits(1) << GRAPHICS_IMAGE_ID) | GRAPHICS_TEXTURE_T;
-const bits GRAPHICS_QUAD_T = (bits(1) << GRAPHICS_QUAD_ID) | OBJECT_T;
-const bits GRAPHICS_FONT_T = (bits(1) << GRAPHICS_FONT_ID) | OBJECT_T;
-const bits GRAPHICS_PARTICLE_SYSTEM_T = (bits(1) << GRAPHICS_PARTICLE_SYSTEM_ID) | GRAPHICS_DRAWABLE_T;
-const bits GRAPHICS_SPRITE_BATCH_T = (bits(1) << GRAPHICS_SPRITE_BATCH_ID) | GRAPHICS_DRAWABLE_T;
-const bits GRAPHICS_CANVAS_T = (bits(1) << GRAPHICS_CANVAS_ID) | GRAPHICS_TEXTURE_T;
-const bits GRAPHICS_SHADER_T = (bits(1) << GRAPHICS_SHADER_ID) | OBJECT_T;
-const bits GRAPHICS_MESH_T = (bits(1) << GRAPHICS_MESH_ID) | GRAPHICS_DRAWABLE_T;
-
-// Image.
-const bits IMAGE_IMAGE_DATA_T = (bits(1) << IMAGE_IMAGE_DATA_ID) | DATA_T;
-const bits IMAGE_COMPRESSED_DATA_T = (bits(1) << IMAGE_COMPRESSED_DATA_ID) | DATA_T;
-
-// Joystick.
-const bits JOYSTICK_JOYSTICK_T = (bits(1) << JOYSTICK_JOYSTICK_ID) | OBJECT_T;
-
-// Math.
-const bits MATH_RANDOM_GENERATOR_T = (bits(1) << MATH_RANDOM_GENERATOR_ID) | OBJECT_T;
-const bits MATH_BEZIER_CURVE_T = (bits(1) << MATH_BEZIER_CURVE_ID) | OBJECT_T;
-
-// Audio.
-const bits AUDIO_SOURCE_T = (bits(1) << AUDIO_SOURCE_ID) | OBJECT_T;
-
-// Sound.
-const bits SOUND_SOUND_DATA_T = (bits(1) << SOUND_SOUND_DATA_ID) | DATA_T;
-const bits SOUND_DECODER_T = bits(1) << SOUND_DECODER_ID;
-
-// Mouse.
-const bits MOUSE_CURSOR_T = (bits(1) << MOUSE_CURSOR_ID) | OBJECT_T;
-
-// Physics.
-const bits PHYSICS_WORLD_T = (bits(1) << PHYSICS_WORLD_ID) | OBJECT_T;
-const bits PHYSICS_CONTACT_T = (bits(1) << PHYSICS_CONTACT_ID) | OBJECT_T;
-const bits PHYSICS_BODY_T = (bits(1) << PHYSICS_BODY_ID) | OBJECT_T;
-const bits PHYSICS_FIXTURE_T = (bits(1) << PHYSICS_FIXTURE_ID) | OBJECT_T;
-const bits PHYSICS_SHAPE_T = (bits(1) << PHYSICS_SHAPE_ID) | OBJECT_T;
-const bits PHYSICS_CIRCLE_SHAPE_T = (bits(1) << PHYSICS_CIRCLE_SHAPE_ID) | PHYSICS_SHAPE_T;
-const bits PHYSICS_POLYGON_SHAPE_T = (bits(1) << PHYSICS_POLYGON_SHAPE_ID) | PHYSICS_SHAPE_T;
-const bits PHYSICS_EDGE_SHAPE_T = (bits(1) << PHYSICS_EDGE_SHAPE_ID) | PHYSICS_SHAPE_T;
-const bits PHYSICS_CHAIN_SHAPE_T = (bits(1) << PHYSICS_CHAIN_SHAPE_ID) | PHYSICS_SHAPE_T;
-const bits PHYSICS_JOINT_T = (bits(1) << PHYSICS_JOINT_ID) | OBJECT_T;
-const bits PHYSICS_MOUSE_JOINT_T = (bits(1) << PHYSICS_MOUSE_JOINT_ID) | PHYSICS_JOINT_T;
-const bits PHYSICS_DISTANCE_JOINT_T = (bits(1) << PHYSICS_DISTANCE_JOINT_ID) | PHYSICS_JOINT_T;
-const bits PHYSICS_PRISMATIC_JOINT_T = (bits(1) << PHYSICS_PRISMATIC_JOINT_ID) | PHYSICS_JOINT_T;
-const bits PHYSICS_REVOLUTE_JOINT_T = (bits(1) << PHYSICS_REVOLUTE_JOINT_ID) | PHYSICS_JOINT_T;
-const bits PHYSICS_PULLEY_JOINT_T = (bits(1) << PHYSICS_PULLEY_JOINT_ID) | PHYSICS_JOINT_T;
-const bits PHYSICS_GEAR_JOINT_T = (bits(1) << PHYSICS_GEAR_JOINT_ID) | PHYSICS_JOINT_T;
-const bits PHYSICS_FRICTION_JOINT_T = (bits(1) << PHYSICS_FRICTION_JOINT_ID) | PHYSICS_JOINT_T;
-const bits PHYSICS_WELD_JOINT_T = (bits(1) << PHYSICS_WELD_JOINT_ID) | PHYSICS_JOINT_T;
-const bits PHYSICS_ROPE_JOINT_T = (bits(1) << PHYSICS_ROPE_JOINT_ID) | PHYSICS_JOINT_T;
-const bits PHYSICS_WHEEL_JOINT_T = (bits(1) << PHYSICS_WHEEL_JOINT_ID) | PHYSICS_JOINT_T;
-const bits PHYSICS_MOTOR_JOINT_T = (bits(1) << PHYSICS_MOTOR_JOINT_ID) | PHYSICS_JOINT_T;
-
-// Thread.
-const bits THREAD_THREAD_T = (bits(1) << THREAD_THREAD_ID) | OBJECT_T;
-const bits THREAD_CHANNEL_T = (bits(1) << THREAD_CHANNEL_ID) | OBJECT_T;
-
-// Modules.
-const bits MODULE_FILESYSTEM_T = (bits(1) << MODULE_FILESYSTEM_ID) | MODULE_T;
-const bits MODULE_GRAPHICS_T = (bits(1) << MODULE_GRAPHICS_ID) | MODULE_T;
-const bits MODULE_IMAGE_T = (bits(1) << MODULE_IMAGE_ID) | MODULE_T;
-const bits MODULE_SOUND_T = (bits(1) << MODULE_SOUND_ID) | MODULE_T;
+typedef std::bitset<TYPE_MAX_ENUM> TypeBits;
+
+/**
+ * Array of length TYPE_MAX_ENUM containing the flags for each love Type.
+ **/
+extern const TypeBits *typeFlags;
 
 bool getType(const char *in, Type &out);
-bool getType(Type in, const char  *&out);
+bool getType(Type in, const char *&out);
 
 } // love
 

+ 7 - 7
jni/love/src/common/version.h

@@ -25,13 +25,13 @@ namespace love
 {
 
 // Version stuff.
-#define LOVE_VERSION_STRING "0.9.2"
-const int VERSION_MAJOR = 0;
-const int VERSION_MINOR = 9;
-const int VERSION_REV = 2;
-const char *VERSION = LOVE_VERSION_STRING;
-const char *VERSION_COMPATIBILITY[] =  { VERSION, "0.9.1", "0.9.0", 0 };
-const char *VERSION_CODENAME = "Baby Inspector";
+#define LOVE_VERSION_STRING "0.10.0"
+static const int VERSION_MAJOR = 0;
+static const int VERSION_MINOR = 10;
+static const int VERSION_REV = 0;
+static const char *VERSION = LOVE_VERSION_STRING;
+static const char *VERSION_COMPATIBILITY[] =  { VERSION, 0 };
+static const char *VERSION_CODENAME = "";
 
 } // love
 

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

@@ -25,7 +25,7 @@ namespace love
 
 Data *luax_checkdata(lua_State *L, int idx)
 {
-	return luax_checktype<Data>(L, idx, "Data", DATA_T);
+	return luax_checktype<Data>(L, idx, DATA_ID);
 }
 
 int w_Data_getString(lua_State *L)
@@ -59,7 +59,7 @@ const luaL_Reg w_Data_functions[] =
 
 int w_Data_open(lua_State *L)
 {
-	luax_register_type(L, "Data", w_Data_functions);
+	luax_register_type(L, DATA_ID, w_Data_functions);
 	return 0;
 }
 

+ 32 - 28
jni/love/src/libraries/enet/enet.cpp

@@ -190,7 +190,7 @@ static ENetPacket *read_packet(lua_State *l, int idx, enet_uint8 *channel_id) {
 	}
 
 	if (argc >= idx+1 && !lua_isnil(l, idx+1)) {
-		*channel_id = luaL_checkint(l, idx+1);
+		*channel_id = (int) luaL_checknumber(l, idx+1);
 	}
 
 	packet = enet_packet_create(data, size, flags);
@@ -226,13 +226,13 @@ static int host_create(lua_State *l) {
 
 	switch (lua_gettop(l)) {
 		case 5:
-			if (!lua_isnil(l, 5)) out_bandwidth = luaL_checkint(l, 5);
+			if (!lua_isnil(l, 5)) out_bandwidth = (int) luaL_checknumber(l, 5);
 		case 4:
-			if (!lua_isnil(l, 4)) in_bandwidth = luaL_checkint(l, 4);
+			if (!lua_isnil(l, 4)) in_bandwidth = (int) luaL_checknumber(l, 4);
 		case 3:
-			if (!lua_isnil(l, 3)) channel_count = luaL_checkint(l, 3);
+			if (!lua_isnil(l, 3)) channel_count = (int) luaL_checknumber(l, 3);
 		case 2:
-			if (!lua_isnil(l, 2)) peer_count = luaL_checkint(l, 2);
+			if (!lua_isnil(l, 2)) peer_count = (int) luaL_checknumber(l, 2);
 	}
 
 	// printf("host create, peers=%d, channels=%d, in=%d, out=%d\n",
@@ -279,7 +279,7 @@ static int host_service(lua_State *l) {
 	int timeout = 0, out;
 
 	if (lua_gettop(l) > 1)
-		timeout = luaL_checkint(l, 2);
+		timeout = (int) luaL_checknumber(l, 2);
 
 	out = enet_host_service(host, &event, timeout);
 	if (out == 0) return 0;
@@ -348,9 +348,9 @@ static int host_connect(lua_State *l) {
 
 	switch (lua_gettop(l)) {
 		case 4:
-			if (!lua_isnil(l, 4)) data = luaL_checkint(l, 4);
+			if (!lua_isnil(l, 4)) data = (int) luaL_checknumber(l, 4);
 		case 3:
-			if (!lua_isnil(l, 3)) channel_count = luaL_checkint(l, 3);
+			if (!lua_isnil(l, 3)) channel_count = (int) luaL_checknumber(l, 3);
 	}
 
 	// printf("host connect, channels=%d, data=%d\n", channel_count, data);
@@ -392,7 +392,7 @@ static int host_channel_limit(lua_State *l) {
 	if (!host) {
 		return luaL_error(l, "Tried to index a nil host!");
 	}
-	int limit = luaL_checkint(l, 2);
+	int limit = (int) luaL_checknumber(l, 2);
 	enet_host_channel_limit(host, limit);
 	return 0;
 }
@@ -402,8 +402,8 @@ static int host_bandwidth_limit(lua_State *l) {
 	if (!host) {
 		return luaL_error(l, "Tried to index a nil host!");
 	}
-	enet_uint32 in_bandwidth = luaL_checkint(l, 2);
-	enet_uint32 out_bandwidth = luaL_checkint(l, 2);
+	enet_uint32 in_bandwidth = (int) luaL_checknumber(l, 2);
+	enet_uint32 out_bandwidth = (int) luaL_checknumber(l, 2);
 	enet_host_bandwidth_limit(host, in_bandwidth, out_bandwidth);
 	return 0;
 }
@@ -473,7 +473,7 @@ static int host_get_peer(lua_State *l) {
 		return luaL_error(l, "Tried to index a nil host!");
 	}
 
-	int peer_index = luaL_checkint(l, 2) - 1;
+	int peer_index = (int) luaL_checknumber(l, 2) - 1;
 
 	if (peer_index < 0 || ((size_t) peer_index) >= host->peerCount) {
 		luaL_argerror (l, 2, "Invalid peer index");
@@ -517,9 +517,9 @@ static int peer_ping(lua_State *l) {
 static int peer_throttle_configure(lua_State *l) {
 	ENetPeer *peer = check_peer(l, 1);
 
-	enet_uint32 interval = luaL_checkint(l, 2);
-	enet_uint32 acceleration = luaL_checkint(l, 3);
-	enet_uint32 deceleration = luaL_checkint(l, 4);
+	enet_uint32 interval = (int) luaL_checknumber(l, 2);
+	enet_uint32 acceleration = (int) luaL_checknumber(l, 3);
+	enet_uint32 deceleration = (int) luaL_checknumber(l, 4);
 
 	enet_peer_throttle_configure(peer, interval, acceleration, deceleration);
 	return 0;
@@ -529,7 +529,7 @@ static int peer_round_trip_time(lua_State *l) {
 	ENetPeer *peer = check_peer(l, 1);
 
 	if (lua_gettop(l) > 1) {
-		enet_uint32 round_trip_time = luaL_checkint(l, 2);
+		enet_uint32 round_trip_time = (int) luaL_checknumber(l, 2);
 		peer->roundTripTime = round_trip_time;
 	}
 
@@ -542,7 +542,7 @@ static int peer_last_round_trip_time(lua_State *l) {
 	ENetPeer *peer = check_peer(l, 1);
 
 	if (lua_gettop(l) > 1) {
-		enet_uint32 round_trip_time = luaL_checkint(l, 2);
+		enet_uint32 round_trip_time = (int) luaL_checknumber(l, 2);
 		peer->lastRoundTripTime = round_trip_time;
 	}
 	lua_pushinteger (l, peer->lastRoundTripTime);
@@ -554,7 +554,7 @@ static int peer_ping_interval(lua_State *l) {
 	ENetPeer *peer = check_peer(l, 1);
 
 	if (lua_gettop(l) > 1) {
-		enet_uint32 interval = luaL_checkint(l, 2);
+		enet_uint32 interval = (int) luaL_checknumber(l, 2);
 		enet_peer_ping_interval (peer, interval);
 	}
 
@@ -572,11 +572,11 @@ static int peer_timeout(lua_State *l) {
 
 	switch (lua_gettop(l)) {
 		case 4:
-			if (!lua_isnil(l, 4)) timeout_maximum = luaL_checkint(l, 4);
+			if (!lua_isnil(l, 4)) timeout_maximum = (int) luaL_checknumber(l, 4);
 		case 3:
-			if (!lua_isnil(l, 3)) timeout_minimum = luaL_checkint(l, 3);
+			if (!lua_isnil(l, 3)) timeout_minimum = (int) luaL_checknumber(l, 3);
 		case 2:
-			if (!lua_isnil(l, 2)) timeout_limit = luaL_checkint(l, 2);
+			if (!lua_isnil(l, 2)) timeout_limit = (int) luaL_checknumber(l, 2);
 	}
 
 	enet_peer_timeout (peer, timeout_limit, timeout_minimum, timeout_maximum);
@@ -591,7 +591,7 @@ static int peer_timeout(lua_State *l) {
 static int peer_disconnect(lua_State *l) {
 	ENetPeer *peer = check_peer(l, 1);
 
-	enet_uint32 data = lua_gettop(l) > 1 ? luaL_checkint(l, 2) : 0;
+	enet_uint32 data = lua_gettop(l) > 1 ? (int) luaL_checknumber(l, 2) : 0;
 	enet_peer_disconnect(peer, data);
 	return 0;
 }
@@ -599,7 +599,7 @@ static int peer_disconnect(lua_State *l) {
 static int peer_disconnect_now(lua_State *l) {
 	ENetPeer *peer = check_peer(l, 1);
 
-	enet_uint32 data = lua_gettop(l) > 1 ? luaL_checkint(l, 2) : 0;
+	enet_uint32 data = lua_gettop(l) > 1 ? (int) luaL_checknumber(l, 2) : 0;
 	enet_peer_disconnect_now(peer, data);
 	return 0;
 }
@@ -607,7 +607,7 @@ static int peer_disconnect_now(lua_State *l) {
 static int peer_disconnect_later(lua_State *l) {
 	ENetPeer *peer = check_peer(l, 1);
 
-	enet_uint32 data = lua_gettop(l) > 1 ? luaL_checkint(l, 2) : 0;
+	enet_uint32 data = lua_gettop(l) > 1 ? (int) luaL_checknumber(l, 2) : 0;
 	enet_peer_disconnect_later(peer, data);
 	return 0;
 }
@@ -683,7 +683,7 @@ static int peer_receive(lua_State *l) {
 	enet_uint8 channel_id = 0;
 
 	if (lua_gettop(l) > 1) {
-		channel_id = luaL_checkint(l, 2);
+		channel_id = (int) luaL_checknumber(l, 2);
 	}
 
 	packet = enet_peer_receive(peer, &channel_id);
@@ -770,6 +770,10 @@ static const struct luaL_Reg enet_peer_funcs [] = {
 	{NULL, NULL}
 };
 
+extern "C" {
+	void luax_register(lua_State *L, const char *name, const luaL_Reg *l);
+}
+
 int luaopen_enet(lua_State *l) {
 	enet_initialize();
 	atexit(enet_deinitialize);
@@ -777,14 +781,14 @@ int luaopen_enet(lua_State *l) {
 	// create metatables
 	luaL_newmetatable(l, "enet_host");
 	lua_newtable(l); // index
-	luaL_register(l, NULL, enet_host_funcs);
+	luax_register(l, NULL, enet_host_funcs);
 	lua_setfield(l, -2, "__index");
 	lua_pushcfunction(l, host_gc);
 	lua_setfield(l, -2, "__gc");
 
 	luaL_newmetatable(l, "enet_peer");
 	lua_newtable(l);
-	luaL_register(l, NULL, enet_peer_funcs);
+	luax_register(l, NULL, enet_peer_funcs);
 	lua_setfield(l, -2, "__index");
 	lua_pushcfunction(l, peer_tostring);
 	lua_setfield(l, -2, "__tostring");
@@ -799,7 +803,7 @@ int luaopen_enet(lua_State *l) {
 
 	lua_setfield(l, LUA_REGISTRYINDEX, "enet_peers");
 
-	luaL_register(l, "enet", enet_funcs);
+	luax_register(l, "enet", enet_funcs);
 
 	// return the enet table created with luaL_register
 	return 1;

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 151 - 258
jni/love/src/libraries/glad/glad.cpp


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 377 - 461
jni/love/src/libraries/glad/glad.hpp


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 243 - 572
jni/love/src/libraries/glad/gladfuncs.hpp


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 206 - 175
jni/love/src/libraries/lodepng/lodepng.cpp


+ 83 - 91
jni/love/src/libraries/lodepng/lodepng.h

@@ -1,7 +1,7 @@
 /*
-LodePNG version 20131222
+LodePNG version 20141130
 
-Copyright (c) 2005-2013 Lode Vandevenne
+Copyright (c) 2005-2014 Lode Vandevenne
 
 This software is provided 'as-is', without any express or implied
 warranty. In no event will the authors be held liable for any damages
@@ -33,6 +33,8 @@ freely, subject to the following restrictions:
 #include <string>
 #endif /*__cplusplus*/
 
+#define LODEPNG_VERSION_STRING "20141130"
+
 /*
 The following #defines are used to create code sections. They can be disabled
 to disable code sections, which can give faster compile time and smaller binary.
@@ -195,7 +197,8 @@ unsigned lodepng_encode24_file(const char* filename,
 namespace lodepng
 {
 #ifdef LODEPNG_COMPILE_DECODER
-/*Same as lodepng_decode_memory, but decodes to an std::vector.*/
+/*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype
+is the format to output the pixels to. Default is RGBA 8-bit per channel.*/
 unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
                 const unsigned char* in, size_t insize,
                 LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
@@ -214,7 +217,8 @@ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
 #endif //LODEPNG_COMPILE_DECODER
 
 #ifdef LODEPNG_COMPILE_ENCODER
-/*Same as lodepng_encode_memory, but encodes to an std::vector.*/
+/*Same as lodepng_encode_memory, but encodes to an std::vector. colortype
+is that of the raw input data. The output PNG color type will be auto chosen.*/
 unsigned encode(std::vector<unsigned char>& out,
                 const unsigned char* in, unsigned w, unsigned h,
                 LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
@@ -280,7 +284,7 @@ struct LodePNGCompressSettings /*deflate = compress*/
   /*LZ77 related settings*/
   unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/
   unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/
-  unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Typical value: 2048.*/
+  unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/
   unsigned minmatch; /*mininum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/
   unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/
   unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/
@@ -496,13 +500,14 @@ LodePNGColorMode structs to describe the input and output color type.
 See the reference manual at the end of this header file to see which color conversions are supported.
 return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported)
 The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel
-of the output color type (lodepng_get_bpp)
-The fix_png value works as described in struct LodePNGDecoderSettings.
-Note: for 16-bit per channel colors, uses big endian format like PNG does.
+of the output color type (lodepng_get_bpp).
+For < 8 bpp images, there should not be padding bits at the end of scanlines.
+For 16-bit per channel colors, uses big endian format like PNG does.
+Return value is LodePNG error code
 */
 unsigned lodepng_convert(unsigned char* out, const unsigned char* in,
                          LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in,
-                         unsigned w, unsigned h, unsigned fix_png);
+                         unsigned w, unsigned h);
 
 #ifdef LODEPNG_COMPILE_DECODER
 /*
@@ -514,16 +519,7 @@ typedef struct LodePNGDecoderSettings
   LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/
 
   unsigned ignore_crc; /*ignore CRC checksums*/
-  /*
-  The fix_png setting, if 1, makes the decoder tolerant towards some PNG images
-  that do not correctly follow the PNG specification. This only supports errors
-  that are fixable, were found in images that are actually used on the web, and
-  are silently tolerated by other decoders as well. Currently only one such fix
-  is implemented: if a palette index is out of bounds given the palette size,
-  interpret it as opaque black.
-  By default this value is 0, which makes it stop with an error on such images.
-  */
-  unsigned fix_png;
+
   unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/
 
 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
@@ -556,46 +552,39 @@ typedef enum LodePNGFilterStrategy
   LFS_PREDEFINED
 } LodePNGFilterStrategy;
 
-/*automatically use color type with less bits per pixel if losslessly possible. Default: LAC_AUTO*/
-typedef enum LodePNGAutoConvert
+/*Gives characteristics about the colors of the image, which helps decide which color model to use for encoding.
+Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/
+typedef struct LodePNGColorProfile
 {
-  LAC_NO, /*use color type user requested*/
-  LAC_ALPHA, /*use color type user requested, but if only opaque pixels and RGBA or grey+alpha, use RGB or grey*/
-  LAC_AUTO, /*use PNG color type that can losslessly represent the uncompressed image the smallest possible*/
-  /*
-  like AUTO, but do not choose 1, 2 or 4 bit per pixel types.
-  sometimes a PNG image compresses worse if less than 8 bits per pixels.
-  */
-  LAC_AUTO_NO_NIBBLES,
-  /*
-  like AUTO, but never choose palette color type. For small images, encoding
-  the palette may take more bytes than what is gained. Note that AUTO also
-  already prevents encoding the palette for extremely small images, but that may
-  not be sufficient because due to the compression it cannot predict when to
-  switch.
-  */
-  LAC_AUTO_NO_PALETTE,
-  LAC_AUTO_NO_NIBBLES_NO_PALETTE
-} LodePNGAutoConvert;
-
-
-/*
-Automatically chooses color type that gives smallest amount of bits in the
-output image, e.g. grey if there are only greyscale pixels, palette if there
-are less than 256 colors, ...
-The auto_convert parameter allows limiting it to not use palette, ...
-*/
+  unsigned colored; /*not greyscale*/
+  unsigned key; /*if true, image is not opaque. Only if true and alpha is false, color key is possible.*/
+  unsigned short key_r; /*these values are always in 16-bit bitdepth in the profile*/
+  unsigned short key_g;
+  unsigned short key_b;
+  unsigned alpha; /*alpha channel or alpha palette required*/
+  unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16.*/
+  unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order*/
+  unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for greyscale only. 16 if 16-bit per channel required.*/
+} LodePNGColorProfile;
+
+void lodepng_color_profile_init(LodePNGColorProfile* profile);
+
+/*Get a LodePNGColorProfile of the image.*/
+unsigned lodepng_get_color_profile(LodePNGColorProfile* profile,
+                                   const unsigned char* image, unsigned w, unsigned h,
+                                   const LodePNGColorMode* mode_in);
+/*The function LodePNG uses internally to decide the PNG color with auto_convert.
+Chooses an optimal color model, e.g. grey if only grey pixels, palette if < 256 colors, ...*/
 unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out,
                                    const unsigned char* image, unsigned w, unsigned h,
-                                   const LodePNGColorMode* mode_in,
-                                   LodePNGAutoConvert auto_convert);
+                                   const LodePNGColorMode* mode_in);
 
 /*Settings for the encoder.*/
 typedef struct LodePNGEncoderSettings
 {
   LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/
 
-  LodePNGAutoConvert auto_convert; /*how to automatically choose output PNG color type, if at all*/
+  unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/
 
   /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than
   8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to
@@ -690,7 +679,11 @@ Third byte: must be uppercase
 Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy
 */
 
-/*get the length of the data of the chunk. Total chunk length has 12 bytes more.*/
+/*
+Gets the length of the data of the chunk. Total chunk length has 12 bytes more.
+There must be at least 4 bytes to read from. If the result value is too large,
+it may be corrupt data.
+*/
 unsigned lodepng_chunk_length(const unsigned char* chunk);
 
 /*puts the 4-byte type in null terminated string*/
@@ -901,8 +894,8 @@ TODO:
 [X] let the "isFullyOpaque" function check color keys and transparent palettes too
 [X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl"
 [ ] don't stop decoding on errors like 69, 57, 58 (make warnings)
-[ ] make option to choose if the raw image with non multiple of 8 bits per scanline should have padding bits or not
 [ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes
+[ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ...
 */
 
 #endif /*LODEPNG_H inclusion guard*/
@@ -1240,20 +1233,22 @@ behaviour.
 
 If, when decoding, you want the raw image to be something else than the default,
 you need to set the color type and bit depth you want in the LodePNGColorMode,
-or the parameters of the simple function of LodePNG you're using.
+or the parameters colortype and bitdepth of the simple decoding function.
 
-If, when encoding, you use another color type than the default in the input
+If, when encoding, you use another color type than the default in the raw input
 image, you need to specify its color type and bit depth in the LodePNGColorMode
-of the raw image, or use the parameters of the simplefunction of LodePNG you're
-using.
+of the raw image, or use the parameters colortype and bitdepth of the simple
+encoding function.
 
 If, when encoding, you don't want LodePNG to choose the output PNG color type
 but control it yourself, you need to set auto_convert in the encoder settings
-to LAC_NONE, and specify the color type you want in the LodePNGInfo of the
-encoder.
+to false, and specify the color type you want in the LodePNGInfo of the
+encoder (including palette: it can generate a palette if auto_convert is true,
+otherwise not).
 
-If you do any of the above, LodePNG may need to do a color conversion, which
-follows the rules below, and may sometimes not be allowed.
+If the input and output color type differ (whether user chosen or auto chosen),
+LodePNG will do a color conversion, which follows the rules below, and may
+sometimes result in an error.
 
 To avoid some confusion:
 -the decoder converts from PNG to raw image
@@ -1275,7 +1270,7 @@ To avoid some confusion:
 Non supported color conversions:
 -color to greyscale: no error is thrown, but the result will look ugly because
 only the red channel is taken
--anything, to palette when that palette does not have that color in it: in this
+-anything to palette when that palette does not have that color in it: in this
 case an error is thrown
 
 Supported color conversions:
@@ -1285,10 +1280,10 @@ Supported color conversions:
 -removing alpha channel
 -higher to smaller bitdepth, and vice versa
 
-If you want no color conversion to be done:
+If you want no color conversion to be done (e.g. for speed or control):
 -In the encoder, you can make it save a PNG with any color type by giving the
 raw color mode and LodePNGInfo the same color mode, and setting auto_convert to
-LAC_NO.
+false.
 -In the decoder, you can make it store the pixel data in the same color type
 as the PNG has, by setting the color_convert setting to false. Settings in
 info_raw are then ignored.
@@ -1455,6 +1450,8 @@ LodePNG. For the C++ version, only the standard C++ library is needed on top.
 Add the files lodepng.c(pp) and lodepng.h to your project, include
 lodepng.h where needed, and your program can read/write PNG files.
 
+It is compatible with C90 and up, and C++03 and up.
+
 If performance is important, use optimization when compiling! For both the
 encoder and decoder, this makes a large difference.
 
@@ -1470,49 +1467,40 @@ LodePNG is developed in gcc so this compiler is natively supported. It gives no
 warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++
 version 4.7.1 on Linux, 32-bit and 64-bit.
 
-*) Mingw
+*) Clang
 
-The Mingw compiler (a port of gcc) for Windows is fully supported by LodePNG.
+Fully supported and warning-free.
 
-*) Visual Studio 2005 and up, Visual C++ Express Edition 2005 and up
+*) Mingw
+
+The Mingw compiler (a port of gcc for Windows) should be fully supported by
+LodePNG.
 
-Visual Studio may give warnings about 'fopen' being deprecated. A multiplatform library
-can't support the proposed Visual Studio alternative however, so LodePNG keeps using
-fopen. If you don't want to see the deprecated warnings, put this on top of lodepng.h
-before the inclusions:
-#define _CRT_SECURE_NO_DEPRECATE
+*) Visual Studio and Visual C++ Express Edition
 
-Other than the above warnings, LodePNG should be warning-free with warning
-level 3 (W3). Warning level 4 (W4) will give warnings about integer conversions.
-I'm not planning to resolve these warnings. To get rid of them, let Visual
-Studio use warning level W3 for lodepng.cpp only: right click lodepng.cpp,
-Properties, C/C++, General, Warning Level: Level 3 (/W3).
+LodePNG should be warning-free with warning level W4. Two warnings were disabled
+with pragmas though: warning 4244 about implicit conversions, and warning 4996
+where it wants to use a non-standard function fopen_s instead of the standard C
+fopen.
 
 Visual Studio may want "stdafx.h" files to be included in each source file and
 give an error "unexpected end of file while looking for precompiled header".
-That is not standard C++ and will not be added to the stock LodePNG. You can
+This is not standard C++ and will not be added to the stock LodePNG. You can
 disable it for lodepng.cpp only by right clicking it, Properties, C/C++,
 Precompiled Headers, and set it to Not Using Precompiled Headers there.
 
-*) Visual Studio 6.0
-
-LodePNG support for Visual Studio 6.0 is not guaranteed because VS6 doesn't
-follow the C++ standard correctly.
-
-*) Comeau C/C++
-
-Vesion 20070107 compiles without problems on the Comeau C/C++ Online Test Drive
-at http://www.comeaucomputing.com/tryitout in both C90 and C++ mode.
+NOTE: Modern versions of VS should be fully supported, but old versions, e.g.
+VS6, are not guaranteed to work.
 
 *) Compilers on Macintosh
 
-LodePNG has been reported to work both with the gcc and LLVM for Macintosh, both
-for C and C++.
+LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for
+C and C++.
 
 *) Other Compilers
 
-If you encounter problems on other compilers, feel free to let me know and I may
-try to fix it if the compiler is modern standards complient.
+If you encounter problems on any compilers, feel free to let me know and I may
+try to fix it if the compiler is modern and standards complient.
 
 
 10. examples
@@ -1574,6 +1562,10 @@ yyyymmdd.
 Some changes aren't backwards compatible. Those are indicated with a (!)
 symbol.
 
+*) 23 aug 2014: Reduced needless memory usage of decoder.
+*) 28 jun 2014: Removed fix_png setting, always support palette OOB for
+    simplicity. Made ColorProfile public.
+*) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization.
 *) 22 dec 2013: Power of two windowsize required for optimization.
 *) 15 apr 2013: Fixed bug with LAC_ALPHA and color key.
 *) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png).
@@ -1712,5 +1704,5 @@ Domain: gmail dot com.
 Account: lode dot vandevenne.
 
 
-Copyright (c) 2005-2013 Lode Vandevenne
+Copyright (c) 2005-2014 Lode Vandevenne
 */

+ 3 - 1
jni/love/src/libraries/luasocket/libluasocket/except.c

@@ -11,6 +11,8 @@
 
 #include "except.h"
 
+extern void luax_register(lua_State *L, const char *name, const luaL_Reg *l);
+
 /*=========================================================================*\
 * Internal function prototypes.
 \*=========================================================================*/
@@ -94,6 +96,6 @@ static int global_protect(lua_State *L) {
 * Init module
 \*-------------------------------------------------------------------------*/
 int except_open(lua_State *L) {
-    luaL_openlib(L, NULL, func, 0);
+    luax_register(L, NULL, func);
     return 0;
 }

+ 3 - 1
jni/love/src/libraries/luasocket/libluasocket/inet.c

@@ -12,6 +12,8 @@
 
 #include "inet.h"
 
+extern void luax_register(lua_State *L, const char *name, const luaL_Reg *l);
+
 /*=========================================================================*\
 * Internal function prototypes.
 \*=========================================================================*/
@@ -38,7 +40,7 @@ int inet_open(lua_State *L)
 {
     lua_pushstring(L, "dns");
     lua_newtable(L);
-    luaL_openlib(L, NULL, func, 0);
+    luax_register(L, NULL, func);
     lua_settable(L, -3);
     return 0;
 }

+ 4 - 2
jni/love/src/libraries/luasocket/libluasocket/luasocket.c

@@ -37,6 +37,8 @@
 #include "udp.h"
 #include "select.h"
 
+extern void luax_register(lua_State *L, const char *name, const luaL_Reg *l);
+
 /*-------------------------------------------------------------------------*\
 * Internal function prototypes
 \*-------------------------------------------------------------------------*/
@@ -69,7 +71,7 @@ static luaL_reg func[] = {
 * Skip a few arguments
 \*-------------------------------------------------------------------------*/
 static int global_skip(lua_State *L) {
-    int amount = luaL_checkint(L, 1);
+    int amount = (int) luaL_checknumber(L, 1);
     int ret = lua_gettop(L) - amount - 1;
     return ret >= 0 ? ret : 0;
 }
@@ -89,7 +91,7 @@ static int global_unload(lua_State *L) {
 static int base_open(lua_State *L) {
     if (socket_open()) {
         /* export functions (and leave namespace table on top of stack) */
-        luaL_openlib(L, "socket", func, 0);
+        luax_register(L, "socket", func);
 #ifdef LUASOCKET_DEBUG
         lua_pushstring(L, "_DEBUG");
         lua_pushboolean(L, 1);

+ 4 - 2
jni/love/src/libraries/luasocket/libluasocket/mime.c

@@ -15,6 +15,8 @@
 
 #include "mime.h"
 
+extern void luax_register(lua_State *L, const char *name, const luaL_Reg *l);
+
 /*=========================================================================*\
 * Don't want to trust escape character constants
 \*=========================================================================*/
@@ -83,7 +85,7 @@ static UC b64unbase[256];
 \*-------------------------------------------------------------------------*/
 MIME_API int luaopen_mime_core(lua_State *L)
 {
-    luaL_openlib(L, "mime", func, 0);
+    luax_register(L, "mime", func);
     /* make version string available to scripts */
     lua_pushstring(L, "_VERSION");
     lua_pushstring(L, MIME_VERSION);
@@ -644,7 +646,7 @@ static int eolprocess(int c, int last, const char *marker,
 \*-------------------------------------------------------------------------*/
 static int mime_global_eol(lua_State *L)
 {
-    int ctx = luaL_checkint(L, 1);
+    int ctx = (int) luaL_checknumber(L, 1);
     size_t isize = 0;
     const char *input = luaL_optlstring(L, 2, NULL, &isize);
     const char *last = input + isize;

+ 3 - 1
jni/love/src/libraries/luasocket/libluasocket/select.c

@@ -13,6 +13,8 @@
 #include "timeout.h"
 #include "select.h"
 
+extern void luax_register(lua_State *L, const char *name, const luaL_Reg *l);
+
 /*=========================================================================*\
 * Internal function prototypes.
 \*=========================================================================*/
@@ -39,7 +41,7 @@ static luaL_reg func[] = {
 * Initializes module
 \*-------------------------------------------------------------------------*/
 int select_open(lua_State *L) {
-    luaL_openlib(L, NULL, func, 0);
+    luax_register(L, NULL, func);
     return 0;
 }
 

+ 3 - 1
jni/love/src/libraries/luasocket/libluasocket/tcp.c

@@ -15,6 +15,8 @@
 #include "options.h"
 #include "tcp.h"
 
+extern void luax_register(lua_State *L, const char *name, const luaL_Reg *l);
+
 /*=========================================================================*\
 * Internal function prototypes
 \*=========================================================================*/
@@ -92,7 +94,7 @@ int tcp_open(lua_State *L)
     auxiliar_add2group(L, "tcp{client}", "tcp{any}");
     auxiliar_add2group(L, "tcp{server}", "tcp{any}");
     /* define library functions */
-    luaL_openlib(L, NULL, func, 0); 
+    luax_register(L, NULL, func);
     return 0;
 }
 

+ 3 - 1
jni/love/src/libraries/luasocket/libluasocket/timeout.c

@@ -27,6 +27,8 @@
 #define MAX(x, y) ((x) > (y) ? x : y)
 #endif
 
+extern void luax_register(lua_State *L, const char *name, const luaL_Reg *l);
+
 /*=========================================================================*\
 * Internal function prototypes
 \*=========================================================================*/
@@ -144,7 +146,7 @@ double timeout_gettime(void) {
 * Initializes module
 \*-------------------------------------------------------------------------*/
 int timeout_open(lua_State *L) {
-    luaL_openlib(L, NULL, func, 0);
+    luax_register(L, NULL, func);
     return 0;
 }
 

+ 3 - 1
jni/love/src/libraries/luasocket/libluasocket/udp.c

@@ -23,6 +23,8 @@
 #define MAX(x, y) ((x) > (y) ? x : y)
 #endif 
 
+extern void luax_register(lua_State *L, const char *name, const luaL_Reg *l);
+
 /*=========================================================================*\
 * Internal function prototypes
 \*=========================================================================*/
@@ -95,7 +97,7 @@ int udp_open(lua_State *L)
     auxiliar_add2group(L, "udp{connected}",   "select{able}");
     auxiliar_add2group(L, "udp{unconnected}", "select{able}");
     /* define library functions */
-    luaL_openlib(L, NULL, func, 0); 
+    luax_register(L, NULL, func);
     return 0;
 }
 

+ 10 - 3
jni/love/src/libraries/luasocket/libluasocket/unix.c

@@ -15,6 +15,9 @@
 #include "unix.h"
 #include <sys/un.h> 
 
+extern void luax_register(lua_State *L, const char *name, const luaL_Reg *l);
+extern int luax_c_insistglobal(lua_State *L, const char *k);
+
 /*=========================================================================*\
 * Internal function prototypes
 \*=========================================================================*/
@@ -90,10 +93,14 @@ int luaopen_socket_unix(lua_State *L) {
     auxiliar_add2group(L, "unix{client}", "unix{any}");
     auxiliar_add2group(L, "unix{server}", "unix{any}");
     /* make sure the function ends up in the package table */
-    luaL_openlib(L, "socket", func, 0);
-    /* return the function instead of the 'socket' table */
+    lua_pushcfunction(L, global_create);
+
+    luax_c_insistglobal(L, "socket");
     lua_pushstring(L, "unix");
-    lua_gettable(L, -2);
+    lua_pushvalue(L, -3);
+    lua_settable(L, -3);
+
+    /* return the function instead of the 'socket' table */
     return 1;
 }
 

+ 27 - 1
jni/love/src/libraries/luautf8/lutf8lib.c

@@ -43,6 +43,9 @@
 
 #define MAXUNICODE	0x10FFFF
 
+/* size of buffer for 'utf8esc' function (taken from lobject.h) */
+#define UTF8BUFFSZ	8
+
 #define iscont(p)	((*(p) & 0xC0) == 0x80)
 
 
@@ -146,10 +149,33 @@ static int codepoint (lua_State *L) {
 }
 
 
+/* taken from lobject.c */
+static int utf8esc (char *buff, unsigned long x) {
+	int n = 1;  /* number of bytes put in buffer (backwards) */
+	lua_assert(x <= 0x10FFFF);
+	if (x < 0x80)  /* ascii? */
+		buff[UTF8BUFFSZ - 1] = (char) x;
+	else {  /* need continuation bytes */
+		unsigned int mfb = 0x3f;  /* maximum that fits in first byte */
+		do {  /* add continuation bytes */
+			buff[UTF8BUFFSZ - (n++)] = (char) (0x80 | (x & 0x3f));
+			x >>= 6;  /* remove added bits */
+			mfb >>= 1;  /* now there is one less bit available in first byte */
+		} while (x > mfb);  /* still needs continuation byte? */
+		buff[UTF8BUFFSZ - n] = (char) ((~mfb << 1) | x);  /* add first byte */
+	}
+	return n;
+}
+
 static void pushutfchar (lua_State *L, int arg) {
   lua_Integer code = luaL_checkinteger(L, arg);
   luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range");
-  lua_pushfstring(L, "%U", (long)code);
+
+  /* the %U string format does not exist in lua 5.1 or 5.2, so we emulate it */
+  /* (code from luaO_pushvfstring in lobject.c) */
+  char buff[UTF8BUFFSZ];
+  int l = utf8esc(buff, (long) code);
+  lua_pushlstring(L, buff + UTF8BUFFSZ - l, l);
 }
 
 

+ 1516 - 0
jni/love/src/libraries/lz4/lz4.c

@@ -0,0 +1,1516 @@
+/*
+   LZ4 - Fast LZ compression algorithm
+   Copyright (C) 2011-2015, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   You can contact the author at :
+   - LZ4 source repository : https://github.com/Cyan4973/lz4
+   - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+*/
+
+
+/**************************************
+*  Tuning parameters
+**************************************/
+/*
+ * HEAPMODE :
+ * Select how default compression functions will allocate memory for their hash table,
+ * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()).
+ */
+#define HEAPMODE 0
+
+/*
+ * ACCELERATION_DEFAULT :
+ * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0
+ */
+#define ACCELERATION_DEFAULT 1
+
+
+/**************************************
+*  CPU Feature Detection
+**************************************/
+/*
+ * LZ4_FORCE_SW_BITCOUNT
+ * Define this parameter if your target system or compiler does not support hardware bit count
+ */
+#if defined(_MSC_VER) && defined(_WIN32_WCE)   /* Visual Studio for Windows CE does not support Hardware bit count */
+#  define LZ4_FORCE_SW_BITCOUNT
+#endif
+
+
+/**************************************
+*  Includes
+**************************************/
+#include "lz4.h"
+
+
+/**************************************
+*  Compiler Options
+**************************************/
+#ifdef _MSC_VER    /* Visual Studio */
+#  define FORCE_INLINE static __forceinline
+#  include <intrin.h>
+#  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
+#  pragma warning(disable : 4293)        /* disable: C4293: too large shift (32-bits) */
+#else
+#  if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)   /* C99 */
+#    if defined(__GNUC__) || defined(__clang__)
+#      define FORCE_INLINE static inline __attribute__((always_inline))
+#    else
+#      define FORCE_INLINE static inline
+#    endif
+#  else
+#    define FORCE_INLINE static
+#  endif   /* __STDC_VERSION__ */
+#endif  /* _MSC_VER */
+
+/* LZ4_GCC_VERSION is defined into lz4.h */
+#if (LZ4_GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
+#  define expect(expr,value)    (__builtin_expect ((expr),(value)) )
+#else
+#  define expect(expr,value)    (expr)
+#endif
+
+#define likely(expr)     expect((expr) != 0, 1)
+#define unlikely(expr)   expect((expr) != 0, 0)
+
+
+/**************************************
+*  Memory routines
+**************************************/
+#include <stdlib.h>   /* malloc, calloc, free */
+#define ALLOCATOR(n,s) calloc(n,s)
+#define FREEMEM        free
+#include <string.h>   /* memset, memcpy */
+#define MEM_INIT       memset
+
+
+/**************************************
+*  Basic Types
+**************************************/
+#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)   /* C99 */
+# include <stdint.h>
+  typedef  uint8_t BYTE;
+  typedef uint16_t U16;
+  typedef uint32_t U32;
+  typedef  int32_t S32;
+  typedef uint64_t U64;
+#else
+  typedef unsigned char       BYTE;
+  typedef unsigned short      U16;
+  typedef unsigned int        U32;
+  typedef   signed int        S32;
+  typedef unsigned long long  U64;
+#endif
+
+
+/**************************************
+*  Reading and writing into memory
+**************************************/
+#define STEPSIZE sizeof(size_t)
+
+static unsigned LZ4_64bits(void) { return sizeof(void*)==8; }
+
+static unsigned LZ4_isLittleEndian(void)
+{
+    const union { U32 i; BYTE c[4]; } one = { 1 };   /* don't use static : performance detrimental  */
+    return one.c[0];
+}
+
+
+static U16 LZ4_read16(const void* memPtr)
+{
+    U16 val16;
+    memcpy(&val16, memPtr, 2);
+    return val16;
+}
+
+static U16 LZ4_readLE16(const void* memPtr)
+{
+    if (LZ4_isLittleEndian())
+    {
+        return LZ4_read16(memPtr);
+    }
+    else
+    {
+        const BYTE* p = (const BYTE*)memPtr;
+        return (U16)((U16)p[0] + (p[1]<<8));
+    }
+}
+
+static void LZ4_writeLE16(void* memPtr, U16 value)
+{
+    if (LZ4_isLittleEndian())
+    {
+        memcpy(memPtr, &value, 2);
+    }
+    else
+    {
+        BYTE* p = (BYTE*)memPtr;
+        p[0] = (BYTE) value;
+        p[1] = (BYTE)(value>>8);
+    }
+}
+
+static U32 LZ4_read32(const void* memPtr)
+{
+    U32 val32;
+    memcpy(&val32, memPtr, 4);
+    return val32;
+}
+
+static U64 LZ4_read64(const void* memPtr)
+{
+    U64 val64;
+    memcpy(&val64, memPtr, 8);
+    return val64;
+}
+
+static size_t LZ4_read_ARCH(const void* p)
+{
+    if (LZ4_64bits())
+        return (size_t)LZ4_read64(p);
+    else
+        return (size_t)LZ4_read32(p);
+}
+
+
+static void LZ4_copy4(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 4); }
+
+static void LZ4_copy8(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 8); }
+
+/* customized version of memcpy, which may overwrite up to 7 bytes beyond dstEnd */
+static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
+{
+    BYTE* d = (BYTE*)dstPtr;
+    const BYTE* s = (const BYTE*)srcPtr;
+    BYTE* e = (BYTE*)dstEnd;
+    do { LZ4_copy8(d,s); d+=8; s+=8; } while (d<e);
+}
+
+
+/**************************************
+*  Common Constants
+**************************************/
+#define MINMATCH 4
+
+#define COPYLENGTH 8
+#define LASTLITERALS 5
+#define MFLIMIT (COPYLENGTH+MINMATCH)
+static const int LZ4_minLength = (MFLIMIT+1);
+
+#define KB *(1 <<10)
+#define MB *(1 <<20)
+#define GB *(1U<<30)
+
+#define MAXD_LOG 16
+#define MAX_DISTANCE ((1 << MAXD_LOG) - 1)
+
+#define ML_BITS  4
+#define ML_MASK  ((1U<<ML_BITS)-1)
+#define RUN_BITS (8-ML_BITS)
+#define RUN_MASK ((1U<<RUN_BITS)-1)
+
+
+/**************************************
+*  Common Utils
+**************************************/
+#define LZ4_STATIC_ASSERT(c)    { enum { LZ4_static_assert = 1/(int)(!!(c)) }; }   /* use only *after* variable declarations */
+
+
+/**************************************
+*  Common functions
+**************************************/
+static unsigned LZ4_NbCommonBytes (register size_t val)
+{
+    if (LZ4_isLittleEndian())
+    {
+        if (LZ4_64bits())
+        {
+#       if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)
+            unsigned long r = 0;
+            _BitScanForward64( &r, (U64)val );
+            return (int)(r>>3);
+#       elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+            return (__builtin_ctzll((U64)val) >> 3);
+#       else
+            static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
+            return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
+#       endif
+        }
+        else /* 32 bits */
+        {
+#       if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+            unsigned long r;
+            _BitScanForward( &r, (U32)val );
+            return (int)(r>>3);
+#       elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+            return (__builtin_ctz((U32)val) >> 3);
+#       else
+            static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
+            return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
+#       endif
+        }
+    }
+    else   /* Big Endian CPU */
+    {
+        if (LZ4_64bits())
+        {
+#       if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)
+            unsigned long r = 0;
+            _BitScanReverse64( &r, val );
+            return (unsigned)(r>>3);
+#       elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+            return (__builtin_clzll((U64)val) >> 3);
+#       else
+            unsigned r;
+            if (!(val>>32)) { r=4; } else { r=0; val>>=32; }
+            if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
+            r += (!val);
+            return r;
+#       endif
+        }
+        else /* 32 bits */
+        {
+#       if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+            unsigned long r = 0;
+            _BitScanReverse( &r, (unsigned long)val );
+            return (unsigned)(r>>3);
+#       elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+            return (__builtin_clz((U32)val) >> 3);
+#       else
+            unsigned r;
+            if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
+            r += (!val);
+            return r;
+#       endif
+        }
+    }
+}
+
+static unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
+{
+    const BYTE* const pStart = pIn;
+
+    while (likely(pIn<pInLimit-(STEPSIZE-1)))
+    {
+        size_t diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);
+        if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; }
+        pIn += LZ4_NbCommonBytes(diff);
+        return (unsigned)(pIn - pStart);
+    }
+
+    if (LZ4_64bits()) if ((pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; }
+    if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; }
+    if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
+    return (unsigned)(pIn - pStart);
+}
+
+
+#ifndef LZ4_COMMONDEFS_ONLY
+/**************************************
+*  Local Constants
+**************************************/
+#define LZ4_HASHLOG   (LZ4_MEMORY_USAGE-2)
+#define HASHTABLESIZE (1 << LZ4_MEMORY_USAGE)
+#define HASH_SIZE_U32 (1 << LZ4_HASHLOG)       /* required as macro for static allocation */
+
+static const int LZ4_64Klimit = ((64 KB) + (MFLIMIT-1));
+static const U32 LZ4_skipTrigger = 6;  /* Increase this value ==> compression run slower on incompressible data */
+
+
+/**************************************
+*  Local Structures and types
+**************************************/
+typedef struct {
+    U32 hashTable[HASH_SIZE_U32];
+    U32 currentOffset;
+    U32 initCheck;
+    const BYTE* dictionary;
+    BYTE* bufferStart;   /* obsolete, used for slideInputBuffer */
+    U32 dictSize;
+} LZ4_stream_t_internal;
+
+typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive;
+typedef enum { byPtr, byU32, byU16 } tableType_t;
+
+typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive;
+typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;
+
+typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
+typedef enum { full = 0, partial = 1 } earlyEnd_directive;
+
+
+/**************************************
+*  Local Utils
+**************************************/
+int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; }
+int LZ4_compressBound(int isize)  { return LZ4_COMPRESSBOUND(isize); }
+int LZ4_sizeofState() { return LZ4_STREAMSIZE; }
+
+
+
+/********************************
+*  Compression functions
+********************************/
+
+static U32 LZ4_hashSequence(U32 sequence, tableType_t const tableType)
+{
+    if (tableType == byU16)
+        return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));
+    else
+        return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));
+}
+
+static const U64 prime5bytes = 889523592379ULL;
+static U32 LZ4_hashSequence64(size_t sequence, tableType_t const tableType)
+{
+    const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG;
+    const U32 hashMask = (1<<hashLog) - 1;
+    return ((sequence * prime5bytes) >> (40 - hashLog)) & hashMask;
+}
+
+static U32 LZ4_hashSequenceT(size_t sequence, tableType_t const tableType)
+{
+    if (LZ4_64bits())
+        return LZ4_hashSequence64(sequence, tableType);
+    return LZ4_hashSequence((U32)sequence, tableType);
+}
+
+static U32 LZ4_hashPosition(const void* p, tableType_t tableType) { return LZ4_hashSequenceT(LZ4_read_ARCH(p), tableType); }
+
+static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase)
+{
+    switch (tableType)
+    {
+    case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; }
+    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; }
+    case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; }
+    }
+}
+
+static void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+    U32 h = LZ4_hashPosition(p, tableType);
+    LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);
+}
+
+static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+    if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; }
+    if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; }
+    { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; }   /* default, to ensure a return */
+}
+
+static const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+    U32 h = LZ4_hashPosition(p, tableType);
+    return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);
+}
+
+FORCE_INLINE int LZ4_compress_generic(
+                 void* const ctx,
+                 const char* const source,
+                 char* const dest,
+                 const int inputSize,
+                 const int maxOutputSize,
+                 const limitedOutput_directive outputLimited,
+                 const tableType_t tableType,
+                 const dict_directive dict,
+                 const dictIssue_directive dictIssue,
+                 const U32 acceleration)
+{
+    LZ4_stream_t_internal* const dictPtr = (LZ4_stream_t_internal*)ctx;
+
+    const BYTE* ip = (const BYTE*) source;
+    const BYTE* base;
+    const BYTE* lowLimit;
+    const BYTE* const lowRefLimit = ip - dictPtr->dictSize;
+    const BYTE* const dictionary = dictPtr->dictionary;
+    const BYTE* const dictEnd = dictionary + dictPtr->dictSize;
+    const size_t dictDelta = dictEnd - (const BYTE*)source;
+    const BYTE* anchor = (const BYTE*) source;
+    const BYTE* const iend = ip + inputSize;
+    const BYTE* const mflimit = iend - MFLIMIT;
+    const BYTE* const matchlimit = iend - LASTLITERALS;
+
+    BYTE* op = (BYTE*) dest;
+    BYTE* const olimit = op + maxOutputSize;
+
+    U32 forwardH;
+    size_t refDelta=0;
+
+    /* Init conditions */
+    if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0;   /* Unsupported input size, too large (or negative) */
+    switch(dict)
+    {
+    case noDict:
+    default:
+        base = (const BYTE*)source;
+        lowLimit = (const BYTE*)source;
+        break;
+    case withPrefix64k:
+        base = (const BYTE*)source - dictPtr->currentOffset;
+        lowLimit = (const BYTE*)source - dictPtr->dictSize;
+        break;
+    case usingExtDict:
+        base = (const BYTE*)source - dictPtr->currentOffset;
+        lowLimit = (const BYTE*)source;
+        break;
+    }
+    if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0;   /* Size too large (not within 64K limit) */
+    if (inputSize<LZ4_minLength) goto _last_literals;                  /* Input too small, no compression (all literals) */
+
+    /* First Byte */
+    LZ4_putPosition(ip, ctx, tableType, base);
+    ip++; forwardH = LZ4_hashPosition(ip, tableType);
+
+    /* Main Loop */
+    for ( ; ; )
+    {
+        const BYTE* match;
+        BYTE* token;
+        {
+            const BYTE* forwardIp = ip;
+            unsigned step = 1;
+            unsigned searchMatchNb = acceleration << LZ4_skipTrigger;
+
+            /* Find a match */
+            do {
+                U32 h = forwardH;
+                ip = forwardIp;
+                forwardIp += step;
+                step = (searchMatchNb++ >> LZ4_skipTrigger);
+
+                if (unlikely(forwardIp > mflimit)) goto _last_literals;
+
+                match = LZ4_getPositionOnHash(h, ctx, tableType, base);
+                if (dict==usingExtDict)
+                {
+                    if (match<(const BYTE*)source)
+                    {
+                        refDelta = dictDelta;
+                        lowLimit = dictionary;
+                    }
+                    else
+                    {
+                        refDelta = 0;
+                        lowLimit = (const BYTE*)source;
+                    }
+                }
+                forwardH = LZ4_hashPosition(forwardIp, tableType);
+                LZ4_putPositionOnHash(ip, h, ctx, tableType, base);
+
+            } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0)
+                || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))
+                || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) );
+        }
+
+        /* Catch up */
+        while ((ip>anchor) && (match+refDelta > lowLimit) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; }
+
+        {
+            /* Encode Literal length */
+            unsigned litLength = (unsigned)(ip - anchor);
+            token = op++;
+            if ((outputLimited) && (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)))
+                return 0;   /* Check output limit */
+            if (litLength>=RUN_MASK)
+            {
+                int len = (int)litLength-RUN_MASK;
+                *token=(RUN_MASK<<ML_BITS);
+                for(; len >= 255 ; len-=255) *op++ = 255;
+                *op++ = (BYTE)len;
+            }
+            else *token = (BYTE)(litLength<<ML_BITS);
+
+            /* Copy Literals */
+            LZ4_wildCopy(op, anchor, op+litLength);
+            op+=litLength;
+        }
+
+_next_match:
+        /* Encode Offset */
+        LZ4_writeLE16(op, (U16)(ip-match)); op+=2;
+
+        /* Encode MatchLength */
+        {
+            unsigned matchLength;
+
+            if ((dict==usingExtDict) && (lowLimit==dictionary))
+            {
+                const BYTE* limit;
+                match += refDelta;
+                limit = ip + (dictEnd-match);
+                if (limit > matchlimit) limit = matchlimit;
+                matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);
+                ip += MINMATCH + matchLength;
+                if (ip==limit)
+                {
+                    unsigned more = LZ4_count(ip, (const BYTE*)source, matchlimit);
+                    matchLength += more;
+                    ip += more;
+                }
+            }
+            else
+            {
+                matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);
+                ip += MINMATCH + matchLength;
+            }
+
+            if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength>>8) > olimit)))
+                return 0;    /* Check output limit */
+            if (matchLength>=ML_MASK)
+            {
+                *token += ML_MASK;
+                matchLength -= ML_MASK;
+                for (; matchLength >= 510 ; matchLength-=510) { *op++ = 255; *op++ = 255; }
+                if (matchLength >= 255) { matchLength-=255; *op++ = 255; }
+                *op++ = (BYTE)matchLength;
+            }
+            else *token += (BYTE)(matchLength);
+        }
+
+        anchor = ip;
+
+        /* Test end of chunk */
+        if (ip > mflimit) break;
+
+        /* Fill table */
+        LZ4_putPosition(ip-2, ctx, tableType, base);
+
+        /* Test next position */
+        match = LZ4_getPosition(ip, ctx, tableType, base);
+        if (dict==usingExtDict)
+        {
+            if (match<(const BYTE*)source)
+            {
+                refDelta = dictDelta;
+                lowLimit = dictionary;
+            }
+            else
+            {
+                refDelta = 0;
+                lowLimit = (const BYTE*)source;
+            }
+        }
+        LZ4_putPosition(ip, ctx, tableType, base);
+        if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1)
+            && (match+MAX_DISTANCE>=ip)
+            && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) )
+        { token=op++; *token=0; goto _next_match; }
+
+        /* Prepare next loop */
+        forwardH = LZ4_hashPosition(++ip, tableType);
+    }
+
+_last_literals:
+    /* Encode Last Literals */
+    {
+        const size_t lastRun = (size_t)(iend - anchor);
+        if ((outputLimited) && ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize))
+            return 0;   /* Check output limit */
+        if (lastRun >= RUN_MASK)
+        {
+            size_t accumulator = lastRun - RUN_MASK;
+            *op++ = RUN_MASK << ML_BITS;
+            for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;
+            *op++ = (BYTE) accumulator;
+        }
+        else
+        {
+            *op++ = (BYTE)(lastRun<<ML_BITS);
+        }
+        memcpy(op, anchor, lastRun);
+        op += lastRun;
+    }
+
+    /* End */
+    return (int) (((char*)op)-dest);
+}
+
+
+int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+    LZ4_resetStream((LZ4_stream_t*)state);
+    if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
+
+    if (maxOutputSize >= LZ4_compressBound(inputSize))
+    {
+        if (inputSize < LZ4_64Klimit)
+            return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU16,                        noDict, noDictIssue, acceleration);
+        else
+            return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
+    }
+    else
+    {
+        if (inputSize < LZ4_64Klimit)
+            return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byU16,                        noDict, noDictIssue, acceleration);
+        else
+            return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
+    }
+}
+
+
+int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+#if (HEAPMODE)
+    void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t));   /* malloc-calloc always properly aligned */
+#else
+    LZ4_stream_t ctx;
+    void* ctxPtr = &ctx;
+#endif
+
+    int result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration);
+
+#if (HEAPMODE)
+    FREEMEM(ctxPtr);
+#endif
+    return result;
+}
+
+
+int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+    return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1);
+}
+
+
+/* hidden debug function */
+/* strangely enough, gcc generates faster code when this function is uncommented, even if unused */
+int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+    LZ4_stream_t ctx;
+
+    LZ4_resetStream(&ctx);
+
+    if (inputSize < LZ4_64Klimit)
+        return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16,                        noDict, noDictIssue, acceleration);
+    else
+        return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
+}
+
+
+/********************************
+*  destSize variant
+********************************/
+
+static int LZ4_compress_destSize_generic(
+                       void* const ctx,
+                 const char* const src,
+                       char* const dst,
+                       int*  const srcSizePtr,
+                 const int targetDstSize,
+                 const tableType_t tableType)
+{
+    const BYTE* ip = (const BYTE*) src;
+    const BYTE* base = (const BYTE*) src;
+    const BYTE* lowLimit = (const BYTE*) src;
+    const BYTE* anchor = ip;
+    const BYTE* const iend = ip + *srcSizePtr;
+    const BYTE* const mflimit = iend - MFLIMIT;
+    const BYTE* const matchlimit = iend - LASTLITERALS;
+
+    BYTE* op = (BYTE*) dst;
+    BYTE* const oend = op + targetDstSize;
+    BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */;
+    BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */);
+    BYTE* const oMaxSeq = oMaxLit - 1 /* token */;
+
+    U32 forwardH;
+
+
+    /* Init conditions */
+    if (targetDstSize < 1) return 0;                                     /* Impossible to store anything */
+    if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0;            /* Unsupported input size, too large (or negative) */
+    if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0;   /* Size too large (not within 64K limit) */
+    if (*srcSizePtr<LZ4_minLength) goto _last_literals;                  /* Input too small, no compression (all literals) */
+
+    /* First Byte */
+    *srcSizePtr = 0;
+    LZ4_putPosition(ip, ctx, tableType, base);
+    ip++; forwardH = LZ4_hashPosition(ip, tableType);
+
+    /* Main Loop */
+    for ( ; ; )
+    {
+        const BYTE* match;
+        BYTE* token;
+        {
+            const BYTE* forwardIp = ip;
+            unsigned step = 1;
+            unsigned searchMatchNb = 1 << LZ4_skipTrigger;
+
+            /* Find a match */
+            do {
+                U32 h = forwardH;
+                ip = forwardIp;
+                forwardIp += step;
+                step = (searchMatchNb++ >> LZ4_skipTrigger);
+
+                if (unlikely(forwardIp > mflimit))
+                    goto _last_literals;
+
+                match = LZ4_getPositionOnHash(h, ctx, tableType, base);
+                forwardH = LZ4_hashPosition(forwardIp, tableType);
+                LZ4_putPositionOnHash(ip, h, ctx, tableType, base);
+
+            } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))
+                || (LZ4_read32(match) != LZ4_read32(ip)) );
+        }
+
+        /* Catch up */
+        while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }
+
+        {
+            /* Encode Literal length */
+            unsigned litLength = (unsigned)(ip - anchor);
+            token = op++;
+            if (op + ((litLength+240)/255) + litLength > oMaxLit)
+            {
+                /* Not enough space for a last match */
+                op--;
+                goto _last_literals;
+            }
+            if (litLength>=RUN_MASK)
+            {
+                unsigned len = litLength - RUN_MASK;
+                *token=(RUN_MASK<<ML_BITS);
+                for(; len >= 255 ; len-=255) *op++ = 255;
+                *op++ = (BYTE)len;
+            }
+            else *token = (BYTE)(litLength<<ML_BITS);
+
+            /* Copy Literals */
+            LZ4_wildCopy(op, anchor, op+litLength);
+            op += litLength;
+        }
+
+_next_match:
+        /* Encode Offset */
+        LZ4_writeLE16(op, (U16)(ip-match)); op+=2;
+
+        /* Encode MatchLength */
+        {
+            size_t matchLength;
+
+            matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);
+
+            if (op + ((matchLength+240)/255) > oMaxMatch)
+            {
+                /* Match description too long : reduce it */
+                matchLength = (15-1) + (oMaxMatch-op) * 255;
+            }
+            //printf("offset %5i, matchLength%5i \n", (int)(ip-match), matchLength + MINMATCH);
+            ip += MINMATCH + matchLength;
+
+            if (matchLength>=ML_MASK)
+            {
+                *token += ML_MASK;
+                matchLength -= ML_MASK;
+                while (matchLength >= 255) { matchLength-=255; *op++ = 255; }
+                *op++ = (BYTE)matchLength;
+            }
+            else *token += (BYTE)(matchLength);
+        }
+
+        anchor = ip;
+
+        /* Test end of block */
+        if (ip > mflimit) break;
+        if (op > oMaxSeq) break;
+
+        /* Fill table */
+        LZ4_putPosition(ip-2, ctx, tableType, base);
+
+        /* Test next position */
+        match = LZ4_getPosition(ip, ctx, tableType, base);
+        LZ4_putPosition(ip, ctx, tableType, base);
+        if ( (match+MAX_DISTANCE>=ip)
+            && (LZ4_read32(match)==LZ4_read32(ip)) )
+        { token=op++; *token=0; goto _next_match; }
+
+        /* Prepare next loop */
+        forwardH = LZ4_hashPosition(++ip, tableType);
+    }
+
+_last_literals:
+    /* Encode Last Literals */
+    {
+        size_t lastRunSize = (size_t)(iend - anchor);
+        if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend)
+        {
+            /* adapt lastRunSize to fill 'dst' */
+            lastRunSize  = (oend-op) - 1;
+            lastRunSize -= (lastRunSize+240)/255;
+        }
+        ip = anchor + lastRunSize;
+
+        if (lastRunSize >= RUN_MASK)
+        {
+            size_t accumulator = lastRunSize - RUN_MASK;
+            *op++ = RUN_MASK << ML_BITS;
+            for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;
+            *op++ = (BYTE) accumulator;
+        }
+        else
+        {
+            *op++ = (BYTE)(lastRunSize<<ML_BITS);
+        }
+        memcpy(op, anchor, lastRunSize);
+        op += lastRunSize;
+    }
+
+    /* End */
+    *srcSizePtr = (int) (((const char*)ip)-src);
+    return (int) (((char*)op)-dst);
+}
+
+
+static int LZ4_compress_destSize_extState (void* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize)
+{
+    LZ4_resetStream((LZ4_stream_t*)state);
+
+    if (targetDstSize >= LZ4_compressBound(*srcSizePtr))   /* compression success is guaranteed */
+    {
+        return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1);
+    }
+    else
+    {
+        if (*srcSizePtr < LZ4_64Klimit)
+            return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, byU16);
+        else
+            return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, LZ4_64bits() ? byU32 : byPtr);
+    }
+}
+
+
+int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize)
+{
+#if (HEAPMODE)
+    void* ctx = ALLOCATOR(1, sizeof(LZ4_stream_t));   /* malloc-calloc always properly aligned */
+#else
+    LZ4_stream_t ctxBody;
+    void* ctx = &ctxBody;
+#endif
+
+    int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize);
+
+#if (HEAPMODE)
+    FREEMEM(ctx);
+#endif
+    return result;
+}
+
+
+
+/********************************
+*  Streaming functions
+********************************/
+
+LZ4_stream_t* LZ4_createStream(void)
+{
+    LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64);
+    LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal));    /* A compilation error here means LZ4_STREAMSIZE is not large enough */
+    LZ4_resetStream(lz4s);
+    return lz4s;
+}
+
+void LZ4_resetStream (LZ4_stream_t* LZ4_stream)
+{
+    MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t));
+}
+
+int LZ4_freeStream (LZ4_stream_t* LZ4_stream)
+{
+    FREEMEM(LZ4_stream);
+    return (0);
+}
+
+
+#define HASH_UNIT sizeof(size_t)
+int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)
+{
+    LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict;
+    const BYTE* p = (const BYTE*)dictionary;
+    const BYTE* const dictEnd = p + dictSize;
+    const BYTE* base;
+
+    if ((dict->initCheck) || (dict->currentOffset > 1 GB))  /* Uninitialized structure, or reuse overflow */
+        LZ4_resetStream(LZ4_dict);
+
+    if (dictSize < (int)HASH_UNIT)
+    {
+        dict->dictionary = NULL;
+        dict->dictSize = 0;
+        return 0;
+    }
+
+    if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB;
+    dict->currentOffset += 64 KB;
+    base = p - dict->currentOffset;
+    dict->dictionary = p;
+    dict->dictSize = (U32)(dictEnd - p);
+    dict->currentOffset += dict->dictSize;
+
+    while (p <= dictEnd-HASH_UNIT)
+    {
+        LZ4_putPosition(p, dict->hashTable, byU32, base);
+        p+=3;
+    }
+
+    return dict->dictSize;
+}
+
+
+static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src)
+{
+    if ((LZ4_dict->currentOffset > 0x80000000) ||
+        ((size_t)LZ4_dict->currentOffset > (size_t)src))   /* address space overflow */
+    {
+        /* rescale hash table */
+        U32 delta = LZ4_dict->currentOffset - 64 KB;
+        const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize;
+        int i;
+        for (i=0; i<HASH_SIZE_U32; i++)
+        {
+            if (LZ4_dict->hashTable[i] < delta) LZ4_dict->hashTable[i]=0;
+            else LZ4_dict->hashTable[i] -= delta;
+        }
+        LZ4_dict->currentOffset = 64 KB;
+        if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB;
+        LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize;
+    }
+}
+
+
+int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+    LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_stream;
+    const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize;
+
+    const BYTE* smallest = (const BYTE*) source;
+    if (streamPtr->initCheck) return 0;   /* Uninitialized structure detected */
+    if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd;
+    LZ4_renormDictT(streamPtr, smallest);
+    if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
+
+    /* Check overlapping input/dictionary space */
+    {
+        const BYTE* sourceEnd = (const BYTE*) source + inputSize;
+        if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd))
+        {
+            streamPtr->dictSize = (U32)(dictEnd - sourceEnd);
+            if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB;
+            if (streamPtr->dictSize < 4) streamPtr->dictSize = 0;
+            streamPtr->dictionary = dictEnd - streamPtr->dictSize;
+        }
+    }
+
+    /* prefix mode : source data follows dictionary */
+    if (dictEnd == (const BYTE*)source)
+    {
+        int result;
+        if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
+            result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration);
+        else
+            result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration);
+        streamPtr->dictSize += (U32)inputSize;
+        streamPtr->currentOffset += (U32)inputSize;
+        return result;
+    }
+
+    /* external dictionary mode */
+    {
+        int result;
+        if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
+            result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration);
+        else
+            result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration);
+        streamPtr->dictionary = (const BYTE*)source;
+        streamPtr->dictSize = (U32)inputSize;
+        streamPtr->currentOffset += (U32)inputSize;
+        return result;
+    }
+}
+
+
+/* Hidden debug function, to force external dictionary mode */
+int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize)
+{
+    LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_dict;
+    int result;
+    const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize;
+
+    const BYTE* smallest = dictEnd;
+    if (smallest > (const BYTE*) source) smallest = (const BYTE*) source;
+    LZ4_renormDictT((LZ4_stream_t_internal*)LZ4_dict, smallest);
+
+    result = LZ4_compress_generic(LZ4_dict, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);
+
+    streamPtr->dictionary = (const BYTE*)source;
+    streamPtr->dictSize = (U32)inputSize;
+    streamPtr->currentOffset += (U32)inputSize;
+
+    return result;
+}
+
+
+int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize)
+{
+    LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict;
+    const BYTE* previousDictEnd = dict->dictionary + dict->dictSize;
+
+    if ((U32)dictSize > 64 KB) dictSize = 64 KB;   /* useless to define a dictionary > 64 KB */
+    if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize;
+
+    memmove(safeBuffer, previousDictEnd - dictSize, dictSize);
+
+    dict->dictionary = (const BYTE*)safeBuffer;
+    dict->dictSize = (U32)dictSize;
+
+    return dictSize;
+}
+
+
+
+/*******************************
+*  Decompression functions
+*******************************/
+/*
+ * This generic decompression function cover all use cases.
+ * It shall be instantiated several times, using different sets of directives
+ * Note that it is essential this generic function is really inlined,
+ * in order to remove useless branches during compilation optimization.
+ */
+FORCE_INLINE int LZ4_decompress_generic(
+                 const char* const source,
+                 char* const dest,
+                 int inputSize,
+                 int outputSize,         /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */
+
+                 int endOnInput,         /* endOnOutputSize, endOnInputSize */
+                 int partialDecoding,    /* full, partial */
+                 int targetOutputSize,   /* only used if partialDecoding==partial */
+                 int dict,               /* noDict, withPrefix64k, usingExtDict */
+                 const BYTE* const lowPrefix,  /* == dest if dict == noDict */
+                 const BYTE* const dictStart,  /* only if dict==usingExtDict */
+                 const size_t dictSize         /* note : = 0 if noDict */
+                 )
+{
+    /* Local Variables */
+    const BYTE* ip = (const BYTE*) source;
+    const BYTE* const iend = ip + inputSize;
+
+    BYTE* op = (BYTE*) dest;
+    BYTE* const oend = op + outputSize;
+    BYTE* cpy;
+    BYTE* oexit = op + targetOutputSize;
+    const BYTE* const lowLimit = lowPrefix - dictSize;
+
+    const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize;
+    const size_t dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4};
+    const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};
+
+    const int safeDecode = (endOnInput==endOnInputSize);
+    const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));
+
+
+    /* Special cases */
+    if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT;                         /* targetOutputSize too high => decode everything */
+    if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1;  /* Empty output buffer */
+    if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1);
+
+
+    /* Main Loop */
+    while (1)
+    {
+        unsigned token;
+        size_t length;
+        const BYTE* match;
+
+        /* get literal length */
+        token = *ip++;
+        if ((length=(token>>ML_BITS)) == RUN_MASK)
+        {
+            unsigned s;
+            do
+            {
+                s = *ip++;
+                length += s;
+            }
+            while (likely((endOnInput)?ip<iend-RUN_MASK:1) && (s==255));
+            if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)(op))) goto _output_error;   /* overflow detection */
+            if ((safeDecode) && unlikely((size_t)(ip+length)<(size_t)(ip))) goto _output_error;   /* overflow detection */
+        }
+
+        /* copy literals */
+        cpy = op+length;
+        if (((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) )
+            || ((!endOnInput) && (cpy>oend-COPYLENGTH)))
+        {
+            if (partialDecoding)
+            {
+                if (cpy > oend) goto _output_error;                           /* Error : write attempt beyond end of output buffer */
+                if ((endOnInput) && (ip+length > iend)) goto _output_error;   /* Error : read attempt beyond end of input buffer */
+            }
+            else
+            {
+                if ((!endOnInput) && (cpy != oend)) goto _output_error;       /* Error : block decoding must stop exactly there */
+                if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error;   /* Error : input must be consumed */
+            }
+            memcpy(op, ip, length);
+            ip += length;
+            op += length;
+            break;     /* Necessarily EOF, due to parsing restrictions */
+        }
+        LZ4_wildCopy(op, ip, cpy);
+        ip += length; op = cpy;
+
+        /* get offset */
+        match = cpy - LZ4_readLE16(ip); ip+=2;
+        if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error;   /* Error : offset outside destination buffer */
+
+        /* get matchlength */
+        length = token & ML_MASK;
+        if (length == ML_MASK)
+        {
+            unsigned s;
+            do
+            {
+                if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error;
+                s = *ip++;
+                length += s;
+            } while (s==255);
+            if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error;   /* overflow detection */
+        }
+        length += MINMATCH;
+
+        /* check external dictionary */
+        if ((dict==usingExtDict) && (match < lowPrefix))
+        {
+            if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error;   /* doesn't respect parsing restriction */
+
+            if (length <= (size_t)(lowPrefix-match))
+            {
+                /* match can be copied as a single segment from external dictionary */
+                match = dictEnd - (lowPrefix-match);
+                memmove(op, match, length); op += length;
+            }
+            else
+            {
+                /* match encompass external dictionary and current segment */
+                size_t copySize = (size_t)(lowPrefix-match);
+                memcpy(op, dictEnd - copySize, copySize);
+                op += copySize;
+                copySize = length - copySize;
+                if (copySize > (size_t)(op-lowPrefix))   /* overlap within current segment */
+                {
+                    BYTE* const endOfMatch = op + copySize;
+                    const BYTE* copyFrom = lowPrefix;
+                    while (op < endOfMatch) *op++ = *copyFrom++;
+                }
+                else
+                {
+                    memcpy(op, lowPrefix, copySize);
+                    op += copySize;
+                }
+            }
+            continue;
+        }
+
+        /* copy repeated sequence */
+        cpy = op + length;
+        if (unlikely((op-match)<8))
+        {
+            const size_t dec64 = dec64table[op-match];
+            op[0] = match[0];
+            op[1] = match[1];
+            op[2] = match[2];
+            op[3] = match[3];
+            match += dec32table[op-match];
+            LZ4_copy4(op+4, match);
+            op += 8; match -= dec64;
+        } else { LZ4_copy8(op, match); op+=8; match+=8; }
+
+        if (unlikely(cpy>oend-12))
+        {
+            if (cpy > oend-LASTLITERALS) goto _output_error;    /* Error : last LASTLITERALS bytes must be literals */
+            if (op < oend-8)
+            {
+                LZ4_wildCopy(op, match, oend-8);
+                match += (oend-8) - op;
+                op = oend-8;
+            }
+            while (op<cpy) *op++ = *match++;
+        }
+        else
+            LZ4_wildCopy(op, match, cpy);
+        op=cpy;   /* correction */
+    }
+
+    /* end of decoding */
+    if (endOnInput)
+       return (int) (((char*)op)-dest);     /* Nb of output bytes decoded */
+    else
+       return (int) (((const char*)ip)-source);   /* Nb of input bytes read */
+
+    /* Overflow error detected */
+_output_error:
+    return (int) (-(((const char*)ip)-source))-1;
+}
+
+
+int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize)
+{
+    return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0);
+}
+
+int LZ4_decompress_safe_partial(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize)
+{
+    return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0);
+}
+
+int LZ4_decompress_fast(const char* source, char* dest, int originalSize)
+{
+    return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)(dest - 64 KB), NULL, 64 KB);
+}
+
+
+/* streaming decompression functions */
+
+typedef struct
+{
+    const BYTE* externalDict;
+    size_t extDictSize;
+    const BYTE* prefixEnd;
+    size_t prefixSize;
+} LZ4_streamDecode_t_internal;
+
+/*
+ * If you prefer dynamic allocation methods,
+ * LZ4_createStreamDecode()
+ * provides a pointer (void*) towards an initialized LZ4_streamDecode_t structure.
+ */
+LZ4_streamDecode_t* LZ4_createStreamDecode(void)
+{
+    LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOCATOR(1, sizeof(LZ4_streamDecode_t));
+    return lz4s;
+}
+
+int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream)
+{
+    FREEMEM(LZ4_stream);
+    return 0;
+}
+
+/*
+ * LZ4_setStreamDecode
+ * Use this function to instruct where to find the dictionary
+ * This function is not necessary if previous data is still available where it was decoded.
+ * Loading a size of 0 is allowed (same effect as no dictionary).
+ * Return : 1 if OK, 0 if error
+ */
+int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize)
+{
+    LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode;
+    lz4sd->prefixSize = (size_t) dictSize;
+    lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize;
+    lz4sd->externalDict = NULL;
+    lz4sd->extDictSize  = 0;
+    return 1;
+}
+
+/*
+*_continue() :
+    These decoding functions allow decompression of multiple blocks in "streaming" mode.
+    Previously decoded blocks must still be available at the memory position where they were decoded.
+    If it's not possible, save the relevant part of decoded data into a safe buffer,
+    and indicate where it stands using LZ4_setStreamDecode()
+*/
+int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize)
+{
+    LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode;
+    int result;
+
+    if (lz4sd->prefixEnd == (BYTE*)dest)
+    {
+        result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
+                                        endOnInputSize, full, 0,
+                                        usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
+        if (result <= 0) return result;
+        lz4sd->prefixSize += result;
+        lz4sd->prefixEnd  += result;
+    }
+    else
+    {
+        lz4sd->extDictSize = lz4sd->prefixSize;
+        lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;
+        result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
+                                        endOnInputSize, full, 0,
+                                        usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize);
+        if (result <= 0) return result;
+        lz4sd->prefixSize = result;
+        lz4sd->prefixEnd  = (BYTE*)dest + result;
+    }
+
+    return result;
+}
+
+int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize)
+{
+    LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode;
+    int result;
+
+    if (lz4sd->prefixEnd == (BYTE*)dest)
+    {
+        result = LZ4_decompress_generic(source, dest, 0, originalSize,
+                                        endOnOutputSize, full, 0,
+                                        usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
+        if (result <= 0) return result;
+        lz4sd->prefixSize += originalSize;
+        lz4sd->prefixEnd  += originalSize;
+    }
+    else
+    {
+        lz4sd->extDictSize = lz4sd->prefixSize;
+        lz4sd->externalDict = (BYTE*)dest - lz4sd->extDictSize;
+        result = LZ4_decompress_generic(source, dest, 0, originalSize,
+                                        endOnOutputSize, full, 0,
+                                        usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize);
+        if (result <= 0) return result;
+        lz4sd->prefixSize = originalSize;
+        lz4sd->prefixEnd  = (BYTE*)dest + originalSize;
+    }
+
+    return result;
+}
+
+
+/*
+Advanced decoding functions :
+*_usingDict() :
+    These decoding functions work the same as "_continue" ones,
+    the dictionary must be explicitly provided within parameters
+*/
+
+FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize)
+{
+    if (dictSize==0)
+        return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0);
+    if (dictStart+dictSize == dest)
+    {
+        if (dictSize >= (int)(64 KB - 1))
+            return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0);
+        return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0);
+    }
+    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);
+}
+
+int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
+{
+    return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize);
+}
+
+int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize)
+{
+    return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize);
+}
+
+/* debug function */
+int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
+{
+    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);
+}
+
+
+/***************************************************
+*  Obsolete Functions
+***************************************************/
+/* obsolete compression functions */
+int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); }
+int LZ4_compress(const char* source, char* dest, int inputSize) { return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize)); }
+int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); }
+int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); }
+int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, maxDstSize, 1); }
+int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) { return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); }
+
+/*
+These function names are deprecated and should no longer be used.
+They are only provided here for compatibility with older user programs.
+- LZ4_uncompress is totally equivalent to LZ4_decompress_fast
+- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe
+*/
+int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); }
+int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); }
+
+
+/* Obsolete Streaming functions */
+
+int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; }
+
+static void LZ4_init(LZ4_stream_t_internal* lz4ds, BYTE* base)
+{
+    MEM_INIT(lz4ds, 0, LZ4_STREAMSIZE);
+    lz4ds->bufferStart = base;
+}
+
+int LZ4_resetStreamState(void* state, char* inputBuffer)
+{
+    if ((((size_t)state) & 3) != 0) return 1;   /* Error : pointer is not aligned on 4-bytes boundary */
+    LZ4_init((LZ4_stream_t_internal*)state, (BYTE*)inputBuffer);
+    return 0;
+}
+
+void* LZ4_create (char* inputBuffer)
+{
+    void* lz4ds = ALLOCATOR(8, LZ4_STREAMSIZE_U64);
+    LZ4_init ((LZ4_stream_t_internal*)lz4ds, (BYTE*)inputBuffer);
+    return lz4ds;
+}
+
+char* LZ4_slideInputBuffer (void* LZ4_Data)
+{
+    LZ4_stream_t_internal* ctx = (LZ4_stream_t_internal*)LZ4_Data;
+    int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB);
+    return (char*)(ctx->bufferStart + dictSize);
+}
+
+/* Obsolete streaming decompression functions */
+
+int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize)
+{
+    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB);
+}
+
+int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize)
+{
+    return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB);
+}
+
+#endif   /* LZ4_COMMONDEFS_ONLY */
+

+ 360 - 0
jni/love/src/libraries/lz4/lz4.h

@@ -0,0 +1,360 @@
+/*
+   LZ4 - Fast LZ compression algorithm
+   Header File
+   Copyright (C) 2011-2015, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   You can contact the author at :
+   - LZ4 source repository : https://github.com/Cyan4973/lz4
+   - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+*/
+#pragma once
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*
+ * lz4.h provides block compression functions, and gives full buffer control to programmer.
+ * If you need to generate inter-operable compressed data (respecting LZ4 frame specification),
+ * and can let the library handle its own memory, please use lz4frame.h instead.
+*/
+
+/**************************************
+*  Version
+**************************************/
+#define LZ4_VERSION_MAJOR    1    /* for breaking interface changes  */
+#define LZ4_VERSION_MINOR    7    /* for new (non-breaking) interface capabilities */
+#define LZ4_VERSION_RELEASE  0    /* for tweaks, bug-fixes, or development */
+#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)
+int LZ4_versionNumber (void);
+
+/**************************************
+*  Tuning parameter
+**************************************/
+/*
+ * LZ4_MEMORY_USAGE :
+ * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
+ * Increasing memory usage improves compression ratio
+ * Reduced memory usage can improve speed, due to cache effect
+ * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
+ */
+#define LZ4_MEMORY_USAGE 14
+
+
+/**************************************
+*  Simple Functions
+**************************************/
+
+int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize);
+int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize);
+
+/*
+LZ4_compress_default() :
+    Compresses 'sourceSize' bytes from buffer 'source'
+    into already allocated 'dest' buffer of size 'maxDestSize'.
+    Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize).
+    It also runs faster, so it's a recommended setting.
+    If the function cannot compress 'source' into a more limited 'dest' budget,
+    compression stops *immediately*, and the function result is zero.
+    As a consequence, 'dest' content is not valid.
+    This function never writes outside 'dest' buffer, nor read outside 'source' buffer.
+        sourceSize  : Max supported value is LZ4_MAX_INPUT_VALUE
+        maxDestSize : full or partial size of buffer 'dest' (which must be already allocated)
+        return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize)
+              or 0 if compression fails
+
+LZ4_decompress_safe() :
+    compressedSize : is the precise full size of the compressed block.
+    maxDecompressedSize : is the size of destination buffer, which must be already allocated.
+    return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize)
+             If destination buffer is not large enough, decoding will stop and output an error code (<0).
+             If the source stream is detected malformed, the function will stop decoding and return a negative result.
+             This function is protected against buffer overflow exploits, including malicious data packets.
+             It never writes outside output buffer, nor reads outside input buffer.
+*/
+
+
+/**************************************
+*  Advanced Functions
+**************************************/
+#define LZ4_MAX_INPUT_SIZE        0x7E000000   /* 2 113 929 216 bytes */
+#define LZ4_COMPRESSBOUND(isize)  ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
+
+/*
+LZ4_compressBound() :
+    Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible)
+    This function is primarily useful for memory allocation purposes (destination buffer size).
+    Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).
+    Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize)
+        inputSize  : max supported value is LZ4_MAX_INPUT_SIZE
+        return : maximum output size in a "worst case" scenario
+              or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE)
+*/
+int LZ4_compressBound(int inputSize);
+
+/*
+LZ4_compress_fast() :
+    Same as LZ4_compress_default(), but allows to select an "acceleration" factor.
+    The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
+    It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.
+    An acceleration value of "1" is the same as regular LZ4_compress_default()
+    Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1.
+*/
+int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration);
+
+
+/*
+LZ4_compress_fast_extState() :
+    Same compression function, just using an externally allocated memory space to store compression state.
+    Use LZ4_sizeofState() to know how much memory must be allocated,
+    and allocate it on 8-bytes boundaries (using malloc() typically).
+    Then, provide it as 'void* state' to compression function.
+*/
+int LZ4_sizeofState(void);
+int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration);
+
+
+/*
+LZ4_compress_destSize() :
+    Reverse the logic, by compressing as much data as possible from 'source' buffer
+    into already allocated buffer 'dest' of size 'targetDestSize'.
+    This function either compresses the entire 'source' content into 'dest' if it's large enough,
+    or fill 'dest' buffer completely with as much data as possible from 'source'.
+        *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'.
+                         New value is necessarily <= old value.
+        return : Nb bytes written into 'dest' (necessarily <= targetDestSize)
+              or 0 if compression fails
+*/
+int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize);
+
+
+/*
+LZ4_decompress_fast() :
+    originalSize : is the original and therefore uncompressed size
+    return : the number of bytes read from the source buffer (in other words, the compressed size)
+             If the source stream is detected malformed, the function will stop decoding and return a negative result.
+             Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes.
+    note : This function fully respect memory boundaries for properly formed compressed data.
+           It is a bit faster than LZ4_decompress_safe().
+           However, it does not provide any protection against intentionally modified data stream (malicious input).
+           Use this function in trusted environment only (data to decode comes from a trusted source).
+*/
+int LZ4_decompress_fast (const char* source, char* dest, int originalSize);
+
+/*
+LZ4_decompress_safe_partial() :
+    This function decompress a compressed block of size 'compressedSize' at position 'source'
+    into destination buffer 'dest' of size 'maxDecompressedSize'.
+    The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached,
+    reducing decompression time.
+    return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize)
+       Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller.
+             Always control how many bytes were decoded.
+             If the source stream is detected malformed, the function will stop decoding and return a negative result.
+             This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets
+*/
+int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize);
+
+
+/***********************************************
+*  Streaming Compression Functions
+***********************************************/
+#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4)
+#define LZ4_STREAMSIZE     (LZ4_STREAMSIZE_U64 * sizeof(long long))
+/*
+ * LZ4_stream_t
+ * information structure to track an LZ4 stream.
+ * important : init this structure content before first use !
+ * note : only allocated directly the structure if you are statically linking LZ4
+ *        If you are using liblz4 as a DLL, please use below construction methods instead.
+ */
+typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t;
+
+/*
+ * LZ4_resetStream
+ * Use this function to init an allocated LZ4_stream_t structure
+ */
+void LZ4_resetStream (LZ4_stream_t* streamPtr);
+
+/*
+ * LZ4_createStream will allocate and initialize an LZ4_stream_t structure
+ * LZ4_freeStream releases its memory.
+ * In the context of a DLL (liblz4), please use these methods rather than the static struct.
+ * They are more future proof, in case of a change of LZ4_stream_t size.
+ */
+LZ4_stream_t* LZ4_createStream(void);
+int           LZ4_freeStream (LZ4_stream_t* streamPtr);
+
+/*
+ * LZ4_loadDict
+ * Use this function to load a static dictionary into LZ4_stream.
+ * Any previous data will be forgotten, only 'dictionary' will remain in memory.
+ * Loading a size of 0 is allowed.
+ * Return : dictionary size, in bytes (necessarily <= 64 KB)
+ */
+int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize);
+
+/*
+ * LZ4_compress_fast_continue
+ * Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression ratio.
+ * Important : Previous data blocks are assumed to still be present and unmodified !
+ * 'dst' buffer must be already allocated.
+ * If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.
+ * If not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero.
+ */
+int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int maxDstSize, int acceleration);
+
+/*
+ * LZ4_saveDict
+ * If previously compressed data block is not guaranteed to remain available at its memory location
+ * save it into a safer place (char* safeBuffer)
+ * Note : you don't need to call LZ4_loadDict() afterwards,
+ *        dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue()
+ * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error
+ */
+int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dictSize);
+
+
+/************************************************
+*  Streaming Decompression Functions
+************************************************/
+
+#define LZ4_STREAMDECODESIZE_U64  4
+#define LZ4_STREAMDECODESIZE     (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))
+typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t;
+/*
+ * LZ4_streamDecode_t
+ * information structure to track an LZ4 stream.
+ * init this structure content using LZ4_setStreamDecode or memset() before first use !
+ *
+ * In the context of a DLL (liblz4) please prefer usage of construction methods below.
+ * They are more future proof, in case of a change of LZ4_streamDecode_t size in the future.
+ * LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure
+ * LZ4_freeStreamDecode releases its memory.
+ */
+LZ4_streamDecode_t* LZ4_createStreamDecode(void);
+int                 LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);
+
+/*
+ * LZ4_setStreamDecode
+ * Use this function to instruct where to find the dictionary.
+ * Setting a size of 0 is allowed (same effect as reset).
+ * Return : 1 if OK, 0 if error
+ */
+int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize);
+
+/*
+*_continue() :
+    These decoding functions allow decompression of multiple blocks in "streaming" mode.
+    Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB)
+    In the case of a ring buffers, decoding buffer must be either :
+    - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions)
+      In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB).
+    - Larger than encoding buffer, by a minimum of maxBlockSize more bytes.
+      maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block.
+      In which case, encoding and decoding buffers do not need to be synchronized,
+      and encoding ring buffer can have any size, including small ones ( < 64 KB).
+    - _At least_ 64 KB + 8 bytes + maxBlockSize.
+      In which case, encoding and decoding buffers do not need to be synchronized,
+      and encoding ring buffer can have any size, including larger than decoding buffer.
+    Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer,
+    and indicate where it is saved using LZ4_setStreamDecode()
+*/
+int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize);
+int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize);
+
+
+/*
+Advanced decoding functions :
+*_usingDict() :
+    These decoding functions work the same as
+    a combination of LZ4_setStreamDecode() followed by LZ4_decompress_x_continue()
+    They are stand-alone. They don't need nor update an LZ4_streamDecode_t structure.
+*/
+int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize);
+int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize);
+
+
+
+/**************************************
+*  Obsolete Functions
+**************************************/
+/* Deprecate Warnings */
+/* Should these warnings messages be a problem,
+   it is generally possible to disable them,
+   with -Wno-deprecated-declarations for gcc
+   or _CRT_SECURE_NO_WARNINGS in Visual for example.
+   You can also define LZ4_DEPRECATE_WARNING_DEFBLOCK. */
+#ifndef LZ4_DEPRECATE_WARNING_DEFBLOCK
+#  define LZ4_DEPRECATE_WARNING_DEFBLOCK
+#  define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+#  if (LZ4_GCC_VERSION >= 405) || defined(__clang__)
+#    define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))
+#  elif (LZ4_GCC_VERSION >= 301)
+#    define LZ4_DEPRECATED(message) __attribute__((deprecated))
+#  elif defined(_MSC_VER)
+#    define LZ4_DEPRECATED(message) __declspec(deprecated(message))
+#  else
+#    pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler")
+#    define LZ4_DEPRECATED(message)
+#  endif
+#endif /* LZ4_DEPRECATE_WARNING_DEFBLOCK */
+
+/* Obsolete compression functions */
+/* These functions are planned to start generate warnings by r131 approximately */
+int LZ4_compress               (const char* source, char* dest, int sourceSize);
+int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize);
+int LZ4_compress_withState               (void* state, const char* source, char* dest, int inputSize);
+int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
+int LZ4_compress_continue                (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize);
+int LZ4_compress_limitedOutput_continue  (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
+
+/* Obsolete decompression functions */
+/* These function names are completely deprecated and must no longer be used.
+   They are only provided here for compatibility with older programs.
+    - LZ4_uncompress is the same as LZ4_decompress_fast
+    - LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe
+   These function prototypes are now disabled; uncomment them only if you really need them.
+   It is highly recommended to stop using these prototypes and migrate to maintained ones */
+/* int LZ4_uncompress (const char* source, char* dest, int outputSize); */
+/* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */
+
+/* Obsolete streaming functions; use new streaming interface whenever possible */
+LZ4_DEPRECATED("use LZ4_createStream() instead") void* LZ4_create (char* inputBuffer);
+LZ4_DEPRECATED("use LZ4_createStream() instead") int   LZ4_sizeofStreamState(void);
+LZ4_DEPRECATED("use LZ4_resetStream() instead")  int   LZ4_resetStreamState(void* state, char* inputBuffer);
+LZ4_DEPRECATED("use LZ4_saveDict() instead")     char* LZ4_slideInputBuffer (void* state);
+
+/* Obsolete streaming decoding functions */
+LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize);
+LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize);
+
+
+#if defined (__cplusplus)
+}
+#endif

+ 730 - 0
jni/love/src/libraries/lz4/lz4hc.c

@@ -0,0 +1,730 @@
+/*
+    LZ4 HC - High Compression Mode of LZ4
+    Copyright (C) 2011-2015, Yann Collet.
+
+    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are
+    met:
+
+    * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+    copyright notice, this list of conditions and the following disclaimer
+    in the documentation and/or other materials provided with the
+    distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    You can contact the author at :
+       - LZ4 source repository : https://github.com/Cyan4973/lz4
+       - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+*/
+
+
+
+/**************************************
+*  Tuning Parameter
+**************************************/
+static const int LZ4HC_compressionLevel_default = 9;
+
+
+/**************************************
+*  Includes
+**************************************/
+#include "lz4hc.h"
+
+
+/**************************************
+*  Local Compiler Options
+**************************************/
+#if defined(__GNUC__)
+#  pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+#if defined (__clang__)
+#  pragma clang diagnostic ignored "-Wunused-function"
+#endif
+
+
+/**************************************
+*  Common LZ4 definition
+**************************************/
+#define LZ4_COMMONDEFS_ONLY
+#include "lz4.c"
+
+
+/**************************************
+*  Local Constants
+**************************************/
+#define DICTIONARY_LOGSIZE 16
+#define MAXD (1<<DICTIONARY_LOGSIZE)
+#define MAXD_MASK (MAXD - 1)
+
+#define HASH_LOG (DICTIONARY_LOGSIZE-1)
+#define HASHTABLESIZE (1 << HASH_LOG)
+#define HASH_MASK (HASHTABLESIZE - 1)
+
+#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)
+
+static const int g_maxCompressionLevel = 16;
+
+
+/**************************************
+*  Local Types
+**************************************/
+typedef struct
+{
+    U32   hashTable[HASHTABLESIZE];
+    U16   chainTable[MAXD];
+    const BYTE* end;        /* next block here to continue on current prefix */
+    const BYTE* base;       /* All index relative to this position */
+    const BYTE* dictBase;   /* alternate base for extDict */
+    BYTE* inputBuffer;      /* deprecated */
+    U32   dictLimit;        /* below that point, need extDict */
+    U32   lowLimit;         /* below that point, no more dict */
+    U32   nextToUpdate;     /* index from which to continue dictionary update */
+    U32   compressionLevel;
+} LZ4HC_Data_Structure;
+
+
+/**************************************
+*  Local Macros
+**************************************/
+#define HASH_FUNCTION(i)       (((i) * 2654435761U) >> ((MINMATCH*8)-HASH_LOG))
+//#define DELTANEXTU16(p)        chainTable[(p) & MAXD_MASK]   /* flexible, MAXD dependent */
+#define DELTANEXTU16(p)        chainTable[(U16)(p)]   /* faster */
+
+static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
+
+
+
+/**************************************
+*  HC Compression
+**************************************/
+static void LZ4HC_init (LZ4HC_Data_Structure* hc4, const BYTE* start)
+{
+    MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable));
+    MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
+    hc4->nextToUpdate = 64 KB;
+    hc4->base = start - 64 KB;
+    hc4->end = start;
+    hc4->dictBase = start - 64 KB;
+    hc4->dictLimit = 64 KB;
+    hc4->lowLimit = 64 KB;
+}
+
+
+/* Update chains up to ip (excluded) */
+FORCE_INLINE void LZ4HC_Insert (LZ4HC_Data_Structure* hc4, const BYTE* ip)
+{
+    U16* chainTable = hc4->chainTable;
+    U32* HashTable  = hc4->hashTable;
+    const BYTE* const base = hc4->base;
+    const U32 target = (U32)(ip - base);
+    U32 idx = hc4->nextToUpdate;
+
+    while(idx < target)
+    {
+        U32 h = LZ4HC_hashPtr(base+idx);
+        size_t delta = idx - HashTable[h];
+        if (delta>MAX_DISTANCE) delta = MAX_DISTANCE;
+        DELTANEXTU16(idx) = (U16)delta;
+        HashTable[h] = idx;
+        idx++;
+    }
+
+    hc4->nextToUpdate = target;
+}
+
+
+FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_Data_Structure* hc4,   /* Index table will be updated */
+                                               const BYTE* ip, const BYTE* const iLimit,
+                                               const BYTE** matchpos,
+                                               const int maxNbAttempts)
+{
+    U16* const chainTable = hc4->chainTable;
+    U32* const HashTable = hc4->hashTable;
+    const BYTE* const base = hc4->base;
+    const BYTE* const dictBase = hc4->dictBase;
+    const U32 dictLimit = hc4->dictLimit;
+    const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1);
+    U32 matchIndex;
+    const BYTE* match;
+    int nbAttempts=maxNbAttempts;
+    size_t ml=0;
+
+    /* HC4 match finder */
+    LZ4HC_Insert(hc4, ip);
+    matchIndex = HashTable[LZ4HC_hashPtr(ip)];
+
+    while ((matchIndex>=lowLimit) && (nbAttempts))
+    {
+        nbAttempts--;
+        if (matchIndex >= dictLimit)
+        {
+            match = base + matchIndex;
+            if (*(match+ml) == *(ip+ml)
+                && (LZ4_read32(match) == LZ4_read32(ip)))
+            {
+                size_t mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH;
+                if (mlt > ml) { ml = mlt; *matchpos = match; }
+            }
+        }
+        else
+        {
+            match = dictBase + matchIndex;
+            if (LZ4_read32(match) == LZ4_read32(ip))
+            {
+                size_t mlt;
+                const BYTE* vLimit = ip + (dictLimit - matchIndex);
+                if (vLimit > iLimit) vLimit = iLimit;
+                mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH;
+                if ((ip+mlt == vLimit) && (vLimit < iLimit))
+                    mlt += LZ4_count(ip+mlt, base+dictLimit, iLimit);
+                if (mlt > ml) { ml = mlt; *matchpos = base + matchIndex; }   /* virtual matchpos */
+            }
+        }
+        matchIndex -= DELTANEXTU16(matchIndex);
+    }
+
+    return (int)ml;
+}
+
+
+FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (
+    LZ4HC_Data_Structure* hc4,
+    const BYTE* const ip,
+    const BYTE* const iLowLimit,
+    const BYTE* const iHighLimit,
+    int longest,
+    const BYTE** matchpos,
+    const BYTE** startpos,
+    const int maxNbAttempts)
+{
+    U16* const chainTable = hc4->chainTable;
+    U32* const HashTable = hc4->hashTable;
+    const BYTE* const base = hc4->base;
+    const U32 dictLimit = hc4->dictLimit;
+    const BYTE* const lowPrefixPtr = base + dictLimit;
+    const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1);
+    const BYTE* const dictBase = hc4->dictBase;
+    U32   matchIndex;
+    int nbAttempts = maxNbAttempts;
+    int delta = (int)(ip-iLowLimit);
+
+
+    /* First Match */
+    LZ4HC_Insert(hc4, ip);
+    matchIndex = HashTable[LZ4HC_hashPtr(ip)];
+
+    while ((matchIndex>=lowLimit) && (nbAttempts))
+    {
+        nbAttempts--;
+        if (matchIndex >= dictLimit)
+        {
+            const BYTE* matchPtr = base + matchIndex;
+            if (*(iLowLimit + longest) == *(matchPtr - delta + longest))
+                if (LZ4_read32(matchPtr) == LZ4_read32(ip))
+                {
+                    int mlt = MINMATCH + LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);
+                    int back = 0;
+
+                    while ((ip+back>iLowLimit)
+                           && (matchPtr+back > lowPrefixPtr)
+                           && (ip[back-1] == matchPtr[back-1]))
+                            back--;
+
+                    mlt -= back;
+
+                    if (mlt > longest)
+                    {
+                        longest = (int)mlt;
+                        *matchpos = matchPtr+back;
+                        *startpos = ip+back;
+                    }
+                }
+        }
+        else
+        {
+            const BYTE* matchPtr = dictBase + matchIndex;
+            if (LZ4_read32(matchPtr) == LZ4_read32(ip))
+            {
+                size_t mlt;
+                int back=0;
+                const BYTE* vLimit = ip + (dictLimit - matchIndex);
+                if (vLimit > iHighLimit) vLimit = iHighLimit;
+                mlt = LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
+                if ((ip+mlt == vLimit) && (vLimit < iHighLimit))
+                    mlt += LZ4_count(ip+mlt, base+dictLimit, iHighLimit);
+                while ((ip+back > iLowLimit) && (matchIndex+back > lowLimit) && (ip[back-1] == matchPtr[back-1])) back--;
+                mlt -= back;
+                if ((int)mlt > longest) { longest = (int)mlt; *matchpos = base + matchIndex + back; *startpos = ip+back; }
+            }
+        }
+        matchIndex -= DELTANEXTU16(matchIndex);
+    }
+
+    return longest;
+}
+
+
+typedef enum { noLimit = 0, limitedOutput = 1 } limitedOutput_directive;
+
+#define LZ4HC_DEBUG 0
+#if LZ4HC_DEBUG
+static unsigned debug = 0;
+#endif
+
+FORCE_INLINE int LZ4HC_encodeSequence (
+    const BYTE** ip,
+    BYTE** op,
+    const BYTE** anchor,
+    int matchLength,
+    const BYTE* const match,
+    limitedOutput_directive limitedOutputBuffer,
+    BYTE* oend)
+{
+    int length;
+    BYTE* token;
+
+#if LZ4HC_DEBUG
+    if (debug) printf("literal : %u  --  match : %u  --  offset : %u\n", (U32)(*ip - *anchor), (U32)matchLength, (U32)(*ip-match));
+#endif
+
+    /* Encode Literal length */
+    length = (int)(*ip - *anchor);
+    token = (*op)++;
+    if ((limitedOutputBuffer) && ((*op + (length>>8) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1;   /* Check output limit */
+    if (length>=(int)RUN_MASK) { int len; *token=(RUN_MASK<<ML_BITS); len = length-RUN_MASK; for(; len > 254 ; len-=255) *(*op)++ = 255;  *(*op)++ = (BYTE)len; }
+    else *token = (BYTE)(length<<ML_BITS);
+
+    /* Copy Literals */
+    LZ4_wildCopy(*op, *anchor, (*op) + length);
+    *op += length;
+
+    /* Encode Offset */
+    LZ4_writeLE16(*op, (U16)(*ip-match)); *op += 2;
+
+    /* Encode MatchLength */
+    length = (int)(matchLength-MINMATCH);
+    if ((limitedOutputBuffer) && (*op + (length>>8) + (1 + LASTLITERALS) > oend)) return 1;   /* Check output limit */
+    if (length>=(int)ML_MASK) { *token+=ML_MASK; length-=ML_MASK; for(; length > 509 ; length-=510) { *(*op)++ = 255; *(*op)++ = 255; } if (length > 254) { length-=255; *(*op)++ = 255; } *(*op)++ = (BYTE)length; }
+    else *token += (BYTE)(length);
+
+    /* Prepare next loop */
+    *ip += matchLength;
+    *anchor = *ip;
+
+    return 0;
+}
+
+
+static int LZ4HC_compress_generic (
+    void* ctxvoid,
+    const char* source,
+    char* dest,
+    int inputSize,
+    int maxOutputSize,
+    int compressionLevel,
+    limitedOutput_directive limit
+    )
+{
+    LZ4HC_Data_Structure* ctx = (LZ4HC_Data_Structure*) ctxvoid;
+    const BYTE* ip = (const BYTE*) source;
+    const BYTE* anchor = ip;
+    const BYTE* const iend = ip + inputSize;
+    const BYTE* const mflimit = iend - MFLIMIT;
+    const BYTE* const matchlimit = (iend - LASTLITERALS);
+
+    BYTE* op = (BYTE*) dest;
+    BYTE* const oend = op + maxOutputSize;
+
+    unsigned maxNbAttempts;
+    int   ml, ml2, ml3, ml0;
+    const BYTE* ref=NULL;
+    const BYTE* start2=NULL;
+    const BYTE* ref2=NULL;
+    const BYTE* start3=NULL;
+    const BYTE* ref3=NULL;
+    const BYTE* start0;
+    const BYTE* ref0;
+
+
+    /* init */
+    if (compressionLevel > g_maxCompressionLevel) compressionLevel = g_maxCompressionLevel;
+    if (compressionLevel < 1) compressionLevel = LZ4HC_compressionLevel_default;
+    maxNbAttempts = 1 << (compressionLevel-1);
+    ctx->end += inputSize;
+
+    ip++;
+
+    /* Main Loop */
+    while (ip < mflimit)
+    {
+        ml = LZ4HC_InsertAndFindBestMatch (ctx, ip, matchlimit, (&ref), maxNbAttempts);
+        if (!ml) { ip++; continue; }
+
+        /* saved, in case we would skip too much */
+        start0 = ip;
+        ref0 = ref;
+        ml0 = ml;
+
+_Search2:
+        if (ip+ml < mflimit)
+            ml2 = LZ4HC_InsertAndGetWiderMatch(ctx, ip + ml - 2, ip + 1, matchlimit, ml, &ref2, &start2, maxNbAttempts);
+        else ml2 = ml;
+
+        if (ml2 == ml)  /* No better match */
+        {
+            if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
+            continue;
+        }
+
+        if (start0 < ip)
+        {
+            if (start2 < ip + ml0)   /* empirical */
+            {
+                ip = start0;
+                ref = ref0;
+                ml = ml0;
+            }
+        }
+
+        /* Here, start0==ip */
+        if ((start2 - ip) < 3)   /* First Match too small : removed */
+        {
+            ml = ml2;
+            ip = start2;
+            ref =ref2;
+            goto _Search2;
+        }
+
+_Search3:
+        /*
+        * Currently we have :
+        * ml2 > ml1, and
+        * ip1+3 <= ip2 (usually < ip1+ml1)
+        */
+        if ((start2 - ip) < OPTIMAL_ML)
+        {
+            int correction;
+            int new_ml = ml;
+            if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
+            if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH;
+            correction = new_ml - (int)(start2 - ip);
+            if (correction > 0)
+            {
+                start2 += correction;
+                ref2 += correction;
+                ml2 -= correction;
+            }
+        }
+        /* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */
+
+        if (start2 + ml2 < mflimit)
+            ml3 = LZ4HC_InsertAndGetWiderMatch(ctx, start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3, maxNbAttempts);
+        else ml3 = ml2;
+
+        if (ml3 == ml2) /* No better match : 2 sequences to encode */
+        {
+            /* ip & ref are known; Now for ml */
+            if (start2 < ip+ml)  ml = (int)(start2 - ip);
+            /* Now, encode 2 sequences */
+            if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
+            ip = start2;
+            if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml2, ref2, limit, oend)) return 0;
+            continue;
+        }
+
+        if (start3 < ip+ml+3) /* Not enough space for match 2 : remove it */
+        {
+            if (start3 >= (ip+ml)) /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
+            {
+                if (start2 < ip+ml)
+                {
+                    int correction = (int)(ip+ml - start2);
+                    start2 += correction;
+                    ref2 += correction;
+                    ml2 -= correction;
+                    if (ml2 < MINMATCH)
+                    {
+                        start2 = start3;
+                        ref2 = ref3;
+                        ml2 = ml3;
+                    }
+                }
+
+                if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
+                ip  = start3;
+                ref = ref3;
+                ml  = ml3;
+
+                start0 = start2;
+                ref0 = ref2;
+                ml0 = ml2;
+                goto _Search2;
+            }
+
+            start2 = start3;
+            ref2 = ref3;
+            ml2 = ml3;
+            goto _Search3;
+        }
+
+        /*
+        * OK, now we have 3 ascending matches; let's write at least the first one
+        * ip & ref are known; Now for ml
+        */
+        if (start2 < ip+ml)
+        {
+            if ((start2 - ip) < (int)ML_MASK)
+            {
+                int correction;
+                if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
+                if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;
+                correction = ml - (int)(start2 - ip);
+                if (correction > 0)
+                {
+                    start2 += correction;
+                    ref2 += correction;
+                    ml2 -= correction;
+                }
+            }
+            else
+            {
+                ml = (int)(start2 - ip);
+            }
+        }
+        if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
+
+        ip = start2;
+        ref = ref2;
+        ml = ml2;
+
+        start2 = start3;
+        ref2 = ref3;
+        ml2 = ml3;
+
+        goto _Search3;
+    }
+
+    /* Encode Last Literals */
+    {
+        int lastRun = (int)(iend - anchor);
+        if ((limit) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0;  /* Check output limit */
+        if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<<ML_BITS); lastRun-=RUN_MASK; for(; lastRun > 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; }
+        else *op++ = (BYTE)(lastRun<<ML_BITS);
+        memcpy(op, anchor, iend - anchor);
+        op += iend-anchor;
+    }
+
+    /* End */
+    return (int) (((char*)op)-dest);
+}
+
+
+int LZ4_sizeofStateHC(void) { return sizeof(LZ4HC_Data_Structure); }
+
+int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel)
+{
+    if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0;   /* Error : state is not aligned for pointers (32 or 64 bits) */
+    LZ4HC_init ((LZ4HC_Data_Structure*)state, (const BYTE*)src);
+    if (maxDstSize < LZ4_compressBound(srcSize))
+        return LZ4HC_compress_generic (state, src, dst, srcSize, maxDstSize, compressionLevel, limitedOutput);
+    else
+        return LZ4HC_compress_generic (state, src, dst, srcSize, maxDstSize, compressionLevel, noLimit);
+}
+
+int LZ4_compress_HC(const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel)
+{
+    LZ4HC_Data_Structure state;
+    return LZ4_compress_HC_extStateHC(&state, src, dst, srcSize, maxDstSize, compressionLevel);
+}
+
+
+
+/**************************************
+*  Streaming Functions
+**************************************/
+/* allocation */
+LZ4_streamHC_t* LZ4_createStreamHC(void) { return (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t)); }
+int             LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr) { free(LZ4_streamHCPtr); return 0; }
+
+
+/* initialization */
+void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
+{
+    LZ4_STATIC_ASSERT(sizeof(LZ4HC_Data_Structure) <= sizeof(LZ4_streamHC_t));   /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */
+    ((LZ4HC_Data_Structure*)LZ4_streamHCPtr)->base = NULL;
+    ((LZ4HC_Data_Structure*)LZ4_streamHCPtr)->compressionLevel = (unsigned)compressionLevel;
+}
+
+int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize)
+{
+    LZ4HC_Data_Structure* ctxPtr = (LZ4HC_Data_Structure*) LZ4_streamHCPtr;
+    if (dictSize > 64 KB)
+    {
+        dictionary += dictSize - 64 KB;
+        dictSize = 64 KB;
+    }
+    LZ4HC_init (ctxPtr, (const BYTE*)dictionary);
+    if (dictSize >= 4) LZ4HC_Insert (ctxPtr, (const BYTE*)dictionary +(dictSize-3));
+    ctxPtr->end = (const BYTE*)dictionary + dictSize;
+    return dictSize;
+}
+
+
+/* compression */
+
+static void LZ4HC_setExternalDict(LZ4HC_Data_Structure* ctxPtr, const BYTE* newBlock)
+{
+    if (ctxPtr->end >= ctxPtr->base + 4)
+        LZ4HC_Insert (ctxPtr, ctxPtr->end-3);   /* Referencing remaining dictionary content */
+    /* Only one memory segment for extDict, so any previous extDict is lost at this stage */
+    ctxPtr->lowLimit  = ctxPtr->dictLimit;
+    ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base);
+    ctxPtr->dictBase  = ctxPtr->base;
+    ctxPtr->base = newBlock - ctxPtr->dictLimit;
+    ctxPtr->end  = newBlock;
+    ctxPtr->nextToUpdate = ctxPtr->dictLimit;   /* match referencing will resume from there */
+}
+
+static int LZ4_compressHC_continue_generic (LZ4HC_Data_Structure* ctxPtr,
+                                            const char* source, char* dest,
+                                            int inputSize, int maxOutputSize, limitedOutput_directive limit)
+{
+    /* auto-init if forgotten */
+    if (ctxPtr->base == NULL)
+        LZ4HC_init (ctxPtr, (const BYTE*) source);
+
+    /* Check overflow */
+    if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB)
+    {
+        size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit;
+        if (dictSize > 64 KB) dictSize = 64 KB;
+
+        LZ4_loadDictHC((LZ4_streamHC_t*)ctxPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);
+    }
+
+    /* Check if blocks follow each other */
+    if ((const BYTE*)source != ctxPtr->end)
+        LZ4HC_setExternalDict(ctxPtr, (const BYTE*)source);
+
+    /* Check overlapping input/dictionary space */
+    {
+        const BYTE* sourceEnd = (const BYTE*) source + inputSize;
+        const BYTE* dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;
+        const BYTE* dictEnd   = ctxPtr->dictBase + ctxPtr->dictLimit;
+        if ((sourceEnd > dictBegin) && ((const BYTE*)source < dictEnd))
+        {
+            if (sourceEnd > dictEnd) sourceEnd = dictEnd;
+            ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase);
+            if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit;
+        }
+    }
+
+    return LZ4HC_compress_generic (ctxPtr, source, dest, inputSize, maxOutputSize, ctxPtr->compressionLevel, limit);
+}
+
+int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+    if (maxOutputSize < LZ4_compressBound(inputSize))
+        return LZ4_compressHC_continue_generic ((LZ4HC_Data_Structure*)LZ4_streamHCPtr, source, dest, inputSize, maxOutputSize, limitedOutput);
+    else
+        return LZ4_compressHC_continue_generic ((LZ4HC_Data_Structure*)LZ4_streamHCPtr, source, dest, inputSize, maxOutputSize, noLimit);
+}
+
+
+/* dictionary saving */
+
+int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
+{
+    LZ4HC_Data_Structure* streamPtr = (LZ4HC_Data_Structure*)LZ4_streamHCPtr;
+    int prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit));
+    if (dictSize > 64 KB) dictSize = 64 KB;
+    if (dictSize < 4) dictSize = 0;
+    if (dictSize > prefixSize) dictSize = prefixSize;
+    memmove(safeBuffer, streamPtr->end - dictSize, dictSize);
+    {
+        U32 endIndex = (U32)(streamPtr->end - streamPtr->base);
+        streamPtr->end = (const BYTE*)safeBuffer + dictSize;
+        streamPtr->base = streamPtr->end - endIndex;
+        streamPtr->dictLimit = endIndex - dictSize;
+        streamPtr->lowLimit = endIndex - dictSize;
+        if (streamPtr->nextToUpdate < streamPtr->dictLimit) streamPtr->nextToUpdate = streamPtr->dictLimit;
+    }
+    return dictSize;
+}
+
+
+/***********************************
+*  Deprecated Functions
+***********************************/
+/* Deprecated compression functions */
+/* These functions are planned to start generate warnings by r131 approximately */
+int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
+int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
+int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
+int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }
+int LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
+int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); }
+int LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
+int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); }
+int LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); }
+int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); }
+
+
+/* Deprecated streaming functions */
+/* These functions currently generate deprecation warnings */
+int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }
+
+int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
+{
+    if ((((size_t)state) & (sizeof(void*)-1)) != 0) return 1;   /* Error : pointer is not aligned for pointer (32 or 64 bits) */
+    LZ4HC_init((LZ4HC_Data_Structure*)state, (const BYTE*)inputBuffer);
+    ((LZ4HC_Data_Structure*)state)->inputBuffer = (BYTE*)inputBuffer;
+    return 0;
+}
+
+void* LZ4_createHC (char* inputBuffer)
+{
+    void* hc4 = ALLOCATOR(1, sizeof(LZ4HC_Data_Structure));
+    LZ4HC_init ((LZ4HC_Data_Structure*)hc4, (const BYTE*)inputBuffer);
+    ((LZ4HC_Data_Structure*)hc4)->inputBuffer = (BYTE*)inputBuffer;
+    return hc4;
+}
+
+int LZ4_freeHC (void* LZ4HC_Data)
+{
+    FREEMEM(LZ4HC_Data);
+    return (0);
+}
+
+int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel)
+{
+    return LZ4HC_compress_generic (LZ4HC_Data, source, dest, inputSize, 0, compressionLevel, noLimit);
+}
+
+int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel)
+{
+    return LZ4HC_compress_generic (LZ4HC_Data, source, dest, inputSize, maxOutputSize, compressionLevel, limitedOutput);
+}
+
+char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
+{
+    LZ4HC_Data_Structure* hc4 = (LZ4HC_Data_Structure*)LZ4HC_Data;
+    int dictSize = LZ4_saveDictHC((LZ4_streamHC_t*)LZ4HC_Data, (char*)(hc4->inputBuffer), 64 KB);
+    return (char*)(hc4->inputBuffer + dictSize);
+}

+ 189 - 0
jni/love/src/libraries/lz4/lz4hc.h

@@ -0,0 +1,189 @@
+/*
+   LZ4 HC - High Compression Mode of LZ4
+   Header File
+   Copyright (C) 2011-2015, Yann Collet.
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   You can contact the author at :
+   - LZ4 source repository : https://github.com/Cyan4973/lz4
+   - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+*/
+#pragma once
+
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*****************************
+*  Includes
+*****************************/
+#include <stddef.h>   /* size_t */
+
+
+/**************************************
+*  Block Compression
+**************************************/
+int LZ4_compress_HC (const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel);
+/*
+LZ4_compress_HC :
+    Destination buffer 'dst' must be already allocated.
+    Compression completion is guaranteed if 'dst' buffer is sized to handle worst circumstances (data not compressible)
+    Worst size evaluation is provided by function LZ4_compressBound() (see "lz4.h")
+      srcSize  : Max supported value is LZ4_MAX_INPUT_SIZE (see "lz4.h")
+      compressionLevel : Recommended values are between 4 and 9, although any value between 0 and 16 will work.
+                         0 means "use default value" (see lz4hc.c).
+                         Values >16 behave the same as 16.
+      return : the number of bytes written into buffer 'dst'
+            or 0 if compression fails.
+*/
+
+
+/* Note :
+   Decompression functions are provided within LZ4 source code (see "lz4.h") (BSD license)
+*/
+
+
+int LZ4_sizeofStateHC(void);
+int LZ4_compress_HC_extStateHC(void* state, const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel);
+/*
+LZ4_compress_HC_extStateHC() :
+   Use this function if you prefer to manually allocate memory for compression tables.
+   To know how much memory must be allocated for the compression tables, use :
+      int LZ4_sizeofStateHC();
+
+   Allocated memory must be aligned on 8-bytes boundaries (which a normal malloc() will do properly).
+
+   The allocated memory can then be provided to the compression functions using 'void* state' parameter.
+   LZ4_compress_HC_extStateHC() is equivalent to previously described function.
+   It just uses externally allocated memory for stateHC.
+*/
+
+
+/**************************************
+*  Streaming Compression
+**************************************/
+#define LZ4_STREAMHCSIZE        262192
+#define LZ4_STREAMHCSIZE_SIZET (LZ4_STREAMHCSIZE / sizeof(size_t))
+typedef struct { size_t table[LZ4_STREAMHCSIZE_SIZET]; } LZ4_streamHC_t;
+/*
+  LZ4_streamHC_t
+  This structure allows static allocation of LZ4 HC streaming state.
+  State must then be initialized using LZ4_resetStreamHC() before first use.
+
+  Static allocation should only be used in combination with static linking.
+  If you want to use LZ4 as a DLL, please use construction functions below, which are future-proof.
+*/
+
+
+LZ4_streamHC_t* LZ4_createStreamHC(void);
+int             LZ4_freeStreamHC (LZ4_streamHC_t* streamHCPtr);
+/*
+  These functions create and release memory for LZ4 HC streaming state.
+  Newly created states are already initialized.
+  Existing state space can be re-used anytime using LZ4_resetStreamHC().
+  If you use LZ4 as a DLL, use these functions instead of static structure allocation,
+  to avoid size mismatch between different versions.
+*/
+
+void LZ4_resetStreamHC (LZ4_streamHC_t* streamHCPtr, int compressionLevel);
+int  LZ4_loadDictHC (LZ4_streamHC_t* streamHCPtr, const char* dictionary, int dictSize);
+
+int LZ4_compress_HC_continue (LZ4_streamHC_t* streamHCPtr, const char* src, char* dst, int srcSize, int maxDstSize);
+
+int LZ4_saveDictHC (LZ4_streamHC_t* streamHCPtr, char* safeBuffer, int maxDictSize);
+
+/*
+  These functions compress data in successive blocks of any size, using previous blocks as dictionary.
+  One key assumption is that previous blocks (up to 64 KB) remain read-accessible while compressing next blocks.
+  There is an exception for ring buffers, which can be smaller 64 KB.
+  Such case is automatically detected and correctly handled by LZ4_compress_HC_continue().
+
+  Before starting compression, state must be properly initialized, using LZ4_resetStreamHC().
+  A first "fictional block" can then be designated as initial dictionary, using LZ4_loadDictHC() (Optional).
+
+  Then, use LZ4_compress_HC_continue() to compress each successive block.
+  It works like LZ4_compress_HC(), but use previous memory blocks as dictionary to improve compression.
+  Previous memory blocks (including initial dictionary when present) must remain accessible and unmodified during compression.
+  As a reminder, size 'dst' buffer to handle worst cases, using LZ4_compressBound(), to ensure success of compression operation.
+
+  If, for any reason, previous data blocks can't be preserved unmodified in memory during next compression block,
+  you must save it to a safer memory space, using LZ4_saveDictHC().
+  Return value of LZ4_saveDictHC() is the size of dictionary effectively saved into 'safeBuffer'.
+*/
+
+
+
+/**************************************
+*  Deprecated Functions
+**************************************/
+/* Deprecate Warnings */
+/* Should these warnings messages be a problem,
+   it is generally possible to disable them,
+   with -Wno-deprecated-declarations for gcc
+   or _CRT_SECURE_NO_WARNINGS in Visual for example.
+   You can also define LZ4_DEPRECATE_WARNING_DEFBLOCK. */
+#ifndef LZ4_DEPRECATE_WARNING_DEFBLOCK
+#  define LZ4_DEPRECATE_WARNING_DEFBLOCK
+#  define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+#  if (LZ4_GCC_VERSION >= 405) || defined(__clang__)
+#    define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))
+#  elif (LZ4_GCC_VERSION >= 301)
+#    define LZ4_DEPRECATED(message) __attribute__((deprecated))
+#  elif defined(_MSC_VER)
+#    define LZ4_DEPRECATED(message) __declspec(deprecated(message))
+#  else
+#    pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler")
+#    define LZ4_DEPRECATED(message)
+#  endif
+#endif // LZ4_DEPRECATE_WARNING_DEFBLOCK
+
+/* compression functions */
+/* these functions are planned to trigger warning messages by r131 approximately */
+int LZ4_compressHC                (const char* source, char* dest, int inputSize);
+int LZ4_compressHC_limitedOutput  (const char* source, char* dest, int inputSize, int maxOutputSize);
+int LZ4_compressHC2               (const char* source, char* dest, int inputSize, int compressionLevel);
+int LZ4_compressHC2_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
+int LZ4_compressHC_withStateHC               (void* state, const char* source, char* dest, int inputSize);
+int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
+int LZ4_compressHC2_withStateHC              (void* state, const char* source, char* dest, int inputSize, int compressionLevel);
+int LZ4_compressHC2_limitedOutput_withStateHC(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
+int LZ4_compressHC_continue               (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize);
+int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
+
+/* Streaming functions following the older model; should no longer be used */
+LZ4_DEPRECATED("use LZ4_createStreamHC() instead") void* LZ4_createHC (char* inputBuffer);
+LZ4_DEPRECATED("use LZ4_saveDictHC() instead")     char* LZ4_slideInputBufferHC (void* LZ4HC_Data);
+LZ4_DEPRECATED("use LZ4_freeStreamHC() instead")   int   LZ4_freeHC (void* LZ4HC_Data);
+LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int   LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel);
+LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int   LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
+LZ4_DEPRECATED("use LZ4_createStreamHC() instead") int   LZ4_sizeofStreamStateHC(void);
+LZ4_DEPRECATED("use LZ4_resetStreamHC() instead")  int   LZ4_resetStreamStateHC(void* state, char* inputBuffer);
+
+
+#if defined (__cplusplus)
+}
+#endif

+ 528 - 0
jni/love/src/libraries/noise1234/noise1234.cpp

@@ -0,0 +1,528 @@
+// Noise1234
+// Author: Stefan Gustavson ([email protected])
+//
+// This library is public domain software, released by the author
+// into the public domain in February 2011. You may do anything
+// you like with it. You may even remove all attributions,
+// but of course I'd appreciate it if you kept my name somewhere.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+
+/** \file
+		\brief Implements the Noise1234 class for producing Perlin noise.
+		\author Stefan Gustavson ([email protected])
+*/
+
+/*
+ * This implementation is "Improved Noise" as presented by
+ * Ken Perlin at Siggraph 2002. The 3D function is a direct port
+ * of his Java reference code available on www.noisemachine.com
+ * (although I cleaned it up and made the code more readable),
+ * but the 1D, 2D and 4D cases were implemented from scratch
+ * by me.
+ *
+ * This is a highly reusable class. It has no dependencies
+ * on any other file, apart from its own header file.
+ */
+
+
+#include	"noise1234.h"
+
+// This is the new and improved, C(2) continuous interpolant
+#define FADE(t) ( t * t * t * ( t * ( t * 6 - 15 ) + 10 ) )
+
+#define FASTFLOOR(x) ( ((x)>0) ? ((int)x) : ((int)x-1 ) )
+#define LERP(t, a, b) ((a) + (t)*((b)-(a)))
+
+
+//---------------------------------------------------------------------
+// Static data
+
+/*
+ * Permutation table. This is just a random jumble of all numbers 0-255,
+ * repeated twice to avoid wrapping the index at 255 for each lookup.
+ * This needs to be exactly the same for all instances on all platforms,
+ * so it's easiest to just keep it as static explicit data.
+ * This also removes the need for any initialisation of this class.
+ *
+ * Note that making this an int[] instead of a char[] might make the
+ * code run faster on platforms with a high penalty for unaligned single
+ * byte addressing. Intel x86 is generally single-byte-friendly, but
+ * some other CPUs are faster with 4-aligned reads.
+ * However, a char[] is smaller, which avoids cache trashing, and that
+ * is probably the most important aspect on most architectures.
+ * This array is accessed a *lot* by the noise functions.
+ * A vector-valued noise over 3D accesses it 96 times, and a
+ * float-valued 4D noise 64 times. We want this to fit in the cache!
+ */
+unsigned char Noise1234::perm[] = {151,160,137,91,90,15,
+  131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
+  190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
+  88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
+  77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
+  102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
+  135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
+  5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
+  223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
+  129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
+  251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
+  49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
+  138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,
+  151,160,137,91,90,15,
+  131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
+  190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
+  88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
+  77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
+  102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
+  135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
+  5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
+  223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
+  129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
+  251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
+  49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
+  138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
+};
+
+//---------------------------------------------------------------------
+
+/*
+ * Helper functions to compute gradients-dot-residualvectors (1D to 4D)
+ * Note that these generate gradients of more than unit length. To make
+ * a close match with the value range of classic Perlin noise, the final
+ * noise values need to be rescaled. To match the RenderMan noise in a
+ * statistical sense, the approximate scaling values (empirically
+ * determined from test renderings) are:
+ * 1D noise needs rescaling with 0.188
+ * 2D noise needs rescaling with 0.507
+ * 3D noise needs rescaling with 0.936
+ * 4D noise needs rescaling with 0.87
+ * Note that these noise functions are the most practical and useful
+ * signed version of Perlin noise. To return values according to the
+ * RenderMan specification from the SL noise() and pnoise() functions,
+ * the noise values need to be scaled and offset to [0,1], like this:
+ * float SLnoise = (Noise1234::noise(x,y,z) + 1.0) * 0.5;
+ */
+
+float  Noise1234::grad( int hash, float x ) {
+    int h = hash & 15;
+    float grad = 1.0 + (h & 7);  // Gradient value 1.0, 2.0, ..., 8.0
+    if (h&8) grad = -grad;         // and a random sign for the gradient
+    return ( grad * x );           // Multiply the gradient with the distance
+}
+
+float  Noise1234::grad( int hash, float x, float y ) {
+    int h = hash & 7;      // Convert low 3 bits of hash code
+    float u = h<4 ? x : y;  // into 8 simple gradient directions,
+    float v = h<4 ? y : x;  // and compute the dot product with (x,y).
+    return ((h&1)? -u : u) + ((h&2)? -2.0*v : 2.0*v);
+}
+
+float  Noise1234::grad( int hash, float x, float y , float z ) {
+    int h = hash & 15;     // Convert low 4 bits of hash code into 12 simple
+    float u = h<8 ? x : y; // gradient directions, and compute dot product.
+    float v = h<4 ? y : h==12||h==14 ? x : z; // Fix repeats at h = 12 to 15
+    return ((h&1)? -u : u) + ((h&2)? -v : v);
+}
+
+float  Noise1234::grad( int hash, float x, float y, float z, float t ) {
+    int h = hash & 31;      // Convert low 5 bits of hash code into 32 simple
+    float u = h<24 ? x : y; // gradient directions, and compute dot product.
+    float v = h<16 ? y : z;
+    float w = h<8 ? z : t;
+    return ((h&1)? -u : u) + ((h&2)? -v : v) + ((h&4)? -w : w);
+}
+
+//---------------------------------------------------------------------
+/** 1D float Perlin noise, SL "noise()"
+ */
+float Noise1234::noise( float x )
+{
+    int ix0, ix1;
+    float fx0, fx1;
+    float s, n0, n1;
+
+    ix0 = FASTFLOOR( x ); // Integer part of x
+    fx0 = x - ix0;       // Fractional part of x
+    fx1 = fx0 - 1.0f;
+    ix1 = ( ix0+1 ) & 0xff;
+    ix0 = ix0 & 0xff;    // Wrap to 0..255
+
+    s = FADE( fx0 );
+
+    n0 = grad( perm[ ix0 ], fx0 );
+    n1 = grad( perm[ ix1 ], fx1 );
+    return 0.188f * ( LERP( s, n0, n1 ) );
+}
+
+//---------------------------------------------------------------------
+/** 1D float Perlin periodic noise, SL "pnoise()"
+ */
+float Noise1234::pnoise( float x, int px )
+{
+    int ix0, ix1;
+    float fx0, fx1;
+    float s, n0, n1;
+
+    ix0 = FASTFLOOR( x ); // Integer part of x
+    fx0 = x - ix0;       // Fractional part of x
+    fx1 = fx0 - 1.0f;
+    ix1 = (( ix0 + 1 ) % px) & 0xff; // Wrap to 0..px-1 *and* wrap to 0..255
+    ix0 = ( ix0 % px ) & 0xff;      // (because px might be greater than 256)
+
+    s = FADE( fx0 );
+
+    n0 = grad( perm[ ix0 ], fx0 );
+    n1 = grad( perm[ ix1 ], fx1 );
+    return 0.188f * ( LERP( s, n0, n1 ) );
+}
+
+
+//---------------------------------------------------------------------
+/** 2D float Perlin noise.
+ */
+float Noise1234::noise( float x, float y )
+{
+    int ix0, iy0, ix1, iy1;
+    float fx0, fy0, fx1, fy1;
+    float s, t, nx0, nx1, n0, n1;
+
+    ix0 = FASTFLOOR( x ); // Integer part of x
+    iy0 = FASTFLOOR( y ); // Integer part of y
+    fx0 = x - ix0;        // Fractional part of x
+    fy0 = y - iy0;        // Fractional part of y
+    fx1 = fx0 - 1.0f;
+    fy1 = fy0 - 1.0f;
+    ix1 = (ix0 + 1) & 0xff;  // Wrap to 0..255
+    iy1 = (iy0 + 1) & 0xff;
+    ix0 = ix0 & 0xff;
+    iy0 = iy0 & 0xff;
+    
+    t = FADE( fy0 );
+    s = FADE( fx0 );
+
+    nx0 = grad(perm[ix0 + perm[iy0]], fx0, fy0);
+    nx1 = grad(perm[ix0 + perm[iy1]], fx0, fy1);
+    n0 = LERP( t, nx0, nx1 );
+
+    nx0 = grad(perm[ix1 + perm[iy0]], fx1, fy0);
+    nx1 = grad(perm[ix1 + perm[iy1]], fx1, fy1);
+    n1 = LERP(t, nx0, nx1);
+
+    return 0.507f * ( LERP( s, n0, n1 ) );
+}
+
+//---------------------------------------------------------------------
+/** 2D float Perlin periodic noise.
+ */
+float Noise1234::pnoise( float x, float y, int px, int py )
+{
+    int ix0, iy0, ix1, iy1;
+    float fx0, fy0, fx1, fy1;
+    float s, t, nx0, nx1, n0, n1;
+
+    ix0 = FASTFLOOR( x ); // Integer part of x
+    iy0 = FASTFLOOR( y ); // Integer part of y
+    fx0 = x - ix0;        // Fractional part of x
+    fy0 = y - iy0;        // Fractional part of y
+    fx1 = fx0 - 1.0f;
+    fy1 = fy0 - 1.0f;
+    ix1 = (( ix0 + 1 ) % px) & 0xff;  // Wrap to 0..px-1 and wrap to 0..255
+    iy1 = (( iy0 + 1 ) % py) & 0xff;  // Wrap to 0..py-1 and wrap to 0..255
+    ix0 = ( ix0 % px ) & 0xff;
+    iy0 = ( iy0 % py ) & 0xff;
+    
+    t = FADE( fy0 );
+    s = FADE( fx0 );
+
+    nx0 = grad(perm[ix0 + perm[iy0]], fx0, fy0);
+    nx1 = grad(perm[ix0 + perm[iy1]], fx0, fy1);
+    n0 = LERP( t, nx0, nx1 );
+
+    nx0 = grad(perm[ix1 + perm[iy0]], fx1, fy0);
+    nx1 = grad(perm[ix1 + perm[iy1]], fx1, fy1);
+    n1 = LERP(t, nx0, nx1);
+
+    return 0.507f * ( LERP( s, n0, n1 ) );
+}
+
+
+//---------------------------------------------------------------------
+/** 3D float Perlin noise.
+ */
+float Noise1234::noise( float x, float y, float z )
+{
+    int ix0, iy0, ix1, iy1, iz0, iz1;
+    float fx0, fy0, fz0, fx1, fy1, fz1;
+    float s, t, r;
+    float nxy0, nxy1, nx0, nx1, n0, n1;
+
+    ix0 = FASTFLOOR( x ); // Integer part of x
+    iy0 = FASTFLOOR( y ); // Integer part of y
+    iz0 = FASTFLOOR( z ); // Integer part of z
+    fx0 = x - ix0;        // Fractional part of x
+    fy0 = y - iy0;        // Fractional part of y
+    fz0 = z - iz0;        // Fractional part of z
+    fx1 = fx0 - 1.0f;
+    fy1 = fy0 - 1.0f;
+    fz1 = fz0 - 1.0f;
+    ix1 = ( ix0 + 1 ) & 0xff; // Wrap to 0..255
+    iy1 = ( iy0 + 1 ) & 0xff;
+    iz1 = ( iz0 + 1 ) & 0xff;
+    ix0 = ix0 & 0xff;
+    iy0 = iy0 & 0xff;
+    iz0 = iz0 & 0xff;
+    
+    r = FADE( fz0 );
+    t = FADE( fy0 );
+    s = FADE( fx0 );
+
+    nxy0 = grad(perm[ix0 + perm[iy0 + perm[iz0]]], fx0, fy0, fz0);
+    nxy1 = grad(perm[ix0 + perm[iy0 + perm[iz1]]], fx0, fy0, fz1);
+    nx0 = LERP( r, nxy0, nxy1 );
+
+    nxy0 = grad(perm[ix0 + perm[iy1 + perm[iz0]]], fx0, fy1, fz0);
+    nxy1 = grad(perm[ix0 + perm[iy1 + perm[iz1]]], fx0, fy1, fz1);
+    nx1 = LERP( r, nxy0, nxy1 );
+
+    n0 = LERP( t, nx0, nx1 );
+
+    nxy0 = grad(perm[ix1 + perm[iy0 + perm[iz0]]], fx1, fy0, fz0);
+    nxy1 = grad(perm[ix1 + perm[iy0 + perm[iz1]]], fx1, fy0, fz1);
+    nx0 = LERP( r, nxy0, nxy1 );
+
+    nxy0 = grad(perm[ix1 + perm[iy1 + perm[iz0]]], fx1, fy1, fz0);
+    nxy1 = grad(perm[ix1 + perm[iy1 + perm[iz1]]], fx1, fy1, fz1);
+    nx1 = LERP( r, nxy0, nxy1 );
+
+    n1 = LERP( t, nx0, nx1 );
+    
+    return 0.936f * ( LERP( s, n0, n1 ) );
+}
+
+//---------------------------------------------------------------------
+/** 3D float Perlin periodic noise.
+ */
+float Noise1234::pnoise( float x, float y, float z, int px, int py, int pz )
+{
+    int ix0, iy0, ix1, iy1, iz0, iz1;
+    float fx0, fy0, fz0, fx1, fy1, fz1;
+    float s, t, r;
+    float nxy0, nxy1, nx0, nx1, n0, n1;
+
+    ix0 = FASTFLOOR( x ); // Integer part of x
+    iy0 = FASTFLOOR( y ); // Integer part of y
+    iz0 = FASTFLOOR( z ); // Integer part of z
+    fx0 = x - ix0;        // Fractional part of x
+    fy0 = y - iy0;        // Fractional part of y
+    fz0 = z - iz0;        // Fractional part of z
+    fx1 = fx0 - 1.0f;
+    fy1 = fy0 - 1.0f;
+    fz1 = fz0 - 1.0f;
+    ix1 = (( ix0 + 1 ) % px ) & 0xff; // Wrap to 0..px-1 and wrap to 0..255
+    iy1 = (( iy0 + 1 ) % py ) & 0xff; // Wrap to 0..py-1 and wrap to 0..255
+    iz1 = (( iz0 + 1 ) % pz ) & 0xff; // Wrap to 0..pz-1 and wrap to 0..255
+    ix0 = ( ix0 % px ) & 0xff;
+    iy0 = ( iy0 % py ) & 0xff;
+    iz0 = ( iz0 % pz ) & 0xff;
+    
+    r = FADE( fz0 );
+    t = FADE( fy0 );
+    s = FADE( fx0 );
+
+    nxy0 = grad(perm[ix0 + perm[iy0 + perm[iz0]]], fx0, fy0, fz0);
+    nxy1 = grad(perm[ix0 + perm[iy0 + perm[iz1]]], fx0, fy0, fz1);
+    nx0 = LERP( r, nxy0, nxy1 );
+
+    nxy0 = grad(perm[ix0 + perm[iy1 + perm[iz0]]], fx0, fy1, fz0);
+    nxy1 = grad(perm[ix0 + perm[iy1 + perm[iz1]]], fx0, fy1, fz1);
+    nx1 = LERP( r, nxy0, nxy1 );
+
+    n0 = LERP( t, nx0, nx1 );
+
+    nxy0 = grad(perm[ix1 + perm[iy0 + perm[iz0]]], fx1, fy0, fz0);
+    nxy1 = grad(perm[ix1 + perm[iy0 + perm[iz1]]], fx1, fy0, fz1);
+    nx0 = LERP( r, nxy0, nxy1 );
+
+    nxy0 = grad(perm[ix1 + perm[iy1 + perm[iz0]]], fx1, fy1, fz0);
+    nxy1 = grad(perm[ix1 + perm[iy1 + perm[iz1]]], fx1, fy1, fz1);
+    nx1 = LERP( r, nxy0, nxy1 );
+
+    n1 = LERP( t, nx0, nx1 );
+    
+    return 0.936f * ( LERP( s, n0, n1 ) );
+}
+
+
+//---------------------------------------------------------------------
+/** 4D float Perlin noise.
+ */
+
+float Noise1234::noise( float x, float y, float z, float w )
+{
+    int ix0, iy0, iz0, iw0, ix1, iy1, iz1, iw1;
+    float fx0, fy0, fz0, fw0, fx1, fy1, fz1, fw1;
+    float s, t, r, q;
+    float nxyz0, nxyz1, nxy0, nxy1, nx0, nx1, n0, n1;
+
+    ix0 = FASTFLOOR( x ); // Integer part of x
+    iy0 = FASTFLOOR( y ); // Integer part of y
+    iz0 = FASTFLOOR( z ); // Integer part of y
+    iw0 = FASTFLOOR( w ); // Integer part of w
+    fx0 = x - ix0;        // Fractional part of x
+    fy0 = y - iy0;        // Fractional part of y
+    fz0 = z - iz0;        // Fractional part of z
+    fw0 = w - iw0;        // Fractional part of w
+    fx1 = fx0 - 1.0f;
+    fy1 = fy0 - 1.0f;
+    fz1 = fz0 - 1.0f;
+    fw1 = fw0 - 1.0f;
+    ix1 = ( ix0 + 1 ) & 0xff;  // Wrap to 0..255
+    iy1 = ( iy0 + 1 ) & 0xff;
+    iz1 = ( iz0 + 1 ) & 0xff;
+    iw1 = ( iw0 + 1 ) & 0xff;
+    ix0 = ix0 & 0xff;
+    iy0 = iy0 & 0xff;
+    iz0 = iz0 & 0xff;
+    iw0 = iw0 & 0xff;
+
+    q = FADE( fw0 );
+    r = FADE( fz0 );
+    t = FADE( fy0 );
+    s = FADE( fx0 );
+
+    nxyz0 = grad(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx0, fy0, fz0, fw0);
+    nxyz1 = grad(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx0, fy0, fz0, fw1);
+    nxy0 = LERP( q, nxyz0, nxyz1 );
+        
+    nxyz0 = grad(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx0, fy0, fz1, fw0);
+    nxyz1 = grad(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx0, fy0, fz1, fw1);
+    nxy1 = LERP( q, nxyz0, nxyz1 );
+        
+    nx0 = LERP ( r, nxy0, nxy1 );
+
+    nxyz0 = grad(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx0, fy1, fz0, fw0);
+    nxyz1 = grad(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx0, fy1, fz0, fw1);
+    nxy0 = LERP( q, nxyz0, nxyz1 );
+        
+    nxyz0 = grad(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx0, fy1, fz1, fw0);
+    nxyz1 = grad(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx0, fy1, fz1, fw1);
+    nxy1 = LERP( q, nxyz0, nxyz1 );
+
+    nx1 = LERP ( r, nxy0, nxy1 );
+
+    n0 = LERP( t, nx0, nx1 );
+
+    nxyz0 = grad(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx1, fy0, fz0, fw0);
+    nxyz1 = grad(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx1, fy0, fz0, fw1);
+    nxy0 = LERP( q, nxyz0, nxyz1 );
+        
+    nxyz0 = grad(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx1, fy0, fz1, fw0);
+    nxyz1 = grad(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx1, fy0, fz1, fw1);
+    nxy1 = LERP( q, nxyz0, nxyz1 );
+
+    nx0 = LERP ( r, nxy0, nxy1 );
+
+    nxyz0 = grad(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx1, fy1, fz0, fw0);
+    nxyz1 = grad(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx1, fy1, fz0, fw1);
+    nxy0 = LERP( q, nxyz0, nxyz1 );
+        
+    nxyz0 = grad(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx1, fy1, fz1, fw0);
+    nxyz1 = grad(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx1, fy1, fz1, fw1);
+    nxy1 = LERP( q, nxyz0, nxyz1 );
+
+    nx1 = LERP ( r, nxy0, nxy1 );
+
+    n1 = LERP( t, nx0, nx1 );
+
+    return 0.87f * ( LERP( s, n0, n1 ) );
+}
+
+//---------------------------------------------------------------------
+/** 4D float Perlin periodic noise.
+ */
+
+float Noise1234::pnoise( float x, float y, float z, float w,
+                            int px, int py, int pz, int pw )
+{
+    int ix0, iy0, iz0, iw0, ix1, iy1, iz1, iw1;
+    float fx0, fy0, fz0, fw0, fx1, fy1, fz1, fw1;
+    float s, t, r, q;
+    float nxyz0, nxyz1, nxy0, nxy1, nx0, nx1, n0, n1;
+
+    ix0 = FASTFLOOR( x ); // Integer part of x
+    iy0 = FASTFLOOR( y ); // Integer part of y
+    iz0 = FASTFLOOR( z ); // Integer part of y
+    iw0 = FASTFLOOR( w ); // Integer part of w
+    fx0 = x - ix0;        // Fractional part of x
+    fy0 = y - iy0;        // Fractional part of y
+    fz0 = z - iz0;        // Fractional part of z
+    fw0 = w - iw0;        // Fractional part of w
+    fx1 = fx0 - 1.0f;
+    fy1 = fy0 - 1.0f;
+    fz1 = fz0 - 1.0f;
+    fw1 = fw0 - 1.0f;
+    ix1 = (( ix0 + 1 ) % px ) & 0xff;  // Wrap to 0..px-1 and wrap to 0..255
+    iy1 = (( iy0 + 1 ) % py ) & 0xff;  // Wrap to 0..py-1 and wrap to 0..255
+    iz1 = (( iz0 + 1 ) % pz ) & 0xff;  // Wrap to 0..pz-1 and wrap to 0..255
+    iw1 = (( iw0 + 1 ) % pw ) & 0xff;  // Wrap to 0..pw-1 and wrap to 0..255
+    ix0 = ( ix0 % px ) & 0xff;
+    iy0 = ( iy0 % py ) & 0xff;
+    iz0 = ( iz0 % pz ) & 0xff;
+    iw0 = ( iw0 % pw ) & 0xff;
+
+    q = FADE( fw0 );
+    r = FADE( fz0 );
+    t = FADE( fy0 );
+    s = FADE( fx0 );
+
+    nxyz0 = grad(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx0, fy0, fz0, fw0);
+    nxyz1 = grad(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx0, fy0, fz0, fw1);
+    nxy0 = LERP( q, nxyz0, nxyz1 );
+        
+    nxyz0 = grad(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx0, fy0, fz1, fw0);
+    nxyz1 = grad(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx0, fy0, fz1, fw1);
+    nxy1 = LERP( q, nxyz0, nxyz1 );
+        
+    nx0 = LERP ( r, nxy0, nxy1 );
+
+    nxyz0 = grad(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx0, fy1, fz0, fw0);
+    nxyz1 = grad(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx0, fy1, fz0, fw1);
+    nxy0 = LERP( q, nxyz0, nxyz1 );
+        
+    nxyz0 = grad(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx0, fy1, fz1, fw0);
+    nxyz1 = grad(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx0, fy1, fz1, fw1);
+    nxy1 = LERP( q, nxyz0, nxyz1 );
+
+    nx1 = LERP ( r, nxy0, nxy1 );
+
+    n0 = LERP( t, nx0, nx1 );
+
+    nxyz0 = grad(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx1, fy0, fz0, fw0);
+    nxyz1 = grad(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx1, fy0, fz0, fw1);
+    nxy0 = LERP( q, nxyz0, nxyz1 );
+        
+    nxyz0 = grad(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx1, fy0, fz1, fw0);
+    nxyz1 = grad(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx1, fy0, fz1, fw1);
+    nxy1 = LERP( q, nxyz0, nxyz1 );
+
+    nx0 = LERP ( r, nxy0, nxy1 );
+
+    nxyz0 = grad(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx1, fy1, fz0, fw0);
+    nxyz1 = grad(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx1, fy1, fz0, fw1);
+    nxy0 = LERP( q, nxyz0, nxyz1 );
+        
+    nxyz0 = grad(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx1, fy1, fz1, fw0);
+    nxyz1 = grad(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx1, fy1, fz1, fw1);
+    nxy1 = LERP( q, nxyz0, nxyz1 );
+
+    nx1 = LERP ( r, nxy0, nxy1 );
+
+    n1 = LERP( t, nx0, nx1 );
+
+    return 0.87f * ( LERP( s, n0, n1 ) );
+}
+
+//---------------------------------------------------------------------

+ 57 - 0
jni/love/src/libraries/noise1234/noise1234.h

@@ -0,0 +1,57 @@
+// Noise1234
+// Author: Stefan Gustavson ([email protected])
+//
+// This library is public domain software, released by the author
+// into the public domain in February 2011. You may do anything
+// you like with it. You may even remove all attributions,
+// but of course I'd appreciate it if you kept my name somewhere.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+
+/** \file
+		\brief Declares the Noise1234 class for producing Perlin noise.
+		\author Stefan Gustavson ([email protected])
+*/
+
+/*
+ * This is a clean, fast, modern and free Perlin noise class in C++.
+ * Being a stand-alone class with no external dependencies, it is
+ * highly reusable without source code modifications.
+ *
+ * Note:
+ * Replacing the "float" type with "double" can actually make this run faster
+ * on some platforms. A templatized version of Noise1234 could be useful.
+ */
+
+class Noise1234 {
+
+  public:
+    Noise1234() {}
+    ~Noise1234() {}
+
+/** 1D, 2D, 3D and 4D float Perlin noise, SL "noise()"
+ */
+    static float noise( float x );
+    static float noise( float x, float y );
+    static float noise( float x, float y, float z );
+    static float noise( float x, float y, float z, float w );
+
+/** 1D, 2D, 3D and 4D float Perlin periodic noise, SL "pnoise()"
+ */
+    static float pnoise( float x, int px );
+    static float pnoise( float x, float y, int px, int py );
+    static float pnoise( float x, float y, float z, int px, int py, int pz );
+    static float pnoise( float x, float y, float z, float w,
+                              int px, int py, int pz, int pw );
+
+  private:
+    static unsigned char perm[];
+    static float  grad( int hash, float x );
+    static float  grad( int hash, float x, float y );
+    static float  grad( int hash, float x, float y , float z );
+    static float  grad( int hash, float x, float y, float z, float t );
+
+};

+ 3 - 263
jni/love/src/libraries/noise1234/simplexnoise1234.cpp

@@ -13,6 +13,9 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 // General Public License for more details.
 
+// Modified by the LOVE Development Team to remove 3D and 4D implementations due
+// to patent issues.
+
 /** \file
 		\brief Implements the SimplexNoise1234 class for producing Perlin simplex noise.
 		\author Stefan Gustavson ([email protected])
@@ -114,34 +117,6 @@ float  SimplexNoise1234::grad( int hash, float x, float y ) {
     return ((h&1)? -u : u) + ((h&2)? -2.0f*v : 2.0f*v);
 }
 
-float  SimplexNoise1234::grad( int hash, float x, float y , float z ) {
-    int h = hash & 15;     // Convert low 4 bits of hash code into 12 simple
-    float u = h<8 ? x : y; // gradient directions, and compute dot product.
-    float v = h<4 ? y : h==12||h==14 ? x : z; // Fix repeats at h = 12 to 15
-    return ((h&1)? -u : u) + ((h&2)? -v : v);
-}
-
-float  SimplexNoise1234::grad( int hash, float x, float y, float z, float t ) {
-    int h = hash & 31;      // Convert low 5 bits of hash code into 32 simple
-    float u = h<24 ? x : y; // gradient directions, and compute dot product.
-    float v = h<16 ? y : z;
-    float w = h<8 ? z : t;
-    return ((h&1)? -u : u) + ((h&2)? -v : v) + ((h&4)? -w : w);
-}
-
-  // A lookup table to traverse the simplex around a given point in 4D.
-  // Details can be found where this table is used, in the 4D noise method.
-  /* TODO: This should not be required, backport it from Bill's GLSL code! */
-  static unsigned char simplex[64][4] = {
-    {0,1,2,3},{0,1,3,2},{0,0,0,0},{0,2,3,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,2,3,0},
-    {0,2,1,3},{0,0,0,0},{0,3,1,2},{0,3,2,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,3,2,0},
-    {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},
-    {1,2,0,3},{0,0,0,0},{1,3,0,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,3,0,1},{2,3,1,0},
-    {1,0,2,3},{1,0,3,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,0,3,1},{0,0,0,0},{2,1,3,0},
-    {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},
-    {2,0,1,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,0,1,2},{3,0,2,1},{0,0,0,0},{3,1,2,0},
-    {2,1,0,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,1,0,2},{0,0,0,0},{3,2,0,1},{3,2,1,0}};
-
 // 1D simplex noise
 float SimplexNoise1234::noise(float x) {
 
@@ -233,238 +208,3 @@ float SimplexNoise1234::noise(float x, float y) {
     // The result is scaled to return values in the interval [-1,1].
     return 45.23f * (n0 + n1 + n2); // TODO: The scale factor is preliminary!
   }
-
-// 3D simplex noise
-float SimplexNoise1234::noise(float x, float y, float z) {
-
-// Simple skewing factors for the 3D case
-#define F3 0.333333333
-#define G3 0.166666667
-
-    float n0, n1, n2, n3; // Noise contributions from the four corners
-
-    // Skew the input space to determine which simplex cell we're in
-    float s = (x+y+z)*F3; // Very nice and simple skew factor for 3D
-    float xs = x+s;
-    float ys = y+s;
-    float zs = z+s;
-    int i = FASTFLOOR(xs);
-    int j = FASTFLOOR(ys);
-    int k = FASTFLOOR(zs);
-
-    float t = (float)(i+j+k)*G3; 
-    float X0 = i-t; // Unskew the cell origin back to (x,y,z) space
-    float Y0 = j-t;
-    float Z0 = k-t;
-    float x0 = x-X0; // The x,y,z distances from the cell origin
-    float y0 = y-Y0;
-    float z0 = z-Z0;
-
-    // For the 3D case, the simplex shape is a slightly irregular tetrahedron.
-    // Determine which simplex we are in.
-    int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
-    int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
-
-/* This code would benefit from a backport from the GLSL version! */
-    if(x0>=y0) {
-      if(y0>=z0)
-        { i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } // X Y Z order
-        else if(x0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } // X Z Y order
-        else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } // Z X Y order
-      }
-    else { // x0<y0
-      if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } // Z Y X order
-      else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } // Y Z X order
-      else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } // Y X Z order
-    }
-
-    // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
-    // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
-    // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
-    // c = 1/6.
-
-    float x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords
-    float y1 = y0 - j1 + G3;
-    float z1 = z0 - k1 + G3;
-    float x2 = x0 - i2 + 2.0f*G3; // Offsets for third corner in (x,y,z) coords
-    float y2 = y0 - j2 + 2.0f*G3;
-    float z2 = z0 - k2 + 2.0f*G3;
-    float x3 = x0 - 1.0f + 3.0f*G3; // Offsets for last corner in (x,y,z) coords
-    float y3 = y0 - 1.0f + 3.0f*G3;
-    float z3 = z0 - 1.0f + 3.0f*G3;
-
-    // Wrap the integer indices at 256, to avoid indexing perm[] out of bounds
-    int ii = i & 0xff;
-    int jj = j & 0xff;
-    int kk = k & 0xff;
-
-    // Calculate the contribution from the four corners
-    float t0 = 0.6f - x0*x0 - y0*y0 - z0*z0;
-    if(t0 < 0.0f) n0 = 0.0f;
-    else {
-      t0 *= t0;
-      n0 = t0 * t0 * grad(perm[ii+perm[jj+perm[kk]]], x0, y0, z0);
-    }
-
-    float t1 = 0.6f - x1*x1 - y1*y1 - z1*z1;
-    if(t1 < 0.0f) n1 = 0.0f;
-    else {
-      t1 *= t1;
-      n1 = t1 * t1 * grad(perm[ii+i1+perm[jj+j1+perm[kk+k1]]], x1, y1, z1);
-    }
-
-    float t2 = 0.6f - x2*x2 - y2*y2 - z2*z2;
-    if(t2 < 0.0f) n2 = 0.0f;
-    else {
-      t2 *= t2;
-      n2 = t2 * t2 * grad(perm[ii+i2+perm[jj+j2+perm[kk+k2]]], x2, y2, z2);
-    }
-
-    float t3 = 0.6f - x3*x3 - y3*y3 - z3*z3;
-    if(t3<0.0f) n3 = 0.0f;
-    else {
-      t3 *= t3;
-      n3 = t3 * t3 * grad(perm[ii+1+perm[jj+1+perm[kk+1]]], x3, y3, z3);
-    }
-
-    // Add contributions from each corner to get the final noise value.
-    // The result is scaled to stay just inside [-1,1]
-    return 32.74f * (n0 + n1 + n2 + n3); // TODO: The scale factor is preliminary!
-  }
-
-
-// 4D simplex noise
-float SimplexNoise1234::noise(float x, float y, float z, float w) {
-  
-  // The skewing and unskewing factors are hairy again for the 4D case
-#define F4 0.309016994 // F4 = (Math.sqrt(5.0)-1.0)/4.0
-#define G4 0.138196601 // G4 = (5.0-Math.sqrt(5.0))/20.0
-
-    float n0, n1, n2, n3, n4; // Noise contributions from the five corners
-
-    // Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in
-    float s = (x + y + z + w) * F4; // Factor for 4D skewing
-    float xs = x + s;
-    float ys = y + s;
-    float zs = z + s;
-    float ws = w + s;
-    int i = FASTFLOOR(xs);
-    int j = FASTFLOOR(ys);
-    int k = FASTFLOOR(zs);
-    int l = FASTFLOOR(ws);
-
-    float t = (i + j + k + l) * G4; // Factor for 4D unskewing
-    float X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space
-    float Y0 = j - t;
-    float Z0 = k - t;
-    float W0 = l - t;
-
-    float x0 = x - X0;  // The x,y,z,w distances from the cell origin
-    float y0 = y - Y0;
-    float z0 = z - Z0;
-    float w0 = w - W0;
-
-    // For the 4D case, the simplex is a 4D shape I won't even try to describe.
-    // To find out which of the 24 possible simplices we're in, we need to
-    // determine the magnitude ordering of x0, y0, z0 and w0.
-    // The method below is a good way of finding the ordering of x,y,z,w and
-    // then find the correct traversal order for the simplex we’re in.
-    // First, six pair-wise comparisons are performed between each possible pair
-    // of the four coordinates, and the results are used to add up binary bits
-    // for an integer index.
-    int c1 = (x0 > y0) ? 32 : 0;
-    int c2 = (x0 > z0) ? 16 : 0;
-    int c3 = (y0 > z0) ? 8 : 0;
-    int c4 = (x0 > w0) ? 4 : 0;
-    int c5 = (y0 > w0) ? 2 : 0;
-    int c6 = (z0 > w0) ? 1 : 0;
-    int c = c1 + c2 + c3 + c4 + c5 + c6;
-
-    int i1, j1, k1, l1; // The integer offsets for the second simplex corner
-    int i2, j2, k2, l2; // The integer offsets for the third simplex corner
-    int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner
-
-    // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order.
-    // Many values of c will never occur, since e.g. x>y>z>w makes x<z, y<w and x<w
-    // impossible. Only the 24 indices which have non-zero entries make any sense.
-    // We use a thresholding to set the coordinates in turn from the largest magnitude.
-    // The number 3 in the "simplex" array is at the position of the largest coordinate.
-    i1 = simplex[c][0]>=3 ? 1 : 0;
-    j1 = simplex[c][1]>=3 ? 1 : 0;
-    k1 = simplex[c][2]>=3 ? 1 : 0;
-    l1 = simplex[c][3]>=3 ? 1 : 0;
-    // The number 2 in the "simplex" array is at the second largest coordinate.
-    i2 = simplex[c][0]>=2 ? 1 : 0;
-    j2 = simplex[c][1]>=2 ? 1 : 0;
-    k2 = simplex[c][2]>=2 ? 1 : 0;
-    l2 = simplex[c][3]>=2 ? 1 : 0;
-    // The number 1 in the "simplex" array is at the second smallest coordinate.
-    i3 = simplex[c][0]>=1 ? 1 : 0;
-    j3 = simplex[c][1]>=1 ? 1 : 0;
-    k3 = simplex[c][2]>=1 ? 1 : 0;
-    l3 = simplex[c][3]>=1 ? 1 : 0;
-    // The fifth corner has all coordinate offsets = 1, so no need to look that up.
-
-    float x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords
-    float y1 = y0 - j1 + G4;
-    float z1 = z0 - k1 + G4;
-    float w1 = w0 - l1 + G4;
-    float x2 = x0 - i2 + 2.0f*G4; // Offsets for third corner in (x,y,z,w) coords
-    float y2 = y0 - j2 + 2.0f*G4;
-    float z2 = z0 - k2 + 2.0f*G4;
-    float w2 = w0 - l2 + 2.0f*G4;
-    float x3 = x0 - i3 + 3.0f*G4; // Offsets for fourth corner in (x,y,z,w) coords
-    float y3 = y0 - j3 + 3.0f*G4;
-    float z3 = z0 - k3 + 3.0f*G4;
-    float w3 = w0 - l3 + 3.0f*G4;
-    float x4 = x0 - 1.0f + 4.0f*G4; // Offsets for last corner in (x,y,z,w) coords
-    float y4 = y0 - 1.0f + 4.0f*G4;
-    float z4 = z0 - 1.0f + 4.0f*G4;
-    float w4 = w0 - 1.0f + 4.0f*G4;
-
-    // Wrap the integer indices at 256, to avoid indexing perm[] out of bounds
-    int ii = i & 0xff;
-    int jj = j & 0xff;
-    int kk = k & 0xff;
-    int ll = l & 0xff;
-
-    // Calculate the contribution from the five corners
-    float t0 = 0.6f - x0*x0 - y0*y0 - z0*z0 - w0*w0;
-    if(t0 < 0.0f) n0 = 0.0f;
-    else {
-      t0 *= t0;
-      n0 = t0 * t0 * grad(perm[ii+perm[jj+perm[kk+perm[ll]]]], x0, y0, z0, w0);
-    }
-
-   float t1 = 0.6f - x1*x1 - y1*y1 - z1*z1 - w1*w1;
-    if(t1 < 0.0f) n1 = 0.0f;
-    else {
-      t1 *= t1;
-      n1 = t1 * t1 * grad(perm[ii+i1+perm[jj+j1+perm[kk+k1+perm[ll+l1]]]], x1, y1, z1, w1);
-    }
-
-   float t2 = 0.6f - x2*x2 - y2*y2 - z2*z2 - w2*w2;
-    if(t2 < 0.0f) n2 = 0.0f;
-    else {
-      t2 *= t2;
-      n2 = t2 * t2 * grad(perm[ii+i2+perm[jj+j2+perm[kk+k2+perm[ll+l2]]]], x2, y2, z2, w2);
-    }
-
-   float t3 = 0.6f - x3*x3 - y3*y3 - z3*z3 - w3*w3;
-    if(t3 < 0.0f) n3 = 0.0f;
-    else {
-      t3 *= t3;
-      n3 = t3 * t3 * grad(perm[ii+i3+perm[jj+j3+perm[kk+k3+perm[ll+l3]]]], x3, y3, z3, w3);
-    }
-
-   float t4 = 0.6f - x4*x4 - y4*y4 - z4*z4 - w4*w4;
-    if(t4 < 0.0f) n4 = 0.0f;
-    else {
-      t4 *= t4;
-      n4 = t4 * t4 * grad(perm[ii+1+perm[jj+1+perm[kk+1+perm[ll+1]]]], x4, y4, z4, w4);
-    }
-
-    // Sum up and scale the result to cover the range [-1,1]
-    return 27.3f * (n0 + n1 + n2 + n3 + n4); // TODO: The scale factor is preliminary!
-  }
-//---------------------------------------------------------------------

+ 4 - 13
jni/love/src/libraries/noise1234/simplexnoise1234.h

@@ -13,6 +13,9 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 // General Public License for more details.
 
+// Modified by the LOVE Development Team to remove 3D and 4D implementations due
+// to patent issues.
+
 /** \file
 		\brief Declares the SimplexNoise1234 class for producing Perlin simplex noise.
 		\author Stefan Gustavson ([email protected])
@@ -35,26 +38,14 @@ class SimplexNoise1234 {
     SimplexNoise1234() {}
     ~SimplexNoise1234() {}
 
-/** 1D, 2D, 3D and 4D float Perlin noise
+/** 1D and 2D float Perlin noise
  */
     static float noise( float x );
     static float noise( float x, float y );
-    static float noise( float x, float y, float z );
-    static float noise( float x, float y, float z, float w );
-
-/** 1D, 2D, 3D and 4D float Perlin noise, with a specified integer period
- */
-    static float pnoise( float x, int px );
-    static float pnoise( float x, float y, int px, int py );
-    static float pnoise( float x, float y, float z, int px, int py, int pz );
-    static float pnoise( float x, float y, float z, float w,
-                              int px, int py, int pz, int pw );
 
   private:
     static unsigned char perm[];
     static float  grad( int hash, float x );
     static float  grad( int hash, float x, float y );
-    static float  grad( int hash, float x, float y , float z );
-    static float  grad( int hash, float x, float y, float z, float t );
 
 };

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 573 - 134
jni/love/src/libraries/stb/stb_image.h


+ 41 - 6
jni/love/src/love.cpp

@@ -41,9 +41,13 @@ extern "C" {
 #endif // LOVE_WINDOWS
 
 #ifdef LOVE_MACOSX
-#include "OSX.h"
+#include "common/OSX.h"
 #endif // LOVE_MACOSX
 
+#ifdef LOVE_IOS
+#include "common/iOS.h"
+#endif
+
 #ifdef LOVE_WINDOWS
 extern "C"
 {
@@ -53,7 +57,7 @@ extern "C"
 // systems is less mediocre?
 LOVE_EXPORT DWORD NvOptimusEnablement = 0x00000001;
 }
-#endif
+#endif // LOVE_WINDOWS
 
 #ifdef LOVE_LEGENDARY_UTF8_ARGV_HACK
 
@@ -106,6 +110,7 @@ static void get_app_arguments(int argc, char **argv, int &new_argc, char **&new_
 			temp_argv.push_back(std::string(argv[i]));
 	}
 
+#ifdef LOVE_MACOSX
 	// Check for a drop file string.
 	std::string dropfilestr = love::osx::checkDropEvents();
 	if (!dropfilestr.empty())
@@ -113,15 +118,24 @@ static void get_app_arguments(int argc, char **argv, int &new_argc, char **&new_
 		temp_argv.insert(temp_argv.begin() + 1, dropfilestr);
 	}
 	else
+#endif
 	{
 		// If it exists, add the love file in love.app/Contents/Resources/ to argv.
-		std::string loveResourcesPath = love::osx::getLoveInResources();
+		std::string loveResourcesPath;
+		bool fused = true;
+#if defined(LOVE_MACOSX)
+		loveResourcesPath = love::osx::getLoveInResources();
+#elif defined(LOVE_IOS)
+		loveResourcesPath = love::ios::getLoveInResources(fused);
+#endif
 		if (!loveResourcesPath.empty())
 		{
-			// Run in pseudo-fused mode.
 			std::vector<std::string>::iterator it = temp_argv.begin();
 			it = temp_argv.insert(it + 1, loveResourcesPath);
-			temp_argv.insert(it + 1, std::string("--fused"));
+
+			// Run in pseudo-fused mode.
+			if (fused)
+				temp_argv.insert(it + 1, std::string("--fused"));
 		}
 	}
 
@@ -190,10 +204,25 @@ static int l_print_sdl_log (lua_State *L) {
 
 int main(int argc, char **argv)
 {
+	int retval = 0;
+
 #ifdef LOVE_ANDROID
 	SDL_SetHint("LOVE_GRAPHICS_USE_OPENGLES", "1");
 #endif
 
+#ifdef LOVE_IOS
+	int orig_argc = argc;
+	char **orig_argv = argv;
+
+	// on iOS we should never programmatically exit the app, so we'll just
+	// "restart" when that is attempted. Games which use threads might cause
+	// some issues if the threads aren't cleaned up properly...
+	while (true)
+	{
+		argc = orig_argc;
+		argv = orig_argv;
+#endif
+
 #ifdef LOVE_LEGENDARY_UTF8_ARGV_HACK
 	int hack_argc = 0;	char **hack_argv = 0;
 	get_utf8_arguments(hack_argc, hack_argv);
@@ -285,7 +314,6 @@ int main(int argc, char **argv)
 	// Call the returned boot function.
 	lua_call(L, 0, 1);
 
-	int retval = 0;
 	if (lua_isnumber(L, -1))
 		retval = (int) lua_tonumber(L, -1);
 
@@ -299,7 +327,14 @@ int main(int argc, char **argv)
 		delete [] hack_argv;
 	}
 #endif // LOVE_LEGENDARY_UTF8_ARGV_HACK || LOVE_LEGENDARY_APP_ARGV_HACK
+
+#ifdef LOVE_IOS
+	} // while (true)
+#endif
+
+#ifdef LOVE_ANDROID
 	SDL_Quit();
+#endif
 
 	return retval;
 }

+ 3 - 3
jni/love/src/modules/audio/Audio.cpp

@@ -29,11 +29,11 @@ StringMap<Audio::DistanceModel, Audio::DISTANCE_MAX_ENUM>::Entry Audio::distance
 {
 	{"none", Audio::DISTANCE_NONE},
 	{"inverse", Audio::DISTANCE_INVERSE},
-	{"inverse clamped", Audio::DISTANCE_INVERSE_CLAMPED},
+	{"inverseclamped", Audio::DISTANCE_INVERSE_CLAMPED},
 	{"linear", Audio::DISTANCE_LINEAR},
-	{"linear clamped", Audio::DISTANCE_LINEAR_CLAMPED},
+	{"linearclamped", Audio::DISTANCE_LINEAR_CLAMPED},
 	{"exponent", Audio::DISTANCE_EXPONENT},
-	{"exponent clamped", Audio::DISTANCE_EXPONENT_CLAMPED}
+	{"exponentclamped", Audio::DISTANCE_EXPONENT_CLAMPED}
 };
 
 StringMap<Audio::DistanceModel, Audio::DISTANCE_MAX_ENUM> Audio::distanceModels(Audio::distanceModelEntries, sizeof(Audio::distanceModelEntries));

+ 5 - 0
jni/love/src/modules/audio/Source.cpp

@@ -34,6 +34,11 @@ Source::~Source()
 {
 }
 
+Source::Type Source::getType() const
+{
+	return type;
+}
+
 bool Source::getConstant(const char *in, Type &out)
 {
 	return types.find(in, out);

+ 2 - 1
jni/love/src/modules/audio/Source.h

@@ -88,7 +88,6 @@ public:
 
 	virtual void setLooping(bool looping) = 0;
 	virtual bool isLooping() const = 0;
-	virtual bool isStatic() const = 0;
 
 	virtual void setMinVolume(float volume) = 0;
 	virtual float getMinVolume() const = 0;
@@ -103,6 +102,7 @@ public:
 	virtual float getMaxDistance() const = 0;
 
 	virtual int getChannels() const = 0;
+	virtual Type getType() const;
 
 	static bool getConstant(const char *in, Type &out);
 	static bool getConstant(Type in, const char  *&out);
@@ -110,6 +110,7 @@ public:
 	static bool getConstant(Unit in, const char  *&out);
 
 protected:
+
 	Type type;
 
 private:

+ 0 - 5
jni/love/src/modules/audio/null/Source.cpp

@@ -170,11 +170,6 @@ bool Source::isLooping() const
 	return looping;
 }
 
-bool Source::isStatic() const
-{
-	return (type == TYPE_STATIC);
-}
-
 void Source::setMinVolume(float volume)
 {
 	this->minVolume = volume;

+ 0 - 1
jni/love/src/modules/audio/null/Source.h

@@ -66,7 +66,6 @@ public:
 	virtual bool isRelative() const;
 	void setLooping(bool looping);
 	bool isLooping() const;
-	bool isStatic() const;
 	virtual void setMinVolume(float volume);
 	virtual float getMinVolume() const;
 	virtual void setMaxVolume(float volume);

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

@@ -36,9 +36,14 @@
 #include "thread/threads.h"
 
 // OpenAL
-#ifdef LOVE_MACOSX_USE_FRAMEWORKS // Frameworks have different include paths.
+#ifdef LOVE_APPLE_USE_FRAMEWORKS // Frameworks have different include paths.
+#ifdef LOVE_IOS
+#include <OpenAL/alc.h>
+#include <OpenAL/al.h>
+#else
 #include <OpenAL-Soft/alc.h>
 #include <OpenAL-Soft/al.h>
+#endif
 #else
 #include <AL/alc.h>
 #include <AL/al.h>

+ 4 - 1
jni/love/src/modules/audio/openal/Pool.cpp

@@ -56,7 +56,9 @@ Pool::Pool()
 	// Create the mutex.
 	mutex = thread::newMutex();
 
+#ifdef AL_SOFT_direct_channels
 	ALboolean hasext = alIsExtensionPresent("AL_SOFT_direct_channels");
+#endif
 
 	// Make all sources available initially.
 	for (int i = 0; i < totalSources; i++)
@@ -126,7 +128,7 @@ void Pool::update()
 
 int Pool::getSourceCount() const
 {
-	return playing.size();
+	return (int) playing.size();
 }
 
 int Pool::getMaxSources() const
@@ -180,6 +182,7 @@ void Pool::stop()
 	for (const auto &i : playing)
 	{
 		i.first->stopAtomic();
+		i.first->rewindAtomic();
 		i.first->release();
 		available.push(i.second);
 	}

+ 8 - 1
jni/love/src/modules/audio/openal/Pool.h

@@ -32,10 +32,17 @@
 #include "thread/threads.h"
 
 // OpenAL
-#ifdef LOVE_MACOSX_USE_FRAMEWORKS
+#ifdef LOVE_APPLE_USE_FRAMEWORKS
+#ifdef LOVE_IOS
+#include <OpenAL/alc.h>
+#include <OpenAL/al.h>
+#include <OpenAL/oalMacOSX_OALExtensions.h>
+#include <OpenAL/oalStaticBufferExtension.h>
+#else
 #include <OpenAL-Soft/alc.h>
 #include <OpenAL-Soft/al.h>
 #include <OpenAL-Soft/alext.h>
+#endif
 #else
 #include <AL/alc.h>
 #include <AL/al.h>

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

@@ -25,6 +25,7 @@
 // STD
 #include <iostream>
 #include <float.h>
+#include <algorithm>
 
 namespace love
 {
@@ -33,6 +34,13 @@ namespace audio
 namespace openal
 {
 
+#ifdef LOVE_IOS
+// OpenAL on iOS barfs if the max distance is +inf.
+static const float MAX_ATTENUATION_DISTANCE = 1000000.0f;
+#else
+static const float MAX_ATTENUATION_DISTANCE = FLT_MAX;
+#endif
+
 class InvalidFormatException : public love::Exception
 {
 public:
@@ -44,6 +52,18 @@ public:
 
 };
 
+class SpatialSupportException : public love::Exception
+{
+public:
+
+	SpatialSupportException()
+		: Exception("This spatial audio functionality is only available for mono Sources. \
+Ensure the Source is not multi-channel before calling this function.")
+	{
+	}
+
+};
+
 StaticDataBuffer::StaticDataBuffer(ALenum format, const ALvoid *data, ALsizei size, ALsizei freq)
 {
 	alGenBuffers(1, &buffer);
@@ -69,7 +89,7 @@ Source::Source(Pool *pool, love::sound::SoundData *soundData)
 	, maxVolume(1.0f)
 	, referenceDistance(1.0f)
 	, rolloffFactor(1.0f)
-	, maxDistance(FLT_MAX)
+	, maxDistance(MAX_ATTENUATION_DISTANCE)
 	, cone()
 	, offsetSamples(0)
 	, offsetSeconds(0)
@@ -82,7 +102,7 @@ Source::Source(Pool *pool, love::sound::SoundData *soundData)
 	if (fmt == 0)
 		throw InvalidFormatException(soundData->getChannels(), soundData->getBitDepth());
 
-	staticBuffer.set(new StaticDataBuffer(fmt, soundData->getData(), soundData->getSize(), soundData->getSampleRate()));
+	staticBuffer.set(new StaticDataBuffer(fmt, soundData->getData(), (ALsizei) soundData->getSize(), soundData->getSampleRate()));
 
 	// The buffer has a +2 retain count right now, but we want it to have +1.
 	staticBuffer->release();
@@ -108,7 +128,7 @@ Source::Source(Pool *pool, love::sound::Decoder *decoder)
 	, maxVolume(1.0f)
 	, referenceDistance(1.0f)
 	, rolloffFactor(1.0f)
-	, maxDistance(FLT_MAX)
+	, maxDistance(MAX_ATTENUATION_DISTANCE)
 	, cone()
 	, offsetSamples(0)
 	, offsetSeconds(0)
@@ -245,13 +265,14 @@ bool Source::isPaused() const
 
 bool Source::isFinished() const
 {
-	return type == TYPE_STATIC ? isStopped() : isStopped() && !isLooping() && decoder->isFinished();
+	return type == TYPE_STATIC ? isStopped() : (isStopped() && !isLooping() && decoder->isFinished());
 }
 
 bool Source::update()
 {
 	if (!valid)
 		return false;
+
 	if (type == TYPE_STATIC)
 	{
 		// Looping mode could have changed.
@@ -290,8 +311,10 @@ bool Source::update()
 			streamAtomic(buffer, decoder.get());
 			alSourceQueueBuffers(source, 1, &buffer);
 		}
+
 		return true;
 	}
+
 	return false;
 }
 
@@ -319,9 +342,7 @@ float Source::getPitch() const
 void Source::setVolume(float volume)
 {
 	if (valid)
-	{
 		alSourcef(source, AL_GAIN, volume);
-	}
 
 	this->volume = volume;
 }
@@ -354,9 +375,7 @@ void Source::seekAtomic(float offset, void *unit)
 				decoder->seek(offset);
 			}
 			else
-			{
 				alSourcef(source, AL_SAMPLE_OFFSET, offset);
-			}
 			break;
 		case Source::UNIT_SECONDS:
 		default:
@@ -367,9 +386,7 @@ void Source::seekAtomic(float offset, void *unit)
 				offsetSamples = offset * decoder->getSampleRate();
 			}
 			else
-			{
 				alSourcef(source, AL_SEC_OFFSET, offset);
-			}
 			break;
 		}
 		if (type == TYPE_STREAM)
@@ -423,6 +440,9 @@ float Source::tell(Source::Unit unit)
 
 void Source::setPosition(float *v)
 {
+	if (channels > 1)
+		throw SpatialSupportException();
+
 	if (valid)
 		alSourcefv(source, AL_POSITION, v);
 
@@ -431,6 +451,9 @@ void Source::setPosition(float *v)
 
 void Source::getPosition(float *v) const
 {
+	if (channels > 1)
+		throw SpatialSupportException();
+
 	if (valid)
 		alGetSourcefv(source, AL_POSITION, v);
 	else
@@ -439,6 +462,9 @@ void Source::getPosition(float *v) const
 
 void Source::setVelocity(float *v)
 {
+	if (channels > 1)
+		throw SpatialSupportException();
+
 	if (valid)
 		alSourcefv(source, AL_VELOCITY, v);
 
@@ -447,6 +473,9 @@ void Source::setVelocity(float *v)
 
 void Source::getVelocity(float *v) const
 {
+	if (channels > 1)
+		throw SpatialSupportException();
+
 	if (valid)
 		alGetSourcefv(source, AL_VELOCITY, v);
 	else
@@ -455,6 +484,9 @@ void Source::getVelocity(float *v) const
 
 void Source::setDirection(float *v)
 {
+	if (channels > 1)
+		throw SpatialSupportException();
+
 	if (valid)
 		alSourcefv(source, AL_DIRECTION, v);
 	else
@@ -463,6 +495,9 @@ void Source::setDirection(float *v)
 
 void Source::getDirection(float *v) const
 {
+	if (channels > 1)
+		throw SpatialSupportException();
+
 	if (valid)
 		alGetSourcefv(source, AL_DIRECTION, v);
 	else
@@ -471,8 +506,11 @@ void Source::getDirection(float *v) const
 
 void Source::setCone(float innerAngle, float outerAngle, float outerVolume)
 {
-	cone.innerAngle = (int) LOVE_TODEG(innerAngle);
-	cone.outerAngle = (int) LOVE_TODEG(outerAngle);
+	if (channels > 1)
+		throw SpatialSupportException();
+
+	cone.innerAngle  = (int) LOVE_TODEG(innerAngle);
+	cone.outerAngle  = (int) LOVE_TODEG(outerAngle);
 	cone.outerVolume = outerVolume;
 
 	if (valid)
@@ -485,13 +523,19 @@ void Source::setCone(float innerAngle, float outerAngle, float outerVolume)
 
 void Source::getCone(float &innerAngle, float &outerAngle, float &outerVolume) const
 {
-	innerAngle = LOVE_TORAD(cone.innerAngle);
-	outerAngle = LOVE_TORAD(cone.outerAngle);
+	if (channels > 1)
+		throw SpatialSupportException();
+
+	innerAngle  = LOVE_TORAD(cone.innerAngle);
+	outerAngle  = LOVE_TORAD(cone.outerAngle);
 	outerVolume = cone.outerVolume;
 }
 
 void Source::setRelative(bool enable)
 {
+	if (channels > 1)
+		throw SpatialSupportException();
+
 	if (valid)
 		alSourcei(source, AL_SOURCE_RELATIVE, relative ? AL_TRUE : AL_FALSE);
 
@@ -500,15 +544,18 @@ void Source::setRelative(bool enable)
 
 bool Source::isRelative() const
 {
+	if (channels > 1)
+		throw SpatialSupportException();
+
 	return relative;
 }
 
-void Source::setLooping(bool looping)
+void Source::setLooping(bool enable)
 {
 	if (valid && type == TYPE_STATIC)
-		alSourcei(source, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
+		alSourcei(source, AL_LOOPING, enable ? AL_TRUE : AL_FALSE);
 
-	this->looping = looping;
+	looping = enable;
 }
 
 bool Source::isLooping() const
@@ -563,9 +610,7 @@ void Source::stopAtomic()
 	if (valid)
 	{
 		if (type == TYPE_STATIC)
-		{
 			alSourceStop(source);
-		}
 		else if (type == TYPE_STREAM)
 		{
 			alSourceStop(source);
@@ -578,8 +623,10 @@ void Source::stopAtomic()
 				alSourceUnqueueBuffers(source, 1, &buffer);
 			}
 		}
+
 		alSourcei(source, AL_BUFFER, AL_NONE);
 	}
+
 	toLoop = 0;
 	valid = false;
 }
@@ -644,7 +691,7 @@ void Source::reset()
 	alSourcef(source, AL_REFERENCE_DISTANCE, referenceDistance);
 	alSourcef(source, AL_ROLLOFF_FACTOR, rolloffFactor);
 	alSourcef(source, AL_MAX_DISTANCE, maxDistance);
-	alSourcei(source, AL_LOOPING, isStatic() && isLooping() ? AL_TRUE : AL_FALSE);
+	alSourcei(source, AL_LOOPING, (type == TYPE_STATIC) && isLooping() ? AL_TRUE : AL_FALSE);
 	alSourcei(source, AL_SOURCE_RELATIVE, relative ? AL_TRUE : AL_FALSE);
 	alSourcei(source, AL_CONE_INNER_ANGLE, cone.innerAngle);
 	alSourcei(source, AL_CONE_OUTER_ANGLE, cone.outerAngle);
@@ -721,19 +768,12 @@ int Source::streamAtomic(ALuint buffer, love::sound::Decoder *d)
 	return decoded;
 }
 
-bool Source::isStatic() const
-{
-	return (type == TYPE_STATIC);
-}
-
 void Source::setMinVolume(float volume)
 {
 	if (valid)
-	{
 		alSourcef(source, AL_MIN_GAIN, volume);
-	}
 
-	this->minVolume = volume;
+	minVolume = volume;
 }
 
 float Source::getMinVolume() const
@@ -752,11 +792,9 @@ float Source::getMinVolume() const
 void Source::setMaxVolume(float volume)
 {
 	if (valid)
-	{
 		alSourcef(source, AL_MAX_GAIN, volume);
-	}
 
-	this->maxVolume = volume;
+	maxVolume = volume;
 }
 
 float Source::getMaxVolume() const
@@ -769,21 +807,25 @@ float Source::getMaxVolume() const
 	}
 
 	// In case the Source isn't playing.
-	return this->maxVolume;
+	return maxVolume;
 }
 
 void Source::setReferenceDistance(float distance)
 {
+	if (channels > 1)
+		throw SpatialSupportException();
+
 	if (valid)
-	{
 		alSourcef(source, AL_REFERENCE_DISTANCE, distance);
-	}
 
-	this->referenceDistance = distance;
+	referenceDistance = distance;
 }
 
 float Source::getReferenceDistance() const
 {
+	if (channels > 1)
+		throw SpatialSupportException();
+
 	if (valid)
 	{
 		ALfloat f;
@@ -792,21 +834,25 @@ float Source::getReferenceDistance() const
 	}
 
 	// In case the Source isn't playing.
-	return this->referenceDistance;
+	return referenceDistance;
 }
 
 void Source::setRolloffFactor(float factor)
 {
+	if (channels > 1)
+		throw SpatialSupportException();
+
 	if (valid)
-	{
 		alSourcef(source, AL_ROLLOFF_FACTOR, factor);
-	}
 
-	this->rolloffFactor = factor;
+	rolloffFactor = factor;
 }
 
 float Source::getRolloffFactor() const
 {
+	if (channels > 1)
+		throw SpatialSupportException();
+
 	if (valid)
 	{
 		ALfloat f;
@@ -815,21 +861,27 @@ float Source::getRolloffFactor() const
 	}
 
 	// In case the Source isn't playing.
-	return this->rolloffFactor;
+	return rolloffFactor;
 }
 
 void Source::setMaxDistance(float distance)
 {
+	if (channels > 1)
+		throw SpatialSupportException();
+
+	distance = std::min(distance, MAX_ATTENUATION_DISTANCE);
+
 	if (valid)
-	{
 		alSourcef(source, AL_MAX_DISTANCE, distance);
-	}
 
-	this->maxDistance = distance;
+	maxDistance = distance;
 }
 
 float Source::getMaxDistance() const
 {
+	if (channels > 1)
+		throw SpatialSupportException();
+
 	if (valid)
 	{
 		ALfloat f;
@@ -838,7 +890,7 @@ float Source::getMaxDistance() const
 	}
 
 	// In case the Source isn't playing.
-	return this->maxDistance;
+	return maxDistance;
 }
 
 int Source::getChannels() const

+ 9 - 11
jni/love/src/modules/audio/openal/Source.h

@@ -29,9 +29,14 @@
 #include "sound/Decoder.h"
 
 // OpenAL
-#ifdef LOVE_MACOSX_USE_FRAMEWORKS
+#ifdef LOVE_APPLE_USE_FRAMEWORKS
+#ifdef LOVE_IOS
+#include <OpenAL/alc.h>
+#include <OpenAL/al.h>
+#else
 #include <OpenAL-Soft/alc.h>
 #include <OpenAL-Soft/al.h>
+#endif
 #else
 #include <AL/alc.h>
 #include <AL/al.h>
@@ -105,7 +110,6 @@ public:
 	virtual bool isRelative() const;
 	void setLooping(bool looping);
 	bool isLooping() const;
-	bool isStatic() const;
 	virtual void setMinVolume(float volume);
 	virtual float getMinVolume() const;
 	virtual void setMaxVolume(float volume);
@@ -166,15 +170,9 @@ private:
 
 	struct Cone
 	{
-		int innerAngle; // degrees
-		int outerAngle; // degrees
-		float outerVolume;
-
-		Cone()
-			: innerAngle(360)
-			, outerAngle(360)
-			, outerVolume(0.0f)
-		{}
+		int innerAngle = 360; // degrees
+		int outerAngle = 360; // degrees
+		float outerVolume = 0.0f;
 	} cone;
 
 	float offsetSamples;

+ 10 - 10
jni/love/src/modules/audio/wrap_Audio.cpp

@@ -44,7 +44,7 @@ int w_getSourceCount(lua_State *L)
 
 int w_newSource(lua_State *L)
 {
-	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
+	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_ID) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_ID))
 		luax_convobj(L, 1, "sound", "newDecoder");
 
 	Source::Type stype = Source::TYPE_STREAM;
@@ -53,21 +53,21 @@ int w_newSource(lua_State *L)
 	if (stypestr && !Source::getConstant(stypestr, stype))
 		return luaL_error(L, "Invalid source type: %s", stypestr);
 
-	if (stype == Source::TYPE_STATIC && luax_istype(L, 1, SOUND_DECODER_T))
+	if (stype == Source::TYPE_STATIC && luax_istype(L, 1, SOUND_DECODER_ID))
 		luax_convobj(L, 1, "sound", "newSoundData");
 
 	Source *t = 0;
 
 	luax_catchexcept(L, [&]() {
-		if (luax_istype(L, 1, SOUND_SOUND_DATA_T))
-			t = instance()->newSource(luax_totype<love::sound::SoundData>(L, 1, "SoundData", SOUND_SOUND_DATA_T));
-		else if (luax_istype(L, 1, SOUND_DECODER_T))
-			t = instance()->newSource(luax_totype<love::sound::Decoder>(L, 1, "Decoder", SOUND_DECODER_T));
+		if (luax_istype(L, 1, SOUND_SOUND_DATA_ID))
+			t = instance()->newSource(luax_totype<love::sound::SoundData>(L, 1, SOUND_SOUND_DATA_ID));
+		else if (luax_istype(L, 1, SOUND_DECODER_ID))
+			t = instance()->newSource(luax_totype<love::sound::Decoder>(L, 1, SOUND_DECODER_ID));
 	});
 
 	if (t)
 	{
-		luax_pushtype(L, "Source", AUDIO_SOURCE_T, t);
+		luax_pushtype(L, AUDIO_SOURCE_ID, t);
 		t->release();
 		return 1;
 	}
@@ -243,7 +243,7 @@ int w_getRecordedData(lua_State *L)
 		lua_pushnil(L);
 	else
 	{
-		luax_pushtype(L, "SoundData", SOUND_SOUND_DATA_T, sd);
+		luax_pushtype(L, SOUND_SOUND_DATA_ID, sd);
 		sd->release();
 	}
 	return 1;
@@ -258,7 +258,7 @@ int w_stopRecording(lua_State *L)
 			lua_pushnil(L);
 		else
 		{
-			luax_pushtype(L, "SoundData", SOUND_SOUND_DATA_T, sd);
+			luax_pushtype(L, SOUND_SOUND_DATA_ID, sd);
 			sd->release();
 		}
 		return 1;
@@ -369,7 +369,7 @@ extern "C" int luaopen_love_audio(lua_State *L)
 	WrappedModule w;
 	w.module = instance;
 	w.name = "audio";
-	w.flags = MODULE_T;
+	w.type = MODULE_ID;
 	w.functions = functions;
 	w.types = types;
 

+ 37 - 27
jni/love/src/modules/audio/wrap_Source.cpp

@@ -29,7 +29,7 @@ namespace audio
 
 Source *luax_checksource(lua_State *L, int idx)
 {
-	return luax_checktype<Source>(L, idx, "Source", AUDIO_SOURCE_T);
+	return luax_checktype<Source>(L, idx, AUDIO_SOURCE_ID);
 }
 
 int w_Source_clone(lua_State *L)
@@ -37,7 +37,7 @@ int w_Source_clone(lua_State *L)
 	Source *t = luax_checksource(L, 1);
 	Source *clone = nullptr;
 	luax_catchexcept(L, [&](){ clone = t->clone(); });
-	luax_pushtype(L, "Source", AUDIO_SOURCE_T, clone);
+	luax_pushtype(L, AUDIO_SOURCE_ID, clone);
 	clone->release();
 	return 1;
 }
@@ -147,7 +147,7 @@ int w_Source_setPosition(lua_State *L)
 	v[0] = (float)luaL_checknumber(L, 2);
 	v[1] = (float)luaL_checknumber(L, 3);
 	v[2] = (float)luaL_optnumber(L, 4, 0);
-	t->setPosition(v);
+	luax_catchexcept(L, [&](){ t->setPosition(v); });
 	return 0;
 }
 
@@ -155,7 +155,7 @@ int w_Source_getPosition(lua_State *L)
 {
 	Source *t = luax_checksource(L, 1);
 	float v[3];
-	t->getPosition(v);
+	luax_catchexcept(L, [&](){ t->getPosition(v); });
 	lua_pushnumber(L, v[0]);
 	lua_pushnumber(L, v[1]);
 	lua_pushnumber(L, v[2]);
@@ -169,7 +169,7 @@ int w_Source_setVelocity(lua_State *L)
 	v[0] = (float)luaL_checknumber(L, 2);
 	v[1] = (float)luaL_checknumber(L, 3);
 	v[2] = (float)luaL_optnumber(L, 4, 0);
-	t->setVelocity(v);
+	luax_catchexcept(L, [&](){ t->setVelocity(v); });
 	return 0;
 }
 
@@ -177,7 +177,7 @@ int w_Source_getVelocity(lua_State *L)
 {
 	Source *t = luax_checksource(L, 1);
 	float v[3];
-	t->getVelocity(v);
+	luax_catchexcept(L, [&](){ t->getVelocity(v); });
 	lua_pushnumber(L, v[0]);
 	lua_pushnumber(L, v[1]);
 	lua_pushnumber(L, v[2]);
@@ -191,7 +191,7 @@ int w_Source_setDirection(lua_State *L)
 	v[0] = (float)luaL_checknumber(L, 2);
 	v[1] = (float)luaL_checknumber(L, 3);
 	v[2] = (float)luaL_optnumber(L, 4, 0);
-	t->setDirection(v);
+	luax_catchexcept(L, [&](){ t->setDirection(v); });
 	return 0;
 }
 
@@ -199,7 +199,7 @@ int w_Source_getDirection(lua_State *L)
 {
 	Source *t = luax_checksource(L, 1);
 	float v[3];
-	t->getDirection(v);
+	luax_catchexcept(L, [&](){ t->getDirection(v); });
 	lua_pushnumber(L, v[0]);
 	lua_pushnumber(L, v[1]);
 	lua_pushnumber(L, v[2]);
@@ -212,7 +212,7 @@ int w_Source_setCone(lua_State *L)
 	float innerAngle = (float) luaL_checknumber(L, 2);
 	float outerAngle = (float) luaL_checknumber(L, 3);
 	float outerVolume = (float) luaL_optnumber(L, 4, 0.0);
-	t->setCone(innerAngle, outerAngle, outerVolume);
+	luax_catchexcept(L, [&](){ t->setCone(innerAngle, outerAngle, outerVolume); });
 	return 0;
 }
 
@@ -220,7 +220,7 @@ int w_Source_getCone(lua_State *L)
 {
 	Source *t = luax_checksource(L, 1);
 	float innerAngle, outerAngle, outerVolume;
-	t->getCone(innerAngle, outerAngle, outerVolume);
+	luax_catchexcept(L, [&](){ t->getCone(innerAngle, outerAngle, outerVolume); });
 	lua_pushnumber(L, innerAngle);
 	lua_pushnumber(L, outerAngle);
 	lua_pushnumber(L, outerVolume);
@@ -230,14 +230,14 @@ int w_Source_getCone(lua_State *L)
 int w_Source_setRelative(lua_State *L)
 {
 	Source *t = luax_checksource(L, 1);
-	t->setRelative(luax_toboolean(L, 2));
+	luax_catchexcept(L, [&](){ t->setRelative(luax_toboolean(L, 2)); });
 	return 0;
 }
 
 int w_Source_isRelative(lua_State *L)
 {
 	Source *t = luax_checksource(L, 1);
-	luax_pushboolean(L, t->isRelative());
+	luax_catchexcept(L, [&](){ luax_pushboolean(L, t->isRelative()); });
 	return 1;
 }
 
@@ -276,13 +276,6 @@ int w_Source_isPlaying(lua_State *L)
 	return 1;
 }
 
-int w_Source_isStatic(lua_State *L)
-{
-	Source *t = luax_checksource(L, 1);
-	luax_pushboolean(L, t->isStatic());
-	return 1;
-}
-
 int w_Source_setVolumeLimits(lua_State *L)
 {
 	Source *t = luax_checksource(L, 1);
@@ -310,16 +303,20 @@ int w_Source_setAttenuationDistances(lua_State *L)
 	float dmax = (float)luaL_checknumber(L, 3);
 	if (dref < .0f || dmax < .0f)
 		return luaL_error(L, "Invalid distances: %f, %f. Must be > 0", dref, dmax);
-	t->setReferenceDistance(dref);
-	t->setMaxDistance(dmax);
+	luax_catchexcept(L, [&]() {
+		t->setReferenceDistance(dref);
+		t->setMaxDistance(dmax);
+	});
 	return 0;
 }
 
 int w_Source_getAttenuationDistances(lua_State *L)
 {
 	Source *t = luax_checksource(L, 1);
-	lua_pushnumber(L, t->getReferenceDistance());
-	lua_pushnumber(L, t->getMaxDistance());
+	luax_catchexcept(L, [&]() {
+		lua_pushnumber(L, t->getReferenceDistance());
+		lua_pushnumber(L, t->getMaxDistance());
+	});
 	return 2;
 }
 
@@ -329,14 +326,14 @@ int w_Source_setRolloff(lua_State *L)
 	float rolloff = (float)luaL_checknumber(L, 2);
 	if (rolloff < .0f)
 		return luaL_error(L, "Invalid rolloff: %f. Must be > 0.", rolloff);
-	t->setRolloffFactor(rolloff);
+	luax_catchexcept(L, [&](){ t->setRolloffFactor(rolloff); });
 	return 0;
 }
 
 int w_Source_getRolloff(lua_State *L)
 {
 	Source *t = luax_checksource(L, 1);
-	lua_pushnumber(L, t->getRolloffFactor());
+	luax_catchexcept(L, [&](){ lua_pushnumber(L, t->getRolloffFactor()); });
 	return 1;
 }
 
@@ -347,6 +344,19 @@ int w_Source_getChannels(lua_State *L)
 	return 1;
 }
 
+int w_Source_getType(lua_State *L)
+{
+	Source *t = luax_checksource(L, 1);
+	Source::Type type = t->getType();
+	const char *str = nullptr;
+
+	if (!Source::getConstant(type, str))
+		return luaL_error(L, "Unknown Source type.");
+
+	lua_pushstring(L, str);
+	return 1;
+}
+
 static const luaL_Reg functions[] =
 {
 	{ "clone", w_Source_clone },
@@ -380,7 +390,6 @@ static const luaL_Reg functions[] =
 	{ "isStopped", w_Source_isStopped },
 	{ "isPaused", w_Source_isPaused },
 	{ "isPlaying", w_Source_isPlaying },
-	{ "isStatic", w_Source_isStatic },
 
 	{ "setVolumeLimits", w_Source_setVolumeLimits },
 	{ "getVolumeLimits", w_Source_getVolumeLimits },
@@ -390,13 +399,14 @@ static const luaL_Reg functions[] =
 	{ "getRolloff", w_Source_getRolloff},
 
 	{ "getChannels", w_Source_getChannels },
+	{ "getType", w_Source_getType },
 
 	{ 0, 0 }
 };
 
 extern "C" int luaopen_source(lua_State *L)
 {
-	return luax_register_type(L, "Source", functions);
+	return luax_register_type(L, AUDIO_SOURCE_ID, functions);
 }
 
 } // audio

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

@@ -57,7 +57,6 @@ int w_Source_isLooping(lua_State *L);
 int w_Source_isStopped(lua_State *L);
 int w_Source_isPaused(lua_State *L);
 int w_Source_isPlaying(lua_State *L);
-int w_Source_isStatic(lua_State *L);
 int w_Source_setVolumeLimits(lua_State *L);
 int w_Source_getVolumeLimits(lua_State *L);
 int w_Source_setAttenuationDistances(lua_State *L);
@@ -65,6 +64,7 @@ int w_Source_getAttenuationDistances(lua_State *L);
 int w_Source_setRolloff(lua_State *L);
 int w_Source_getRolloff(lua_State *L);
 int w_Source_getChannels(lua_State *L);
+int w_Source_getType(lua_State *L);
 extern "C" int luaopen_source(lua_State *L);
 
 } // audio

+ 3 - 4
jni/love/src/modules/event/Event.h

@@ -30,7 +30,7 @@
 #include "joystick/Joystick.h"
 #include "thread/threads.h"
 
-// STL
+// C++
 #include <queue>
 #include <vector>
 
@@ -43,7 +43,7 @@ class Message : public Object
 {
 public:
 
-	Message(const std::string &name, const std::vector<StrongRef<Variant>> &vargs = std::vector<StrongRef<Variant>>());
+	Message(const std::string &name, const std::vector<StrongRef<Variant>> &vargs = {});
 	~Message();
 
 	int toLua(lua_State *L);
@@ -59,7 +59,6 @@ private:
 class Event : public Module
 {
 public:
-
 	Event();
 	virtual ~Event();
 
@@ -71,9 +70,9 @@ public:
 	virtual void clear();
 
 	virtual void pump() = 0;
+	virtual Message *wait() = 0;
 
 protected:
-
 	thread::Mutex *mutex;
 	std::queue<Message *> queue;
 

+ 186 - 128
jni/love/src/modules/event/sdl/Event.cpp

@@ -20,8 +20,9 @@
 
 #include "Event.h"
 
-#include "keyboard/Keyboard.h"
-#include "mouse/Mouse.h"
+#include "filesystem/DroppedFile.h"
+#include "filesystem/Filesystem.h"
+#include "keyboard/sdl/Keyboard.h"
 #include "joystick/JoystickModule.h"
 #include "joystick/sdl/Joystick.h"
 #include "touch/sdl/Touch.h"
@@ -44,15 +45,27 @@ namespace sdl
 // we want them in pixel coordinates (may be different with high-DPI enabled.)
 static void windowToPixelCoords(double *x, double *y)
 {
-#ifndef LOVE_ANDROID
 	window::Window *window = Module::getInstance<window::Window>(Module::M_WINDOW);
-	if (window && x)
-		*x = window->toPixels(*x);
-	if (window && y)
-		*y = window->toPixels(*y);
-#endif
+	if (window)
+		window->windowToPixelCoords(x, y);
 }
 
+#ifndef LOVE_MACOSX
+static void normalizedToPixelCoords(double *x, double *y)
+{
+	window::Window *window = Module::getInstance<window::Window>(Module::M_WINDOW);
+	int w = 1, h = 1;
+
+	if (window)
+		window->getPixelDimensions(w, h);
+
+	if (x)
+		*x = ((*x) * (double) w);
+	if (y)
+		*y = ((*y) * (double) h);
+}
+#endif
+
 // SDL's event watch callbacks trigger when the event is actually posted inside
 // SDL, unlike with SDL_PollEvents. This is useful for some events which require
 // handling inside the function which triggered them on some backends.
@@ -67,9 +80,6 @@ static int SDLCALL watchAppEvents(void * /*udata*/, SDL_Event *event)
 	// with an event watch callback, which will be called inside that function.
 	case SDL_APP_DIDENTERBACKGROUND:
 	case SDL_APP_WILLENTERFOREGROUND:
-		// On Android, before calling setActive we should probably also call a
-		// window function to un-set the graphics mode and delete the context,
-		// after DIDENTERBACKGROUND (and the reverse after WILLENTERFOREGROUND.)
 		if (gfx)
 			gfx->setActive(event->type == SDL_APP_WILLENTERFOREGROUND);
 		break;
@@ -77,11 +87,9 @@ static int SDLCALL watchAppEvents(void * /*udata*/, SDL_Event *event)
 		break;
 	}
 
-	// Don't prevent the event from being processed further.
 	return 1;
 }
 
-
 const char *Event::getName() const
 {
 	return "love.event.sdl";
@@ -90,7 +98,7 @@ const char *Event::getName() const
 Event::Event()
 {
 	if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0)
-		throw love::Exception("%s", SDL_GetError());
+		throw love::Exception("Could not initialize SDL events subsystem (%s)", SDL_GetError());
 
 	SDL_AddEventWatch(watchAppEvents, this);
 }
@@ -146,13 +154,24 @@ Message *Event::convert(const SDL_Event &e) const
 	vargs.reserve(4);
 
 	love::keyboard::Keyboard *kb = nullptr;
-	love::touch::sdl::Touch *touch = nullptr;
+	love::filesystem::Filesystem *filesystem = nullptr;
+
+	love::keyboard::Keyboard::Key key = love::keyboard::Keyboard::KEY_UNKNOWN;
+	love::keyboard::Keyboard::Scancode scancode = love::keyboard::Keyboard::SCANCODE_UNKNOWN;
 
-	love::keyboard::Keyboard::Key key;
-	love::mouse::Mouse::Button button;
 	const char *txt;
+	const char *txt2;
 	std::map<SDL_Keycode, love::keyboard::Keyboard::Key>::const_iterator keyit;
 
+#ifndef LOVE_MACOSX
+	love::touch::sdl::Touch *touchmodule = nullptr;
+	love::touch::Touch::TouchInfo touchinfo;
+#endif
+
+#ifdef LOVE_LINUX
+	static bool touchNormalizationBug = false;
+#endif
+
 	switch (e.type)
 	{
 	case SDL_KEYDOWN:
@@ -166,13 +185,16 @@ Message *Event::convert(const SDL_Event &e) const
 		keyit = keys.find(e.key.keysym.sym);
 		if (keyit != keys.end())
 			key = keyit->second;
-		else
-			key = love::keyboard::Keyboard::KEY_UNKNOWN;
 
 		if (!love::keyboard::Keyboard::getConstant(key, txt))
 			txt = "unknown";
 
+		love::keyboard::sdl::Keyboard::getConstant(e.key.keysym.scancode, scancode);
+		if (!love::keyboard::Keyboard::getConstant(scancode, txt2))
+			txt2 = "unknown";
+
 		vargs.push_back(new Variant(txt, strlen(txt)));
+		vargs.push_back(new Variant(txt2, strlen(txt2)));
 		vargs.push_back(new Variant(e.key.repeat != 0));
 		msg = new Message("keypressed", vargs);
 		break;
@@ -180,13 +202,16 @@ Message *Event::convert(const SDL_Event &e) const
 		keyit = keys.find(e.key.keysym.sym);
 		if (keyit != keys.end())
 			key = keyit->second;
-		else
-			key = love::keyboard::Keyboard::KEY_UNKNOWN;
 
 		if (!love::keyboard::Keyboard::getConstant(key, txt))
 			txt = "unknown";
 
+		love::keyboard::sdl::Keyboard::getConstant(e.key.keysym.scancode, scancode);
+		if (!love::keyboard::Keyboard::getConstant(scancode, txt2))
+			txt2 = "unknown";
+
 		vargs.push_back(new Variant(txt, strlen(txt)));
+		vargs.push_back(new Variant(txt2, strlen(txt2)));
 		msg = new Message("keyreleased", vargs);
 		break;
 	case SDL_TEXTINPUT:
@@ -199,7 +224,7 @@ Message *Event::convert(const SDL_Event &e) const
 		vargs.push_back(new Variant(txt, strlen(txt)));
 		vargs.push_back(new Variant((double) e.edit.start));
 		vargs.push_back(new Variant((double) e.edit.length));
-		msg = new Message("textedit", vargs);
+		msg = new Message("textedited", vargs);
 		break;
 	case SDL_MOUSEMOTION:
 		{
@@ -213,19 +238,32 @@ Message *Event::convert(const SDL_Event &e) const
 			vargs.push_back(new Variant(y));
 			vargs.push_back(new Variant(xrel));
 			vargs.push_back(new Variant(yrel));
+			vargs.push_back(new Variant(e.motion.which == SDL_TOUCH_MOUSEID));
 			msg = new Message("mousemoved", vargs);
 		}
 		break;
 	case SDL_MOUSEBUTTONDOWN:
 	case SDL_MOUSEBUTTONUP:
-		if (buttons.find(e.button.button, button) && mouse::Mouse::getConstant(button, txt))
 		{
+			// SDL uses button index 3 for the right mouse button, but we use
+			// index 2.
+			int button = e.button.button;
+			switch (button)
+			{
+			case SDL_BUTTON_RIGHT:
+				button = 2;
+				break;
+			case SDL_BUTTON_MIDDLE:
+				button = 3;
+				break;
+			}
+
 			double x = (double) e.button.x;
 			double y = (double) e.button.y;
 			windowToPixelCoords(&x, &y);
 			vargs.push_back(new Variant(x));
 			vargs.push_back(new Variant(y));
-			vargs.push_back(new Variant(txt, strlen(txt)));
+			vargs.push_back(new Variant((double) button));
 			vargs.push_back(new Variant(e.button.which == SDL_TOUCH_MOUSEID));
 			msg = new Message((e.type == SDL_MOUSEBUTTONDOWN) ?
 							  "mousepressed" : "mousereleased",
@@ -233,38 +271,59 @@ Message *Event::convert(const SDL_Event &e) const
 		}
 		break;
 	case SDL_MOUSEWHEEL:
-		if (e.wheel.y != 0)
-		{
-			button = (e.wheel.y > 0) ? mouse::Mouse::BUTTON_WHEELUP : mouse::Mouse::BUTTON_WHEELDOWN;
-			if (!love::mouse::Mouse::getConstant(button, txt))
-				break;
-
-			int mx, my;
-			double dmx, dmy;
-			SDL_GetMouseState(&mx, &my);
-			dmx = (double) mx;
-			dmy = (double) my;
-			windowToPixelCoords(&dmx, &dmy);
-
-			vargs.push_back(new Variant(dmx));
-			vargs.push_back(new Variant(dmy));
-			vargs.push_back(new Variant(txt, strlen(txt)));
-			vargs.push_back(new Variant(false));
-			msg = new Message("mousepressed", vargs);
-		}
+		vargs.push_back(new Variant((double) e.wheel.x));
+		vargs.push_back(new Variant((double) e.wheel.y));
+		msg = new Message("wheelmoved", vargs);
 		break;
 	case SDL_FINGERDOWN:
 	case SDL_FINGERUP:
 	case SDL_FINGERMOTION:
+		// Touch events are disabled in OS X because we only actually want touch
+		// screen events, but most touch devices in OS X aren't touch screens
+		// (and SDL doesn't differentiate.) Non-screen touch devices like Mac
+		// trackpads won't give touch coords in the window's coordinate-space.
+#ifndef LOVE_MACOSX
+		touchinfo.id = (int64) e.tfinger.fingerId;
+		touchinfo.x = e.tfinger.x;
+		touchinfo.y = e.tfinger.y;
+		touchinfo.dx = e.tfinger.dx;
+		touchinfo.dy = e.tfinger.dy;
+		touchinfo.pressure = e.tfinger.pressure;
+
+#ifdef LOVE_LINUX
+		// FIXME: hacky workaround for SDL not normalizing touch coordinates in
+		// its X11 backend: https://bugzilla.libsdl.org/show_bug.cgi?id=2307
+		if (touchNormalizationBug || fabs(touchinfo.x) >= 1.5 || fabs(touchinfo.y) >= 1.5 || fabs(touchinfo.dx) >= 1.5 || fabs(touchinfo.dy) >= 1.5)
+		{
+			touchNormalizationBug = true;
+			windowToPixelCoords(&touchinfo.x, &touchinfo.y);
+			windowToPixelCoords(&touchinfo.dx, &touchinfo.dy);
+		}
+		else
+#endif
+		{
+			// SDL's coords are normalized to [0, 1], but we want them in pixels.
+			normalizedToPixelCoords(&touchinfo.x, &touchinfo.y);
+			normalizedToPixelCoords(&touchinfo.dx, &touchinfo.dy);
+		}
+
 		// We need to update the love.touch.sdl internal state from here.
-		touch = (touch::sdl::Touch *) Module::getInstance("love.touch.sdl");
-		if (touch)
-			touch->onEvent(e.tfinger);
-
-		vargs.push_back(new Variant((double) e.tfinger.fingerId));
-		vargs.push_back(new Variant((double) e.tfinger.x));
-		vargs.push_back(new Variant((double) e.tfinger.y));
-		vargs.push_back(new Variant((double) e.tfinger.pressure));
+		touchmodule = (touch::sdl::Touch *) Module::getInstance("love.touch.sdl");
+		if (touchmodule)
+			touchmodule->onEvent(e.type, touchinfo);
+
+		// This is a bit hackish and we lose the higher 32 bits of the id on
+		// 32-bit systems, but SDL only ever gives id's that at most use as many
+		// bits as can fit in a pointer (for now.)
+		// We use lightuserdata instead of a lua_Number (double) because doubles
+		// can't represent all possible id values on 64-bit systems.
+		vargs.push_back(new Variant((void *) (intptr_t) touchinfo.id));
+		vargs.push_back(new Variant(touchinfo.x));
+		vargs.push_back(new Variant(touchinfo.y));
+		vargs.push_back(new Variant(touchinfo.dx));
+		vargs.push_back(new Variant(touchinfo.dy));
+		vargs.push_back(new Variant(touchinfo.pressure));
+
 		if (e.type == SDL_FINGERDOWN)
 			txt = "touchpressed";
 		else if (e.type == SDL_FINGERUP)
@@ -272,14 +331,7 @@ Message *Event::convert(const SDL_Event &e) const
 		else
 			txt = "touchmoved";
 		msg = new Message(txt, vargs);
-		break;
-	case SDL_MULTIGESTURE:
-		vargs.push_back(new Variant((double) e.mgesture.x));
-		vargs.push_back(new Variant((double) e.mgesture.y));
-		vargs.push_back(new Variant((double) e.mgesture.dTheta));
-		vargs.push_back(new Variant((double) e.mgesture.dDist));
-		vargs.push_back(new Variant((double) e.mgesture.numFingers));
-		msg = new Message("touchgestured", vargs);
+#endif
 		break;
 	case SDL_JOYBUTTONDOWN:
 	case SDL_JOYBUTTONUP:
@@ -297,6 +349,27 @@ Message *Event::convert(const SDL_Event &e) const
 		msg = convertWindowEvent(e);
 		break;
 	case SDL_DROPFILE:
+		filesystem = Module::getInstance<filesystem::Filesystem>(Module::M_FILESYSTEM);
+		if (filesystem != nullptr)
+		{
+			// Allow mounting any dropped path, so zips or dirs can be mounted.
+			filesystem->allowMountingForPath(e.drop.file);
+
+			if (filesystem->isRealDirectory(e.drop.file))
+			{
+				vargs.push_back(new Variant(e.drop.file, strlen(e.drop.file)));
+				msg = new Message("directorydropped", vargs);
+			}
+			else
+			{
+				Proxy proxy;
+				proxy.object = new love::filesystem::DroppedFile(e.drop.file);
+				proxy.type = FILESYSTEM_DROPPED_FILE_ID;
+				vargs.push_back(new Variant(proxy.type, &proxy));
+				msg = new Message("filedropped", vargs);
+				proxy.object->release();
+			}
+		}
 		SDL_free(e.drop.file);
 		break;
 	case SDL_QUIT:
@@ -310,9 +383,9 @@ Message *Event::convert(const SDL_Event &e) const
 		break;
 	}
 
+	// We gave +1 refs to the StrongRef list, so we should release them.
 	for (const StrongRef<Variant> &v : vargs)
 	{
-		// We gave +1 refs to the StrongRef list, so we should release them.
 		if (v.get() != nullptr)
 			v->release();
 	}
@@ -341,12 +414,12 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const
 	{
 	case SDL_JOYBUTTONDOWN:
 	case SDL_JOYBUTTONUP:
-		proxy.flags = JOYSTICK_JOYSTICK_T;
-		proxy.data = joymodule->getJoystickFromID(e.jbutton.which);
-		if (!proxy.data)
+		proxy.type = JOYSTICK_JOYSTICK_ID;
+		proxy.object = joymodule->getJoystickFromID(e.jbutton.which);
+		if (!proxy.object)
 			break;
 
-		vargs.push_back(new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy));
+		vargs.push_back(new Variant(proxy.type, (void *) &proxy));
 		vargs.push_back(new Variant((double)(e.jbutton.button+1)));
 		msg = new Message((e.type == SDL_JOYBUTTONDOWN) ?
 						  "joystickpressed" : "joystickreleased",
@@ -354,12 +427,12 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const
 		break;
 	case SDL_JOYAXISMOTION:
 		{
-			proxy.flags = JOYSTICK_JOYSTICK_T;
-			proxy.data = joymodule->getJoystickFromID(e.jaxis.which);
-			if (!proxy.data)
+			proxy.type = JOYSTICK_JOYSTICK_ID;
+			proxy.object = joymodule->getJoystickFromID(e.jaxis.which);
+			if (!proxy.object)
 				break;
 
-			vargs.push_back(new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy));
+			vargs.push_back(new Variant(proxy.type, (void *) &proxy));
 			vargs.push_back(new Variant((double)(e.jaxis.axis+1)));
 			float value = joystick::Joystick::clampval(e.jaxis.value / 32768.0f);
 			vargs.push_back(new Variant((double) value));
@@ -370,12 +443,12 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const
 		if (!joystick::sdl::Joystick::getConstant(e.jhat.value, hat) || !joystick::Joystick::getConstant(hat, txt))
 			break;
 
-		proxy.flags = JOYSTICK_JOYSTICK_T;
-		proxy.data = joymodule->getJoystickFromID(e.jhat.which);
-		if (!proxy.data)
+		proxy.type = JOYSTICK_JOYSTICK_ID;
+		proxy.object = joymodule->getJoystickFromID(e.jhat.which);
+		if (!proxy.object)
 			break;
 
-		vargs.push_back(new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy));
+		vargs.push_back(new Variant(proxy.type, (void *) &proxy));
 		vargs.push_back(new Variant((double)(e.jhat.hat+1)));
 		vargs.push_back(new Variant(txt, strlen(txt)));
 		msg = new Message("joystickhat", vargs);
@@ -388,12 +461,12 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const
 		if (!joystick::Joystick::getConstant(padbutton, txt))
 			break;
 
-		proxy.flags = JOYSTICK_JOYSTICK_T;
-		proxy.data = joymodule->getJoystickFromID(e.cbutton.which);
-		if (!proxy.data)
+		proxy.type = JOYSTICK_JOYSTICK_ID;
+		proxy.object = joymodule->getJoystickFromID(e.cbutton.which);
+		if (!proxy.object)
 			break;
 
-		vargs.push_back(new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy));
+		vargs.push_back(new Variant(proxy.type, (void *) &proxy));
 		vargs.push_back(new Variant(txt, strlen(txt)));
 		msg = new Message(e.type == SDL_CONTROLLERBUTTONDOWN ?
 						  "gamepadpressed" : "gamepadreleased", vargs);
@@ -404,12 +477,13 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const
 			if (!joystick::Joystick::getConstant(padaxis, txt))
 				break;
 
-			proxy.flags = JOYSTICK_JOYSTICK_T;
-			proxy.data = joymodule->getJoystickFromID(e.caxis.which);
-			if (!proxy.data)
+			proxy.type = JOYSTICK_JOYSTICK_ID;
+			proxy.object = joymodule->getJoystickFromID(e.caxis.which);
+			if (!proxy.object)
 				break;
 
-			vargs.push_back(new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy));
+			vargs.push_back(new Variant(proxy.type, (void *) &proxy));
+
 			vargs.push_back(new Variant(txt, strlen(txt)));
 			float value = joystick::Joystick::clampval(e.caxis.value / 32768.0f);
 			vargs.push_back(new Variant((double) value));
@@ -418,32 +492,48 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const
 		break;
 	case SDL_JOYDEVICEADDED:
 		// jdevice.which is the joystick device index.
-		proxy.data = joymodule->addJoystick(e.jdevice.which);
-		proxy.flags = JOYSTICK_JOYSTICK_T;
-		if (proxy.data)
+		proxy.object = joymodule->addJoystick(e.jdevice.which);
+		proxy.type = JOYSTICK_JOYSTICK_ID;
+		if (proxy.object)
 		{
-			vargs.push_back(new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy));
+			vargs.push_back(new Variant(proxy.type, (void *) &proxy));
 			msg = new Message("joystickadded", vargs);
 		}
 		break;
 	case SDL_JOYDEVICEREMOVED:
 		// jdevice.which is the joystick instance ID now.
-		proxy.data = joymodule->getJoystickFromID(e.jdevice.which);
-		proxy.flags = JOYSTICK_JOYSTICK_T;
-		if (proxy.data)
+		proxy.object = joymodule->getJoystickFromID(e.jdevice.which);
+		proxy.type = JOYSTICK_JOYSTICK_ID;
+		if (proxy.object)
 		{
-			joymodule->removeJoystick((joystick::Joystick *) proxy.data);
-			vargs.push_back(new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy));
+			joymodule->removeJoystick((joystick::Joystick *) proxy.object);
+			vargs.push_back(new Variant(proxy.type, (void *) &proxy));
 			msg = new Message("joystickremoved", vargs);
 		}
 		break;
 	default:
 		break;
+#ifdef LOVE_ANDROID
+		case SDL_WINDOWEVENT_MINIMIZED:
+		{
+			audio::Audio *audio = Module::getInstance<audio::Audio>(Module::M_AUDIO);
+			if (audio)
+				audio->pause();
+		}
+		break;
+		case SDL_WINDOWEVENT_RESTORED:
+		{
+			audio::Audio *audio = Module::getInstance<audio::Audio>(Module::M_AUDIO);
+			if (audio)
+				audio->resume();
+		}
+		break;
+#endif
 	}
 
+	// We gave +1 refs to the StrongRef list, so we should release them.
 	for (const StrongRef<Variant> &v : vargs)
 	{
-		// We gave +1 refs to the StrongRef list, so we should release them.
 		if (v.get() != nullptr)
 			v->release();
 	}
@@ -487,24 +577,13 @@ Message *Event::convertWindowEvent(const SDL_Event &e) const
 		msg = new Message("visible", vargs);
 		break;
 	case SDL_WINDOWEVENT_RESIZED:
-		win = Module::getInstance<window::Window>(Module::M_WINDOW);
-		if (win)
 		{
 			int px_w = e.window.data1;
 			int px_h = e.window.data2;
 
-			// 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);
-#endif
-
-			win->onWindowResize(e.window.data1, e.window.data2);
-
-			graphics::Graphics *gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
-			if (gfx)
-				gfx->setViewportSize(px_w, px_h);
 
 			vargs.push_back(new Variant((double) px_w));
 			vargs.push_back(new Variant((double) px_h));
@@ -513,27 +592,16 @@ Message *Event::convertWindowEvent(const SDL_Event &e) const
 			msg = new Message("resize", vargs);
 		}
 		break;
-#ifdef LOVE_ANDROID
-		case SDL_WINDOWEVENT_MINIMIZED:
-		{
-			audio::Audio *audio = Module::getInstance<audio::Audio>(Module::M_AUDIO);
-			if (audio)
-				audio->pause();
-		}
-		break;
-		case SDL_WINDOWEVENT_RESTORED:
-		{
-			audio::Audio *audio = Module::getInstance<audio::Audio>(Module::M_AUDIO);
-			if (audio)
-				audio->resume();
-		}
+	case SDL_WINDOWEVENT_SIZE_CHANGED:
+		win = Module::getInstance<window::Window>(Module::M_WINDOW);
+		if (win)
+			win->onSizeChanged(e.window.data1, e.window.data2);
 		break;
-#endif
 	}
 
+	// We gave +1 refs to the StrongRef list, so we should release them.
 	for (const StrongRef<Variant> &v : vargs)
 	{
-		// We gave +1 refs to the StrongRef list, so we should release them.
 		if (v.get() != nullptr)
 			v->release();
 	}
@@ -557,6 +625,7 @@ std::map<SDL_Keycode, love::keyboard::Keyboard::Key> Event::createKeyMap()
 	k[SDLK_EXCLAIM] = Keyboard::KEY_EXCLAIM;
 	k[SDLK_QUOTEDBL] = Keyboard::KEY_QUOTEDBL;
 	k[SDLK_HASH] = Keyboard::KEY_HASH;
+	k[SDLK_PERCENT] = Keyboard::KEY_PERCENT;
 	k[SDLK_DOLLAR] = Keyboard::KEY_DOLLAR;
 	k[SDLK_AMPERSAND] = Keyboard::KEY_AMPERSAND;
 	k[SDLK_QUOTE] = Keyboard::KEY_QUOTE;
@@ -761,17 +830,6 @@ std::map<SDL_Keycode, love::keyboard::Keyboard::Key> Event::createKeyMap()
 
 std::map<SDL_Keycode, love::keyboard::Keyboard::Key> Event::keys = Event::createKeyMap();
 
-EnumMap<love::mouse::Mouse::Button, Uint8, love::mouse::Mouse::BUTTON_MAX_ENUM>::Entry Event::buttonEntries[] =
-{
-	{ love::mouse::Mouse::BUTTON_LEFT, SDL_BUTTON_LEFT},
-	{ love::mouse::Mouse::BUTTON_MIDDLE, SDL_BUTTON_MIDDLE},
-	{ love::mouse::Mouse::BUTTON_RIGHT, SDL_BUTTON_RIGHT},
-	{ love::mouse::Mouse::BUTTON_X1, SDL_BUTTON_X1},
-	{ love::mouse::Mouse::BUTTON_X2, SDL_BUTTON_X2},
-};
-
-EnumMap<love::mouse::Mouse::Button, Uint8, love::mouse::Mouse::BUTTON_MAX_ENUM> Event::buttons(Event::buttonEntries, sizeof(Event::buttonEntries));
-
 } // sdl
 } // event
 } // love

+ 0 - 5
jni/love/src/modules/event/sdl/Event.h

@@ -23,8 +23,6 @@
 
 // LOVE
 #include "event/Event.h"
-#include "common/runtime.h"
-#include "common/EnumMap.h"
 
 // SDL
 #include <SDL_events.h>
@@ -77,9 +75,6 @@ private:
 	static std::map<SDL_Keycode, love::keyboard::Keyboard::Key> createKeyMap();
 	static std::map<SDL_Keycode, love::keyboard::Keyboard::Key> keys;
 
-	static EnumMap<love::mouse::Mouse::Button, Uint8, love::mouse::Mouse::BUTTON_MAX_ENUM>::Entry buttonEntries[];
-	static EnumMap<love::mouse::Mouse::Button, Uint8, love::mouse::Mouse::BUTTON_MAX_ENUM> buttons;
-
 }; // Event
 
 } // sdl

+ 8 - 12
jni/love/src/modules/event/sdl/wrap_Event.cpp → jni/love/src/modules/event/wrap_Event.cpp

@@ -23,21 +23,18 @@
 // LOVE
 #include "common/runtime.h"
 
-// sdlevent
-#include "Event.h"
+#include "sdl/Event.h"
 
 namespace love
 {
 namespace event
 {
-namespace sdl
-{
 
 #define instance() (Module::getInstance<Event>(Module::M_EVENT))
 
 static int poll_i(lua_State *L)
 {
-	Message *m = nullptr;
+	Message *m;
 
 	while (instance()->poll(m))
 	{
@@ -58,13 +55,13 @@ int w_pump(lua_State *)
 
 int w_poll(lua_State *L)
 {
-	lua_pushcclosure(L, poll_i, 0);
+	lua_pushcclosure(L, &poll_i, 0);
 	return 1;
 }
 
 int w_wait(lua_State *L)
 {
-	Message *m = nullptr;
+	Message *m;
 
 	if ((m = instance()->wait()))
 	{
@@ -78,7 +75,7 @@ int w_wait(lua_State *L)
 
 int w_push(lua_State *L)
 {
-	Message *m = nullptr;
+	Message *m;
 
 	bool success = (m = Message::fromLua(L, 1)) != NULL;
 	luax_pushboolean(L, success);
@@ -124,7 +121,7 @@ extern "C" int luaopen_love_event(lua_State *L)
 	Event *instance = instance();
 	if (instance == nullptr)
 	{
-		luax_catchexcept(L, [&](){ instance = new Event(); });
+		luax_catchexcept(L, [&](){ instance = new love::event::sdl::Event(); });
 	}
 	else
 		instance->retain();
@@ -132,13 +129,12 @@ extern "C" int luaopen_love_event(lua_State *L)
 	WrappedModule w;
 	w.module = instance;
 	w.name = "event";
-	w.flags = MODULE_T;
+	w.type = MODULE_ID;
 	w.functions = functions;
-	w.types = nullptr;
+	w.types = 0;
 
 	return luax_register_module(L, w);
 }
 
-} // sdl
 } // event
 } // love

+ 3 - 6
jni/love/src/modules/event/sdl/wrap_Event.h → jni/love/src/modules/event/wrap_Event.h

@@ -18,8 +18,8 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
-#ifndef LOVE_EVENT_SDL_WRAP_EVENT_H
-#define LOVE_EVENT_SDL_WRAP_EVENT_H
+#ifndef LOVE_EVENT_WRAP_EVENT_H
+#define LOVE_EVENT_WRAP_EVENT_H
 
 // LOVE
 #include "common/config.h"
@@ -29,8 +29,6 @@ namespace love
 {
 namespace event
 {
-namespace sdl
-{
 
 int w_pump(lua_State *L);
 int w_poll(lua_State *L);
@@ -41,8 +39,7 @@ int w_quit(lua_State *L);
 
 extern "C" LOVE_EXPORT int luaopen_love_event(lua_State *L);
 
-} // sdl
 } // event
 } // love
 
-#endif // LOVE_EVENT_SDL_WRAP_EVENT_H
+#endif // LOVE_EVENT_WRAP_EVENT_H

+ 256 - 0
jni/love/src/modules/filesystem/DroppedFile.cpp

@@ -0,0 +1,256 @@
+/**
+ * Copyright (c) 2006-2015 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 "DroppedFile.h"
+#include "common/utf8.h"
+
+// Assume POSIX or Visual Studio.
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef LOVE_WINDOWS
+#include <wchar.h>
+#else
+#include <unistd.h> // POSIX.
+#endif
+
+namespace love
+{
+namespace filesystem
+{
+
+DroppedFile::DroppedFile(const std::string &filename)
+	: filename(filename)
+	, file(nullptr)
+	, mode(MODE_CLOSED)
+	, bufferMode(BUFFER_NONE)
+	, bufferSize(0)
+{
+}
+
+DroppedFile::~DroppedFile()
+{
+	if (mode != MODE_CLOSED)
+		close();
+}
+
+bool DroppedFile::open(Mode newmode)
+{
+	if (newmode == MODE_CLOSED)
+		return true;
+
+	// File already open?
+	if (file != nullptr)
+		return false;
+
+#ifdef LOVE_WINDOWS
+	// make sure non-ASCII filenames work.
+	std::wstring modestr = to_widestr(getModeString(newmode));
+	std::wstring wfilename = to_widestr(filename);
+
+	file = _wfopen(wfilename.c_str(), modestr.c_str());
+#else
+	file = fopen(filename.c_str(), getModeString(newmode));
+#endif
+
+	if (newmode == MODE_READ && file == nullptr)
+		throw love::Exception("Could not open file %s. Does not exist.", filename.c_str());
+
+	mode = newmode;
+
+	if (file != nullptr && !setBuffer(bufferMode, bufferSize))
+	{
+		// Revert to buffer defaults if we don't successfully set the buffer.
+		bufferMode = BUFFER_NONE;
+		bufferSize = 0;
+	}
+
+	return file != nullptr;
+}
+
+bool DroppedFile::close()
+{
+	if (file == nullptr || fclose(file) != 0)
+		return false;
+
+	mode = MODE_CLOSED;
+	file = nullptr;
+
+	return true;
+}
+
+bool DroppedFile::isOpen() const
+{
+	return mode != MODE_CLOSED && file != nullptr;
+}
+
+int64 DroppedFile::getSize()
+{
+#ifdef LOVE_WINDOWS
+
+	// make sure non-ASCII filenames work.
+	std::wstring wfilename = to_widestr(filename);
+
+	struct _stat buf;
+	if (_wstat(wfilename.c_str(), &buf) != 0)
+		return -1;
+
+	return (int64) buf.st_size;
+
+#else
+
+	// Assume POSIX support...
+	struct stat buf;
+	if (stat(filename.c_str(), &buf) != 0)
+		return -1;
+
+	return (int64) buf.st_size;
+
+#endif
+}
+
+int64 DroppedFile::read(void *dst, int64 size)
+{
+	if (!file || mode != MODE_READ)
+		throw love::Exception("File is not opened for reading.");
+
+	if (size < 0)
+		throw love::Exception("Invalid read size.");
+
+	size_t read = fread(dst, 1, (size_t) size, file);
+
+	return (int64) read;
+}
+
+bool DroppedFile::write(const void *data, int64 size)
+{
+	if (!file || (mode != MODE_WRITE && mode != MODE_APPEND))
+		throw love::Exception("File is not opened for writing.");
+
+	if (size < 0)
+		throw love::Exception("Invalid write size.");
+
+	int64 written = (int64) fwrite(data, 1, (size_t) size, file);
+
+	return written == size;
+}
+
+bool DroppedFile::flush()
+{
+	if (!file || (mode != MODE_WRITE && mode != MODE_APPEND))
+		throw love::Exception("File is not opened for writing.");
+
+	return fflush(file) == 0;
+}
+
+bool DroppedFile::isEOF()
+{
+	return file == nullptr || feof(file) != 0;
+}
+
+int64 DroppedFile::tell()
+{
+	if (file == nullptr)
+		return -1;
+
+	return (int64) ftell(file);
+}
+
+bool DroppedFile::seek(uint64 pos)
+{
+	return file != nullptr && fseek(file, (long) pos, SEEK_SET) == 0;
+}
+
+bool DroppedFile::setBuffer(BufferMode bufmode, int64 size)
+{
+	if (size < 0)
+		return false;
+
+	if (bufmode == BUFFER_NONE)
+		size = 0;
+
+	// If the file isn't open, we'll make sure the buffer values are set in
+	// DroppedFile::open.
+	if (!isOpen())
+	{
+		bufferMode = bufmode;
+		bufferSize = size;
+		return true;
+	}
+
+	int vbufmode;
+	switch (bufmode)
+	{
+	case File::BUFFER_NONE:
+	default:
+		vbufmode = _IONBF;
+		break;
+	case File::BUFFER_LINE:
+		vbufmode = _IOLBF;
+		break;
+	case File::BUFFER_FULL:
+		vbufmode = _IOFBF;
+		break;
+	}
+
+	if (setvbuf(file, nullptr, vbufmode, (size_t) size) != 0)
+		return false;
+
+	bufferMode = bufmode;
+	bufferSize = size;
+
+	return true;
+}
+
+File::BufferMode DroppedFile::getBuffer(int64 &size) const
+{
+	size = bufferSize;
+	return bufferMode;
+}
+
+const std::string &DroppedFile::getFilename() const
+{
+	return filename;
+}
+
+File::Mode DroppedFile::getMode() const
+{
+	return mode;
+}
+
+const char *DroppedFile::getModeString(Mode mode)
+{
+	switch (mode)
+	{
+	case File::MODE_CLOSED:
+	default:
+		return "c";
+	case File::MODE_READ:
+		return "rb";
+	case File::MODE_WRITE:
+		return "wb";
+	case File::MODE_APPEND:
+		return "ab";
+	}
+}
+
+} // filesystem
+} // love

+ 83 - 0
jni/love/src/modules/filesystem/DroppedFile.h

@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_FILESYSTEM_DROPPED_FILE_H
+#define LOVE_FILESYSTEM_DROPPED_FILE_H
+
+// LOVE
+#include "common/config.h"
+#include "File.h"
+
+// C
+#include <cstdio>
+
+namespace love
+{
+namespace filesystem
+{
+
+/**
+ * File which is created when a user drags and drops an actual file onto the
+ * LOVE game. Uses C's stdio. Filenames are system-dependent full paths.
+ **/
+class DroppedFile : public File
+{
+public:
+
+	DroppedFile(const std::string &filename);
+	virtual ~DroppedFile();
+
+	// Implements File.
+	using File::read;
+	using File::write;
+	bool open(Mode mode) override;
+	bool close() override;
+	bool isOpen() const override;
+	int64 getSize() override;
+	int64 read(void *dst, int64 size) override;
+	bool write(const void *data, int64 size) override;
+	bool flush() override;
+	bool isEOF() override;
+	int64 tell() override;
+	bool seek(uint64 pos) override;
+	bool setBuffer(BufferMode bufmode, int64 size) override;
+	BufferMode getBuffer(int64 &size) const override;
+	Mode getMode() const override;
+	const std::string &getFilename() const override;
+
+private:
+
+	static const char *getModeString(Mode mode);
+
+	std::string filename;
+
+	FILE *file;
+
+	Mode mode;
+
+	BufferMode bufferMode;
+	int64 bufferSize;
+
+}; // DroppedFile
+
+} // filesystem
+} // love
+
+#endif // LOVE_FILESYSTEM_DROPPED_FILE_H

+ 66 - 4
jni/love/src/modules/filesystem/File.cpp

@@ -29,6 +29,68 @@ File::~File()
 {
 }
 
+FileData *File::read(int64 size)
+{
+	bool isopen = isOpen();
+
+	if (!isopen && !open(MODE_READ))
+		throw love::Exception("Could not read file %s.", getFilename().c_str());
+
+	int64 max = getSize();
+	int64 cur = tell();
+	size = (size == ALL) ? max : size;
+
+	if (size < 0)
+		throw love::Exception("Invalid read size.");
+
+	// Clamping because the file offset may be in a weird position.
+	if (cur < 0)
+		cur = 0;
+	else if (cur > max)
+		cur = max;
+
+	if (cur + size > max)
+		size = max - cur;
+
+	FileData *fileData = new FileData(size, getFilename());
+	int64 bytesRead = read(fileData->getData(), size);
+
+	if (bytesRead < 0 || (bytesRead == 0 && bytesRead != size))
+	{
+		delete fileData;
+		throw love::Exception("Could not read from file.");
+	}
+
+	if (bytesRead < size)
+	{
+		FileData *tmpFileData = new FileData(bytesRead, getFilename());
+		memcpy(tmpFileData->getData(), fileData->getData(), (size_t) bytesRead);
+		fileData->release();
+		fileData = tmpFileData;
+	}
+
+	if (!isopen)
+		close();
+
+	return fileData;
+}
+
+bool File::write(const Data *data, int64 size)
+{
+	return write(data->getData(), (size == ALL) ? data->getSize() : size);
+}
+
+std::string File::getExtension() const
+{
+	const std::string &filename = getFilename();
+	std::string::size_type idx = filename.rfind('.');
+
+	if (idx != std::string::npos)
+		return filename.substr(idx+1);
+	else
+		return std::string();
+}
+
 bool File::getConstant(const char *in, Mode &out)
 {
 	return modes.find(in, out);
@@ -51,10 +113,10 @@ bool File::getConstant(BufferMode in, const char *&out)
 
 StringMap<File::Mode, File::MODE_MAX_ENUM>::Entry File::modeEntries[] =
 {
-	{"c", File::CLOSED},
-	{"r", File::READ},
-	{"w", File::WRITE},
-	{"a", File::APPEND},
+	{"c", File::MODE_CLOSED},
+	{"r", File::MODE_READ},
+	{"w", File::MODE_WRITE},
+	{"a", File::MODE_APPEND},
 };
 
 StringMap<File::Mode, File::MODE_MAX_ENUM> File::modes(File::modeEntries, sizeof(File::modeEntries));

+ 10 - 10
jni/love/src/modules/filesystem/File.h

@@ -49,10 +49,10 @@ public:
 	 **/
 	enum Mode
 	{
-		CLOSED,
-		READ,
-		WRITE,
-		APPEND,
+		MODE_CLOSED,
+		MODE_READ,
+		MODE_WRITE,
+		MODE_APPEND,
 		MODE_MAX_ENUM
 	};
 
@@ -77,7 +77,7 @@ public:
 	/**
 	 * Opens the file in a certain mode.
 	 *
-	 * @param mode READ, WRITE, APPEND.
+	 * @param mode MODE_READ, MODE_WRITE, MODE_APPEND.
 	 * @return True if successful, false otherwise.
 	 **/
 	virtual bool open(Mode mode) = 0;
@@ -107,7 +107,7 @@ public:
 	 * @param size The number of bytes to attempt reading, or -1 for EOF.
 	 * @return A newly allocated Data object.
 	 **/
-	virtual FileData *read(int64 size = ALL) = 0;
+	virtual FileData *read(int64 size = ALL);
 
 	/**
 	 * Reads data into the destination buffer.
@@ -134,7 +134,7 @@ public:
 	 * @param size The number of bytes to attempt writing, or -1 for everything.
 	 * @return True of success, false otherwise.
 	 **/
-	virtual bool write(const Data *data, int64 size = ALL) = 0;
+	virtual bool write(const Data *data, int64 size = ALL);
 
 	/**
 	 * Flushes the currently buffered file data to disk. Only applicable in
@@ -147,7 +147,7 @@ public:
 	 *
 	 * @return True if EOF, false otherwise.
 	 **/
-	virtual bool eof() = 0;
+	virtual bool isEOF() = 0;
 
 	/**
 	 * Gets the current position in the File.
@@ -192,13 +192,13 @@ public:
 	 * Gets the filename for this File, or empty string if none.
 	 * @return The filename for this File.
 	 **/
-	virtual std::string getFilename() const = 0;
+	virtual const std::string &getFilename() const = 0;
 
 	/**
 	 * Gets the file extension for this File, or empty string if none.
 	 * @return The file extension for this File (without the dot).
 	 **/
-	virtual std::string getExtension() const = 0;
+	virtual std::string getExtension() const;
 
 	static bool getConstant(const char *in, Mode &out);
 	static bool getConstant(Mode in, const char *&out);

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

@@ -0,0 +1,105 @@
+/**
+ * Copyright (c) 2006-2015 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 "Filesystem.h"
+#include "common/utf8.h"
+
+// Assume POSIX or Visual Studio.
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(LOVE_MACOSX)
+#include "common/OSX.h"
+#elif defined(LOVE_IOS)
+#include "common/iOS.h"
+#elif defined(LOVE_WINDOWS)
+#include <windows.h>
+#include "common/utf8.h"
+#elif defined(LOVE_LINUX)
+#include <unistd.h>
+#endif
+
+namespace love
+{
+namespace filesystem
+{
+
+Filesystem::Filesystem()
+{
+}
+
+Filesystem::~Filesystem()
+{
+}
+
+bool Filesystem::isRealDirectory(const std::string &path) const
+{
+#ifdef LOVE_WINDOWS
+	// make sure non-ASCII paths work.
+	std::wstring wpath = to_widestr(path);
+
+	struct _stat buf;
+	if (_wstat(wpath.c_str(), &buf) != 0)
+		return false;
+
+	return (buf.st_mode & _S_IFDIR) == _S_IFDIR;
+#else
+	// Assume POSIX support...
+	struct stat buf;
+	if (stat(path.c_str(), &buf) != 0)
+		return false;
+
+	return S_ISDIR(buf.st_mode) != 0;
+#endif
+}
+
+std::string Filesystem::getExecutablePath() const
+{
+#if defined(LOVE_MACOSX)
+	return love::osx::getExecutablePath();
+#elif defined(LOVE_IOS)
+	return love::ios::getExecutablePath();
+#elif defined(LOVE_WINDOWS)
+
+	wchar_t buffer[MAX_PATH + 1] = {0};
+
+	if (GetModuleFileNameW(nullptr, buffer, MAX_PATH) == 0)
+		return "";
+
+	return to_utf8(buffer);
+
+#elif defined(LOVE_LINUX)
+
+	char buffer[2048] = {0};
+
+	ssize_t len = readlink("/proc/self/exe", buffer, 2048);
+	if (len <= 0)
+		return "";
+
+	return std::string(buffer, len);
+
+#else
+#error Missing implementation for Filesystem::getExecutablePath!
+#endif
+}
+
+} // filesystem
+} // love

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

@@ -0,0 +1,265 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_FILESYSTEM_FILESYSTEM_H
+#define LOVE_FILESYSTEM_FILESYSTEM_H
+
+// LOVE
+#include "common/config.h"
+#include "common/Module.h"
+#include "common/int.h"
+#include "FileData.h"
+#include "File.h"
+
+// C++
+#include <string>
+#include <vector>
+
+// In Windows, we would like to use "LOVE" as the
+// application folder, but in Linux, we like .love.
+#define LOVE_APPDATA_PREFIX ""
+#ifdef LOVE_WINDOWS
+#	define LOVE_APPDATA_FOLDER "LOVE"
+#	define LOVE_PATH_SEPARATOR "/"
+#	define LOVE_MAX_PATH _MAX_PATH
+#else
+#	if defined(LOVE_MACOSX) || defined(LOVE_IOS)
+#		define LOVE_APPDATA_FOLDER "LOVE"
+#	elif defined(LOVE_LINUX)
+#		define LOVE_APPDATA_FOLDER "love"
+#	else
+#		define LOVE_APPDATA_PREFIX "."
+#		define LOVE_APPDATA_FOLDER "love"
+#	endif
+#	define LOVE_PATH_SEPARATOR "/"
+#	define LOVE_MAX_PATH MAXPATHLEN
+#endif
+
+namespace love
+{
+namespace filesystem
+{
+
+class Filesystem : public Module
+{
+public:
+
+	Filesystem();
+	virtual ~Filesystem();
+
+	// Implements Module.
+	virtual ModuleType getModuleType() const { return M_FILESYSTEM; }
+
+	virtual void init(const char *arg0) = 0;
+
+	virtual void setFused(bool fused) = 0;
+	virtual bool isFused() const = 0;
+
+	/**
+	 * This sets up the save directory. If the
+	 * it is already set up, nothing happens.
+	 * @return True on success, false otherwise.
+	 **/
+	virtual bool setupWriteDirectory() = 0;
+
+	/**
+	 * Sets the name of the save folder.
+	 * @param ident The name of the game. Will be used to
+	 * to create the folder in the LOVE data folder.
+	 **/
+	virtual bool setIdentity(const char *ident, bool appendToPath = false) = 0;
+	virtual const char *getIdentity() const = 0;
+
+	/**
+	 * Sets the path to the game source.
+	 * This can only be set once.
+	 * @param source Path to a directory or a .love-file.
+	 **/
+	virtual bool setSource(const char *source) = 0;
+
+	/**
+	 * Gets the path to the game source.
+	 * Returns a 0-length string if the source has not been set.
+	 **/
+	virtual const char *getSource() const = 0;
+
+	virtual bool mount(const char *archive, const char *mountpoint, bool appendToPath = false) = 0;
+	virtual bool unmount(const char *archive) = 0;
+
+	/**
+	 * Creates a new file.
+	 **/
+	virtual File *newFile(const char *filename) const = 0;
+
+	/**
+	 * Creates a new FileData object. Data will be copied.
+	 * @param data Pointer to the data.
+	 * @param size The size of the data.
+	 * @param filename The full filename used to file type identification.
+	 **/
+	virtual FileData *newFileData(void *data, unsigned int size, const char *filename) const = 0;
+
+	/**
+	 * Creates a new FileData object from base64 data.
+	 * @param b64 The base64 data.
+	 **/
+	virtual FileData *newFileData(const char *b64, const char *filename) const = 0;
+
+	/**
+	 * Gets the current working directory.
+	 **/
+	virtual const char *getWorkingDirectory() = 0;
+
+	/**
+	 * Gets the user home directory.
+	 **/
+	virtual std::string getUserDirectory() = 0;
+
+	/**
+	 * Gets the APPDATA directory. On Windows, this is the folder
+	 * in the %APPDATA% enviroment variable. On Linux, this is the
+	 * user home folder.
+	 **/
+	virtual std::string getAppdataDirectory() = 0;
+
+	/**
+	 * Gets the full path of the save folder.
+	 **/
+	virtual const char *getSaveDirectory() = 0;
+
+	/**
+	 * Gets the full path to the directory containing the game source.
+	 * For example if the game source is C:\Games\mygame.love, this will return
+	 * C:\Games.
+	 **/
+	virtual std::string getSourceBaseDirectory() const = 0;
+
+	/**
+	 * Gets the real directory path containing the file.
+	 **/
+	virtual std::string getRealDirectory(const char *filename) const = 0;
+
+	/**
+	 * Checks if a path is a directory.
+	 * @param dir The directory name to check.
+	 **/
+	virtual bool isDirectory(const char *dir) const = 0;
+
+	/**
+	 * Checks if a filename exists.
+	 * @param file The filename to check.
+	 **/
+	virtual bool isFile(const char *file) const = 0;
+
+	/**
+	 * Creates a directory. Write dir must be set.
+	 * @param dir The directory to create.
+	 **/
+	virtual bool createDirectory(const char *dir) = 0;
+
+	/**
+	 * Removes a file (or directory).
+	 * @param file The file or directory to remove.
+	 **/
+	virtual bool remove(const char *file) = 0;
+
+	/**
+	 * Reads data from a file.
+	 * @param filename The name of the file to read from.
+	 * @param size The size in bytes of the data to read.
+	 **/
+	virtual FileData *read(const char *filename, int64 size = File::ALL) const = 0;
+
+	/**
+	 * Write data to a file.
+	 * @param filename The name of the file to write to.
+	 * @param data The data to write.
+	 * @param size The size in bytes of the data to write.
+	 **/
+	virtual void write(const char *filename, const void *data, int64 size) const = 0;
+
+	/**
+	 * Append data to a file, creating it if it doesn't exist.
+	 * @param filename The name of the file to write to.
+	 * @param data The data to append.
+	 * @param size The size in bytes of the data to append.
+	 **/
+	virtual void append(const char *filename, const void *data, int64 size) const = 0;
+
+	/**
+	 * This "native" method returns a table of all
+	 * files in a given directory.
+	 **/
+	virtual void getDirectoryItems(const char *dir, std::vector<std::string> &items) = 0;
+
+	/**
+	 * Gets the last modification time of a file, in seconds
+	 * since the Unix epoch.
+	 * @param filename The name of the file.
+	 **/
+	virtual int64 getLastModified(const char *filename) const = 0;
+
+	/**
+	 * Gets the size of a file in bytes.
+	 * @param filename The name of the file.
+	 **/
+	virtual int64 getSize(const char *filename) const = 0;
+
+	/**
+	 * Enable or disable symbolic link support in love.filesystem.
+	 **/
+	virtual void setSymlinksEnabled(bool enable) = 0;
+
+	/**
+	 * Gets whether symbolic link support is enabled.
+	 **/
+	virtual bool areSymlinksEnabled() const = 0;
+
+	/**
+	 * Gets whether a filepath is actually a symlink.
+	 * Always returns false if symlinks are not enabled.
+	 **/
+	virtual bool isSymlink(const char *filename) const = 0;
+
+	// Require path accessors
+	// Not const because it's R/W
+	virtual std::vector<std::string> &getRequirePath() = 0;
+
+	/**
+	 * Allows a full (OS-dependent) path to be used with Filesystem::mount.
+	 **/
+	virtual void allowMountingForPath(const std::string &path) = 0;
+
+	/**
+	 * Gets whether the given full (OS-dependent) path is a directory.
+	 **/
+	virtual bool isRealDirectory(const std::string &path) const;
+
+	/**
+	 * Gets the full platform-dependent path to the executable.
+	 **/
+	virtual std::string getExecutablePath() const;
+
+}; // Filesystem
+
+} // filesystem
+} // love
+
+#endif // LOVE_FILESYSTEM_FILESYSTEM_H

+ 32 - 99
jni/love/src/modules/filesystem/physfs/File.cpp

@@ -39,8 +39,8 @@ namespace physfs
 
 File::File(const std::string &filename)
 	: filename(filename)
-	, file(0)
-	, mode(CLOSED)
+	, file(nullptr)
+	, mode(MODE_CLOSED)
 	, bufferMode(BUFFER_NONE)
 	, bufferSize(0)
 {
@@ -48,25 +48,25 @@ File::File(const std::string &filename)
 
 File::~File()
 {
-	if (mode != CLOSED)
+	if (mode != MODE_CLOSED)
 		close();
 }
 
 bool File::open(Mode mode)
 {
-	if (mode == CLOSED)
+	if (mode == MODE_CLOSED)
 		return true;
 
 	// File must exist if read mode.
-	if ((mode == READ) && !PHYSFS_exists(filename.c_str()))
+	if ((mode == MODE_READ) && !PHYSFS_exists(filename.c_str()))
 		throw love::Exception("Could not open file %s. Does not exist.", filename.c_str());
 
 	// Check whether the write directory is set.
-	if ((mode == APPEND || mode == WRITE) && (PHYSFS_getWriteDir() == 0) && !hack_setupWriteDirectory())
+	if ((mode == MODE_APPEND || mode == MODE_WRITE) && (PHYSFS_getWriteDir() == 0) && !hack_setupWriteDirectory())
 		throw love::Exception("Could not set write directory.");
 
 	// File already open?
-	if (file != 0)
+	if (file != nullptr)
 		return false;
 
 	PHYSFS_getLastError(); // Clear the error buffer.
@@ -74,13 +74,13 @@ bool File::open(Mode mode)
 
 	switch (mode)
 	{
-	case READ:
+	case MODE_READ:
 		handle = PHYSFS_openRead(filename.c_str());
 		break;
-	case APPEND:
+	case MODE_APPEND:
 		handle = PHYSFS_openAppend(filename.c_str());
 		break;
-	case WRITE:
+	case MODE_WRITE:
 		handle = PHYSFS_openWrite(filename.c_str());
 		break;
 	default:
@@ -99,94 +99,50 @@ bool File::open(Mode mode)
 
 	this->mode = mode;
 
-	if (file != 0 && !setBuffer(bufferMode, bufferSize))
+	if (file != nullptr && !setBuffer(bufferMode, bufferSize))
 	{
 		// Revert to buffer defaults if we don't successfully set the buffer.
 		bufferMode = BUFFER_NONE;
 		bufferSize = 0;
 	}
 
-	return (file != 0);
+	return (file != nullptr);
 }
 
 bool File::close()
 {
-	if (!PHYSFS_close(file))
+	if (file == nullptr || !PHYSFS_close(file))
 		return false;
-	mode = CLOSED;
-	file = 0;
+
+	mode = MODE_CLOSED;
+	file = nullptr;
+
 	return true;
 }
 
 bool File::isOpen() const
 {
-	return mode != CLOSED && file != 0;
+	return mode != MODE_CLOSED && file != nullptr;
 }
 
 int64 File::getSize()
 {
 	// If the file is closed, open it to
 	// check the size.
-	if (file == 0)
+	if (file == nullptr)
 	{
-		open(READ);
-		int64 size = (int64)PHYSFS_fileLength(file);
+		open(MODE_READ);
+		int64 size = (int64) PHYSFS_fileLength(file);
 		close();
 		return size;
 	}
 
-	return (int64)PHYSFS_fileLength(file);
-}
-
-
-FileData *File::read(int64 size)
-{
-	bool isOpen = (file != 0);
-
-	if (!isOpen && !open(READ))
-		throw love::Exception("Could not read file %s.", filename.c_str());
-
-	int64 max = getSize();
-	int64 cur = tell();
-	size = (size == ALL) ? max : size;
-
-	if (size < 0)
-		throw love::Exception("Invalid read size.");
-
-	// Clamping because the file offset may be in a weird position.
-	if (cur < 0)
-		cur = 0;
-	else if (cur > max)
-		cur = max;
-
-	if (cur + size > max)
-		size = max - cur;
-
-	FileData *fileData = new FileData(size, getFilename());
-	int64 bytesRead = read(fileData->getData(), size);
-
-	if (bytesRead < 0 || (bytesRead == 0 && bytesRead != size))
-	{
-		delete fileData;
-		throw love::Exception("Could not read from file.");
-	}
-	if (bytesRead < size)
-	{
-		FileData *tmpFileData = new FileData(bytesRead, getFilename());
-		memcpy(tmpFileData->getData(), fileData->getData(), (size_t) bytesRead);
-		delete fileData;
-		fileData = tmpFileData;
-	}
-
-	if (!isOpen)
-		close();
-
-	return fileData;
+	return (int64) PHYSFS_fileLength(file);
 }
 
 int64 File::read(void *dst, int64 size)
 {
-	if (!file || mode != READ)
+	if (!file || mode != MODE_READ)
 		throw love::Exception("File is not opened for reading.");
 
 	int64 max = (int64)PHYSFS_fileLength(file);
@@ -205,7 +161,7 @@ int64 File::read(void *dst, int64 size)
 
 bool File::write(const void *data, int64 size)
 {
-	if (!file || (mode != WRITE && mode != APPEND))
+	if (!file || (mode != MODE_WRITE && mode != MODE_APPEND))
 		throw love::Exception("File is not opened for writing.");
 
 	// Another clamp, for the time being.
@@ -215,7 +171,7 @@ bool File::write(const void *data, int64 size)
 		throw love::Exception("Invalid write size.");
 
 	// Try to write.
-	int64 written = static_cast<int64>(PHYSFS_write(file, data, 1, (PHYSFS_uint32) size));
+	int64 written = (int64) PHYSFS_write(file, data, 1, (PHYSFS_uint32) size);
 
 	// Check that correct amount of data was written.
 	if (written != size)
@@ -231,14 +187,9 @@ bool File::write(const void *data, int64 size)
 	return true;
 }
 
-bool File::write(const Data *data, int64 size)
-{
-	return write(data->getData(), (size == ALL) ? data->getSize() : size);
-}
-
 bool File::flush()
 {
-	if (!file || (mode != WRITE && mode != APPEND))
+	if (!file || (mode != MODE_WRITE && mode != MODE_APPEND))
 		throw love::Exception("File is not opened for writing.");
 
 	return PHYSFS_flush(file) != 0;
@@ -261,16 +212,14 @@ inline bool test_eof(File *, PHYSFS_File *file)
 }
 #endif
 
-bool File::eof()
+bool File::isEOF()
 {
-	if (file == 0 || test_eof(this, file))
-		return true;
-	return false;
+	return file == nullptr || test_eof(this, file);
 }
 
 int64 File::tell()
 {
-	if (file == 0)
+	if (file == nullptr)
 		return -1;
 
 	return (int64) PHYSFS_tell(file);
@@ -278,23 +227,17 @@ int64 File::tell()
 
 bool File::seek(uint64 pos)
 {
-	if (file == 0)
-		return false;
-
-	if (!PHYSFS_seek(file, (PHYSFS_uint64) pos))
-		return false;
-	return true;
+	return file != nullptr && PHYSFS_seek(file, (PHYSFS_uint64) pos) != 0;
 }
 
 bool File::setBuffer(BufferMode bufmode, int64 size)
 {
-	// No negativity allowed!
 	if (size < 0)
 		return false;
 
 	// If the file isn't open, we'll make sure the buffer values are set in
 	// File::open.
-	if (file == 0 || mode == CLOSED)
+	if (!isOpen())
 	{
 		bufferMode = bufmode;
 		bufferSize = size;
@@ -331,21 +274,11 @@ File::BufferMode File::getBuffer(int64 &size) const
 	return bufferMode;
 }
 
-std::string File::getFilename() const
+const std::string &File::getFilename() const
 {
 	return filename;
 }
 
-std::string File::getExtension() const
-{
-	std::string::size_type idx = filename.rfind('.');
-
-	if (idx != std::string::npos)
-		return filename.substr(idx+1);
-	else
-		return std::string();
-}
-
 filesystem::File::Mode File::getMode() const
 {
 	return mode;

+ 17 - 18
jni/love/src/modules/filesystem/physfs/File.h

@@ -25,7 +25,7 @@
 #include "filesystem/File.h"
 
 // PhysFS
-#ifdef LOVE_MACOSX_USE_FRAMEWORKS
+#ifdef LOVE_APPLE_USE_FRAMEWORKS
 #include <physfs/physfs.h>
 #else
 #include <physfs.h>
@@ -54,23 +54,22 @@ public:
 	virtual ~File();
 
 	// Implements love::filesystem::File.
-	bool open(Mode mode);
-	bool close();
-	bool isOpen() const;
-	int64 getSize();
-	FileData *read(int64 size = ALL);
-	int64 read(void *dst, int64 size);
-	bool write(const void *data, int64 size);
-	bool write(const Data *data, int64 size = ALL);
-	bool flush();
-	bool eof();
-	int64 tell();
-	bool seek(uint64 pos);
-	bool setBuffer(BufferMode bufmode, int64 size);
-	BufferMode getBuffer(int64 &size) const;
-	Mode getMode() const;
-	std::string getFilename() const;
-	std::string getExtension() const;
+	using love::filesystem::File::read;
+	using love::filesystem::File::write;
+	bool open(Mode mode) override;
+	bool close() override;
+	bool isOpen() const override;
+	int64 getSize() override;
+	virtual int64 read(void *dst, int64 size) override;
+	bool write(const void *data, int64 size) override;
+	bool flush() override;
+	bool isEOF() override;
+	int64 tell() override;
+	bool seek(uint64 pos) override;
+	bool setBuffer(BufferMode bufmode, int64 size) override;
+	BufferMode getBuffer(int64 &size) const override;
+	Mode getMode() const override;
+	const std::string &getFilename() const override;
 
 private:
 

+ 80 - 164
jni/love/src/modules/filesystem/physfs/Filesystem.cpp

@@ -18,15 +18,37 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
-#include "common/config.h"
-
 #include <iostream>
 #include <sstream>
+#include <algorithm>
 
 #include "common/utf8.h"
 #include "common/b64.h"
 
 #include "Filesystem.h"
+#include "File.h"
+
+// PhysFS
+#ifdef LOVE_APPLE_USE_FRAMEWORKS
+#include <physfs/physfs.h>
+#else
+#include <physfs.h>
+#endif
+
+// For great CWD. (Current Working Directory)
+// Using this instead of boost::filesystem which totally
+// cramped our style.
+#ifdef LOVE_WINDOWS
+#	include <windows.h>
+#	include <direct.h>
+#else
+#	include <sys/param.h>
+#	include <unistd.h>
+#endif
+
+#ifdef LOVE_IOS
+#	include "common/iOS.h"
+#endif
 
 #include "SDL.h"
 #include <string>
@@ -81,15 +103,15 @@ namespace physfs
 {
 
 Filesystem::Filesystem()
-	: initialized(false)
-	, fused(false)
+	: fused(false)
 	, fusedSet(false)
 {
+	requirePath = {"?.lua", "?/init.lua"};
 }
 
 Filesystem::~Filesystem()
 {
-	if (initialized)
+	if (PHYSFS_isInit())
 		PHYSFS_deinit();
 }
 
@@ -101,13 +123,14 @@ const char *Filesystem::getName() const
 void Filesystem::init(const char *arg0)
 {
 	if (!PHYSFS_init(arg0))
-		throw Exception(PHYSFS_getLastError());
+		throw love::Exception("%s", PHYSFS_getLastError());
 
-#ifdef LOVE_ANDROID
-	PHYSFS_permitSymbolicLinks (1);
-#endif
+	PHYSFS_Version version = {};
+	PHYSFS_getLinkedVersion(&version);
 
-	initialized = true;
+	// FIXME: This is a workaround for a bug in PHYSFS_enumerateFiles in 2.1-alpha.
+	if (version.major == 2 && version.minor == 1)
+		PHYSFS_permitSymbolicLinks(1);
 }
 
 void Filesystem::setFused(bool fused)
@@ -127,7 +150,7 @@ bool Filesystem::isFused() const
 
 bool Filesystem::setIdentity(const char *ident, bool appendToPath)
 {
-	if (!initialized)
+	if (!PHYSFS_isInit())
 		return false;
 
 	std::string old_save_path = save_path_full;
@@ -185,7 +208,7 @@ bool Filesystem::setIdentity(const char *ident, bool appendToPath)
 
 	// Try to add the save directory to the search path.
 	// (No error on fail, it means that the path doesn't exist).
-	PHYSFS_addToSearchPath(save_path_full.c_str(), appendToPath);
+	PHYSFS_mount(save_path_full.c_str(), nullptr, appendToPath);
 
 	// HACK: This forces setupWriteDirectory to be called the next time a file
 	// is opened for writing - otherwise it won't be called at all if it was
@@ -202,7 +225,7 @@ const char *Filesystem::getIdentity() const
 
 bool Filesystem::setSource(const char *source)
 {
-	if (!initialized)
+	if (!PHYSFS_isInit())
 		return false;
 
 	// Check whether directory is already set.
@@ -253,7 +276,7 @@ bool Filesystem::setSource(const char *source)
 			new_search_path = game_path;
 			sdcard_main->close(sdcard_main);
 
-			if (!PHYSFS_addToSearchPath(new_search_path.c_str(), 1)) {
+			if (!PHYSFS_mount(new_search_path.c_str(), nullptr, 1)) {
 				SDL_Log ("mounting of %s failed", new_search_path.c_str());
 				return false;
 			}
@@ -265,10 +288,9 @@ bool Filesystem::setSource(const char *source)
 	}
 #else
 	// Add the directory.
-	if (!PHYSFS_addToSearchPath(new_search_path.c_str(), 1)) {
+	if (!PHYSFS_mount(new_search_path.c_str(), nullptr, 1)) {
 		SDL_Log ("mounting of %s failed", new_search_path.c_str());
 		return false;
-	}
 #endif
 
 	// Save the game source.
@@ -284,7 +306,7 @@ const char *Filesystem::getSource() const
 
 bool Filesystem::setupWriteDirectory()
 {
-	if (!initialized)
+	if (!PHYSFS_isInit())
 		return false;
 
 	// These must all be set.
@@ -329,7 +351,7 @@ bool Filesystem::setupWriteDirectory()
 		return false;
 
 	// Add the directory. (Will not be readded if already present).
-	if (!PHYSFS_addToSearchPath(save_path_full.c_str(), 0))
+	if (!PHYSFS_mount(save_path_full.c_str(), nullptr, 0))
 	{
 		PHYSFS_setWriteDir(nullptr); // Clear the write directory in case of error.
 		return false;
@@ -340,13 +362,18 @@ bool Filesystem::setupWriteDirectory()
 
 bool Filesystem::mount(const char *archive, const char *mountpoint, bool appendToPath)
 {
-	if (!initialized || !archive)
+	if (!PHYSFS_isInit() || !archive)
 		return false;
 
 	std::string realPath;
 	std::string sourceBase = getSourceBaseDirectory();
 
-	if (isFused() && sourceBase.compare(archive) == 0)
+	// Check whether the given archive path is in the list of allowed full paths.
+	auto it = std::find(allowedMountPaths.begin(), allowedMountPaths.end(), archive);
+
+	if (it != allowedMountPaths.end())
+		realPath = *it;
+	else if (isFused() && sourceBase.compare(archive) == 0)
 	{
 		// Special case: if the game is fused and the archive is the source's
 		// base directory, mount it even though it's outside of the save dir.
@@ -376,18 +403,23 @@ bool Filesystem::mount(const char *archive, const char *mountpoint, bool appendT
 	if (realPath.length() == 0)
 		return false;
 
-	return PHYSFS_mount(realPath.c_str(), mountpoint, appendToPath);
+	return PHYSFS_mount(realPath.c_str(), mountpoint, appendToPath) != 0;
 }
 
 bool Filesystem::unmount(const char *archive)
 {
-	if (!initialized || !archive)
+	if (!PHYSFS_isInit() || !archive)
 		return false;
 
 	std::string realPath;
 	std::string sourceBase = getSourceBaseDirectory();
 
-	if (isFused() && sourceBase.compare(archive) == 0)
+	// Check whether the given archive path is in the list of allowed full paths.
+	auto it = std::find(allowedMountPaths.begin(), allowedMountPaths.end(), archive);
+
+	if (it != allowedMountPaths.end())
+		realPath = *it;
+	else if (isFused() && sourceBase.compare(archive) == 0)
 	{
 		// Special case: if the game is fused and the archive is the source's
 		// base directory, unmount it even though it's outside of the save dir.
@@ -412,10 +444,10 @@ bool Filesystem::unmount(const char *archive)
 	if (!mountPoint)
 		return false;
 
-	return PHYSFS_removeFromSearchPath(realPath.c_str());
+	return PHYSFS_removeFromSearchPath(realPath.c_str()) != 0;
 }
 
-File *Filesystem::newFile(const char *filename) const
+love::filesystem::File *Filesystem::newFile(const char *filename) const
 {
 	return new File(filename);
 }
@@ -432,7 +464,7 @@ FileData *Filesystem::newFileData(void *data, unsigned int size, const char *fil
 
 FileData *Filesystem::newFileData(const char *b64, const char *filename) const
 {
-	int size = strlen(b64);
+	int size = (int) strlen(b64);
 	int outsize = 0;
 	char *dst = b64_decode(b64, size, outsize);
 	FileData *fd = new FileData(outsize, std::string(filename));
@@ -485,6 +517,8 @@ std::string Filesystem::getAppdataDirectory()
 		std::string udir = getUserDirectory();
 		udir.append("/Library/Application Support");
 		appdata = normalize(udir);
+#elif defined(LOVE_IOS)
+		appdata = normalize(love::ios::getAppdataDirectory());
 #elif defined(LOVE_LINUX)
 		char *xdgdatahome = getenv("XDG_DATA_HOME");
 		if (!xdgdatahome)
@@ -540,19 +574,14 @@ std::string Filesystem::getRealDirectory(const char *filename) const
 	return std::string(dir);
 }
 
-bool Filesystem::exists(const char *file) const
-{
-	return PHYSFS_exists(file);
-}
-
-bool Filesystem::isDirectory(const char *file) const
+bool Filesystem::isDirectory(const char *dir) const
 {
-	return PHYSFS_isDirectory(file);
+	return PHYSFS_isDirectory(dir) != 0;
 }
 
 bool Filesystem::isFile(const char *file) const
 {
-	return exists(file) && !isDirectory(file);
+	return PHYSFS_exists(file) && !PHYSFS_isDirectory(file);
 }
 
 bool Filesystem::createDirectory(const char *dir)
@@ -575,11 +604,11 @@ bool Filesystem::remove(const char *file)
 	return true;
 }
 
-Data *Filesystem::read(const char *filename, int64 size) const
+FileData *Filesystem::read(const char *filename, int64 size) const
 {
 	File file(filename);
 
-	file.open(File::READ);
+	file.open(File::MODE_READ);
 
 	// close() is called in the File destructor.
 	return file.read(size);
@@ -589,7 +618,7 @@ void Filesystem::write(const char *filename, const void *data, int64 size) const
 {
 	File file(filename);
 
-	file.open(File::WRITE);
+	file.open(File::MODE_WRITE);
 
 	// close() is called in the File destructor.
 	if (!file.write(data, size))
@@ -600,145 +629,21 @@ void Filesystem::append(const char *filename, const void *data, int64 size) cons
 {
 	File file(filename);
 
-	file.open(File::APPEND);
+	file.open(File::MODE_APPEND);
 
 	// close() is called in the File destructor.
 	if (!file.write(data, size))
 		throw love::Exception("Data could not be written.");
 }
 
-int Filesystem::getDirectoryItems(lua_State *L)
+void Filesystem::getDirectoryItems(const char *dir, std::vector<std::string> &items)
 {
-	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;
-
-	lua_newtable(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++;
-	}
+		items.push_back(*i);
 
 	PHYSFS_freeList(rc);
-
-	return 1;
-}
-
-int Filesystem::lines_i(lua_State *L)
-{
-	const int bufsize = 1024;
-	char buf[bufsize];
-	int linesize = 0;
-	bool newline = false;
-
-	File *file = luax_checktype<File>(L, lua_upvalueindex(1), "File", FILESYSTEM_FILE_T);
-
-	// Only accept read mode at this point.
-	if (file->getMode() != File::READ)
-		return luaL_error(L, "File needs to stay in read mode.");
-
-	int64 pos = file->tell();
-	int64 userpos = -1;
-
-	if (lua_isnoneornil(L, lua_upvalueindex(2)) == 0)
-	{
-		// User may have changed the file position.
-		userpos = pos;
-		pos = (int64) lua_tonumber(L, lua_upvalueindex(2));
-		if (userpos != pos)
-			file->seek(pos);
-	}
-
-	while (!newline && !file->eof())
-	{
-		// This 64-bit to 32-bit integer cast should be safe as it never exceeds bufsize.
-		int read = (int) file->read(buf, bufsize);
-		if (read < 0)
-			return luaL_error(L, "Could not read from file.");
-
-		linesize += read;
-
-		for (int i = 0; i < read; i++)
-		{
-			if (buf[i] == '\n')
-			{
-				linesize -= read - i;
-				newline = true;
-				break;
-			}
-		}
-	}
-
-	if (newline || (file->eof() && linesize > 0))
-	{
-		if (linesize < bufsize)
-		{
-			// We have the line in the buffer on the stack. No 'new' and 'read' needed.
-			lua_pushlstring(L, buf, linesize > 0 && buf[linesize - 1] == '\r' ? linesize - 1 : linesize);
-			if (userpos < 0)
-				file->seek(pos + linesize + 1);
-		}
-		else
-		{
-			char *str = 0;
-			try
-			{
-				str = new char[linesize + 1];
-			}
-			catch(std::bad_alloc &)
-			{
-				// Can't lua_error (longjmp) in exception handlers.
-			}
-
-			if (!str)
-				return luaL_error(L, "Out of memory.");
-
-			file->seek(pos);
-
-			// Read the \n anyway and save us a call to seek.
-			if (file->read(str, linesize + 1) == -1)
-			{
-				delete [] str;
-				return luaL_error(L, "Could not read from file.");
-			}
-
-			lua_pushlstring(L, str, str[linesize - 1] == '\r' ? linesize - 1 : linesize);
-			delete [] str;
-		}
-
-		if (userpos >= 0)
-		{
-			// Save new position in upvalue.
-			lua_pushnumber(L, (lua_Number)(pos + linesize + 1));
-			lua_replace(L, lua_upvalueindex(2));
-			file->seek(userpos);
-		}
-
-		return 1;
-	}
-
-	// EOF reached.
-	if (userpos >= 0 && luax_toboolean(L, lua_upvalueindex(3)))
-		file->seek(userpos);
-	else
-		file->close();
-
-	return 0;
 }
 
 int64 Filesystem::getLastModified(const char *filename) const
@@ -773,6 +678,17 @@ bool Filesystem::isSymlink(const char *filename) const
 	return PHYSFS_isSymbolicLink(filename) != 0;
 }
 
+std::vector<std::string> &Filesystem::getRequirePath()
+{
+	return requirePath;
+}
+
+void Filesystem::allowMountingForPath(const std::string &path)
+{
+	if (std::find(allowedMountPaths.begin(), allowedMountPaths.end(), path) == allowedMountPaths.end())
+		allowedMountPaths.push_back(path);
+}
+
 } // physfs
 } // filesystem
 } // love

+ 14 - 182
jni/love/src/modules/filesystem/physfs/Filesystem.h

@@ -24,46 +24,9 @@
 // STD
 #include <cstdlib>
 #include <cstring>
-#include <string>
 
 // LOVE
-#include "common/Module.h"
-#include "common/config.h"
-#include "common/int.h"
-#include "common/runtime.h"
-#include "filesystem/FileData.h"
-#include "File.h"
-
-// For great CWD. (Current Working Directory)
-// Using this instead of boost::filesystem which totally
-// cramped our style.
-#ifdef LOVE_WINDOWS
-#	include <windows.h>
-#	include <direct.h>
-#else
-#	include <sys/param.h>
-#	include <unistd.h>
-#endif
-
-// In Windows, we would like to use "LOVE" as the
-// application folder, but in Linux, we like .love.
-#define LOVE_APPDATA_PREFIX ""
-#ifdef LOVE_WINDOWS
-#	define LOVE_APPDATA_FOLDER "LOVE"
-#	define LOVE_PATH_SEPARATOR "/"
-#	define LOVE_MAX_PATH _MAX_PATH
-#else
-#	ifdef LOVE_MACOSX
-#		define LOVE_APPDATA_FOLDER "LOVE"
-#	elif defined(LOVE_LINUX)
-#		define LOVE_APPDATA_FOLDER "love"
-#	else
-#		define LOVE_APPDATA_PREFIX "."
-#		define LOVE_APPDATA_FOLDER "love"
-#	endif
-#	define LOVE_PATH_SEPARATOR "/"
-#	define LOVE_MAX_PATH MAXPATHLEN
-#endif
+#include "filesystem/Filesystem.h"
 
 namespace love
 {
@@ -72,7 +35,7 @@ namespace filesystem
 namespace physfs
 {
 
-class Filesystem : public Module
+class Filesystem : public love::filesystem::Filesystem
 {
 public:
 
@@ -80,7 +43,6 @@ public:
 	virtual ~Filesystem();
 
 	// Implements Module.
-	virtual ModuleType getModuleType() const { return M_FILESYSTEM; }
 	const char *getName() const;
 
 	void init(const char *arg0);
@@ -88,186 +50,54 @@ public:
 	void setFused(bool fused);
 	bool isFused() const;
 
-	/**
-	 * This sets up the save directory. If the
-	 * it is already set up, nothing happens.
-	 * @return True on success, false otherwise.
-	 **/
 	bool setupWriteDirectory();
 
-	/**
-	 * Sets the name of the save folder.
-	 * @param ident The name of the game. Will be used to
-	 * to create the folder in the LOVE data folder.
-	 **/
 	bool setIdentity(const char *ident, bool appendToPath = false);
 	const char *getIdentity() const;
 
-	/**
-	 * Sets the path to the game source.
-	 * This can only be set once.
-	 * @param source Path to a directory or a .love-file.
-	 **/
 	bool setSource(const char *source);
 
-	/**
-	 * Gets the path to the game source.
-	 * Returns a 0-length string if the source has not been set.
-	 **/
 	const char *getSource() const;
 
 	bool mount(const char *archive, const char *mountpoint, bool appendToPath = false);
 	bool unmount(const char *archive);
 
-	/**
-	 * Creates a new file.
-	 **/
 	File *newFile(const char *filename) const;
 
-	/**
-	 * Creates a new FileData object. Data will be copied.
-	 * @param data Pointer to the data.
-	 * @param size The size of the data.
-	 * @param filename The full filename used to file type identification.
-	 **/
 	FileData *newFileData(void *data, unsigned int size, const char *filename) const;
-
-	/**
-	 * Creates a new FileData object from base64 data.
-	 * @param b64 The base64 data.
-	 **/
 	FileData *newFileData(const char *b64, const char *filename) const;
 
-	/**
-	 * Gets the current working directory.
-	 **/
 	const char *getWorkingDirectory();
-
-	/**
-	 * Gets the user home directory.
-	 **/
 	std::string getUserDirectory();
-
-	/**
-	 * Gets the APPDATA directory. On Windows, this is the folder
-	 * in the %APPDATA% enviroment variable. On Linux, this is the
-	 * user home folder.
-	 **/
 	std::string getAppdataDirectory();
-
-	/**
-	 * Gets the full path of the save folder.
-	 **/
 	const char *getSaveDirectory();
-
-	/**
-	 * Gets the full path to the directory containing the game source.
-	 * For example if the game source is C:\Games\mygame.love, this will return
-	 * C:\Games.
-	 **/
 	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.
-	 * @param file The filename to check.
-	 **/
-	bool exists(const char *file) const;
-
-	/**
-	 * Checks if an existing file really is a directory.
-	 * @param file The filename to check.
-	 **/
-	bool isDirectory(const char *file) const;
-
-	/**
-	 * Checks if an existing file really is a file,
-	 * and not a directory.
-	 * @param file The filename to check.
-	 **/
+	bool isDirectory(const char *dir) const;
 	bool isFile(const char *file) const;
 
-	/**
-	 * Creates a directory. Write dir must be set.
-	 * @param dir The directory to create.
-	 **/
 	bool createDirectory(const char *dir);
 
-	/**
-	 * Removes a file (or directory).
-	 * @param file The file or directory to remove.
-	 **/
 	bool remove(const char *file);
 
-	/**
-	 * Reads data from a file.
-	 * @param filename The name of the file to read from.
-	 * @param size The size in bytes of the data to read.
-	 **/
-	Data *read(const char *filename, int64 size = File::ALL) const;
-
-	/**
-	 * Write data to a file.
-	 * @param filename The name of the file to write to.
-	 * @param data The data to write.
-	 * @param size The size in bytes of the data to write.
-	 **/
+	FileData *read(const char *filename, int64 size = File::ALL) const;
 	void write(const char *filename, const void *data, int64 size) const;
-
-	/**
-	 * Append data to a file, creating it if it doesn't exist.
-	 * @param filename The name of the file to write to.
-	 * @param data The data to append.
-	 * @param size The size in bytes of the data to append.
-	 **/
 	void append(const char *filename, const void *data, int64 size) const;
 
-	/**
-	 * This "native" method returns a table of all
-	 * files in a given directory.
-	 **/
-	int getDirectoryItems(lua_State *L);
-
-	/**
-	 * Gets the last modification time of a file, in seconds
-	 * since the Unix epoch.
-	 * @param filename The name of the file.
-	 **/
-	int64 getLastModified(const char *filename) const;
+	void getDirectoryItems(const char *dir, std::vector<std::string> &items);
 
-	/**
-	 * Gets the size of a file in bytes.
-	 * @param filename The name of the file.
-	 **/
+	int64 getLastModified(const char *filename) const;
 	int64 getSize(const char *filename) const;
 
-	/**
-	 * Enable or disable symbolic link support in love.filesystem.
-	 **/
 	void setSymlinksEnabled(bool enable);
-
-	/**
-	 * Gets whether symbolic link support is enabled.
-	 **/
 	bool areSymlinksEnabled() const;
-
-	/**
-	 * Gets whether a filepath is actually a symlink.
-	 * Always returns false if symlinks are not enabled.
-	 **/
 	bool isSymlink(const char *filename) const;
 
-	/**
-	 * Text file line-reading iterator function used and
-	 * pushed on the Lua stack by love.filesystem.lines
-	 * and File:lines.
-	 **/
-	static int lines_i(lua_State *L);
+	std::vector<std::string> &getRequirePath();
+
+	void allowMountingForPath(const std::string &path);
 
 private:
 
@@ -289,14 +119,16 @@ private:
 	// The full path to the source of the game.
 	std::string game_source;
 
-	// Workaround for machines without PhysFS 2.0
-	bool initialized;
-
 	// Allow saving outside of the LOVE_APPDATA_FOLDER
 	// for release 'builds'
 	bool fused;
 	bool fusedSet;
 
+	// Search path for require
+	std::vector<std::string> requirePath;
+
+	std::vector<std::string> allowedMountPaths;
+
 }; // Filesystem
 
 } // physfs

+ 62 - 0
jni/love/src/modules/filesystem/wrap_DroppedFile.cpp

@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "wrap_DroppedFile.h"
+#include "wrap_File.h"
+
+namespace love
+{
+namespace filesystem
+{
+
+DroppedFile *luax_checkdroppedfile(lua_State *L, int idx)
+{
+	return luax_checktype<DroppedFile>(L, idx, FILESYSTEM_DROPPED_FILE_ID);
+}
+
+static const luaL_Reg functions[] =
+{
+	// Inherits from File.
+	{ "getSize", w_File_getSize },
+	{ "open", w_File_open },
+	{ "close", w_File_close },
+	{ "isOpen", w_File_isOpen },
+	{ "read", w_File_read },
+	{ "write", w_File_write },
+	{ "flush", w_File_flush },
+	{ "isEOF", w_File_isEOF },
+	{ "tell", w_File_tell },
+	{ "seek", w_File_seek },
+	{ "lines", w_File_lines },
+	{ "setBuffer", w_File_setBuffer },
+	{ "getBuffer", w_File_getBuffer },
+	{ "getMode", w_File_getMode },
+	{ "getFilename", w_File_getFilename },
+	{ "getExtension", w_File_getExtension },
+	{ 0, 0 }
+};
+
+extern "C" int luaopen_droppedfile(lua_State *L)
+{
+	return luax_register_type(L, FILESYSTEM_DROPPED_FILE_ID, functions);
+}
+
+} // filesystem
+} // love

+ 39 - 0
jni/love/src/modules/filesystem/wrap_DroppedFile.h

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

+ 131 - 15
jni/love/src/modules/filesystem/wrap_File.cpp

@@ -20,8 +20,6 @@
 
 #include "wrap_File.h"
 
-#include "physfs/Filesystem.h"
-
 #include "common/Data.h"
 #include "common/Exception.h"
 #include "common/int.h"
@@ -45,7 +43,7 @@ int luax_ioError(lua_State *L, const char *fmt, ...)
 
 File *luax_checkfile(lua_State *L, int idx)
 {
-	return luax_checktype<File>(L, idx, "File", FILESYSTEM_FILE_T);
+	return luax_checktype<File>(L, idx, FILESYSTEM_FILE_ID);
 }
 
 int w_File_getSize(lua_State *L)
@@ -112,7 +110,7 @@ int w_File_read(lua_State *L)
 	File *file = luax_checkfile(L, 1);
 	Data *d = 0;
 
-	int64 size = (int64)luaL_optnumber(L, 2, File::ALL);
+	int64 size = (int64) luaL_optnumber(L, 2, (lua_Number) File::ALL);
 
 	try
 	{
@@ -151,11 +149,11 @@ int w_File_write(lua_State *L)
 			return luax_ioError(L, "%s", e.what());
 		}
 	}
-	else if (luax_istype(L, 2, DATA_T))
+	else if (luax_istype(L, 2, DATA_ID))
 	{
 		try
 		{
-			love::Data *data = luax_totype<love::Data>(L, 2, "Data", DATA_T);
+			love::Data *data = luax_totype<love::Data>(L, 2, DATA_ID);
 			result = file->write(data, luaL_optinteger(L, 3, data->getSize()));
 		}
 		catch (love::Exception &e)
@@ -188,10 +186,10 @@ int w_File_flush(lua_State *L)
 	return 1;
 }
 
-int w_File_eof(lua_State *L)
+int w_File_isEOF(lua_State *L)
 {
 	File *file = luax_checkfile(L, 1);
-	luax_pushboolean(L, file->eof());
+	luax_pushboolean(L, file->isEOF());
 	return 1;
 }
 
@@ -223,26 +221,128 @@ int w_File_seek(lua_State *L)
 	return 1;
 }
 
+int w_File_lines_i(lua_State *L)
+{
+	const int bufsize = 1024;
+	char buf[bufsize];
+	int linesize = 0;
+	bool newline = false;
+
+	File *file = luax_checktype<File>(L, lua_upvalueindex(1), FILESYSTEM_FILE_ID);
+
+	// Only accept read mode at this point.
+	if (file->getMode() != File::MODE_READ)
+		return luaL_error(L, "File needs to stay in read mode.");
+
+	int64 pos = file->tell();
+	int64 userpos = -1;
+
+	if (lua_isnoneornil(L, lua_upvalueindex(2)) == 0)
+	{
+		// User may have changed the file position.
+		userpos = pos;
+		pos = (int64) lua_tonumber(L, lua_upvalueindex(2));
+		if (userpos != pos)
+			file->seek(pos);
+	}
+
+	while (!newline && !file->isEOF())
+	{
+		// This 64-bit to 32-bit integer cast should be safe as it never exceeds bufsize.
+		int read = (int) file->read(buf, bufsize);
+		if (read < 0)
+			return luaL_error(L, "Could not read from file.");
+
+		linesize += read;
+
+		for (int i = 0; i < read; i++)
+		{
+			if (buf[i] == '\n')
+			{
+				linesize -= read - i;
+				newline = true;
+				break;
+			}
+		}
+	}
+
+	if (newline || (file->isEOF() && linesize > 0))
+	{
+		if (linesize < bufsize)
+		{
+			// We have the line in the buffer on the stack. No 'new' and 'read' needed.
+			lua_pushlstring(L, buf, linesize > 0 && buf[linesize - 1] == '\r' ? linesize - 1 : linesize);
+			if (userpos < 0)
+				file->seek(pos + linesize + 1);
+		}
+		else
+		{
+			char *str = 0;
+			try
+			{
+				str = new char[linesize + 1];
+			}
+			catch(std::bad_alloc &)
+			{
+				// Can't lua_error (longjmp) in exception handlers.
+			}
+
+			if (!str)
+				return luaL_error(L, "Out of memory.");
+
+			file->seek(pos);
+
+			// Read the \n anyway and save us a call to seek.
+			if (file->read(str, linesize + 1) == -1)
+			{
+				delete [] str;
+				return luaL_error(L, "Could not read from file.");
+			}
+
+			lua_pushlstring(L, str, str[linesize - 1] == '\r' ? linesize - 1 : linesize);
+			delete [] str;
+		}
+
+		if (userpos >= 0)
+		{
+			// Save new position in upvalue.
+			lua_pushnumber(L, (lua_Number)(pos + linesize + 1));
+			lua_replace(L, lua_upvalueindex(2));
+			file->seek(userpos);
+		}
+
+		return 1;
+	}
+
+	// EOF reached.
+	if (userpos >= 0 && luax_toboolean(L, lua_upvalueindex(3)))
+		file->seek(userpos);
+	else
+		file->close();
+
+	return 0;
+}
+
 int w_File_lines(lua_State *L)
 {
 	File *file = luax_checkfile(L, 1);
 
 	lua_pushnumber(L, 0); // File position.
-	luax_pushboolean(L, file->getMode() != File::CLOSED); // Save current file mode.
+	luax_pushboolean(L, file->getMode() != File::MODE_CLOSED); // Save current file mode.
 
-	if (file->getMode() != File::READ)
+	if (file->getMode() != File::MODE_READ)
 	{
-		if (file->getMode() != File::CLOSED)
+		if (file->getMode() != File::MODE_CLOSED)
 			file->close();
 
 		bool success = false;
-		luax_catchexcept(L, [&](){ success = file->open(File::READ); });
+		luax_catchexcept(L, [&](){ success = file->open(File::MODE_READ); });
 
 		if (!success)
 			return luaL_error(L, "Could not open file.");
 	}
 
-	lua_pushcclosure(L, physfs::Filesystem::lines_i, 3);
+	lua_pushcclosure(L, w_File_lines_i, 3);
 	return 1;
 }
 
@@ -299,6 +399,20 @@ int w_File_getMode(lua_State *L)
 	return 1;
 }
 
+int w_File_getFilename(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+	luax_pushstring(L, file->getFilename());
+	return 1;
+}
+
+int w_File_getExtension(lua_State *L)
+{
+	File *file = luax_checkfile(L, 1);
+	luax_pushstring(L, file->getExtension());
+	return 1;
+}
+
 static const luaL_Reg functions[] =
 {
 	{ "getSize", w_File_getSize },
@@ -308,19 +422,21 @@ static const luaL_Reg functions[] =
 	{ "read", w_File_read },
 	{ "write", w_File_write },
 	{ "flush", w_File_flush },
-	{ "eof", w_File_eof },
+	{ "isEOF", w_File_isEOF },
 	{ "tell", w_File_tell },
 	{ "seek", w_File_seek },
 	{ "lines", w_File_lines },
 	{ "setBuffer", w_File_setBuffer },
 	{ "getBuffer", w_File_getBuffer },
 	{ "getMode", w_File_getMode },
+	{ "getFilename", w_File_getFilename },
+	{ "getExtension", w_File_getExtension },
 	{ 0, 0 }
 };
 
 extern "C" int luaopen_file(lua_State *L)
 {
-	return luax_register_type(L, "File", functions);
+	return luax_register_type(L, FILESYSTEM_FILE_ID, functions);
 }
 
 } // filesystem

+ 4 - 1
jni/love/src/modules/filesystem/wrap_File.h

@@ -41,13 +41,16 @@ int w_File_isOpen(lua_State *L);
 int w_File_read(lua_State *L);
 int w_File_write(lua_State *L);
 int w_File_flush(lua_State *L);
-int w_File_eof(lua_State *L);
+int w_File_isEOF(lua_State *L);
 int w_File_tell(lua_State *L);
 int w_File_seek(lua_State *L);
+int w_File_lines_i(lua_State *L);
 int w_File_lines(lua_State *L);
 int w_File_setBuffer(lua_State *L);
 int w_File_getBuffer(lua_State *L);
 int w_File_getMode(lua_State *L);
+int w_File_getFilename(lua_State *L);
+int w_File_getExtension(lua_State *L);
 extern "C" int luaopen_file(lua_State *L);
 
 } // filesystem

+ 2 - 2
jni/love/src/modules/filesystem/wrap_FileData.cpp

@@ -29,7 +29,7 @@ namespace filesystem
 
 FileData *luax_checkfiledata(lua_State *L, int idx)
 {
-	return luax_checktype<FileData>(L, idx, "FileData", FILESYSTEM_FILE_DATA_T);
+	return luax_checktype<FileData>(L, idx, FILESYSTEM_FILE_DATA_ID);
 }
 
 int w_FileData_getFilename(lua_State *L)
@@ -61,7 +61,7 @@ static const luaL_Reg w_FileData_functions[] =
 
 extern "C" int luaopen_filedata(lua_State *L)
 {
-	return luax_register_type(L, "FileData", w_FileData_functions);
+	return luax_register_type(L, FILESYSTEM_FILE_DATA_ID, w_FileData_functions);
 }
 
 } // filesystem

+ 92 - 61
jni/love/src/modules/filesystem/wrap_Filesystem.cpp

@@ -21,6 +21,7 @@
 // LOVE
 #include "wrap_Filesystem.h"
 #include "wrap_File.h"
+#include "wrap_DroppedFile.h"
 #include "wrap_FileData.h"
 
 #include "physfs/Filesystem.h"
@@ -28,12 +29,17 @@
 // SDL
 #include <SDL_loadso.h>
 
+// STL
+#include <vector>
+#include <string>
+#include <sstream>
+
 namespace love
 {
 namespace filesystem
 {
-	
-#define instance() (Module::getInstance<physfs::Filesystem>(Module::M_FILESYSTEM))
+
+#define instance() (Module::getInstance<Filesystem>(Module::M_FILESYSTEM))
 
 bool hack_setupWriteDirectory()
 {
@@ -119,7 +125,7 @@ int w_newFile(lua_State *L)
 	const char *filename = luaL_checkstring(L, 1);
 
 	const char *str = 0;
-	File::Mode mode = File::CLOSED;
+	File::Mode mode = File::MODE_CLOSED;
 
 	if (lua_isstring(L, 2))
 	{
@@ -130,7 +136,7 @@ int w_newFile(lua_State *L)
 
 	File *t = instance()->newFile(filename);
 
-	if (mode != File::CLOSED)
+	if (mode != File::MODE_CLOSED)
 	{
 		try
 		{
@@ -144,7 +150,7 @@ int w_newFile(lua_State *L)
 		}
 	}
 
-	luax_pushtype(L, "File", FILESYSTEM_FILE_T, t);
+	luax_pushtype(L, FILESYSTEM_FILE_ID, t);
 	t->release();
 	return 1;
 }
@@ -159,12 +165,12 @@ FileData *luax_getfiledata(lua_State *L, int idx)
 		const char *filename = luaL_checkstring(L, idx);
 		file = instance()->newFile(filename);
 	}
-	else if (luax_istype(L, idx, FILESYSTEM_FILE_T))
+	else if (luax_istype(L, idx, FILESYSTEM_FILE_ID))
 	{
 		file = luax_checkfile(L, idx);
 		file->retain();
 	}
-	else if (luax_istype(L, idx, FILESYSTEM_FILE_DATA_T))
+	else if (luax_istype(L, idx, FILESYSTEM_FILE_DATA_ID))
 	{
 		data = luax_checkfiledata(L, idx);
 		data->retain();
@@ -180,7 +186,7 @@ FileData *luax_getfiledata(lua_State *L, int idx)
 	{
 		luax_catchexcept(L,
 			[&]() { data = file->read(); },
-			[&]() { file->release(); }
+			[&](bool) { file->release(); }
 		);
 	}
 
@@ -197,7 +203,7 @@ int w_newFileData(lua_State *L)
 			luax_convobj(L, 1, "filesystem", "newFile");
 
 		// Get FileData from the File.
-		if (luax_istype(L, 1, FILESYSTEM_FILE_T))
+		if (luax_istype(L, 1, FILESYSTEM_FILE_ID))
 		{
 			File *file = luax_checkfile(L, 1);
 
@@ -210,7 +216,7 @@ int w_newFileData(lua_State *L)
 			{
 				return luax_ioError(L, "%s", e.what());
 			}
-			luax_pushtype(L, "FileData", FILESYSTEM_FILE_DATA_T, data);
+			luax_pushtype(L, FILESYSTEM_FILE_DATA_ID, data);
 			data->release();
 			return 1;
 		}
@@ -242,7 +248,7 @@ int w_newFileData(lua_State *L)
 		return luaL_error(L, "Invalid FileData decoder: %s", decstr);
 	}
 
-	luax_pushtype(L, "FileData", FILESYSTEM_FILE_DATA_T, t);
+	luax_pushtype(L, FILESYSTEM_FILE_DATA_ID, t);
 	t->release();
 	return 1;
 }
@@ -295,10 +301,9 @@ int w_getRealDirectory(lua_State *L)
 	return 1;
 }
 
-int w_exists(lua_State *L)
+int w_getExecutablePath(lua_State *L)
 {
-	const char *arg = luaL_checkstring(L, 1);
-	luax_pushboolean(L, instance()->exists(arg));
+	luax_pushstring(L, instance()->getExecutablePath());
 	return 1;
 }
 
@@ -367,9 +372,9 @@ static int w_write_or_append(lua_State *L, File::Mode mode)
 	const char *input = 0;
 	size_t len = 0;
 
-	if (luax_istype(L, 2, DATA_T))
+	if (luax_istype(L, 2, DATA_ID))
 	{
-		love::Data *data = luax_totype<love::Data>(L, 2, "Data", DATA_T);
+		love::Data *data = luax_totype<love::Data>(L, 2, DATA_ID);
 		input = (const char *) data->getData();
 		len = data->getSize();
 	}
@@ -383,7 +388,7 @@ static int w_write_or_append(lua_State *L, File::Mode mode)
 
 	try
 	{
-		if (mode == File::APPEND)
+		if (mode == File::MODE_APPEND)
 			instance()->append(filename, (const void *) input, len);
 		else
 			instance()->write(filename, (const void *) input, len);
@@ -399,17 +404,31 @@ static int w_write_or_append(lua_State *L, File::Mode mode)
 
 int w_write(lua_State *L)
 {
-	return w_write_or_append(L, File::WRITE);
+	return w_write_or_append(L, File::MODE_WRITE);
 }
 
 int w_append(lua_State *L)
 {
-	return w_write_or_append(L, File::APPEND);
+	return w_write_or_append(L, File::MODE_APPEND);
 }
 
 int w_getDirectoryItems(lua_State *L)
 {
-	return instance()->getDirectoryItems(L);
+	const char *dir = luaL_checkstring(L, 1);
+	std::vector<std::string> items;
+
+	instance()->getDirectoryItems(dir, items);
+
+	lua_createtable(L, (int) items.size(), 0);
+
+	for (int i = 0; i < (int) items.size(); i++)
+	{
+		lua_pushstring(L, items[i].c_str());
+		lua_rawseti(L, -2, i + 1);
+	}
+
+	// Return the table.
+	return 1;
 }
 
 int w_lines(lua_State *L)
@@ -421,7 +440,7 @@ int w_lines(lua_State *L)
 		file = instance()->newFile(lua_tostring(L, 1));
 		bool success = false;
 
-		luax_catchexcept(L, [&](){ success = file->open(File::READ); });
+		luax_catchexcept(L, [&](){ success = file->open(File::MODE_READ); });
 
 		if (!success)
 		{
@@ -429,13 +448,13 @@ int w_lines(lua_State *L)
 			return luaL_error(L, "Could not open file.");
 		}
 
-		luax_pushtype(L, "File", FILESYSTEM_FILE_T, file);
+		luax_pushtype(L, FILESYSTEM_FILE_ID, file);
 		file->release();
 	}
 	else
 		return luaL_argerror(L, 1, "expected filename.");
 
-	lua_pushcclosure(L, physfs::Filesystem::lines_i, 1);
+	lua_pushcclosure(L, w_File_lines_i, 1);
 	return 1;
 }
 
@@ -530,58 +549,67 @@ int w_isSymlink(lua_State *L)
 	return 1;
 }
 
-int loader(lua_State *L)
+int w_getRequirePath(lua_State *L)
 {
-	const char *filename = lua_tostring(L, -1);
+	std::stringstream path;
+	bool seperator = false;
+	for (auto &element : instance()->getRequirePath())
+	{
+		if (seperator)
+			path << ";";
+		else
+			seperator = true;
+
+		path << element;
+	}
+
+	luax_pushstring(L, path.str());
+	return 1;
+}
 
-	std::string tmp(filename);
-	tmp += ".lua";
+int w_setRequirePath(lua_State *L)
+{
+	std::string element = luax_checkstring(L, 1);
+	auto &requirePath = instance()->getRequirePath();
 
-	int size = tmp.size();
+	requirePath.clear();
+	std::stringstream path;
+	path << element;
 
-	for (int i=0; i<size-4; i++)
-	{
-		if (tmp[i] == '.')
-		{
-			tmp[i] = '/';
-		}
-	}
+	while(std::getline(path, element, ';'))
+		requirePath.push_back(element);
 
-	// Check whether file exists.
-	if (instance()->exists(tmp.c_str()))
-	{
-		lua_pop(L, 1);
-		lua_pushstring(L, tmp.c_str());
-		// Ok, load it.
-		return w_load(L);
-	}
+	return 0;
+}
+
+int loader(lua_State *L)
+{
+	std::string modulename = luax_tostring(L, 1);
 
-	tmp = filename;
-	size = tmp.size();
-	for (int i=0; i<size; i++)
+	for (char &c : modulename)
 	{
-		if (tmp[i] == '.')
-		{
-			tmp[i] = '/';
-		}
+		if (c == '.')
+			c = '/';
 	}
 
-	if (instance()->isDirectory(tmp.c_str()))
+	auto *inst = instance();
+	for (std::string element : inst->getRequirePath())
 	{
-		tmp += "/init.lua";
-		if (instance()->exists(tmp.c_str()))
+		size_t pos = element.find('?');
+		if (pos != std::string::npos)
+			element.replace(pos, 1, modulename);
+
+		if (inst->isFile(element.c_str()))
 		{
 			lua_pop(L, 1);
-			lua_pushstring(L, tmp.c_str());
-			// Ok, load it.
+			lua_pushstring(L, element.c_str());
 			return w_load(L);
 		}
 	}
 
-	std::string errstr = "\n\tno file '%s' in LOVE game directories.";
-	errstr += errstr;
+	std::string errstr = "\n\tno '%s' in LOVE game directories.";
 
-	lua_pushfstring(L, errstr.c_str(), (tmp + ".lua").c_str(), (tmp + "/init.lua").c_str());
+	lua_pushfstring(L, errstr.c_str(), modulename.c_str());
 	return 1;
 }
 
@@ -677,7 +705,7 @@ static const luaL_Reg functions[] =
 	{ "getSaveDirectory", w_getSaveDirectory },
 	{ "getSourceBaseDirectory", w_getSourceBaseDirectory },
 	{ "getRealDirectory", w_getRealDirectory },
-	{ "exists", w_exists },
+	{ "getExecutablePath", w_getExecutablePath },
 	{ "isDirectory", w_isDirectory },
 	{ "isFile", w_isFile },
 	{ "createDirectory", w_createDirectory },
@@ -694,19 +722,22 @@ static const luaL_Reg functions[] =
 	{ "areSymlinksEnabled", w_areSymlinksEnabled },
 	{ "isSymlink", w_isSymlink },
 	{ "newFileData", w_newFileData },
+	{ "getRequirePath", w_getRequirePath },
+	{ "setRequirePath", w_setRequirePath },
 	{ 0, 0 }
 };
 
 static const lua_CFunction types[] =
 {
 	luaopen_file,
+	luaopen_droppedfile,
 	luaopen_filedata,
 	0
 };
 
 extern "C" int luaopen_love_filesystem(lua_State *L)
 {
-	physfs::Filesystem *instance = instance();
+	Filesystem *instance = instance();
 	if (instance == nullptr)
 	{
 		luax_catchexcept(L, [&](){ instance = new physfs::Filesystem(); });
@@ -721,7 +752,7 @@ extern "C" int luaopen_love_filesystem(lua_State *L)
 	WrappedModule w;
 	w.module = instance;
 	w.name = "filesystem";
-	w.flags = MODULE_FILESYSTEM_T;
+	w.type = MODULE_FILESYSTEM_ID;
 	w.functions = functions;
 	w.types = types;
 

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

@@ -57,7 +57,7 @@ int w_getAppdataDirectory(lua_State *L);
 int w_getSaveDirectory(lua_State *L);
 int w_getSourceBaseDirectory(lua_State *L);
 int w_getRealDirectory(lua_State *L);
-int w_exists(lua_State *L);
+int w_getExecutablePath(lua_State *L);
 int w_isDirectory(lua_State *L);
 int w_isFile(lua_State *L);
 int w_createDirectory(lua_State *L);
@@ -75,6 +75,8 @@ int w_getSize(lua_State *L);
 int w_setSymlinksEnabled(lua_State *L);
 int w_areSymlinksEnabled(lua_State *L);
 int w_isSymlink(lua_State *L);
+int w_getRequirePath(lua_State *L);
+int w_setRequirePath(lua_State *L);
 int loader(lua_State *L);
 int extloader(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_filesystem(lua_State *L);

+ 338 - 0
jni/love/src/modules/font/BMFontRasterizer.cpp

@@ -0,0 +1,338 @@
+/**
+ * Copyright (c) 2006-2015 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 "BMFontRasterizer.h"
+#include "filesystem/Filesystem.h"
+#include "image/Image.h"
+
+// C++
+#include <sstream>
+#include <vector>
+#include <algorithm>
+
+// C
+#include <cstdlib>
+#include <cstring>
+
+namespace love
+{
+namespace font
+{
+
+namespace
+{
+
+/**
+ * Helper class for parsing lines in BMFont definition files.
+ * NOTE: Does not properly handle multi-value attributes (e.g. 'padding' or
+ * 'spacing'.)
+ **/
+class BMFontLine
+{
+public:
+
+	BMFontLine(const std::string &line);
+
+	const std::string &getTag() const { return tag; }
+
+	int getAttributeInt(const char *name) const;
+	std::string getAttributeString(const char *name) const;
+
+private:
+
+	std::string tag;
+	std::unordered_map<std::string, std::string> attributes;
+
+};
+
+// This is not entirely robust...
+BMFontLine::BMFontLine(const std::string &line)
+{
+	// The tag name should always be at the start of the line.
+	tag = line.substr(0, line.find(' '));
+
+	size_t startpos = 0;
+
+	while (startpos < line.length())
+	{
+		// Find the next '=', which indicates a key-value pair.
+		size_t fpos = line.find('=', startpos);
+		if (fpos == std::string::npos || fpos + 1 >= line.length())
+			break;
+
+		// The key should be between a space character and the '='.
+		size_t keystart = line.rfind(' ', fpos);
+		if (keystart == std::string::npos)
+			break;
+
+		keystart++;
+
+		std::string key = line.substr(keystart, fpos - keystart);
+
+		size_t valstart = fpos + 1;
+		size_t valend = valstart + 1;
+
+		if (line[valstart] == '"')
+		{
+			// Values can be surrounded by quotes (a literal string.)
+			valstart++;
+			valend = line.find('"', valstart) - 1;
+		}
+		else
+		{
+			// Otherwise look for the next space character after the '='.
+			valend = line.find(' ', valstart + 1) - 1;
+		}
+
+		valend = std::min(valend, line.length() - 1);
+
+		attributes[key] = line.substr(valstart, valend - valstart + 1);
+
+		startpos = valend + 1;
+	}
+}
+
+int BMFontLine::getAttributeInt(const char *name) const
+{
+	auto it = attributes.find(name);
+	if (it == attributes.end())
+		return 0;
+
+	return (int) strtol(it->second.c_str(), nullptr, 10);
+}
+
+std::string BMFontLine::getAttributeString(const char *name) const
+{
+	auto it = attributes.find(name);
+	if (it == attributes.end())
+		return "";
+
+	return it->second;
+}
+
+} // anonymous namespace
+
+
+BMFontRasterizer::BMFontRasterizer(love::filesystem::FileData *fontdef, const std::vector<image::ImageData *> &imagelist)
+	: fontSize(0)
+	, unicode(false)
+	, lineHeight(0)
+{
+	const std::string &filename = fontdef->getFilename();
+
+	size_t separatorpos = filename.rfind('/');
+	if (separatorpos != std::string::npos)
+		fontFolder = filename.substr(0, separatorpos);
+
+	// The parseConfig function will try to load any missing page images.
+	for (int i = 0; i < (int) imagelist.size(); i++)
+		images[i] = imagelist[i];
+
+	std::string configtext((const char *) fontdef->getData(), fontdef->getSize());
+
+	parseConfig(configtext);
+}
+
+BMFontRasterizer::~BMFontRasterizer()
+{
+}
+
+void BMFontRasterizer::parseConfig(const std::string &configtext)
+{
+	std::stringstream ss(configtext);
+	std::string line;
+
+	while (std::getline(ss, line))
+	{
+		BMFontLine cline(line);
+
+		const std::string &tag = cline.getTag();
+
+		if (tag == "info")
+		{
+			fontSize = cline.getAttributeInt("size");
+			unicode  = cline.getAttributeInt("unicode") > 0;
+		}
+		else if (tag == "common")
+		{
+			lineHeight = cline.getAttributeInt("lineHeight");
+			metrics.ascent = cline.getAttributeInt("base");
+		}
+		else if (tag == "page")
+		{
+			int pageindex = cline.getAttributeInt("id");
+			std::string filename = cline.getAttributeString("file");
+
+			// The file name is relative to the font file's folder.
+			if (!fontFolder.empty())
+				filename = fontFolder + "/" + filename;
+
+			// Load the page file from disk into an ImageData, if necessary.
+			if (images[pageindex].get() == nullptr)
+			{
+				using namespace love::filesystem;
+
+				Filesystem *filesystem = Module::getInstance<Filesystem>(Module::M_FILESYSTEM);
+				image::Image *imagemodule = Module::getInstance<image::Image>(Module::M_IMAGE);
+
+				if (!filesystem)
+					throw love::Exception("Filesystem module not loaded!");
+				if (!imagemodule)
+					throw love::Exception("Image module not loaded!");
+
+				// Release these variables right away since StrongRef retains.
+				StrongRef<filesystem::FileData> data = filesystem->read(filename.c_str());
+				data->release();
+
+				images[pageindex].set(imagemodule->newImageData(data.get()));
+				images[pageindex]->release();
+			}
+		}
+		else if (tag == "char")
+		{
+			BMFontCharacter c = {};
+
+			uint32 id = (uint32) cline.getAttributeInt("id");
+
+			c.x    = cline.getAttributeInt("x");
+			c.y    = cline.getAttributeInt("y");
+			c.page = cline.getAttributeInt("page");
+
+			c.metrics.width    =  cline.getAttributeInt("width");
+			c.metrics.height   =  cline.getAttributeInt("height");
+			c.metrics.bearingX =  cline.getAttributeInt("xoffset");
+			c.metrics.bearingY = -cline.getAttributeInt("yoffset");
+			c.metrics.advance  =  cline.getAttributeInt("xadvance");
+
+			characters[id] = c;
+		}
+		else if (tag == "kerning")
+		{
+			uint32 firstid  = (uint32) cline.getAttributeInt("first");
+			uint32 secondid = (uint32) cline.getAttributeInt("second");
+
+			uint64 packedids = ((uint64) firstid << 32) | (uint64) secondid;
+
+			kerning[packedids] = cline.getAttributeInt("amount");
+		}
+	}
+
+	if (characters.size() == 0)
+		throw love::Exception("Invalid BMFont file (no character definitions?)");
+
+	// Try to guess the line height if the lineheight attribute isn't found.
+	bool guessheight = lineHeight == 0;
+
+	// Verify the glyph character attributes.
+	for (const auto &cpair : characters)
+	{
+		const BMFontCharacter &c = cpair.second;
+
+		if (!unicode && cpair.first > 127)
+			throw love::Exception("Invalid BMFont character id (only unicode and ASCII are supported)");
+
+		if (c.page < 0 || images[c.page].get() == nullptr)
+			throw love::Exception("Invalid BMFont character page id: %d", c.page);
+
+		const image::ImageData *id = images[c.page].get();
+
+		if (!id->inside(c.x, c.y) || !id->inside(c.x + c.metrics.width - 1, c.y + c.metrics.height - 1))
+			throw love::Exception("Invalid BMFont character coordinates.");
+
+		if (guessheight)
+			lineHeight = std::max(lineHeight, c.metrics.height);
+	}
+
+	metrics.height = lineHeight;
+}
+
+int BMFontRasterizer::getLineHeight() const
+{
+	return lineHeight;
+}
+
+GlyphData *BMFontRasterizer::getGlyphData(uint32 glyph) const
+{
+	auto it = characters.find(glyph);
+
+	// Return an empty GlyphData if we don't have the glyph character.
+	if (it == characters.end())
+		return new GlyphData(glyph, GlyphMetrics(), GlyphData::FORMAT_RGBA);
+
+	const BMFontCharacter &c = it->second;
+	GlyphData *g = new GlyphData(glyph, c.metrics, GlyphData::FORMAT_RGBA);
+
+	const auto &imagepair = images.find(c.page);
+
+	if (imagepair == images.end())
+	{
+		g->release();
+		return new GlyphData(glyph, GlyphMetrics(), GlyphData::FORMAT_RGBA);
+	}
+
+	image::ImageData *imagedata = imagepair->second.get();
+	image::pixel *pixels = (image::pixel *) g->getData();
+	const image::pixel *ipixels = (const image::pixel *) imagedata->getData();
+
+	love::thread::Lock lock(imagedata->getMutex());
+
+	// Copy the subsection of the texture from the ImageData to the GlyphData.
+	for (int y = 0; y < c.metrics.height; y++)
+	{
+		size_t idindex = (c.y + y) * imagedata->getWidth() + c.x;
+		memcpy(&pixels[y * c.metrics.width], &ipixels[idindex], sizeof(image::pixel) * c.metrics.width);
+	}
+
+	return g;
+}
+
+int BMFontRasterizer::getGlyphCount() const
+{
+	return (int) characters.size();
+}
+
+bool BMFontRasterizer::hasGlyph(uint32 glyph) const
+{
+	return characters.find(glyph) != characters.end();
+}
+
+float BMFontRasterizer::getKerning(uint32 leftglyph, uint32 rightglyph) const
+{
+	uint64 packedglyphs = ((uint64) leftglyph << 32) | (uint64) rightglyph;
+
+	auto it = kerning.find(packedglyphs);
+	if (it != kerning.end())
+		return it->second;
+
+	return 0.0f;
+}
+
+bool BMFontRasterizer::accepts(love::filesystem::FileData *fontdef)
+{
+	const char *data = (const char *) fontdef->getData();
+
+	// Check if the "info" tag is at the start of the file. This is a truly
+	// crappy test. Is the tag even guaranteed to be at the start?
+	return fontdef->getSize() > 4 && memcmp(data, "info", 4) == 0;
+}
+
+} // font
+} // love

+ 90 - 0
jni/love/src/modules/font/BMFontRasterizer.h

@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_FONT_BMFONT_RASTERIZER_H
+#define LOVE_FONT_BMFONT_RASTERIZER_H
+
+// LOVE
+#include "common/config.h"
+#include "Rasterizer.h"
+#include "image/ImageData.h"
+
+// C++
+#include <unordered_map>
+#include <vector>
+
+namespace love
+{
+namespace font
+{
+
+/**
+ * Rasterizer for BMFont bitmap fonts.
+ **/
+class BMFontRasterizer : public Rasterizer
+{
+public:
+
+	BMFontRasterizer(love::filesystem::FileData *fontdef, const std::vector<image::ImageData *> &imagelist);
+	virtual ~BMFontRasterizer();
+
+	// Implements Rasterizer.
+	int getLineHeight() const override;
+	GlyphData *getGlyphData(uint32 glyph) const override;
+	int getGlyphCount() const override;
+	bool hasGlyph(uint32 glyph) const override;
+	float getKerning(uint32 leftglyph, uint32 rightglyph) const;
+
+	static bool accepts(love::filesystem::FileData *fontdef);
+
+private:
+
+	struct BMFontCharacter
+	{
+		int x;
+		int y;
+		int page;
+		GlyphMetrics metrics;
+	};
+
+	void parseConfig(const std::string &config);
+
+	std::string fontFolder;
+
+	// Image pages, indexed by their page id.
+	std::unordered_map<int, StrongRef<image::ImageData>> images;
+
+	// Glyph characters, indexed by their glyph id.
+	std::unordered_map<uint32, BMFontCharacter> characters;
+
+	// Kerning information, indexed by two (packed) characters.
+	std::unordered_map<uint64, int> kerning;
+
+	int fontSize;
+	bool unicode;
+
+	int lineHeight;
+
+}; // BMFontRasterizer
+
+} // font
+} // love
+
+#endif // LOVE_FONT_BMFONT_RASTERIZER_H

+ 105 - 0
jni/love/src/modules/font/Font.cpp

@@ -0,0 +1,105 @@
+/**
+ * Copyright (c) 2006-2015 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 "Font.h"
+#include "BMFontRasterizer.h"
+#include "ImageRasterizer.h"
+
+#include "libraries/utf8/utf8.h"
+
+namespace love
+{
+namespace font
+{
+
+// Default TrueType font.
+#include "Vera.ttf.h"
+
+class DefaultFontData : public love::Data
+{
+public:
+
+	void *getData() const override { return Vera_ttf; }
+	size_t getSize() const override { return sizeof(Vera_ttf); }
+};
+
+Rasterizer *Font::newTrueTypeRasterizer(int size, TrueTypeRasterizer::Hinting hinting)
+{
+	StrongRef<DefaultFontData> data(new DefaultFontData);
+	data->release();
+
+	return newTrueTypeRasterizer(data.get(), size, hinting);
+}
+
+Rasterizer *Font::newBMFontRasterizer(love::filesystem::FileData *fontdef, const std::vector<image::ImageData *> &images)
+{
+	return new BMFontRasterizer(fontdef, images);
+}
+
+Rasterizer *Font::newImageRasterizer(love::image::ImageData *data, const std::string &text, int extraspacing)
+{
+	std::vector<uint32> glyphs;
+	glyphs.reserve(text.size());
+
+	try
+	{
+		utf8::iterator<std::string::const_iterator> i(text.begin(), text.begin(), text.end());
+		utf8::iterator<std::string::const_iterator> end(text.end(), text.begin(), text.end());
+
+		while (i != end)
+			glyphs.push_back(*i++);
+	}
+	catch (utf8::exception &e)
+	{
+		throw love::Exception("UTF-8 decoding error: %s", e.what());
+	}
+
+	return newImageRasterizer(data, &glyphs[0], (int) glyphs.size(), extraspacing);
+}
+
+Rasterizer *Font::newImageRasterizer(love::image::ImageData *data, uint32 *glyphs, int numglyphs, int extraspacing)
+{
+	return new ImageRasterizer(data, glyphs, numglyphs, extraspacing);
+}
+
+GlyphData *Font::newGlyphData(Rasterizer *r, const std::string &text)
+{
+	uint32 codepoint = 0;
+
+	try
+	{
+		codepoint = utf8::peek_next(text.begin(), text.end());
+	}
+	catch (utf8::exception &e)
+	{
+		throw love::Exception("UTF-8 decoding error: %s", e.what());
+	}
+
+	return r->getGlyphData(codepoint);
+}
+
+GlyphData *Font::newGlyphData(Rasterizer *r, uint32 glyph)
+{
+	return r->getGlyphData(glyph);
+}
+
+} // font
+} // love

+ 17 - 10
jni/love/src/modules/font/Font.h

@@ -23,12 +23,15 @@
 
 // LOVE
 #include "Rasterizer.h"
+#include "TrueTypeRasterizer.h"
 #include "image/ImageData.h"
+#include "filesystem/FileData.h"
 #include "common/Module.h"
 #include "common/int.h"
 
-// STD
+// C++
 #include <string>
+#include <vector>
 
 namespace love
 {
@@ -42,17 +45,21 @@ public:
 
 	virtual ~Font() {}
 
-	// Implements Module.
-	virtual ModuleType getModuleType() const { return M_FONT; }
+	virtual Rasterizer *newRasterizer(love::filesystem::FileData *data) = 0;
+
+	virtual Rasterizer *newTrueTypeRasterizer(int size, TrueTypeRasterizer::Hinting hinting);
+	virtual Rasterizer *newTrueTypeRasterizer(love::Data *data, int size, TrueTypeRasterizer::Hinting hinting) = 0;
+
+	virtual Rasterizer *newBMFontRasterizer(love::filesystem::FileData *fontdef, const std::vector<image::ImageData *> &images);
 
-	virtual Rasterizer *newRasterizer(int size) = 0;
-	virtual Rasterizer *newRasterizer(Data *data, int size) = 0;
-	virtual Rasterizer *newRasterizer(love::image::ImageData *data, const std::string &glyphs) = 0;
-	virtual Rasterizer *newRasterizer(love::image::ImageData *data, uint32 *glyphs, int length) = 0;
-	virtual GlyphData *newGlyphData(Rasterizer *r, const std::string &glyph) = 0;
-	virtual GlyphData *newGlyphData(Rasterizer *r, uint32 glyph) = 0;
+	virtual Rasterizer *newImageRasterizer(love::image::ImageData *data, const std::string &glyphs, int extraspacing);
+	virtual Rasterizer *newImageRasterizer(love::image::ImageData *data, uint32 *glyphs, int length, int extraspacing);
 
-	// Implement Module
+	virtual GlyphData *newGlyphData(Rasterizer *r, const std::string &glyph);
+	virtual GlyphData *newGlyphData(Rasterizer *r, uint32 glyph);
+
+	// Implement Module.
+	virtual ModuleType getModuleType() const { return M_FONT; }
 	virtual const char *getName() const = 0;
 
 }; // Font

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

@@ -168,7 +168,7 @@ bool GlyphData::getConstant(GlyphData::Format in, const char *&out)
 
 StringMap<GlyphData::Format, GlyphData::FORMAT_MAX_ENUM>::Entry GlyphData::formatEntries[] =
 {
-	{"luminance alpha", GlyphData::FORMAT_LUMINANCE_ALPHA},
+	{"luminancealpha", GlyphData::FORMAT_LUMINANCE_ALPHA},
 	{"rgba", GlyphData::FORMAT_RGBA},
 };
 

+ 4 - 18
jni/love/src/modules/font/ImageRasterizer.cpp

@@ -34,10 +34,11 @@ inline bool equal(const love::image::pixel &a, const love::image::pixel &b)
 	return (a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a);
 }
 
-ImageRasterizer::ImageRasterizer(love::image::ImageData *data, uint32 *glyphs, int numglyphs)
+ImageRasterizer::ImageRasterizer(love::image::ImageData *data, uint32 *glyphs, int numglyphs, int extraspacing)
 	: imageData(data)
 	, glyphs(glyphs)
 	, numglyphs(numglyphs)
+	, extraSpacing(extraspacing)
 {
 	load();
 }
@@ -53,15 +54,14 @@ int ImageRasterizer::getLineHeight() const
 
 GlyphData *ImageRasterizer::getGlyphData(uint32 glyph) const
 {
-	GlyphMetrics gm;
-	memset(&gm, 0, sizeof(GlyphMetrics));
+	GlyphMetrics gm = {};
 
 	// Set relevant glyph metrics if the glyph is in this ImageFont
 	std::map<uint32, ImageGlyphData>::const_iterator it = imageGlyphs.find(glyph);
 	if (it != imageGlyphs.end())
 	{
 		gm.width = it->second.width;
-		gm.advance = it->second.width + it->second.spacing;
+		gm.advance = it->second.width + extraSpacing;
 	}
 
 	gm.height = metrics.height;
@@ -119,10 +119,6 @@ void ImageRasterizer::load()
 		while (start < imgw && equal(pixels[start], spacer))
 			++start;
 
-		// set previous glyph's spacing
-		if (i > 0 && imageGlyphs.size() > 0)
-			imageGlyphs[glyphs[i - 1]].spacing = (start > end) ? (start - end) : 0;
-
 		end = start;
 
 		// Find where glyph ends.
@@ -138,16 +134,6 @@ void ImageRasterizer::load()
 
 		imageGlyphs[glyphs[i]] = imageGlyph;
 	}
-
-	// Find spacing of last glyph
-	if (numglyphs > 0)
-	{
-		start = end;
-		while (start < imgw && equal(pixels[start], spacer))
-			++start;
-
-		imageGlyphs[glyphs[numglyphs - 1]].spacing = (start > end) ? (start - end) : 0;
-	}
 }
 
 int ImageRasterizer::getGlyphCount() const

+ 10 - 8
jni/love/src/modules/font/ImageRasterizer.h

@@ -39,7 +39,7 @@ namespace font
 class ImageRasterizer : public Rasterizer
 {
 public:
-	ImageRasterizer(love::image::ImageData *imageData, uint32 *glyphs, int numglyphs);
+	ImageRasterizer(love::image::ImageData *imageData, uint32 *glyphs, int numglyphs, int extraspacing);
 	virtual ~ImageRasterizer();
 
 	// Implement Rasterizer
@@ -49,6 +49,14 @@ public:
 	virtual bool hasGlyph(uint32 glyph) const;
 
 private:
+
+	// Information about a glyph in the ImageData
+	struct ImageGlyphData
+	{
+		int x;
+		int width;
+	};
+
 	// Load all the glyph positions into memory
 	void load();
 
@@ -61,13 +69,7 @@ private:
 	// Number of glyphs in the font
 	int numglyphs;
 
-	// Information about a glyph in the ImageData
-	struct ImageGlyphData
-	{
-		int x;
-		int width;
-		int spacing;
-	};
+	int extraSpacing;
 
 	std::map<uint32, ImageGlyphData> imageGlyphs;
 

+ 5 - 0
jni/love/src/modules/font/Rasterizer.cpp

@@ -95,5 +95,10 @@ bool Rasterizer::hasGlyphs(const std::string &text) const
 	return true;
 }
 
+float Rasterizer::getKerning(uint32 /*leftglyph*/, uint32 /*rightglyph*/) const
+{
+	return 0.0f;
+}
+
 } // font
 } // love

+ 5 - 0
jni/love/src/modules/font/Rasterizer.h

@@ -105,6 +105,11 @@ public:
 	 **/
 	virtual bool hasGlyphs(const std::string &text) const;
 
+	/**
+	 * Gets the amount of horizontal kerning between two glyphs.
+	 **/
+	virtual float getKerning(uint32 leftglyph, uint32 rightglyph) const;
+
 protected:
 
 	FontMetrics metrics;

+ 49 - 0
jni/love/src/modules/font/TrueTypeRasterizer.cpp

@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "TrueTypeRasterizer.h"
+
+namespace love
+{
+namespace font
+{
+
+bool TrueTypeRasterizer::getConstant(const char *in, Hinting &out)
+{
+	return hintings.find(in, out);
+}
+
+bool TrueTypeRasterizer::getConstant(Hinting in, const char *&out)
+{
+	return hintings.find(in, out);
+}
+
+StringMap<TrueTypeRasterizer::Hinting, TrueTypeRasterizer::HINTING_MAX_ENUM>::Entry TrueTypeRasterizer::hintingEntries[] =
+{
+	{"normal", HINTING_NORMAL},
+	{"light", HINTING_LIGHT},
+	{"mono", HINTING_MONO},
+	{"none", HINTING_NONE},
+};
+
+StringMap<TrueTypeRasterizer::Hinting, TrueTypeRasterizer::HINTING_MAX_ENUM> TrueTypeRasterizer::hintings(TrueTypeRasterizer::hintingEntries, sizeof(TrueTypeRasterizer::hintingEntries));
+
+} // font
+} // love

+ 62 - 0
jni/love/src/modules/font/TrueTypeRasterizer.h

@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_FONT_TRUE_TYPE_RASTERIZER_H
+#define LOVE_FONT_TRUE_TYPE_RASTERIZER_H
+
+// LOVE
+#include "Rasterizer.h"
+#include "common/StringMap.h"
+
+namespace love
+{
+namespace font
+{
+
+class TrueTypeRasterizer : public Rasterizer
+{
+public:
+
+	// Types of hinting for TrueType font glyphs.
+	enum Hinting
+	{
+		HINTING_NORMAL,
+		HINTING_LIGHT,
+		HINTING_MONO,
+		HINTING_NONE,
+		HINTING_MAX_ENUM
+	};
+
+	virtual ~TrueTypeRasterizer() {}
+
+	static bool getConstant(const char *in, Hinting &out);
+	static bool getConstant(Hinting in, const char *&out);
+
+private:
+
+	static StringMap<Hinting, HINTING_MAX_ENUM>::Entry hintingEntries[];
+	static StringMap<Hinting, HINTING_MAX_ENUM> hintings;
+
+}; // TrueTypeRasterizer
+
+} // font
+} // love
+
+#endif // LOVE_FONT_TRUE_TYPE_RASTERIZER_H

+ 9 - 67
jni/love/src/modules/font/freetype/Font.cpp

@@ -21,9 +21,7 @@
 #include "Font.h"
 
 #include "TrueTypeRasterizer.h"
-#include "font/ImageRasterizer.h"
-
-#include "libraries/utf8/utf8.h"
+#include "font/BMFontRasterizer.h"
 
 #include <string.h>
 
@@ -34,9 +32,6 @@ namespace font
 namespace freetype
 {
 
-// Default TrueType font.
-#include "font/Vera.ttf.h"
-
 Font::Font()
 {
 	if (FT_Init_FreeType(&library))
@@ -48,72 +43,19 @@ Font::~Font()
 	FT_Done_FreeType(library);
 }
 
-Rasterizer *Font::newRasterizer(int size)
-{
-	StrongRef<filesystem::FileData> data(new filesystem::FileData(sizeof(Vera_ttf), "Vera.ttf"));
-	data->release();
-
-	memcpy(data->getData(), Vera_ttf, sizeof(Vera_ttf));
-
-	return new TrueTypeRasterizer(library, data.get(), size);
-}
-
-Rasterizer *Font::newRasterizer(Data *data, int size)
-{
-	return new TrueTypeRasterizer(library, data, size);
-}
-
-Rasterizer *Font::newRasterizer(love::image::ImageData *data, const std::string &text)
-{
-	size_t strlen = text.size();
-	size_t numglyphs = 0;
-
-	uint32 *glyphs = new uint32[strlen];
-
-	try
-	{
-		utf8::iterator<std::string::const_iterator> i(text.begin(), text.begin(), text.end());
-		utf8::iterator<std::string::const_iterator> end(text.end(), text.begin(), text.end());
-
-		while (i != end)
-			glyphs[numglyphs++] = *i++;
-	}
-	catch (utf8::exception &e)
-	{
-		delete [] glyphs;
-		throw love::Exception("UTF-8 decoding error: %s", e.what());
-	}
-
-	Rasterizer *r = newRasterizer(data, glyphs, numglyphs);
-	delete [] glyphs;
-
-	return r;
-}
-
-Rasterizer *Font::newRasterizer(love::image::ImageData *data, uint32 *glyphs, int numglyphs)
+Rasterizer *Font::newRasterizer(love::filesystem::FileData *data)
 {
-	return new ImageRasterizer(data, glyphs, numglyphs);
-}
-
-GlyphData *Font::newGlyphData(Rasterizer *r, const std::string &text)
-{
-	uint32 codepoint = 0;
-
-	try
-	{
-		codepoint = utf8::peek_next(text.begin(), text.end());
-	}
-	catch (utf8::exception &e)
-	{
-		throw love::Exception("UTF-8 decoding error: %s", e.what());
-	}
+	if (TrueTypeRasterizer::accepts(library, data))
+		return newTrueTypeRasterizer(data, 12, TrueTypeRasterizer::HINTING_NORMAL);
+	else if (BMFontRasterizer::accepts(data))
+		return newBMFontRasterizer(data, {});
 
-	return r->getGlyphData(codepoint);
+	throw love::Exception("Invalid font file: %s", data->getFilename().c_str());
 }
 
-GlyphData *Font::newGlyphData(Rasterizer *r, uint32 glyph)
+Rasterizer *Font::newTrueTypeRasterizer(love::Data *data, int size, TrueTypeRasterizer::Hinting hinting)
 {
-	return r->getGlyphData(glyph);
+	return new TrueTypeRasterizer(library, data, size, hinting);
 }
 
 const char *Font::getName() const

+ 3 - 14
jni/love/src/modules/font/freetype/Font.h

@@ -25,11 +25,7 @@
 #include "font/Font.h"
 
 // FreeType2
-#ifdef LOVE_MACOSX_USE_FRAMEWORKS
-#include <freetype/ft2build.h>
-#else
 #include <ft2build.h>
-#endif
 #include FT_FREETYPE_H
 #include FT_GLYPH_H
 
@@ -45,19 +41,11 @@ class Font : public love::font::Font
 public:
 
 	Font();
-
-	/**
-	 * Destructor.
-	 **/
 	virtual ~Font();
 
 	// Implements Font
-	Rasterizer *newRasterizer(int size);
-	Rasterizer *newRasterizer(Data *data, int size);
-	Rasterizer *newRasterizer(love::image::ImageData *data, const std::string &text);
-	Rasterizer *newRasterizer(love::image::ImageData *data, uint32 *glyphs, int numglyphs);
-	GlyphData *newGlyphData(Rasterizer *r, const std::string &glyph);
-	GlyphData *newGlyphData(Rasterizer *r, uint32 glyph);
+	Rasterizer *newRasterizer(love::filesystem::FileData *data);
+	Rasterizer *newTrueTypeRasterizer(love::Data *data, int size, TrueTypeRasterizer::Hinting hinting);
 
 	// Implement Module
 	const char *getName() const;
@@ -66,6 +54,7 @@ private:
 
 	// FreeType library
 	FT_Library library;
+
 }; // Font
 
 } // freetype

+ 47 - 9
jni/love/src/modules/font/freetype/TrueTypeRasterizer.cpp

@@ -30,8 +30,9 @@ namespace font
 namespace freetype
 {
 
-TrueTypeRasterizer::TrueTypeRasterizer(FT_Library library, Data *data, int size)
+TrueTypeRasterizer::TrueTypeRasterizer(FT_Library library, love::Data *data, int size, Hinting hinting)
 	: data(data)
+	, hinting(hinting)
 {
 	if (size <= 0)
 		throw love::Exception("Invalid TrueType font size: %d", size);
@@ -53,10 +54,10 @@ TrueTypeRasterizer::TrueTypeRasterizer(FT_Library library, Data *data, int size)
 
 	// Set global metrics
 	FT_Size_Metrics s = face->size->metrics;
-	metrics.advance = s.max_advance >> 6;
-	metrics.ascent = s.ascender >> 6;
-	metrics.descent = s.descender >> 6;
-	metrics.height = s.height >> 6;
+	metrics.advance = (int) (s.max_advance >> 6);
+	metrics.ascent  = (int) (s.ascender >> 6);
+	metrics.descent = (int) (s.descender >> 6);
+	metrics.height  = (int) (s.height >> 6);
 }
 
 TrueTypeRasterizer::~TrueTypeRasterizer()
@@ -75,9 +76,10 @@ GlyphData *TrueTypeRasterizer::getGlyphData(uint32 glyph) const
 	FT_Glyph ftglyph;
 
 	FT_Error err = FT_Err_Ok;
+	FT_ULong loadoption = hintingToLoadOption(hinting);
 
 	// Initialize
-	err = FT_Load_Glyph(face, FT_Get_Char_Index(face, glyph), FT_LOAD_DEFAULT);
+	err = FT_Load_Glyph(face, FT_Get_Char_Index(face, glyph), FT_LOAD_DEFAULT | loadoption);
 
 	if (err != FT_Err_Ok)
 		throw love::Exception("TrueType Font glyph error: FT_Load_Glyph failed (0x%x)", err);
@@ -87,7 +89,11 @@ GlyphData *TrueTypeRasterizer::getGlyphData(uint32 glyph) const
 	if (err != FT_Err_Ok)
 		throw love::Exception("TrueType Font glyph error: FT_Get_Glyph failed (0x%x)", err);
 
-	err = FT_Glyph_To_Bitmap(&ftglyph, FT_RENDER_MODE_NORMAL, 0, 1);
+	FT_Render_Mode rendermode = FT_RENDER_MODE_NORMAL;
+	if (hinting == HINTING_MONO)
+		rendermode = FT_RENDER_MODE_MONO;
+
+	err = FT_Glyph_To_Bitmap(&ftglyph, rendermode, 0, 1);
 
 	if (err != FT_Err_Ok)
 		throw love::Exception("TrueType Font glyph error: FT_Glyph_To_Bitmap failed (0x%x)", err);
@@ -100,7 +106,7 @@ GlyphData *TrueTypeRasterizer::getGlyphData(uint32 glyph) const
 	glyphMetrics.bearingY = bitmap_glyph->top;
 	glyphMetrics.height = bitmap.rows;
 	glyphMetrics.width = bitmap.width;
-	glyphMetrics.advance = ftglyph->advance.x >> 16;
+	glyphMetrics.advance = (int) (ftglyph->advance.x >> 16);
 
 	GlyphData *glyphData = new GlyphData(glyph, glyphMetrics, GlyphData::FORMAT_LUMINANCE_ALPHA);
 
@@ -151,7 +157,7 @@ GlyphData *TrueTypeRasterizer::getGlyphData(uint32 glyph) const
 
 int TrueTypeRasterizer::getGlyphCount() const
 {
-	return face->num_glyphs;
+	return (int) face->num_glyphs;
 }
 
 bool TrueTypeRasterizer::hasGlyph(uint32 glyph) const
@@ -159,6 +165,38 @@ bool TrueTypeRasterizer::hasGlyph(uint32 glyph) const
 	return FT_Get_Char_Index(face, glyph) != 0;
 }
 
+float TrueTypeRasterizer::getKerning(uint32 leftglyph, uint32 rightglyph) const
+{
+	FT_Vector kerning = {};
+	FT_Get_Kerning(face, leftglyph, rightglyph, FT_KERNING_DEFAULT, &kerning);
+	return float(kerning.x >> 6);
+}
+
+bool TrueTypeRasterizer::accepts(FT_Library library, love::Data *data)
+{
+	const FT_Byte *fbase = (const FT_Byte *) data->getData();
+	FT_Long fsize = (FT_Long) data->getSize();
+
+	// Pasing in -1 for the face index lets us test if the data is valid.
+	return FT_New_Memory_Face(library, fbase, fsize, -1, nullptr) == 0;
+}
+
+FT_ULong TrueTypeRasterizer::hintingToLoadOption(Hinting hint)
+{
+	switch (hint)
+	{
+	case HINTING_NORMAL:
+	default:
+		return FT_LOAD_TARGET_NORMAL;
+	case HINTING_LIGHT:
+		return FT_LOAD_TARGET_LIGHT;
+	case HINTING_MONO:
+		return FT_LOAD_TARGET_MONO;
+	case HINTING_NONE:
+		return FT_LOAD_NO_HINTING;
+	}
+}
+
 } // freetype
 } // font
 } // love

+ 17 - 8
jni/love/src/modules/font/freetype/TrueTypeRasterizer.h

@@ -22,10 +22,10 @@
 #define LOVE_FONT_FREETYPE_TRUE_TYPE_RASTERIZER_H
 
 // LOVE
-#include "filesystem/File.h"
-#include "font/Rasterizer.h"
+#include "filesystem/FileData.h"
+#include "font/TrueTypeRasterizer.h"
 
-// TrueType2
+// FreeType2
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include FT_GLYPH_H
@@ -40,10 +40,11 @@ namespace freetype
 /**
  * Holds data for a font object.
  **/
-class TrueTypeRasterizer : public Rasterizer
+class TrueTypeRasterizer : public love::font::TrueTypeRasterizer
 {
 public:
-	TrueTypeRasterizer(FT_Library library, Data *data, int size);
+
+	TrueTypeRasterizer(FT_Library library, love::Data *data, int size, Hinting hinting);
 	virtual ~TrueTypeRasterizer();
 
 	// Implement Rasterizer
@@ -51,15 +52,23 @@ public:
 	virtual GlyphData *getGlyphData(uint32 glyph) const;
 	virtual int getGlyphCount() const;
 	virtual bool hasGlyph(uint32 glyph) const;
+	virtual float getKerning(uint32 leftglyph, uint32 rightglyph) const;
+
+	static bool accepts(FT_Library library, love::Data *data);
 
 private:
 
+	static FT_ULong hintingToLoadOption(Hinting hinting);
+
 	// TrueType face
 	FT_Face face;
 
-	// File data
-	StrongRef<Data> data;
-}; // FreetypeRasterizer
+	// Font data
+	StrongRef<love::Data> data;
+
+	Hinting hinting;
+
+}; // TrueTypeRasterizer
 
 } // freetype
 } // font

+ 0 - 132
jni/love/src/modules/font/freetype/wrap_Font.cpp

@@ -1,132 +0,0 @@
-/**
- * Copyright (c) 2006-2015 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#include "wrap_Font.h"
-
-#include "Font.h"
-
-#include "font/wrap_GlyphData.h"
-#include "font/wrap_Rasterizer.h"
-
-#include "filesystem/wrap_Filesystem.h"
-
-#include "TrueTypeRasterizer.h"
-
-namespace love
-{
-namespace font
-{
-namespace freetype
-{
-
-#define instance() (Module::getInstance<Font>(Module::M_FONT))
-
-int w_newRasterizer(lua_State *L)
-{
-	Rasterizer *t = nullptr;
-
-	if (luax_istype(L, 1, IMAGE_IMAGE_DATA_T))
-	{
-		love::image::ImageData *d = luax_checktype<love::image::ImageData>(L, 1, "ImageData", IMAGE_IMAGE_DATA_T);
-		const char *g = luaL_checkstring(L, 2);
-		std::string glyphs(g);
-		luax_catchexcept(L, [&](){ t = instance()->newRasterizer(d, glyphs); });
-	}
-	else if (lua_type(L, 1) == LUA_TSTRING || luax_istype(L, 1, FILESYSTEM_FILE_T) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
-	{
-		love::filesystem::FileData *d = love::filesystem::luax_getfiledata(L, 1);
-		int size = luaL_optint(L, 2, 12);
-		luax_catchexcept(L,
-			[&]() { t = instance()->newRasterizer(d, size); },
-			[&]() { d->release(); }
-		);
-	}
-	else
-	{
-		// Default font (Vera.)
-		int size = luaL_optint(L, 1, 12);
-		luax_catchexcept(L, [&]() { t = instance()->newRasterizer(size); });
-	}
-
-	luax_pushtype(L, "Rasterizer", FONT_RASTERIZER_T, t);
-	t->release();
-	return 1;
-}
-
-int w_newGlyphData(lua_State *L)
-{
-	Rasterizer *r = luax_checkrasterizer(L, 1);
-	GlyphData *t = nullptr;
-
-	// newGlyphData accepts a unicode character or a codepoint number.
-	if (lua_type(L, 2) == LUA_TSTRING)
-	{
-		std::string glyph = luax_checkstring(L, 2);
-		luax_catchexcept(L, [&](){ t = instance()->newGlyphData(r, glyph); });
-	}
-	else
-	{
-		uint32 g = (uint32) luaL_checknumber(L, 2);
-		t = instance()->newGlyphData(r, g);
-	}
-
-	luax_pushtype(L, "GlyphData", FONT_GLYPH_DATA_T, t);
-	t->release();
-	return 1;
-}
-
-// List of functions to wrap.
-static const luaL_Reg functions[] =
-{
-	{ "newRasterizer",  w_newRasterizer },
-	{ "newGlyphData",  w_newGlyphData },
-	{ 0, 0 }
-};
-
-static const lua_CFunction types[] =
-{
-	luaopen_glyphdata,
-	luaopen_rasterizer,
-	0
-};
-
-extern "C" int luaopen_love_font(lua_State *L)
-{
-	Font *instance = instance();
-	if (instance == nullptr)
-	{
-		luax_catchexcept(L, [&](){ instance = new Font(); });
-	}
-	else
-		instance->retain();
-
-	WrappedModule w;
-	w.module = instance;
-	w.name = "font";
-	w.flags = MODULE_T;
-	w.functions = functions;
-	w.types = types;
-
-	return luax_register_module(L, w);
-}
-
-} // freetype
-} // font
-} // love

+ 235 - 0
jni/love/src/modules/font/wrap_Font.cpp

@@ -0,0 +1,235 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "wrap_Font.h"
+
+#include "Font.h"
+#include "freetype/Font.h"
+
+#include "wrap_GlyphData.h"
+#include "wrap_Rasterizer.h"
+
+#include "filesystem/wrap_Filesystem.h"
+
+namespace love
+{
+namespace font
+{
+
+#define instance() (Module::getInstance<Font>(Module::M_FONT))
+
+int w_newRasterizer(lua_State *L)
+{
+	if (lua_type(L, 1) == LUA_TNUMBER || lua_type(L, 2) == LUA_TNUMBER || lua_isnone(L, 1))
+	{
+		// First or second argument is a number: call newTrueTypeRasterizer.
+		return w_newTrueTypeRasterizer(L);
+	}
+	else if (lua_isnoneornil(L, 2))
+	{
+		// Single argument of another type: call Font::newRasterizer.
+		Rasterizer *t = nullptr;
+		filesystem::FileData *d = filesystem::luax_getfiledata(L, 1);
+
+		luax_catchexcept(L,
+			[&]() { t = instance()->newRasterizer(d); },
+			[&](bool) { d->release(); }
+		);
+
+		luax_pushtype(L, FONT_RASTERIZER_ID, t);
+		t->release();
+		return 1;
+	}
+	else
+	{
+		// Otherwise call newBMFontRasterizer.
+		return w_newBMFontRasterizer(L);
+	}
+}
+
+int w_newTrueTypeRasterizer(lua_State *L)
+{
+	Rasterizer *t = nullptr;
+	TrueTypeRasterizer::Hinting hinting = TrueTypeRasterizer::HINTING_NORMAL;
+
+	if (lua_type(L, 1) == LUA_TNUMBER || lua_isnone(L, 1))
+	{
+		// First argument is a number: use the default TrueType font.
+		int size = (int) luaL_optnumber(L, 1, 12);
+
+		const char *hintstr = lua_isnoneornil(L, 2) ? nullptr : luaL_checkstring(L, 2);
+		if (hintstr && !TrueTypeRasterizer::getConstant(hintstr, hinting))
+			return luaL_error(L, "Invalid TrueType font hinting mode: %s", hintstr);
+
+		luax_catchexcept(L, [&](){ t = instance()->newTrueTypeRasterizer(size, hinting); });
+	}
+	else
+	{
+		love::Data *d = nullptr;
+
+		if (luax_istype(L, 1, DATA_ID))
+			d = luax_checkdata(L, 1);
+		else
+			d = filesystem::luax_getfiledata(L, 1);
+
+		int size = (int) luaL_optnumber(L, 2, 12);
+
+		const char *hintstr = lua_isnoneornil(L, 3) ? nullptr : luaL_checkstring(L, 3);
+		if (hintstr && !TrueTypeRasterizer::getConstant(hintstr, hinting))
+			return luaL_error(L, "Invalid TrueType font hinting mode: %s", hintstr);
+
+		luax_catchexcept(L,
+			[&]() { t = instance()->newTrueTypeRasterizer(d, size, hinting); },
+			[&](bool) { d->release(); }
+		);
+	}
+
+	luax_pushtype(L, FONT_RASTERIZER_ID, t);
+	t->release();
+	return 1;
+}
+
+static void convimagedata(lua_State *L, int idx)
+{
+	if (lua_type(L, 1) == LUA_TSTRING || luax_istype(L, idx, FILESYSTEM_FILE_ID) || luax_istype(L, idx, FILESYSTEM_FILE_DATA_ID))
+		luax_convobj(L, idx, "image", "newImageData");
+}
+
+int w_newBMFontRasterizer(lua_State *L)
+{
+	Rasterizer *t = nullptr;
+
+	filesystem::FileData *d = filesystem::luax_getfiledata(L, 1);
+	std::vector<image::ImageData *> images;
+
+	if (lua_istable(L, 2))
+	{
+		for (int i = 1; i <= (int) luax_objlen(L, 2); i++)
+		{
+			lua_rawgeti(L, 2, i);
+
+			convimagedata(L, -1);
+			image::ImageData *id = luax_checktype<image::ImageData>(L, -1, IMAGE_IMAGE_DATA_ID);
+			images.push_back(id);
+			id->retain();
+
+			lua_pop(L, 1);
+		}
+	}
+	else
+	{
+		for (int i = 2; i <= lua_gettop(L); i++)
+		{
+			convimagedata(L, i);
+			image::ImageData *id = luax_checktype<image::ImageData>(L, i, IMAGE_IMAGE_DATA_ID);
+			images.push_back(id);
+			id->retain();
+		}
+	}
+
+	luax_catchexcept(L,
+		[&]() { t = instance()->newBMFontRasterizer(d, images); },
+		[&](bool) { d->release(); for (auto id : images) id->release(); }
+	);
+
+	luax_pushtype(L, FONT_RASTERIZER_ID, t);
+	t->release();
+	return 1;
+}
+
+int w_newImageRasterizer(lua_State *L)
+{
+	Rasterizer *t = nullptr;
+
+	convimagedata(L, 1);
+
+	image::ImageData *d = luax_checktype<image::ImageData>(L, 1, IMAGE_IMAGE_DATA_ID);
+	std::string glyphs = luax_checkstring(L, 2);
+	int extraspacing = (int) luaL_optnumber(L, 3, 0);
+
+	luax_catchexcept(L, [&](){ t = instance()->newImageRasterizer(d, glyphs, extraspacing); });
+
+	luax_pushtype(L, FONT_RASTERIZER_ID, t);
+	t->release();
+	return 1;
+}
+
+int w_newGlyphData(lua_State *L)
+{
+	Rasterizer *r = luax_checkrasterizer(L, 1);
+	GlyphData *t = nullptr;
+
+	// newGlyphData accepts a unicode character or a codepoint number.
+	if (lua_type(L, 2) == LUA_TSTRING)
+	{
+		std::string glyph = luax_checkstring(L, 2);
+		luax_catchexcept(L, [&](){ t = instance()->newGlyphData(r, glyph); });
+	}
+	else
+	{
+		uint32 g = (uint32) luaL_checknumber(L, 2);
+		t = instance()->newGlyphData(r, g);
+	}
+
+	luax_pushtype(L, FONT_GLYPH_DATA_ID, t);
+	t->release();
+	return 1;
+}
+
+// List of functions to wrap.
+static const luaL_Reg functions[] =
+{
+	{ "newRasterizer",  w_newRasterizer },
+	{ "newTrueTypeRasterizer", w_newTrueTypeRasterizer },
+	{ "newBMFontRasterizer", w_newBMFontRasterizer },
+	{ "newImageRasterizer", w_newImageRasterizer },
+	{ "newGlyphData",  w_newGlyphData },
+	{ 0, 0 }
+};
+
+static const lua_CFunction types[] =
+{
+	luaopen_glyphdata,
+	luaopen_rasterizer,
+	0
+};
+
+extern "C" int luaopen_love_font(lua_State *L)
+{
+	Font *instance = instance();
+	if (instance == nullptr)
+	{
+		luax_catchexcept(L, [&](){ instance = new freetype::Font(); });
+	}
+	else
+		instance->retain();
+
+	WrappedModule w;
+	w.module = instance;
+	w.name = "font";
+	w.type = MODULE_ID;
+	w.functions = functions;
+	w.types = types;
+
+	return luax_register_module(L, w);
+}
+
+} // font
+} // love

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio