Browse Source

Merge branch '12.0-development' into metal

Alex Szpakowski 4 years ago
parent
commit
27897b4af1

+ 4 - 2
src/common/runtime.cpp

@@ -1134,9 +1134,11 @@ Type *luax_type(lua_State *L, int idx)
 	return Type::byName(luaL_checkstring(L, idx));
 }
 
-int luax_resume(lua_State *L, int nargs)
+int luax_resume(lua_State *L, int nargs, int* nres)
 {
-#if LUA_VERSION_NUM >= 502
+#if LUA_VERSION_NUM >= 504
+	return lua_resume(L, nullptr, nargs, nres);
+#elif LUA_VERSION_NUM >= 502
 	return lua_resume(L, nullptr, nargs);
 #else
 	return lua_resume(L, nargs);

+ 1 - 1
src/common/runtime.h

@@ -709,7 +709,7 @@ int luax_catchexcept(lua_State *L, const T& func, const F& finallyfunc)
  * Compatibility shim for lua_resume
  * Exported because it's used in the launcher
  **/
-LOVE_EXPORT int luax_resume(lua_State *L, int nargs);
+LOVE_EXPORT int luax_resume(lua_State *L, int nargs, int* nres);
 
 } // love
 

+ 4 - 4
src/libraries/glad/glad.cpp

@@ -1,8 +1,4 @@
 #include <string.h>
-#include "glad.hpp"
-
-namespace glad {
-
 
 #ifdef GLAD_USE_SDL
 #include <SDL.h>
@@ -13,6 +9,10 @@ namespace glad {
 #include <assert.h>
 #endif
 
+#include "glad.hpp"
+
+namespace glad {
+
 bool gladLoadGL(void) {
 #ifdef GLAD_USE_SDL
     return gladLoadGLLoader(SDL_GL_GetProcAddress);

+ 3 - 1
src/libraries/lua53/lstrlib.c

@@ -73,7 +73,9 @@
 typedef size_t lua_Unsigned;
 #endif
 
-#if LUA_VERSION_NUM == 501
+#if LUA_VERSION_NUM >= 504
+#   define LUAL_BUFFER53_BUFFER(B) (B)->b.b
+#elif LUA_VERSION_NUM == 501
 #	define LUAL_BUFFER53_BUFFER(B) (B)->b.buffer
 #else
 #	define LUAL_BUFFER53_BUFFER(B) (B)->b.initb

+ 1 - 2
src/libraries/lua53/lutf8lib.c

@@ -309,8 +309,7 @@ int luaopen_luautf8 (lua_State *L) {
       lua_setfield(L, -2, l->name);
     }
   }
-  lua_pushliteral(L, UTF8PATT);
+  lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT) / sizeof(char) - 1);
   lua_setfield(L, -2, "charpattern");
   return 1;
 }
-

+ 6 - 1
src/love.cpp

@@ -221,8 +221,13 @@ static DoneAction runlove(int argc, char **argv, int &retval, love::Variant &res
 	lua_newthread(L);
 	lua_pushvalue(L, -2);
 	int stackpos = lua_gettop(L);
-	while (love::luax_resume(L, 0) == LUA_YIELD)
+	int nres;
+	while (love::luax_resume(L, 0, &nres) == LUA_YIELD)
+#if LUA_VERSION_NUM >= 504
+		lua_pop(L, nres);
+#else
 		lua_pop(L, lua_gettop(L) - stackpos);
+#endif
 
 	retval = 0;
 	DoneAction done = DONE_QUIT;

+ 17 - 113
src/modules/graphics/renderstate.cpp

@@ -123,7 +123,7 @@ CompareMode getReversedCompareMode(CompareMode mode)
 	}
 }
 
-static StringMap<BlendMode, BLEND_MAX_ENUM>::Entry blendModeEntries[] =
+STRINGMAP_BEGIN(BlendMode, BLEND_MAX_ENUM, blendMode)
 {
 	{ "alpha",    BLEND_ALPHA    },
 	{ "add",      BLEND_ADD      },
@@ -135,19 +135,17 @@ static StringMap<BlendMode, BLEND_MAX_ENUM>::Entry blendModeEntries[] =
 	{ "replace",  BLEND_REPLACE  },
 	{ "none",     BLEND_NONE     },
 	{ "custom",   BLEND_CUSTOM   },
-};
-
-static StringMap<BlendMode, BLEND_MAX_ENUM> blendModes(blendModeEntries, sizeof(blendModeEntries));
+}
+STRINGMAP_END(BlendMode, BLEND_MAX_ENUM, blendMode)
 
