|
@@ -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);
|