Move replacePixels from Image to Texture

This commit is contained in:
Alex Szpakowski
2020-02-04 19:05:43 -04:00
parent 63c5df6aa7
commit 4716211c14
12 changed files with 168 additions and 143 deletions
-65
View File
@@ -34,7 +34,6 @@ love::Type Image::type("Image", &Texture::type);
Image::Image(TextureType textype, const Settings &settings)
: Texture(textype)
, settings(settings)
, usingDefaultTexture(false)
{
renderTarget = false;
sRGB = isGammaCorrect() && !settings.linear;
@@ -105,70 +104,6 @@ void Image::init(PixelFormat fmt, int w, int h, int dataMipmaps, const Settings
initQuad();
}
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);
love::thread::EmptyLock lock;
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, d);
}
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)
return;
if (d->getFormat() != getPixelFormat())
throw love::Exception("Pixel formats must match.");
if (mipmap < 0 || mipmap >= getMipmapCount())
throw love::Exception("Invalid image mipmap index %d.", mipmap + 1);
if (slice < 0 || (texType == TEXTURE_CUBE && slice >= 6)
|| (texType == TEXTURE_VOLUME && slice >= getDepth(mipmap))
|| (texType == TEXTURE_2D_ARRAY && slice >= getLayerCount()))
{
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);
if (rect.x < 0 || rect.y < 0 || rect.w <= 0 || rect.h <= 0
|| (rect.x + rect.w) > mipw || (rect.y + rect.h) > miph)
{
throw love::Exception("Invalid rectangle dimensions (x=%d, y=%d, w=%d, h=%d) for %dx%d Image.", rect.x, rect.y, rect.w, rect.h, mipw, miph);
}
// We don't currently support partial updates of compressed textures.
if (isPixelFormatCompressed(d->getFormat()) && (rect.x != 0 || rect.y != 0 || rect.w != mipw || rect.h != miph))
throw love::Exception("Compressed textures only support replacing the entire Image.");
Graphics::flushStreamDrawsGlobal();
uploadImageData(d, mipmap, slice, x, y);
if (reloadmipmaps && mipmap == 0 && getMipmapCount() > 1)
generateMipmaps();
}
void Image::replacePixels(const void *data, size_t size, int slice, int mipmap, const Rect &rect, bool reloadmipmaps)
{
Graphics::flushStreamDrawsGlobal();
uploadByteData(format, data, size, mipmap, slice, rect, nullptr);
if (reloadmipmaps && mipmap == 0 && getMipmapCount() > 1)
generateMipmaps();
}
bool Image::getConstant(const char *in, SettingType &out)
{
return settingTypes.find(in, out);
-10
View File
@@ -54,9 +54,6 @@ public:
virtual ~Image();
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);
static bool getConstant(const char *in, SettingType &out);
static bool getConstant(SettingType in, const char *&out);
static const char *getConstant(SettingType in);
@@ -67,16 +64,9 @@ 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, int x, int y);
virtual void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) = 0;
// The settings used to initialize this Image.
Settings settings;
// True if the image wasn't able to be properly created and it had to fall
// back to a default texture.
bool usingDefaultTexture;
private:
Image(TextureType textype, const Settings &settings);
+82
View File
@@ -175,6 +175,7 @@ Texture::Texture(TextureType texType)
, requestedMSAA(1)
, samplerState()
, graphicsMemorySize(0)
, usingDefaultTexture(false)
{
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
if (gfx != nullptr)
@@ -358,6 +359,87 @@ void Texture::drawLayer(Graphics *gfx, int layer, Quad *q, const Matrix4 &m)
}
}
void Texture::uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y)
{
love::image::ImageData *id = dynamic_cast<love::image::ImageData *>(d);
love::thread::EmptyLock lock;
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, d);
}
void Texture::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, int x, int y, bool reloadmipmaps)
{
if (!isReadable())
throw love::Exception("replacePixels can only be called on readable Textures.");
if (getMSAA() > 1)
throw love::Exception("replacePixels cannot be called on a MSAA Texture.");
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
if (gfx != nullptr && gfx->isRenderTargetActive(this))
throw love::Exception("replacePixels cannot be called on this Texture while it's an active render target.");
// No effect if the texture hasn't been created yet.
if (getHandle() == 0 || usingDefaultTexture)
return;
if (d->getFormat() != getPixelFormat())
throw love::Exception("Pixel formats must match.");
if (mipmap < 0 || mipmap >= getMipmapCount())
throw love::Exception("Invalid texture mipmap index %d.", mipmap + 1);
if (slice < 0 || (texType == TEXTURE_CUBE && slice >= 6)
|| (texType == TEXTURE_VOLUME && slice >= getDepth(mipmap))
|| (texType == TEXTURE_2D_ARRAY && slice >= getLayerCount()))
{
throw love::Exception("Invalid texture slice index %d.", slice + 1);
}
Rect rect = {x, y, d->getWidth(), d->getHeight()};
int mipw = getPixelWidth(mipmap);
int miph = getPixelHeight(mipmap);
if (rect.x < 0 || rect.y < 0 || rect.w <= 0 || rect.h <= 0
|| (rect.x + rect.w) > mipw || (rect.y + rect.h) > miph)
{
throw love::Exception("Invalid rectangle dimensions (x=%d, y=%d, w=%d, h=%d) for %dx%d Texture.", rect.x, rect.y, rect.w, rect.h, mipw, miph);
}
// We don't currently support partial updates of compressed textures.
if (isPixelFormatCompressed(d->getFormat()) && (rect.x != 0 || rect.y != 0 || rect.w != mipw || rect.h != miph))
throw love::Exception("Compressed textures only support replacing the entire Texture.");
Graphics::flushStreamDrawsGlobal();
uploadImageData(d, mipmap, slice, x, y);
if (reloadmipmaps && mipmap == 0 && getMipmapCount() > 1)
generateMipmaps();
}
void Texture::replacePixels(const void *data, size_t size, int slice, int mipmap, const Rect &rect, bool reloadmipmaps)
{
if (!isReadable() || getMSAA() > 1)
return;
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
if (gfx != nullptr && gfx->isRenderTargetActive(this))
return;
Graphics::flushStreamDrawsGlobal();
uploadByteData(format, data, size, mipmap, slice, rect, nullptr);
if (reloadmipmaps && mipmap == 0 && getMipmapCount() > 1)
generateMipmaps();
}
int Texture::getWidth(int mip) const
{
return std::max(width >> mip, 1);
+12 -2
View File
@@ -182,6 +182,11 @@ public:
void drawLayer(Graphics *gfx, int layer, const Matrix4 &m);
void drawLayer(Graphics *gfx, int layer, Quad *quad, const Matrix4 &m);
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);
virtual void generateMipmaps() = 0;
virtual ptrdiff_t getRenderTargetHandle() const = 0;
TextureType getTextureType() const;
@@ -212,8 +217,6 @@ public:
virtual void setSamplerState(const SamplerState &s);
const SamplerState &getSamplerState() const;
virtual void generateMipmaps() = 0;
Quad *getQuad() const;
static int getTotalMipmapCount(int w, int h);
@@ -232,6 +235,9 @@ protected:
void initQuad();
void setGraphicsMemorySize(int64 size);
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, love::image::ImageDataBase *imgd = nullptr) = 0;
bool validateDimensions(bool throwException) const;
TextureType texType;
@@ -260,6 +266,10 @@ protected:
int64 graphicsMemorySize;
// True if the image wasn't able to be properly created and it had to fall
// back to a default texture.
bool usingDefaultTexture;
private:
static StringMap<TextureType, TEXTURE_MAX_ENUM>::Entry texTypeEntries[];
+31
View File
@@ -389,6 +389,37 @@ void Canvas::generateMipmaps()
glGenerateMipmap(gltextype);
}
void Canvas::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase */*imgd*/)
{
OpenGL::TempDebugGroup debuggroup("Texture data upload");
gl.bindTextureToUnit(this, 0, false);
OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(pixelformat, false, sRGB);
GLenum gltarget = OpenGL::getGLTextureType(texType);
if (texType == TEXTURE_CUBE)
gltarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
if (isPixelFormatCompressed(pixelformat))
{
if (r.x != 0 || r.y != 0)
throw love::Exception("x and y parameters must be 0 for compressed images.");
if (texType == TEXTURE_2D || texType == TEXTURE_CUBE)
glCompressedTexImage2D(gltarget, level, fmt.internalformat, r.w, r.h, 0, size, data);
else if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME)
glCompressedTexSubImage3D(gltarget, level, 0, 0, slice, r.w, r.h, 1, fmt.internalformat, size, data);
}
else
{
if (texType == TEXTURE_2D || texType == TEXTURE_CUBE)
glTexSubImage2D(gltarget, level, r.x, r.y, r.w, r.h, fmt.externalformat, fmt.type, data);
else if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME)
glTexSubImage3D(gltarget, level, r.x, r.y, slice, r.w, r.h, 1, fmt.externalformat, fmt.type, data);
}
}
} // opengl
} // graphics
} // love
+2
View File
@@ -70,6 +70,8 @@ public:
private:
void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) override;
GLuint fbo;
GLuint texture;
-8
View File
@@ -108,13 +108,6 @@ int w_Canvas_newImageData(lua_State *L)
return 1;
}
int w_Canvas_generateMipmaps(lua_State *L)
{
Canvas *c = luax_checkcanvas(L, 1);
luax_catchexcept(L, [&]() { c->generateMipmaps(); });
return 0;
}
int w_Canvas_getMipmapMode(lua_State *L)
{
Canvas *c = luax_checkcanvas(L, 1);
@@ -130,7 +123,6 @@ static const luaL_Reg w_Canvas_functions[] =
{
{ "renderTo", w_Canvas_renderTo },
{ "newImageData", w_Canvas_newImageData },
{ "generateMipmaps", w_Canvas_generateMipmaps },
{ "getMipmapMode", w_Canvas_getMipmapMode },
{ 0, 0 }
};
-30
View File
@@ -31,38 +31,8 @@ Image *luax_checkimage(lua_State *L, int idx)
return luax_checktype<Image>(L, idx);
}
int w_Image_replacePixels(lua_State *L)
{
Image *i = luax_checkimage(L, 1);
love::image::ImageData *id = luax_checktype<love::image::ImageData>(L, 2);
int slice = 0;
int mipmap = 0;
int x = 0;
int y = 0;
bool reloadmipmaps = false; // TODO i->getMipmapsSource() == Texture::MIPMAPS_SOURCE_GENERATED;
if (i->getTextureType() != TEXTURE_2D)
slice = (int) luaL_checkinteger(L, 3) - 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);
}
luax_catchexcept(L, [&](){ i->replacePixels(id, slice, mipmap, x, y, reloadmipmaps); });
return 0;
}
static const luaL_Reg w_Image_functions[] =
{
{ "replacePixels", w_Image_replacePixels },
{ 0, 0 }
};
+1 -8
View File
@@ -552,14 +552,7 @@ int w_Mesh_getTexture(lua_State *L)
if (tex == nullptr)
return 0;
// FIXME: big hack right here.
if (dynamic_cast<Image *>(tex) != nullptr)
luax_pushtype(L, Image::type, tex);
else if (dynamic_cast<Canvas *>(tex) != nullptr)
luax_pushtype(L, Canvas::type, tex);
else
return luaL_error(L, "Unable to determine texture type.");
luax_pushtype(L, tex);
return 1;
}
+1 -10
View File
@@ -62,16 +62,7 @@ int w_ParticleSystem_setTexture(lua_State *L)
int w_ParticleSystem_getTexture(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
Texture *tex = t->getTexture();
// FIXME: big hack right here.
if (dynamic_cast<Image *>(tex) != nullptr)
luax_pushtype(L, Image::type, tex);
else if (dynamic_cast<Canvas *>(tex) != nullptr)
luax_pushtype(L, Canvas::type, tex);
else
return luaL_error(L, "Unable to determine texture type.");
luax_pushtype(L, t->getTexture());
return 1;
}
+1 -10
View File
@@ -153,16 +153,7 @@ int w_SpriteBatch_setTexture(lua_State *L)
int w_SpriteBatch_getTexture(lua_State *L)
{
SpriteBatch *t = luax_checkspritebatch(L, 1);
Texture *tex = t->getTexture();
// FIXME: big hack right here.
if (dynamic_cast<Image *>(tex) != nullptr)
luax_pushtype(L, Image::type, tex);
else if (dynamic_cast<Canvas *>(tex) != nullptr)
luax_pushtype(L, Canvas::type, tex);
else
return luaL_error(L, "Unable to determine texture type.");
luax_pushtype(L, t->getTexture());
return 1;
}
+38
View File
@@ -322,6 +322,42 @@ int w_Texture_getDepthSampleMode(lua_State *L)
return 1;
}
int w_Texture_generateMipmaps(lua_State *L)
{
Texture *t = luax_checktexture(L, 1);
luax_catchexcept(L, [&]() { t->generateMipmaps(); });
return 0;
}
int w_Texture_replacePixels(lua_State *L)
{
Texture *t = luax_checktexture(L, 1);
love::image::ImageData *id = luax_checktype<love::image::ImageData>(L, 2);
int slice = 0;
int mipmap = 0;
int x = 0;
int y = 0;
bool reloadmipmaps = false; // TODO i->getMipmapsSource() == Texture::MIPMAPS_SOURCE_GENERATED;
if (t->getTextureType() != TEXTURE_2D)
slice = (int) luaL_checkinteger(L, 3) - 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);
}
luax_catchexcept(L, [&](){ t->replacePixels(id, slice, mipmap, x, y, reloadmipmaps); });
return 0;
}
const luaL_Reg w_Texture_functions[] =
{
{ "getTextureType", w_Texture_getTextureType },
@@ -348,6 +384,8 @@ const luaL_Reg w_Texture_functions[] =
{ "isReadable", w_Texture_isReadable },
{ "getDepthSampleMode", w_Texture_getDepthSampleMode },
{ "setDepthSampleMode", w_Texture_setDepthSampleMode },
{ "generateMipmaps", w_Texture_generateMipmaps },
{ "replacePixels", w_Texture_replacePixels },
{ 0, 0 }
};