1313#include " scenemousearea.h"
1414#include " bitmapskin.h"
1515#include " svgskin.h"
16+ #include " cputexturemanager.h"
1617
1718using namespace scratchcpprender ;
1819using namespace libscratchcpp ;
@@ -41,6 +42,7 @@ void RenderedTarget::updateVisibility(bool visible)
4142
4243 setVisible (visible);
4344 calculatePos ();
45+ m_convexHullDirty = true ;
4446}
4547
4648void RenderedTarget::updateX (double x)
@@ -212,6 +214,7 @@ void RenderedTarget::setEngine(IEngine *newEngine)
212214 m_skin = nullptr ;
213215 m_texture = Texture ();
214216 m_oldTexture = Texture ();
217+ m_convexHullDirty = true ;
215218 clearGraphicEffects ();
216219 m_hullPoints.clear ();
217220
@@ -256,9 +259,12 @@ void RenderedTarget::setSpriteModel(SpriteModel *newSpriteModel)
256259 SpriteModel *cloneRoot = m_spriteModel->cloneRoot ();
257260
258261 if (cloneRoot) {
259- // Inherit skins from the clone root
262+ // Inherit skins, texture mananger, convex hull points, etc. from the clone root
260263 RenderedTarget *target = dynamic_cast <RenderedTarget *>(cloneRoot->renderedTarget ());
261264 Q_ASSERT (target);
265+ m_textureManager = target->m_textureManager ;
266+ m_convexHullDirty = target->m_convexHullDirty ;
267+ m_hullPoints = target->m_hullPoints ;
262268
263269 if (target->costumesLoaded ()) {
264270 m_skins = target->m_skins ; // TODO: Avoid copying - maybe using a pointer?
@@ -365,7 +371,9 @@ Rect RenderedTarget::getBounds() const
365371 double right = -std::numeric_limits<double >::infinity ();
366372 double bottom = std::numeric_limits<double >::infinity ();
367373
368- for (const QPointF &point : m_hullPoints) {
374+ const std::vector<QPoint> &points = hullPoints ();
375+
376+ for (const QPointF &point : points) {
369377 QPointF transformed = transformPoint (point.x () - width / 2 , height / 2 - point.y (), originX, originY, rot);
370378 const double x = transformed.x () * scale () / m_stageScale * (m_mirrorHorizontally ? -1 : 1 );
371379 const double y = transformed.y () * scale () / m_stageScale;
@@ -516,67 +524,24 @@ void RenderedTarget::setGraphicEffect(ShaderManager::Effect effect, double value
516524
517525 if (changed)
518526 update ();
527+
528+ // TODO: Set m_convexHullDirty to true if the effect changes shape
519529}
520530
521531void RenderedTarget::clearGraphicEffects ()
522532{
523533 if (!m_graphicEffects.empty ())
524534 update ();
525535
536+ // TODO: Set m_convexHullDirty to true if any of the previous effects changed shape
526537 m_graphicEffects.clear ();
527538}
528539
529- void RenderedTarget::updateHullPoints (QOpenGLFramebufferObject *fbo)
540+ const std::vector<QPoint> & RenderedTarget::hullPoints () const
530541{
531- Q_ASSERT (fbo);
532-
533- if (!m_glF) {
534- m_glF = std::make_unique<QOpenGLFunctions>();
535- m_glF->initializeOpenGLFunctions ();
536- }
537-
538- int width = fbo->width ();
539- int height = fbo->height ();
540- m_hullPoints.clear ();
541- m_hullPoints.reserve (width * height);
542-
543- // Read pixels from framebuffer
544- size_t size = width * height * 4 ;
545- GLubyte *pixelData = new GLubyte[size];
546- m_glF->glReadPixels (0 , 0 , width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixelData);
547-
548- // Flip vertically
549- int rowSize = width * 4 ;
550- GLubyte *tempRow = new GLubyte[rowSize];
551-
552- for (size_t i = 0 ; i < height / 2 ; ++i) {
553- size_t topRowIndex = i * rowSize;
554- size_t bottomRowIndex = (height - 1 - i) * rowSize;
555-
556- // Swap rows
557- memcpy (tempRow, &pixelData[topRowIndex], rowSize);
558- memcpy (&pixelData[topRowIndex], &pixelData[bottomRowIndex], rowSize);
559- memcpy (&pixelData[bottomRowIndex], tempRow, rowSize);
560- }
561-
562- delete[] tempRow;
563-
564- // Fill hull points vector
565- for (int y = 0 ; y < height; y++) {
566- for (int x = 0 ; x < width; x++) {
567- int index = (y * width + x) * 4 ; // RGBA channels
568-
569- // Check alpha channel
570- if (pixelData[index + 3 ] > 0 )
571- m_hullPoints.push_back (QPointF (x, y));
572- }
573- }
574-
575- delete[] pixelData;
576- }
542+ if (convexHullPointsNeeded ())
543+ const_cast <RenderedTarget *>(this )->updateHullPoints ();
577544
578- const std::vector<QPointF> &RenderedTarget::hullPoints () const
579- {
580545 return m_hullPoints;
581546}
582547
@@ -588,12 +553,12 @@ bool RenderedTarget::contains(const QPointF &point) const
588553 if (!boundingRect ().contains (point))
589554 return false ;
590555
556+ const std::vector<QPoint> &points = hullPoints ();
557+
591558 QPoint intPoint = point.toPoint ();
592- auto it = std::lower_bound (m_hullPoints.begin (), m_hullPoints.end (), intPoint, [](const QPointF &lhs, const QPointF &rhs) {
593- return (lhs.y () < rhs.y ()) || (lhs.y () == rhs.y () && lhs.x () < rhs.x ());
594- });
559+ auto it = std::lower_bound (points.begin (), points.end (), intPoint, [](const QPointF &lhs, const QPointF &rhs) { return (lhs.y () < rhs.y ()) || (lhs.y () == rhs.y () && lhs.x () < rhs.x ()); });
595560
596- if (it == m_hullPoints .end ()) {
561+ if (it == points .end ()) {
597562 // The point is beyond the last point in the convex hull
598563 return false ;
599564 }
@@ -659,10 +624,15 @@ void RenderedTarget::calculateRotation()
659624void RenderedTarget::calculateSize ()
660625{
661626 if (m_skin && m_costume) {
627+ GLuint oldTexture = m_texture.handle ();
628+ bool wasValid = m_texture.isValid ();
662629 m_texture = m_skin->getTexture (m_size * m_stageScale);
663630 m_width = m_texture.width ();
664631 m_height = m_texture.height ();
665632 setScale (m_size * m_stageScale / m_skin->getTextureScale (m_texture) / m_costume->bitmapResolution ());
633+
634+ if (wasValid && m_texture.handle () != oldTexture)
635+ m_convexHullDirty = true ;
666636 }
667637}
668638
@@ -679,6 +649,24 @@ void RenderedTarget::handleSceneMouseMove(qreal x, qreal y)
679649 }
680650}
681651
652+ bool RenderedTarget::convexHullPointsNeeded () const
653+ {
654+ return m_convexHullDirty || m_hullPoints.empty ();
655+ }
656+
657+ void RenderedTarget::updateHullPoints ()
658+ {
659+ m_convexHullDirty = false ;
660+
661+ if (!isVisible ()) {
662+ m_hullPoints.clear ();
663+ return ;
664+ }
665+
666+ m_hullPoints = textureManager ()->getTextureConvexHullPoints (m_texture);
667+ // TODO: Apply graphic effects (#117)
668+ }
669+
682670QPointF RenderedTarget::transformPoint (double scratchX, double scratchY, double originX, double originY, double rot) const
683671{
684672 const double cosRot = std::cos (rot);
@@ -688,6 +676,14 @@ QPointF RenderedTarget::transformPoint(double scratchX, double scratchY, double
688676 return QPointF (x, y);
689677}
690678
679+ CpuTextureManager *RenderedTarget::textureManager ()
680+ {
681+ if (!m_textureManager)
682+ m_textureManager = std::make_shared<CpuTextureManager>();
683+
684+ return m_textureManager.get ();
685+ }
686+
691687bool RenderedTarget::mirrorHorizontally () const
692688{
693689 return m_mirrorHorizontally;
0 commit comments