-static StringMap<BlendAlpha, BLENDALPHA_MAX_ENUM>::Entry blendAlphaEntries[] =
+STRINGMAP_BEGIN(BlendAlpha, BLENDALPHA_MAX_ENUM, blendAlpha)
 {
 	{ "alphamultiply", BLENDALPHA_MULTIPLY      },
 	{ "premultiplied", BLENDALPHA_PREMULTIPLIED },
-};
-
-static StringMap<BlendAlpha, BLENDALPHA_MAX_ENUM> blendAlphaModes(blendAlphaEntries, sizeof(blendAlphaEntries));
+}
+STRINGMAP_END(BlendAlpha, BLENDALPHA_MAX_ENUM, blendAlpha)
 
-static StringMap<BlendFactor, BLENDFACTOR_MAX_ENUM>::Entry blendFactorEntries[] =
+STRINGMAP_BEGIN(BlendFactor, BLENDFACTOR_MAX_ENUM, blendFactor)
 {
 	{ "zero",              BLENDFACTOR_ZERO                 },
 	{ "one",               BLENDFACTOR_ONE                  },
@@ -160,22 +158,20 @@ static StringMap<BlendFactor, BLENDFACTOR_MAX_ENUM>::Entry blendFactorEntries[]
 	{ "dstalpha",          BLENDFACTOR_DST_ALPHA            },
 	{ "oneminusdstalpha",  BLENDFACTOR_ONE_MINUS_DST_ALPHA  },
 	{ "srcalphasaturated", BLENDFACTOR_SRC_ALPHA_SATURATED  },
-};
-
-static StringMap<BlendFactor, BLENDFACTOR_MAX_ENUM> blendFactors(blendFactorEntries, sizeof(blendFactorEntries));
+}
+STRINGMAP_END(BlendFactor, BLENDFACTOR_MAX_ENUM, blendFactor)
 
-static StringMap<BlendOperation, BLENDOP_MAX_ENUM>::Entry blendOperationEntries[] =
+STRINGMAP_BEGIN(BlendOperation, BLENDOP_MAX_ENUM, blendOperation)
 {
 	{ "add",             BLENDOP_ADD              },
 	{ "subtract",        BLENDOP_SUBTRACT         },
 	{ "reversesubtract", BLENDOP_REVERSE_SUBTRACT },
 	{ "min",             BLENDOP_MIN              },
 	{ "max",             BLENDOP_MAX              },
-};
-
-static StringMap<BlendOperation, BLENDOP_MAX_ENUM> blendOperations(blendOperationEntries, sizeof(blendOperationEntries));
+}
+STRINGMAP_END(BlendOperation, BLENDOP_MAX_ENUM, blendOperation)
 
-static StringMap<StencilAction, STENCIL_MAX_ENUM>::Entry stencilActionEntries[] =
+STRINGMAP_BEGIN(StencilAction, STENCIL_MAX_ENUM, stencilAction)
 {
 	{ "keep",          STENCIL_KEEP           },
 	{ "zero",          STENCIL_ZERO           },
@@ -185,11 +181,10 @@ static StringMap<StencilAction, STENCIL_MAX_ENUM>::Entry stencilActionEntries[]
 	{ "incrementwrap", STENCIL_INCREMENT_WRAP },
 	{ "decrementwrap", STENCIL_DECREMENT_WRAP },
 	{ "invert",        STENCIL_INVERT         },
-};
-
-static StringMap<StencilAction, STENCIL_MAX_ENUM> stencilActions(stencilActionEntries, sizeof(stencilActionEntries));
+}
+STRINGMAP_END(StencilAction, STENCIL_MAX_ENUM, stencilAction)
 
