diff --git a/src/bitmapskin.cpp b/src/bitmapskin.cpp index d8b1c98..e499f8a 100644 --- a/src/bitmapskin.cpp +++ b/src/bitmapskin.cpp @@ -28,7 +28,7 @@ BitmapSkin::BitmapSkin(libscratchcpp::Costume *costume) : m_image.load(&buffer, format); // Paint the image into a texture - m_texture = createAndPaintTexture(m_image.width(), m_image.height(), false); + m_texture = createAndPaintTexture(m_image.width(), m_image.height()); m_textureSize.setWidth(m_image.width()); m_textureSize.setHeight(m_image.height()); diff --git a/src/skin.cpp b/src/skin.cpp index dd6c150..5429b74 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -9,83 +9,56 @@ using namespace scratchcpprender; Skin::Skin() { + QOpenGLContext *context = QOpenGLContext::currentContext(); + Q_ASSERT(context); + + if (context) { + QObject::connect(context, &QOpenGLContext::aboutToBeDestroyed, &m_signalHandler, [this]() { + // Destroy textures + m_textures.clear(); + }); + } } -Texture Skin::createAndPaintTexture(int width, int height, bool multisampled) +Texture Skin::createAndPaintTexture(int width, int height) { QOpenGLContext *context = QOpenGLContext::currentContext(); if (!context || !context->isValid() || (width <= 0 || height <= 0)) return Texture(); - QOpenGLFunctions glF(context); + QOpenGLExtraFunctions glF(context); glF.initializeOpenGLFunctions(); - // Create offscreen surface - QOffscreenSurface surface; - surface.setFormat(context->format()); - surface.create(); - Q_ASSERT(surface.isValid()); - - // Save old surface - QSurface *oldSurface = context->surface(); - - // Make context active on the surface - context->makeCurrent(&surface); - - const QRectF drawRect(0, 0, width, height); - const QSize drawRectSize = drawRect.size().toSize(); - - // Create multisampled FBO (if the multisampled parameter is set) - QOpenGLFramebufferObjectFormat format; - format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); - - if (multisampled) - format.setSamples(16); + // Render to QImage + QImage image(width, height, QImage::Format_RGBA8888); - QOpenGLFramebufferObject fbo(drawRectSize, format); - fbo.bind(); + // Clear the image to be fully transparent + image.fill(Qt::transparent); - // Create paint device - QOpenGLPaintDevice device(drawRectSize); - QPainter painter(&device); - painter.beginNativePainting(); - painter.setRenderHint(QPainter::Antialiasing, false); - glF.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glF.glClear(GL_COLOR_BUFFER_BIT); - - // Call the skin-specific paint method - paint(&painter); - - // Done with the painting - painter.endNativePainting(); + QPainter painter(&image); + paint(&painter); // Custom paint function painter.end(); - fbo.release(); - - GLuint textureHandle; - - if (multisampled) { - // Create non-multisampled FBO (we can't take the texture from the multisampled FBO) - format.setSamples(0); - - QOpenGLFramebufferObject targetFbo(drawRectSize, format); - targetFbo.bind(); - - // Blit the multisampled FBO to target FBO - QOpenGLFramebufferObject::blitFramebuffer(&targetFbo, &fbo); - - // Take the texture (will call targetFbo.release()) - textureHandle = targetFbo.takeTexture(); - } else { - // Take the texture - textureHandle = fbo.takeTexture(); + image.mirror(); + + // Premultiply alpha + for (int y = 0; y < image.height(); ++y) { + QRgb *line = reinterpret_cast(image.scanLine(y)); + for (int x = 0; x < image.width(); ++x) { + QColor color = QColor::fromRgba(line[x]); + color.setRedF(color.redF() * color.alphaF()); + color.setGreenF(color.greenF() * color.alphaF()); + color.setBlueF(color.blueF() * color.alphaF()); + line[x] = color.rgba(); + } } - // Restore old surface - context->doneCurrent(); - - if (oldSurface) - context->makeCurrent(oldSurface); + // Create final texture from the image + auto texture = std::make_shared(image); + m_textures.push_back(texture); + texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); + texture->setMagnificationFilter(QOpenGLTexture::Linear); - return Texture(textureHandle, drawRectSize); + // Texture(texture, width, height).toImage().save("/home/adazem009/test.png"); + return Texture(texture->textureId(), width, height); } diff --git a/src/skin.h b/src/skin.h index 1bfc147..855ef65 100644 --- a/src/skin.h +++ b/src/skin.h @@ -22,8 +22,12 @@ class Skin virtual double getTextureScale(const Texture &texture) const = 0; protected: - Texture createAndPaintTexture(int width, int height, bool multisampled); + Texture createAndPaintTexture(int width, int height); virtual void paint(QPainter *painter) = 0; + + private: + std::vector> m_textures; + QObject m_signalHandler; // for disconnecting signals after destroyed }; } // namespace scratchcpprender diff --git a/src/svgskin.cpp b/src/svgskin.cpp index 1119bf1..d2c35a6 100644 --- a/src/svgskin.cpp +++ b/src/svgskin.cpp @@ -9,9 +9,8 @@ using namespace scratchcpprender; static const int MAX_TEXTURE_DIMENSION = 2048; static const int INDEX_OFFSET = 8; -SVGSkin::SVGSkin(libscratchcpp::Costume *costume, bool antialiasing) : - Skin(), - m_antialiasing(antialiasing) +SVGSkin::SVGSkin(libscratchcpp::Costume *costume) : + Skin() { if (!costume) return; @@ -86,7 +85,7 @@ Texture SVGSkin::createScaledTexture(int index) return Texture(); } - const Texture texture = createAndPaintTexture(viewBox.width() * scale, viewBox.height() * scale, m_antialiasing); + const Texture texture = createAndPaintTexture(viewBox.width() * scale, viewBox.height() * scale); if (texture.isValid()) { m_textures[index] = texture.handle(); diff --git a/src/svgskin.h b/src/svgskin.h index 5352827..f722e63 100644 --- a/src/svgskin.h +++ b/src/svgskin.h @@ -20,7 +20,7 @@ namespace scratchcpprender class SVGSkin : public Skin { public: - SVGSkin(libscratchcpp::Costume *costume, bool antialiasing = true); + SVGSkin(libscratchcpp::Costume *costume); ~SVGSkin(); Texture getTexture(double scale) const override; @@ -37,7 +37,6 @@ class SVGSkin : public Skin std::unordered_map m_textureObjects; QSvgRenderer m_svgRen; int m_maxIndex = 0; - bool m_antialiasing = false; }; } // namespace scratchcpprender diff --git a/test/skins/bitmapskin_test.cpp b/test/skins/bitmapskin_test.cpp index ab6eb17..48c28d1 100644 --- a/test/skins/bitmapskin_test.cpp +++ b/test/skins/bitmapskin_test.cpp @@ -33,6 +33,8 @@ class BitmapSkinTest : public testing::Test void TearDown() override { ASSERT_EQ(m_context.surface(), &m_surface); + m_jpegSkin.reset(); + m_pngSkin.reset(); m_context.doneCurrent(); } diff --git a/test/skins/svgskin_test.cpp b/test/skins/svgskin_test.cpp index d028d38..7d68832 100644 --- a/test/skins/svgskin_test.cpp +++ b/test/skins/svgskin_test.cpp @@ -22,12 +22,13 @@ class SVGSkinTest : public testing::Test Costume costume("", "", ""); std::string costumeData = readFileStr("image.svg"); costume.setData(costumeData.size(), costumeData.data()); - m_skin = std::make_unique(&costume, false); + m_skin = std::make_unique(&costume); } void TearDown() override { ASSERT_EQ(m_context.surface(), &m_surface); + m_skin.reset(); m_context.doneCurrent(); } @@ -59,10 +60,6 @@ TEST_F(SVGSkinTest, Textures) ASSERT_EQ(m_skin->getTextureScale(texture), scale); } - // Skip images 12, 13 and 15 because they're different on xvfb - if (i == 12 || i == 13 || i >= 15) - continue; - QBuffer buffer; texture.toImage().save(&buffer, "png"); QFile ref("svg_texture_results/" + QString::number(std::min(i, 15)) + ".png"); diff --git a/test/stamp.png b/test/stamp.png index fd5e426..7206580 100644 Binary files a/test/stamp.png and b/test/stamp.png differ diff --git a/test/svg_texture_results/10.png b/test/svg_texture_results/10.png index 01436ab..209737c 100644 Binary files a/test/svg_texture_results/10.png and b/test/svg_texture_results/10.png differ diff --git a/test/svg_texture_results/11.png b/test/svg_texture_results/11.png index 73db02b..5d19737 100644 Binary files a/test/svg_texture_results/11.png and b/test/svg_texture_results/11.png differ diff --git a/test/svg_texture_results/12.png b/test/svg_texture_results/12.png new file mode 100644 index 0000000..3e19546 Binary files /dev/null and b/test/svg_texture_results/12.png differ diff --git a/test/svg_texture_results/13.png b/test/svg_texture_results/13.png new file mode 100644 index 0000000..0a947a3 Binary files /dev/null and b/test/svg_texture_results/13.png differ diff --git a/test/svg_texture_results/14.png b/test/svg_texture_results/14.png index 40bb626..9c2b844 100644 Binary files a/test/svg_texture_results/14.png and b/test/svg_texture_results/14.png differ diff --git a/test/svg_texture_results/15.png b/test/svg_texture_results/15.png new file mode 100644 index 0000000..6b51219 Binary files /dev/null and b/test/svg_texture_results/15.png differ diff --git a/test/svg_texture_results/5.png b/test/svg_texture_results/5.png index b0c553b..26536be 100644 Binary files a/test/svg_texture_results/5.png and b/test/svg_texture_results/5.png differ diff --git a/test/svg_texture_results/6.png b/test/svg_texture_results/6.png index dddac55..c5856f6 100644 Binary files a/test/svg_texture_results/6.png and b/test/svg_texture_results/6.png differ diff --git a/test/svg_texture_results/7.png b/test/svg_texture_results/7.png index 5c80b87..164330a 100644 Binary files a/test/svg_texture_results/7.png and b/test/svg_texture_results/7.png differ diff --git a/test/svg_texture_results/8.png b/test/svg_texture_results/8.png index bb6c391..bba0608 100644 Binary files a/test/svg_texture_results/8.png and b/test/svg_texture_results/8.png differ diff --git a/test/svg_texture_results/9.png b/test/svg_texture_results/9.png index acc5697..dd8ed6d 100644 Binary files a/test/svg_texture_results/9.png and b/test/svg_texture_results/9.png differ