Browse Source

Move replacePixels from Image to Texture

Alex Szpakowski 5 years ago
parent
commit
4716211c14

+ 0 - 65
src/modules/graphics/Image.cpp

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

+ 0 - 10
src/modules/graphics/Image.h

@@ -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 - 0
src/modules/graphics/Texture.cpp

@@ -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
src/modules/graphics/Texture.h

@@ -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 - 0
src/modules/graphics/opengl/Canvas.cpp

@@ -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 - 0
src/modules/graphics/opengl/Canvas.h

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

+ 0 - 8
src/modules/graphics/wrap_Canvas.cpp

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

+ 0 - 30
src/modules/graphics/wrap_Image.cpp

@@ -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
src/modules/graphics/wrap_Mesh.cpp

@@ -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
src/modules/graphics/wrap_ParticleSystem.cpp

@@ -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
src/modules/graphics/wrap_SpriteBatch.cpp

@@ -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 - 0
src/modules/graphics/wrap_Texture.cpp

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