-static StringMap<CompareMode, COMPARE_MAX_ENUM>::Entry compareModeEntries[] =
+STRINGMAP_BEGIN(CompareMode, COMPARE_MAX_ENUM, compareMode)
 {
 	{ "less",     COMPARE_LESS     },
 	{ "lequal",   COMPARE_LEQUAL   },
@@ -199,99 +194,8 @@ static StringMap<CompareMode, COMPARE_MAX_ENUM>::Entry compareModeEntries[] =
 	{ "notequal", COMPARE_NOTEQUAL },
 	{ "always",   COMPARE_ALWAYS   },
 	{ "never",    COMPARE_NEVER    },
-};
-
-static StringMap<CompareMode, COMPARE_MAX_ENUM> compareModes(compareModeEntries, sizeof(compareModeEntries));
-
-bool getConstant(const char *in, BlendMode &out)
-{
-	return blendModes.find(in, out);
-}
-
-bool getConstant(BlendMode in, const char *&out)
-{
-	return blendModes.find(in, out);
-}
-
-std::vector<std::string> getConstants(BlendMode)
-{
-	return blendModes.getNames();
-}
-
-bool getConstant(const char *in, BlendAlpha &out)
-{
-	return blendAlphaModes.find(in, out);
-}
-
-bool getConstant(BlendAlpha in, const char *&out)
-{
-	return blendAlphaModes.find(in, out);
-}
-
-std::vector<std::string> getConstants(BlendAlpha)
-{
-	return blendAlphaModes.getNames();
-}
-
-bool getConstant(const char *in, BlendFactor &out)
-{
-	return blendFactors.find(in, out);
-}
-
-bool getConstant(BlendFactor in, const char *&out)
-{
-	return blendFactors.find(in, out);
-}
-
-std::vector<std::string> getConstants(BlendFactor)
-{
-	return blendFactors.getNames();
-}
-
-bool getConstant(const char *in, BlendOperation &out)
-{
-	return blendOperations.find(in, out);
-}
-
-bool getConstant(BlendOperation in, const char *&out)
-{
-	return blendOperations.find(in, out);
-}
-
-std::vector<std::string> getConstants(BlendOperation)
-{
-	return blendOperations.getNames();
-}
-
-bool getConstant(const char *in, StencilAction &out)
-{
-	return stencilActions.find(in, out);
-}
-
-bool getConstant(StencilAction in, const char *&out)
-{
-	return stencilActions.find(in, out);
-}
-
-std::vector<std::string> getConstants(StencilAction)
-{
-	return stencilActions.getNames();
-}
-
-bool getConstant(const char *in, CompareMode &out)
-{
-	return compareModes.find(in, out);
-}
-
-bool getConstant(CompareMode in, const char *&out)
-{
-	return compareModes.find(in, out);
-}
-
-std::vector<std::string> getConstants(CompareMode)
-{
-	return compareModes.getNames();
 }
+STRINGMAP_END(CompareMode, COMPARE_MAX_ENUM, compareMode)
 
 } // graphics
 } // love

+ 7 - 23
src/modules/graphics/renderstate.h

@@ -22,6 +22,7 @@
 
 #include "common/int.h"
 #include "common/math.h"
+#include "common/StringMap.h"
 #include "vertex.h"
 
 #include <vector>
@@ -203,29 +204,12 @@ bool isAlphaMultiplyBlendSupported(BlendMode mode);
  **/
 CompareMode getReversedCompareMode(CompareMode mode);
 
-bool getConstant(const char *in, BlendMode &out);
-bool getConstant(BlendMode in, const char *&out);
-std::vector<std::string> getConstants(BlendMode);
-
-bool getConstant(const char *in, BlendAlpha &out);
-bool getConstant(BlendAlpha in, const char *&out);
-std::vector<std::string> getConstants(BlendAlpha);
-
-bool getConstant(const char *in, BlendFactor &out);
-bool getConstant(BlendFactor in, const char *&out);
-std::vector<std::string> getConstants(BlendFactor);
-
-bool getConstant(const char *in, BlendOperation &out);
-bool getConstant(BlendOperation in, const char *&out);
-std::vector<std::string> getConstants(BlendOperation);
-
-bool getConstant(const char *in, StencilAction &out);
-bool getConstant(StencilAction in, const char *&out);
-std::vector<std::string> getConstants(StencilAction);
-
-bool getConstant(const char *in, CompareMode &out);
-bool getConstant(CompareMode in, const char *&out);
-std::vector<std::string> getConstants(CompareMode);
+STRINGMAP_DECLARE(BlendMode);
+STRINGMAP_DECLARE(BlendAlpha);
+STRINGMAP_DECLARE(BlendFactor);
+STRINGMAP_DECLARE(BlendOperation);
+STRINGMAP_DECLARE(StencilAction);
+STRINGMAP_DECLARE(CompareMode);
 
 } // graphics
 } // love

