From 2459752c061214c9373d140c0f9e215ff56693a7 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 10 Jan 2018 22:52:28 -0400 Subject: [PATCH] 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). --- src/modules/graphics/Image.cpp | 17 +++++++++++------ src/modules/graphics/Image.h | 4 ++-- src/modules/graphics/opengl/Image.cpp | 5 +---- src/modules/graphics/wrap_Canvas.cpp | 18 ++++++++++-------- src/modules/graphics/wrap_Image.cpp | 22 ++++++++++++++-------- 5 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/modules/graphics/Image.cpp b/src/modules/graphics/Image.cpp index b0501d82e..64622040c 100644 --- a/src/modules/graphics/Image.cpp +++ b/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(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(); diff --git a/src/modules/graphics/Image.h b/src/modules/graphics/Image.h index cb281547d..4bf19192f 100644 --- a/src/modules/graphics/Image.h +++ b/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; diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index 3674827b2..d29d4beba 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/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); diff --git a/src/modules/graphics/wrap_Canvas.cpp b/src/modules/graphics/wrap_Canvas.cpp index 62db895b5..05e71a6e9 100644 --- a/src/modules/graphics/wrap_Canvas.cpp +++ b/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; - slice = (int) luaL_optinteger(L, 6, 1) - 1; - mipmap = (int) luaL_optinteger(L, 7, 1) - 1; + mipmap = (int) luaL_optinteger(L, 3, 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; diff --git a/src/modules/graphics/wrap_Image.cpp b/src/modules/graphics/wrap_Image.cpp index 04e082a10..b778da66b 100644 --- a/src/modules/graphics/wrap_Image.cpp +++ b/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; - } - else if (!reloadmipmaps) - mipmap = (int) luaL_optinteger(L, 3, 1) - 1; - luax_catchexcept(L, [&](){ i->replacePixels(id, slice, mipmap, r, reloadmipmaps); }); + 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); + } + + luax_catchexcept(L, [&](){ i->replacePixels(id, slice, mipmap, x, y, reloadmipmaps); }); return 0; }