mirror of
https://github.com/love2d/love.git
synced 2026-08-16 00:02:12 +02:00
Move replacePixels from Image to Texture
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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[];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 }
|
||||
};
|
||||
|
||||
@@ -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 }
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user