+ 0 - 79
src/modules/graphics/wrap_Buffer.cpp

@@ -309,75 +309,6 @@ static int w_Buffer_setArrayData(lua_State *L)
 	return 0;
 }
 
-static int w_Buffer_setElement(lua_State *L)
-{
-	Buffer *t = luax_checkbuffer(L, 1);
-
-	size_t index = (size_t) (luaL_checkinteger(L, 2) - 1);
-	if (index >= t->getArrayLength())
-		return luaL_error(L, "Invalid Buffer element index: %d", (int) index + 1);
-
-	size_t stride = t->getArrayStride();
-	size_t offset = index * stride;
-	char *data = (char *) t->map() + offset;
-	const auto &members = t->getDataMembers();
-
-	bool istable = lua_istable(L, 3);
-	int idx = istable ? 1 : 3;
-
-	if (istable)
-	{
-		for (const Buffer::DataMember &member : members)
-		{
-			int components = member.info.components;
-
-			for (int i = idx; i < idx + components; i++)
-				lua_rawgeti(L, 3, i);
-
-			luax_writebufferdata(L, -components, member.decl.format, data + member.offset);
-
-			idx += components;
-			lua_pop(L, components);
-		}
-	}
-	else
-	{
-		for (const Buffer::DataMember &member : members)
-		{
-			luax_writebufferdata(L, idx, member.decl.format, data + member.offset);
-			idx += member.info.components;
-		}
-	}
-
-	t->setMappedRangeModified(offset, stride);
-	return 0;
-}
-
-static int w_Buffer_getElement(lua_State *L)
-{
-	Buffer *t = luax_checkbuffer(L, 1);
-	if ((t->getMapFlags() & Buffer::MAP_READ) == 0)
-		return luaL_error(L, "Buffer:getElement requires the buffer to be created with the 'cpureadable' setting set to true.");
-
-	size_t index = (size_t) (luaL_checkinteger(L, 2) - 1);
-	if (index >= t->getArrayLength())
-		return luaL_error(L, "Invalid Buffer element index: %d", (int) index + 1);
-
-	size_t offset = index * t->getArrayStride();
-	const char *data = (const char *) t->map() + offset;
-	const auto &members = t->getDataMembers();
-
-	int n = 0;
-
-	for (const Buffer::DataMember &member : members)
-	{
-		luax_readbufferdata(L, member.decl.format, data + member.offset);
-		n += member.info.components;
-	}
-
-	return n;
-}
-
 static int w_Buffer_getElementCount(lua_State *L)
 {
 	Buffer *t = luax_checkbuffer(L, 1);
@@ -443,25 +374,15 @@ static int w_Buffer_isBufferType(lua_State *L)
 	return 1;
 }
 
-static int w_Buffer_isCPUReadable(lua_State *L)
-{
-	Buffer *t = luax_checkbuffer(L, 1);
-	luax_pushboolean(L, (t->getMapFlags() & Buffer::MAP_READ) != 0);
-	return 1;
-}
-
 static const luaL_Reg w_Buffer_functions[] =
 {
 	{ "flush", w_Buffer_flush },
 	{ "setArrayData", w_Buffer_setArrayData },
-	{ "setElement", w_Buffer_setElement },
-	{ "getElement", w_Buffer_getElement },
 	{ "getElementCount", w_Buffer_getElementCount },
 	{ "getElementStride", w_Buffer_getElementStride },
 	{ "getSize", w_Buffer_getSize },
 	{ "getFormat", w_Buffer_getFormat },
 	{ "isBufferType", w_Buffer_isBufferType },
-	{ "isCPUReadable", w_Buffer_isCPUReadable },
 	{ 0, 0 }
 };
 

