1010#include " stagemodel.h"
1111#include " spritemodel.h"
1212#include " scenemousearea.h"
13+ #include " bitmapskin.h"
14+ #include " svgskin.h"
1315
1416using namespace scratchcpprender ;
1517using namespace libscratchcpp ;
@@ -19,25 +21,12 @@ static const double SVG_SCALE_LIMIT = 0.1; // the maximum viewport dimensions ar
1921RenderedTarget::RenderedTarget (QNanoQuickItem *parent) :
2022 IRenderedTarget(parent)
2123{
22- // Get maximum viewport dimensions
23- QOpenGLContext context;
24- context.create ();
25- Q_ASSERT (context.isValid ());
26-
27- if (context.isValid ()) {
28- QOffscreenSurface surface;
29- surface.create ();
30- Q_ASSERT (surface.isValid ());
31-
32- if (surface.isValid ()) {
33- context.makeCurrent (&surface);
34- GLint dims[2 ];
35- glGetIntegerv (GL_MAX_VIEWPORT_DIMS, dims);
36- m_maximumWidth = dims[0 ] * SVG_SCALE_LIMIT;
37- m_maximumHeight = dims[1 ] * SVG_SCALE_LIMIT;
38- context.doneCurrent ();
39- }
40- }
24+ }
25+
26+ RenderedTarget::~RenderedTarget ()
27+ {
28+ for (const auto &[costume, skin] : m_skins)
29+ delete skin;
4130}
4231
4332void RenderedTarget::updateVisibility (bool visible)
@@ -112,29 +101,13 @@ void RenderedTarget::updateCostume(Costume *costume)
112101 m_costumeMutex.lock ();
113102 m_costume = costume;
114103
115- if (m_costume->dataFormat () == " svg" ) {
116- m_svgRenderer.load (QByteArray::fromRawData (static_cast <const char *>(m_costume->data ()), m_costume->dataSize ()));
117- QRectF rect = m_svgRenderer.viewBoxF ();
118- m_costumeWidth = rect.width ();
119- m_costumeHeight = rect.height ();
120- } else {
121- m_bitmapBuffer.open (QBuffer::WriteOnly);
122- m_bitmapBuffer.write (static_cast <const char *>(m_costume->data ()), m_costume->dataSize ());
123- m_bitmapBuffer.close ();
124- m_bitmapUniqueKey = QString::fromStdString (m_costume->id ());
125- const char *format;
126-
127- {
128- QImageReader reader (&m_bitmapBuffer);
129- format = reader.format ();
130- }
104+ if (m_costumesLoaded) {
105+ auto it = m_skins.find (m_costume);
131106
132- m_bitmapBuffer.close ();
133- m_costumeBitmap.load (&m_bitmapBuffer, format);
134- QSize size = m_costumeBitmap.size ();
135- m_costumeWidth = std::max (0 , size.width ());
136- m_costumeHeight = std::max (0 , size.height ());
137- m_bitmapBuffer.close ();
107+ if (it == m_skins.end ())
108+ m_skin = nullptr ;
109+ else
110+ m_skin = it->second ;
138111 }
139112
140113 m_costumeMutex.unlock ();
@@ -143,10 +116,59 @@ void RenderedTarget::updateCostume(Costume *costume)
143116 calculatePos ();
144117}
145118
119+ bool RenderedTarget::costumesLoaded () const
120+ {
121+ return m_costumesLoaded;
122+ }
123+
124+ void RenderedTarget::loadCostumes ()
125+ {
126+ // Delete previous skins
127+ for (const auto &[costume, skin] : m_skins)
128+ delete skin;
129+
130+ m_skins.clear ();
131+
132+ // Generate a skin for each costume
133+ Target *target = scratchTarget ();
134+
135+ if (!target)
136+ return ;
137+
138+ const auto &costumes = target->costumes ();
139+
140+ for (auto costume : costumes) {
141+ Skin *skin = nullptr ;
142+ if (costume->dataFormat () == " svg" )
143+ skin = new SVGSkin (costume.get ());
144+ else
145+ skin = new BitmapSkin (costume.get ());
146+
147+ if (skin)
148+ m_skins[costume.get ()] = skin;
149+
150+ if (m_costume && costume.get () == m_costume)
151+ m_skin = skin;
152+ }
153+
154+ m_costumesLoaded = true ;
155+
156+ if (m_costume) {
157+ calculateSize ();
158+ calculatePos ();
159+ }
160+ }
161+
146162void RenderedTarget::beforeRedraw ()
147163{
164+ // These properties must be set here to avoid unnecessary calls to update()
148165 setWidth (m_width);
149166 setHeight (m_height);
167+
168+ if (!m_oldTexture.isValid () || (m_texture.isValid () && m_texture != m_oldTexture)) {
169+ m_oldTexture = m_texture;
170+ update ();
171+ }
150172}
151173
152174void RenderedTarget::deinitClone ()
@@ -343,35 +365,9 @@ void RenderedTarget::mouseMoveEvent(QMouseEvent *event)
343365 }
344366}
345367
346- void RenderedTarget::paintSvg (QNanoPainter *painter)
368+ Texture RenderedTarget::texture () const
347369{
348- Q_ASSERT (painter);
349- QOpenGLContext *context = QOpenGLContext::currentContext ();
350- Q_ASSERT (context);
351-
352- if (!context)
353- return ;
354-
355- QOffscreenSurface surface;
356- surface.setFormat (context->format ());
357- surface.create ();
358- Q_ASSERT (surface.isValid ());
359-
360- QSurface *oldSurface = context->surface ();
361- context->makeCurrent (&surface);
362-
363- const QRectF drawRect (0 , 0 , std::min (width (), m_maximumWidth), std::min (height (), m_maximumHeight));
364- const QSize drawRectSize = drawRect.size ().toSize ();
365-
366- QOpenGLPaintDevice device (drawRectSize);
367- QPainter qPainter;
368- qPainter.begin (&device);
369- qPainter.setRenderHints (QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
370- m_svgRenderer.render (&qPainter, drawRect);
371- qPainter.end ();
372-
373- context->doneCurrent ();
374- context->makeCurrent (oldSurface);
370+ return m_texture;
375371}
376372
377373void RenderedTarget::updateHullPoints (QOpenGLFramebufferObject *fbo)
@@ -458,27 +454,24 @@ bool RenderedTarget::contains(const QPointF &point) const
458454
459455void RenderedTarget::calculatePos ()
460456{
461- if (!m_costume || !m_engine)
457+ if (!m_skin || ! m_costume || !m_engine)
462458 return ;
463459
464- if (m_spriteModel) {
465- if (isVisible ()) {
466- double stageWidth = m_engine->stageWidth ();
467- double stageHeight = m_engine->stageHeight ();
468- setX (m_stageScale * (stageWidth / 2 + m_x - m_costume->rotationCenterX () * m_clampedSize / m_costume->bitmapResolution () * (m_mirrorHorizontally ? -1 : 1 )));
469- setY (m_stageScale * (stageHeight / 2 - m_y - m_costume->rotationCenterY () * m_clampedSize / m_costume->bitmapResolution ()));
470- qreal originX = m_costume->rotationCenterX () * m_clampedSize * m_stageScale / m_costume->bitmapResolution ();
471- qreal originY = m_costume->rotationCenterY () * m_clampedSize * m_stageScale / m_costume->bitmapResolution ();
472- setTransformOriginPoint (QPointF (originX, originY));
473- }
474- } else {
460+ if (isVisible () || m_stageModel) {
475461 double stageWidth = m_engine->stageWidth ();
476462 double stageHeight = m_engine->stageHeight ();
477- setX (m_stageScale * (stageWidth / 2 - m_costume->rotationCenterX () / m_costume->bitmapResolution ()));
478- setY (m_stageScale * (stageHeight / 2 - m_costume->rotationCenterY () / m_costume->bitmapResolution ()));
479- qreal originX = m_costume->rotationCenterX () / m_costume->bitmapResolution ();
480- qreal originY = m_costume->rotationCenterY () / m_costume->bitmapResolution ();
463+ setX (m_stageScale * (stageWidth / 2 + m_x - m_costume->rotationCenterX () * m_size / scale () / m_costume->bitmapResolution () * (m_mirrorHorizontally ? - 1 : 1 )));
464+ setY (m_stageScale * (stageHeight / 2 - m_y - m_costume->rotationCenterY () * m_size / scale () / m_costume->bitmapResolution ()));
465+ qreal originX = m_costume->rotationCenterX () * m_stageScale * m_size / scale () / m_costume->bitmapResolution ();
466+ qreal originY = m_costume->rotationCenterY () * m_stageScale * m_size / scale () / m_costume->bitmapResolution ();
481467 setTransformOriginPoint (QPointF (originX, originY));
468+
469+ // Qt ignores the transform origin point if it's (0, 0),
470+ // so set the transform origin to top left in this case.
471+ if (originX == 0 && originY == 0 )
472+ setTransformOrigin (QQuickItem::TopLeft);
473+ else
474+ setTransformOrigin (QQuickItem::Center);
482475 }
483476}
484477
@@ -515,30 +508,13 @@ void RenderedTarget::calculateRotation()
515508
516509void RenderedTarget::calculateSize ()
517510{
518- if (m_costume) {
519- double bitmapRes = m_costume->bitmapResolution ();
520-
521- if (m_costumeWidth == 0 || m_costumeHeight == 0 )
522- m_maxSize = 1 ;
523- else
524- m_maxSize = std::min (m_maximumWidth / (m_costumeWidth * m_stageScale), m_maximumHeight / (m_costumeHeight * m_stageScale));
525-
526- if (m_spriteModel) {
527- m_clampedSize = std::min (m_size, m_maxSize);
528- m_width = m_costumeWidth * m_clampedSize * m_stageScale / bitmapRes;
529- m_height = m_height = m_costumeHeight * m_clampedSize * m_stageScale / bitmapRes;
530- } else {
531- m_width = m_costumeWidth * m_stageScale / bitmapRes;
532- m_height = m_height = m_costumeHeight * m_stageScale / bitmapRes;
533- }
511+ if (m_skin && m_costume) {
512+ Texture texture = m_skin->getTexture (m_size * m_stageScale);
513+ m_texture = texture;
514+ m_width = texture.width ();
515+ m_height = texture.height ();
516+ setScale (m_size * m_stageScale / m_skin->getTextureScale (texture) / m_costume->bitmapResolution ());
534517 }
535-
536- Q_ASSERT (m_maxSize > 0 );
537-
538- if (!m_stageModel && (m_size > m_maxSize) && (m_maxSize != 0 ))
539- setScale (m_size / m_maxSize);
540- else
541- setScale (1 );
542518}
543519
544520void RenderedTarget::handleSceneMouseMove (qreal x, qreal y)
@@ -554,16 +530,6 @@ void RenderedTarget::handleSceneMouseMove(qreal x, qreal y)
554530 }
555531}
556532
557- QBuffer *RenderedTarget::bitmapBuffer ()
558- {
559- return &m_bitmapBuffer;
560- }
561-
562- const QString &RenderedTarget::bitmapUniqueKey () const
563- {
564- return m_bitmapUniqueKey;
565- }
566-
567533void RenderedTarget::lockCostume ()
568534{
569535 m_costumeMutex.lock ();
@@ -578,11 +544,3 @@ bool RenderedTarget::mirrorHorizontally() const
578544{
579545 return m_mirrorHorizontally;
580546}
581-
582- bool RenderedTarget::isSvg () const
583- {
584- if (!m_costume)
585- return false ;
586-
587- return (m_costume->dataFormat () == " svg" );
588- }
0 commit comments