Skip to content

Commit 4fff9c9

Browse files
committed
Add SVG support
1 parent 5655f81 commit 4fff9c9

File tree

10 files changed

+264
-14
lines changed

10 files changed

+264
-14
lines changed

ScratchCPPGui/irenderedtarget.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <qnanoquickitem.h>
66

77
class QBuffer;
8+
class QNanoPainter;
89

910
namespace libscratchcpp
1011
{
@@ -59,6 +60,9 @@ class IRenderedTarget : public QNanoQuickItem
5960
virtual void unlockCostume() = 0;
6061

6162
virtual bool mirrorHorizontally() const = 0;
63+
64+
virtual bool isSvg() const = 0;
65+
virtual void paintSvg(QNanoPainter *painter) = 0;
6266
};
6367

6468
} // namespace scratchcppgui

ScratchCPPGui/renderedtarget.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#include <scratchcpp/iengine.h>
44
#include <scratchcpp/costume.h>
5+
#include <QtSvg/QSvgRenderer>
6+
#include <qnanopainter.h>
57

68
#include "renderedtarget.h"
79
#include "targetpainter.h"
@@ -80,6 +82,8 @@ void RenderedTarget::loadCostume(Costume *costume)
8082
m_imageChanged = true;
8183

8284
if (costume->dataFormat() == "svg") {
85+
if (costume != m_costume)
86+
m_svgRenderer.load(QByteArray::fromRawData(static_cast<const char *>(costume->data()), costume->dataSize()));
8387
}
8488

8589
m_costume = costume;
@@ -202,6 +206,8 @@ void RenderedTarget::doLoadCostume()
202206
Target *target = scratchTarget();
203207

204208
if (m_costume->dataFormat() == "svg") {
209+
QRectF rect = m_svgRenderer.viewBoxF();
210+
calculateSize(target, rect.width(), rect.height());
205211
} else {
206212
m_bitmapBuffer.open(QBuffer::WriteOnly);
207213
m_bitmapBuffer.write(static_cast<const char *>(m_costume->data()), m_costume->dataSize());
@@ -217,6 +223,41 @@ void RenderedTarget::doLoadCostume()
217223
m_costumeMutex.unlock();
218224
}
219225

226+
void RenderedTarget::paintSvg(QNanoPainter *painter)
227+
{
228+
Q_ASSERT(painter);
229+
QOpenGLContext *context = QOpenGLContext::currentContext();
230+
Q_ASSERT(context);
231+
232+
if (!context)
233+
return;
234+
235+
QOffscreenSurface surface;
236+
surface.setFormat(context->format());
237+
surface.create();
238+
Q_ASSERT(surface.isValid());
239+
240+
QSurface *oldSurface = context->surface();
241+
context->makeCurrent(&surface);
242+
243+
const QRectF drawRect(0, 0, width(), height());
244+
const QSize drawRectSize = drawRect.size().toSize();
245+
246+
/*QOpenGLFramebufferObjectFormat fboFormat;
247+
fboFormat.setSamples(16);
248+
fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);*/
249+
250+
QOpenGLPaintDevice device(drawRectSize);
251+
QPainter qPainter;
252+
qPainter.begin(&device);
253+
qPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
254+
m_svgRenderer.render(&qPainter, drawRect);
255+
qPainter.end();
256+
257+
context->doneCurrent();
258+
context->makeCurrent(oldSurface);
259+
}
260+
220261
void RenderedTarget::calculateSize(Target *target, double costumeWidth, double costumeHeight)
221262
{
222263
if (m_costume) {
@@ -258,3 +299,11 @@ bool RenderedTarget::mirrorHorizontally() const
258299
{
259300
return m_mirrorHorizontally;
260301
}
302+
303+
bool RenderedTarget::isSvg() const
304+
{
305+
if (!m_costume)
306+
return false;
307+
308+
return (m_costume->dataFormat() == "svg");
309+
}

ScratchCPPGui/renderedtarget.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <qnanoquickitem.h>
66
#include <QBuffer>
77
#include <QMutex>
8+
#include <QtSvg/QSvgRenderer>
89

910
#include "irenderedtarget.h"
1011

@@ -55,6 +56,9 @@ class RenderedTarget : public IRenderedTarget
5556

5657
bool mirrorHorizontally() const override;
5758

59+
bool isSvg() const override;
60+
void paintSvg(QNanoPainter *painter) override;
61+
5862
signals:
5963
void engineChanged();
6064
void stageModelChanged();
@@ -73,6 +77,7 @@ class RenderedTarget : public IRenderedTarget
7377
libscratchcpp::Costume *m_costume = nullptr;
7478
StageModel *m_stageModel = nullptr;
7579
SpriteModel *m_spriteModel = nullptr;
80+
QSvgRenderer m_svgRenderer;
7681
QBuffer m_bitmapBuffer;
7782
QString m_bitmapUniqueKey;
7883
QMutex m_costumeMutex;

ScratchCPPGui/targetpainter.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@ void TargetPainter::paint(QNanoPainter *painter)
2323
double width = m_target->width();
2424
double height = m_target->height();
2525

26-
QNanoImage image = QNanoImage::fromCache(painter, m_target->bitmapBuffer(), m_target->bitmapUniqueKey());
27-
painter->drawImage(image, 0, 0, width, height);
26+
if (m_target->isSvg())
27+
m_target->paintSvg(painter);
28+
else {
29+
QNanoImage image = QNanoImage::fromCache(painter, m_target->bitmapBuffer(), m_target->bitmapUniqueKey());
30+
painter->drawImage(image, 0, 0, width, height);
31+
}
2832

2933
m_target->unlockCostume();
3034
}

test/image.svg

Lines changed: 56 additions & 0 deletions
Loading

test/mocks/renderedtargetmock.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ class RenderedTargetMock : public IRenderedTarget
4141

4242
MOCK_METHOD(bool, mirrorHorizontally, (), (const, override));
4343

44+
MOCK_METHOD(bool, isSvg, (), (const, override));
45+
MOCK_METHOD(void, paintSvg, (QNanoPainter *), (override));
46+
4447
MOCK_METHOD(QNanoQuickItemPainter *, createItemPainter, (), (const, override));
4548
};
4649

0 commit comments

Comments
 (0)