+ 1 - 6
src/modules/graphics/wrap_Graphics.cpp

@@ -1146,7 +1146,7 @@ int w_newVolumeTexture(lua_State *L)
 
 					for (int slice = 0; slice < slicelen; slice++)
 					{
-						lua_rawgeti(L, -1, mip + 1);
+						lua_rawgeti(L, -1, slice + 1);
 
 						auto data = getImageData(L, -1, true, slice == 0 && mip == 0 ? autodpiscale : nullptr);
 						if (data.first.get())
@@ -1508,11 +1508,6 @@ static void luax_optbuffersettings(lua_State *L, int idx, Buffer::Settings &sett
 	lua_getfield(L, idx, "usage");
 	settings.usage = luax_optbufferusage(L, -1, settings.usage);
 	lua_pop(L, 1);
-
-	if (luax_boolflag(L, idx, "cpureadable", settings.mapFlags & Buffer::MAP_READ))
-		settings.mapFlags = (Buffer::MapFlags)(settings.mapFlags | Buffer::MAP_READ);
-	else
-		settings.mapFlags = (Buffer::MapFlags)(settings.mapFlags & (~Buffer::MAP_READ));
 }
 
 static void luax_checkbufferformat(lua_State *L, int idx, std::vector<Buffer::DataDeclaration> &format)

+ 15 - 0
src/modules/physics/box2d/Body.cpp

@@ -112,6 +112,14 @@ float Body::getAngularVelocity() const
 	return body->GetAngularVelocity();
 }
 
+void Body::getKinematicState(b2Vec2 &pos_o, float &a_o, b2Vec2 &vel_o, float &da_o) const
+{
+	pos_o = Physics::scaleUp(body->GetPosition());
+	a_o = body->GetAngle();
+	vel_o = Physics::scaleUp(body->GetLinearVelocity());
+	da_o = body->GetAngularVelocity();
+}
+
 float Body::getMass() const
 {
 	return body->GetMass();
@@ -225,6 +233,13 @@ void Body::setAngularVelocity(float r)
 	body->SetAngularVelocity(r);
 }
 
+void Body::setKinematicState(b2Vec2 pos, float a, b2Vec2 vel, float da)
+{
+	body->SetTransform(Physics::scaleDown(pos), a);
+	body->SetLinearVelocity(Physics::scaleDown(vel));
+	body->SetAngularVelocity(da);
+}
+
 void Body::setPosition(float x, float y)
 {
 	body->SetTransform(Physics::scaleDown(b2Vec2(x, y)), body->GetAngle());

+ 10 - 0
src/modules/physics/box2d/Body.h

@@ -129,6 +129,11 @@ public:
 	 **/
 	float getAngularVelocity() const;
 
+	/**
+	 * Get the current Body kinematic state. (Position, angle, velocity, angle velocity).
+	 **/
+	void getKinematicState(b2Vec2 &pos_o, float &a_o, b2Vec2& vel_o, float &da_o) const;
+
 	/**
 	 * Gets the Body's mass.
 	 **/
@@ -219,6 +224,11 @@ public:
 	 **/
 	void setAngularVelocity(float r);
 
+	/**
+	 * Set the current Body kinematic state. (Position, angle, velocity, angle velocity).
+	 **/
+	void setKinematicState(b2Vec2 pos, float a, b2Vec2 vel, float da);
+
 	/**
 	 * Sets the current position of the Body.
 	 **/

+ 30 - 0
src/modules/physics/box2d/wrap_Body.cpp

@@ -125,6 +125,21 @@ int w_Body_getAngularVelocity(lua_State *L)
 	return 1;
 }
 
+int w_Body_getKinematicState(lua_State *L)
+{
+	Body *t = luax_checkbody(L, 1);
+	b2Vec2 pos_o, vel_o;
+	float a_o, da_o;
+	t->getKinematicState(pos_o, a_o, vel_o, da_o);
+	lua_pushnumber(L, pos_o.x);
+	lua_pushnumber(L, pos_o.y);
+	lua_pushnumber(L, a_o);
+	lua_pushnumber(L, vel_o.x);
+	lua_pushnumber(L, vel_o.y);
+	lua_pushnumber(L, da_o);
+	return 6;
+}
+
 int w_Body_getMass(lua_State *L)
 {
 	Body *t = luax_checkbody(L, 1);
@@ -313,6 +328,19 @@ int w_Body_setPosition(lua_State *L)
 	return 0;
 }
 
