diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index dbde24e1e..8f5a44eea 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -955,13 +955,24 @@ bool Canvas::checkCreateStencil() return success; } -love::image::ImageData *Canvas::getImageData(love::image::Image *image) +love::image::ImageData *Canvas::getImageData(love::image::Image *image, int x, int y, int w, int h) { + if (x < 0 || y < 0 || w <= 0 || h <= 0 || (x + w) > width || (y + h) > height) + throw love::Exception("Invalid ImageData rectangle dimensions."); + resolveMSAA(); - int row = 4 * width; - int size = row * height; - GLubyte *pixels = new GLubyte[size]; + int row = 4 * w; + int size = row * h; + GLubyte *pixels = nullptr; + try + { + pixels = new GLubyte[size]; + } + catch (std::bad_alloc &) + { + throw love::Exception("Out of memory."); + } // Our texture is attached to 'resolve_fbo' when we use MSAA. if (resolve_fbo != 0 && (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object)) @@ -971,7 +982,7 @@ love::image::ImageData *Canvas::getImageData(love::image::Image *image) else strategy->bindFBO(fbo); - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); if (current) strategy->bindFBO(current->fbo); @@ -979,31 +990,7 @@ love::image::ImageData *Canvas::getImageData(love::image::Image *image) strategy->bindFBO(gl.getDefaultFBO()); // The new ImageData now owns the pixel data, so we don't delete it here. - love::image::ImageData *img = image->newImageData(width, height, (void *)pixels, true); - return img; -} - -void Canvas::getPixel(unsigned char* pixel_rgba, int x, int y) -{ - if (x < 0 || x >= width || y < 0 || y >= width) - throw love::Exception("Attempt to get out-of-range pixel (%d,%d)!", x, y); - - resolveMSAA(); - - // Our texture is attached to 'resolve_fbo' when we use MSAA. - if (resolve_fbo != 0 && (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object)) - glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo); - else if (resolve_fbo != 0 && GLAD_EXT_framebuffer_multisample) - glBindFramebufferEXT(GL_READ_FRAMEBUFFER, resolve_fbo); - else if (current != this) - strategy->bindFBO(fbo); - - glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_rgba); - - if (current && current != this) - strategy->bindFBO(current->fbo); - else if (!current) - strategy->bindFBO(gl.getDefaultFBO()); + return image->newImageData(w, h, pixels, true); } bool Canvas::resolveMSAA() diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index 1f73fa11b..3c4c93a45 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -91,9 +91,7 @@ public: **/ bool checkCreateStencil(); - love::image::ImageData *getImageData(love::image::Image *image); - - void getPixel(unsigned char* pixel_rgba, int x, int y); + love::image::ImageData *getImageData(love::image::Image *image, int x, int y, int w, int h); inline const std::vector &getAttachedCanvases() const { diff --git a/src/modules/graphics/opengl/wrap_Canvas.cpp b/src/modules/graphics/opengl/wrap_Canvas.cpp index 0e1a97651..ec37b60d3 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.cpp +++ b/src/modules/graphics/opengl/wrap_Canvas.cpp @@ -66,28 +66,17 @@ int w_Canvas_getImageData(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); love::image::Image *image = luax_getmodule(L, "image", MODULE_IMAGE_T); - love::image::ImageData *img = canvas->getImageData(image); + int x = luaL_optint(L, 2, 0); + int y = luaL_optint(L, 3, 0); + int w = luaL_optint(L, 4, canvas->getWidth()); + int h = luaL_optint(L, 5, canvas->getHeight()); + + love::image::ImageData *img = canvas->getImageData(image, x, y, w, h); luax_pushtype(L, "ImageData", IMAGE_IMAGE_DATA_T, img); img->release(); return 1; } -int w_Canvas_getPixel(lua_State * L) -{ - Canvas * canvas = luax_checkcanvas(L, 1); - int x = luaL_checkint(L, 2); - int y = luaL_checkint(L, 3); - unsigned char c[4]; - - luax_catchexcept(L, [&](){ canvas->getPixel(c, x, y); }); - - lua_pushnumber(L, c[0]); - lua_pushnumber(L, c[1]); - lua_pushnumber(L, c[2]); - lua_pushnumber(L, c[3]); - return 4; -} - int w_Canvas_clear(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); @@ -152,7 +141,6 @@ static const luaL_Reg functions[] = { "renderTo", w_Canvas_renderTo }, { "getImageData", w_Canvas_getImageData }, - { "getPixel", w_Canvas_getPixel }, { "clear", w_Canvas_clear }, { "getFormat", w_Canvas_getFormat }, { "getMSAA", w_Canvas_getMSAA },