Browse Source

Add support for partial Image updates via Image:replacePixels(imagedata [, sliceindex, mipmap, x, y]) with a smaller-sized ImageData.

Also updated the argument order of Canvas:newImageData to match: (sliceindex, mipmap, x, y, w, h).
Alex Szpakowski 7 years ago
parent
commit
2459752c06

+ 11 - 6
src/modules/graphics/Image.cpp

@@ -99,7 +99,7 @@ void Image::init(PixelFormat fmt, int w, int h, const Settings &settings)
 	initQuad();
 }
 
-void Image::uploadImageData(love::image::ImageDataBase *d, int level, int slice, const Rect &rect)
+void Image::uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y)
 {
 	love::image::ImageData *id = dynamic_cast<love::image::ImageData *>(d);
 
@@ -107,10 +107,11 @@ void Image::uploadImageData(love::image::ImageDataBase *d, int level, int slice,
 	if (id != nullptr)
 		lock.setLock(id->getMutex());
 
+	Rect rect = {x, y, d->getWidth(), d->getHeight()};
 	uploadByteData(d->getFormat(), d->getData(), d->getSize(), level, slice, rect);
 }
 
-void Image::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, const Rect &rect, bool reloadmipmaps)
+void Image::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, int x, int y, bool reloadmipmaps)
 {
 	// No effect if the texture hasn't been created yet.
 	if (getHandle() == 0 || usingDefaultTexture)
@@ -129,6 +130,8 @@ void Image::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap,
 		throw love::Exception("Invalid image slice index %d.", slice + 1);
 	}
 
+	Rect rect = {x, y, d->getWidth(), d->getHeight()};
+
 	int mipw = getPixelWidth(mipmap);
 	int miph = getPixelHeight(mipmap);
 
@@ -144,16 +147,18 @@ void Image::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap,
 		throw love::Exception("Image does not store ImageData!");
 
 	Rect currect = {0, 0, oldd->getWidth(), oldd->getHeight()};
-	Rect newdrect = {0, 0, d->getWidth(), d->getHeight()};
 
 	// We can only replace the internal Data (used when reloading due to setMode)
-	// if the dimensions match.
-	if (rect == currect && rect == newdrect)
+	// if the dimensions match. We also don't currently support partial updates
+	// of compressed textures.
+	if (rect == currect)
 		data.set(slice, mipmap, d);
+	else if (isPixelFormatCompressed(d->getFormat()))
+		throw love::Exception("Compressed textures only support replacing the entire Image.");
 
 	Graphics::flushStreamDrawsGlobal();
 
-	uploadImageData(d, mipmap, slice, rect);
+	uploadImageData(d, mipmap, slice, x, y);
 
 	if (reloadmipmaps && mipmap == 0 && getMipmapCount() > 1)
 		generateMipmaps();

+ 2 - 2
src/modules/graphics/Image.h

@@ -93,7 +93,7 @@ public:
 
 	virtual ~Image();
 
-	void replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, const Rect &rect, bool reloadmipmaps);
+	void replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, int x, int y, bool reloadmipmaps);
 	void replacePixels(const void *data, size_t size, int slice, int mipmap, const Rect &rect, bool reloadmipmaps);
 
 	bool isFormatLinear() const;
@@ -112,7 +112,7 @@ protected:
 	Image(const Slices &data, const Settings &settings);
 	Image(TextureType textype, PixelFormat format, int width, int height, int slices, const Settings &settings);
 
-	void uploadImageData(love::image::ImageDataBase *d, int level, int slice, const Rect &rect);
+	void uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y);
 	virtual void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) = 0;
 
 	virtual void generateMipmaps() = 0;

+ 1 - 4
src/modules/graphics/opengl/Image.cpp

@@ -133,10 +133,7 @@ void Image::loadData()
 			love::image::ImageDataBase *id = data.get(slice, mip);
 
 			if (id != nullptr)
-			{
-				Rect r = {0, 0, id->getWidth(), id->getHeight()};
-				uploadImageData(id, mip, slice, r);
-			}
+				uploadImageData(id, mip, slice, 0, 0);
 		}
 
 		w = std::max(w / 2, 1);

+ 10 - 8
src/modules/graphics/wrap_Canvas.cpp

@@ -94,15 +94,17 @@ int w_Canvas_newImageData(lua_State *L)
 	int mipmap = 0;
 	Rect rect = {0, 0, canvas->getPixelWidth(), canvas->getPixelHeight()};
 
-	if (!lua_isnoneornil(L, 2))
-	{
-		rect.x = (int) luaL_checkinteger(L, 2);
-		rect.y = (int) luaL_checkinteger(L, 3);
-		rect.w = (int) luaL_checkinteger(L, 4);
-		rect.h = (int) luaL_checkinteger(L, 5);
+	if (canvas->getTextureType() != TEXTURE_2D)
+		slice = (int) luaL_checkinteger(L, 2) - 1;
+
+	mipmap = (int) luaL_optinteger(L, 3, 1) - 1;
 
-		slice = (int) luaL_optinteger(L, 6, 1) - 1;
-		mipmap = (int) luaL_optinteger(L, 7, 1) - 1;
+	if (!lua_isnoneornil(L, 4))
+	{
+		rect.x = (int) luaL_checkinteger(L, 4);
+		rect.y = (int) luaL_checkinteger(L, 5);
+		rect.w = (int) luaL_checkinteger(L, 6);
+		rect.h = (int) luaL_checkinteger(L, 7);
 	}
 
 	love::image::ImageData *img = nullptr;

+ 13 - 7
src/modules/graphics/wrap_Image.cpp

@@ -52,19 +52,25 @@ int w_Image_replacePixels(lua_State *L)
 
 	int slice = 0;
 	int mipmap = 0;
-	Rect r = {0, 0, id->getWidth(), id->getHeight()};
+	int x = 0;
+	int y = 0;
 	bool reloadmipmaps = i->getMipmapsType() == Image::MIPMAPS_GENERATED;
 
 	if (i->getTextureType() != TEXTURE_2D)
-	{
 		slice = (int) luaL_checkinteger(L, 3) - 1;
-		if (!reloadmipmaps)
-			mipmap = (int) luaL_optinteger(L, 4, 1) - 1;
+
+	mipmap = (int) luaL_optinteger(L, 4, 1) - 1;
+
+	if (!lua_isnoneornil(L, 5))
+	{
+		x = (int) luaL_checkinteger(L, 5);
+		y = (int) luaL_checkinteger(L, 6);
+
+		if (reloadmipmaps)
+			reloadmipmaps = luax_optboolean(L, 7, reloadmipmaps);
 	}
-	else if (!reloadmipmaps)
-		mipmap = (int) luaL_optinteger(L, 3, 1) - 1;
 
-	luax_catchexcept(L, [&](){ i->replacePixels(id, slice, mipmap, r, reloadmipmaps); });
+	luax_catchexcept(L, [&](){ i->replacePixels(id, slice, mipmap, x, y, reloadmipmaps); });
 	return 0;
 }