+int w_Body_setKinematicState(lua_State *L)
+{
+	Body *t = luax_checkbody(L, 1);
+	float x = (float)luaL_checknumber(L, 2);
+	float y = (float)luaL_checknumber(L, 3);
+	float a = (float)luaL_checknumber(L, 4);
+	float dx = (float)luaL_checknumber(L, 5);
+	float dy = (float)luaL_checknumber(L, 6);
+	float da = (float)luaL_checknumber(L, 7);
+	luax_catchexcept(L, [&](){ t->setKinematicState(b2Vec2(x, y), a, b2Vec2(dx, dy), da); });
+	return 0;
+}
+
 int w_Body_resetMassData(lua_State *L)
 {
 	Body *t = luax_checkbody(L, 1);
@@ -631,6 +659,7 @@ static const luaL_Reg w_Body_functions[] =
 	{ "getWorldCenter", w_Body_getWorldCenter },
 	{ "getLocalCenter", w_Body_getLocalCenter },
 	{ "getAngularVelocity", w_Body_getAngularVelocity },
+	{ "getKinematicState", w_Body_getKinematicState },
 	{ "getMass", w_Body_getMass },
 	{ "getInertia", w_Body_getInertia },
 	{ "getMassData", w_Body_getMassData },
@@ -648,6 +677,7 @@ static const luaL_Reg w_Body_functions[] =
 	{ "setAngle", w_Body_setAngle },
 	{ "setAngularVelocity", w_Body_setAngularVelocity },
 	{ "setPosition", w_Body_setPosition },
+	{ "setKinematicState", w_Body_setKinematicState },
 	{ "resetMassData", w_Body_resetMassData },
 	{ "setMassData", w_Body_setMassData },
 	{ "setMass", w_Body_setMass },

+ 44 - 2
src/modules/sound/SoundData.cpp

@@ -98,7 +98,7 @@ SoundData::SoundData(int samples, int sampleRate, int bitDepth, int channels)
 	load(samples, sampleRate, bitDepth, channels);
 }
 
-SoundData::SoundData(void *d, int samples, int sampleRate, int bitDepth, int channels)
+SoundData::SoundData(const void *d, int samples, int sampleRate, int bitDepth, int channels)
 	: data(0)
 	, size(0)
 	, sampleRate(0)
@@ -129,7 +129,7 @@ SoundData *SoundData::clone() const
 	return new SoundData(*this);
 }
 
-void SoundData::load(int samples, int sampleRate, int bitDepth, int channels, void *newData)
+void SoundData::load(int samples, int sampleRate, int bitDepth, int channels, const void *newData)
 {
 	if (samples <= 0)
 		throw love::Exception("Invalid sample count: %d", samples);
@@ -258,5 +258,47 @@ float SoundData::getSample(int i, int channel) const
 	return getSample(i * channels + (channel - 1));
 }
 
+void SoundData::copyFrom(const SoundData *src, int srcStart, int count, int dstStart)
+{
+	if (channels != src->channels)
+		throw love::Exception("Channel count mismatch!");
+
+	size_t bytesPerSample = (size_t) channels * bitDepth/8;
+	size_t srcBytesPerSample = (size_t) src->channels * src->bitDepth/8;
+	
+	// Check range
+	if (dstStart < 0 || (dstStart+count) * bytesPerSample > size)
+		throw love::Exception("Destination out-of-range!");
+	if (srcStart < 0 || (srcStart+count) * srcBytesPerSample > src->size)
+		throw love::Exception("Source out-of-range!");
+
+	if (bitDepth != src->bitDepth)
+	{
+		// Bit depth mismatch, use get/setSample at loop
+		for (int i = 0; i < count * channels; i++)
+			setSample(dstStart * channels + i, src->getSample(srcStart * channels + i));
+	}
+	else if (this->data == src->data)
+		// May overlap, use memmove
+		memmove(data + dstStart * bytesPerSample, src->data + srcStart * bytesPerSample, count * bytesPerSample);
+	else
+		memcpy(data + dstStart * bytesPerSample, src->data + srcStart * bytesPerSample, count * bytesPerSample);
+}
+
+SoundData *SoundData::slice(int start, int length) const
+{
+	int totalSamples = getSampleCount();
+
+	if (length == 0)
+		throw love::Exception("Invalid slice length: 0");
+	else if (length < 0)
+		length = totalSamples - start;
+
+	if (start < 0 || start + length > totalSamples)
+		throw love::Exception("Attempt to slice at out-of-range position!");
+
+	return new SoundData(data + start * channels * bitDepth/8, length, sampleRate, bitDepth, channels);
+}
+
 } // sound
 } // love

+ 5 - 2
src/modules/sound/SoundData.h

@@ -39,7 +39,7 @@ public:
 
 	SoundData(Decoder *decoder);
 	SoundData(int samples, int sampleRate, int bitDepth, int channels);
-	SoundData(void *d, int samples, int sampleRate, int bitDepth, int channels);
+	SoundData(const void *d, int samples, int sampleRate, int bitDepth, int channels);
 	SoundData(const SoundData &c);
 
 	virtual ~SoundData();
@@ -61,9 +61,12 @@ public:
 	float getSample(int i) const;
 	float getSample(int i, int channel) const;
 
+	void copyFrom(const SoundData *src, int srcStart, int count, int dstStart);
+	SoundData *slice(int start, int length = -1) const;
+
 private:
 
-	void load(int samples, int sampleRate, int bitDepth, int channels, void *newData = 0);
+	void load(int samples, int sampleRate, int bitDepth, int channels, const void *newData = 0);
 
 	uint8 *data;
 	size_t size;

+ 27 - 0
src/modules/sound/wrap_SoundData.cpp

@@ -121,6 +121,31 @@ int w_SoundData_getSample(lua_State *L)
 	return 1;
 }
 
+int w_SoundData_copyFrom(lua_State *L)
+{
+	SoundData *dst = luax_checksounddata(L, 1);
+	const SoundData *src = luax_checksounddata(L, 2);
+
+	int srcStart = (int) luaL_checkinteger(L, 3);
+	int count = (int) luaL_checkinteger(L, 4);
+	int dstStart = (int) luaL_optinteger(L, 5, 0);
+
+	luax_catchexcept(L, [&](){ dst->copyFrom(src, srcStart, count, dstStart); });
+	return 0;
+}
+
+int w_SoundData_slice(lua_State *L)
+{
+	SoundData *t = luax_checksounddata(L, 1), *c = nullptr;
+	int start = (int) luaL_checkinteger(L, 2);
+	int length = (int) luaL_optinteger(L, 3, -1);
+
+	luax_catchexcept(L, [&](){ c = t->slice(start, length); });
+	luax_pushtype(L, c);
+	c->release();
+	return 1;
+}
+
 static const luaL_Reg w_SoundData_functions[] =
 {
 	{ "clone", w_SoundData_clone },
@@ -131,6 +156,8 @@ static const luaL_Reg w_SoundData_functions[] =
 	{ "getDuration", w_SoundData_getDuration },
 	{ "setSample", w_SoundData_setSample },
 	{ "getSample", w_SoundData_getSample },
+	{ "copyFrom", w_SoundData_copyFrom },
+	{ "slice", w_SoundData_slice },
 
 	{ 0, 0 }
 };

+ 1 - 1
src/scripts/boot.lua

@@ -673,7 +673,7 @@ function love.errhand(msg)
 	love.graphics.reset()
 	local font = love.graphics.setNewFont(14)
 
-	love.graphics.setColor(1, 1, 1, 1)
+	love.graphics.setColor(1, 1, 1)
 
 	local trace = debug.traceback()
 

+ 1 - 1
src/scripts/boot.lua.h

@@ -1347,7 +1347,7 @@ const unsigned char boot_lua[] =
 	0x6e, 0x74, 0x28, 0x31, 0x34, 0x29, 0x0a,
 	0x0a,
 	0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 
-	0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x0a,
+	0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x0a,
 	0x0a,
 	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x62, 
 	0x75, 0x67, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x28, 0x29, 0x0a,