@@ -76,6 +76,8 @@ void scratchcpprender::PenLayer::clear()
7676 m_glF->glEnable (GL_SCISSOR_TEST);
7777 m_fbo->release ();
7878
79+ m_textureDirty = true ;
80+ m_boundsDirty = true ;
7981 update ();
8082}
8183
@@ -121,6 +123,8 @@ void scratchcpprender::PenLayer::drawLine(const PenAttributes &penAttributes, do
121123 painter.end ();
122124 m_fbo->release ();
123125
126+ m_textureDirty = true ;
127+ m_boundsDirty = true ;
124128 update ();
125129}
126130
@@ -129,6 +133,84 @@ QOpenGLFramebufferObject *PenLayer::framebufferObject() const
129133 return m_fbo.get ();
130134}
131135
136+ QRgb PenLayer::colorAtScratchPoint (double x, double y) const
137+ {
138+ if (m_textureDirty)
139+ const_cast <PenLayer *>(this )->updateTexture ();
140+
141+ if (!m_texture.isValid ())
142+ return qRgba (0 , 0 , 0 , 0 );
143+
144+ const double width = m_texture.width ();
145+ const double height = m_texture.height ();
146+
147+ // Translate the coordinates
148+ // TODO: Apply scale
149+ x = std::floor (x + width / 2.0 );
150+ y = std::floor (-y + height / 2.0 );
151+
152+ // If the point is outside the texture, return fully transparent color
153+ if ((x < 0 || x >= width) || (y < 0 || y >= height))
154+ return qRgba (0 , 0 , 0 , 0 );
155+
156+ GLubyte *data = m_textureManager.getTextureData (m_texture);
157+ const int index = (y * width + x) * 4 ; // RGBA channels
158+ Q_ASSERT (index >= 0 && index < width * height * 4 );
159+ return qRgba (data[index], data[index + 1 ], data[index + 2 ], data[index + 3 ]);
160+ }
161+
162+ const libscratchcpp::Rect &PenLayer::getBounds () const
163+ {
164+ if (m_textureDirty)
165+ const_cast <PenLayer *>(this )->updateTexture ();
166+
167+ if (m_boundsDirty) {
168+ if (!m_texture.isValid ()) {
169+ m_bounds = libscratchcpp::Rect ();
170+ return m_bounds;
171+ }
172+
173+ m_boundsDirty = false ;
174+ double left = std::numeric_limits<double >::infinity ();
175+ double top = -std::numeric_limits<double >::infinity ();
176+ double right = -std::numeric_limits<double >::infinity ();
177+ double bottom = std::numeric_limits<double >::infinity ();
178+ const double width = m_texture.width ();
179+ const double height = m_texture.height ();
180+ const std::vector<QPoint> &points = m_textureManager.getTextureConvexHullPoints (m_texture);
181+
182+ if (points.empty ()) {
183+ m_bounds = libscratchcpp::Rect ();
184+ return m_bounds;
185+ }
186+
187+ for (const QPointF &point : points) {
188+ // TODO: Apply scale
189+ double x = point.x () - width / 2 ;
190+ double y = -point.y () + height / 2 ;
191+
192+ if (x < left)
193+ left = x;
194+
195+ if (x > right)
196+ right = x;
197+
198+ if (y > top)
199+ top = y;
200+
201+ if (y < bottom)
202+ bottom = y;
203+ }
204+
205+ m_bounds.setLeft (left);
206+ m_bounds.setTop (top);
207+ m_bounds.setRight (right + 1 );
208+ m_bounds.setBottom (bottom - 1 );
209+ }
210+
211+ return m_bounds;
212+ }
213+
132214IPenLayer *PenLayer::getProjectPenLayer (libscratchcpp::IEngine *engine)
133215{
134216 auto it = m_projectPenLayers.find (engine);
@@ -148,3 +230,21 @@ QNanoQuickItemPainter *PenLayer::createItemPainter() const
148230{
149231 return new PenLayerPainter;
150232}
233+
234+ void PenLayer::updateTexture ()
235+ {
236+ if (!m_fbo)
237+ return ;
238+
239+ m_textureDirty = false ;
240+ m_textureManager.removeTexture (m_texture);
241+
242+ if (!m_resolvedFbo || m_resolvedFbo->size () != m_fbo->size ()) {
243+ QOpenGLFramebufferObjectFormat format;
244+ format.setAttachment (QOpenGLFramebufferObject::CombinedDepthStencil);
245+ m_resolvedFbo = std::make_unique<QOpenGLFramebufferObject>(m_fbo->size (), format);
246+ }
247+
248+ QOpenGLFramebufferObject::blitFramebuffer (m_resolvedFbo.get (), m_fbo.get ());
249+ m_texture = Texture (m_resolvedFbo->texture (), m_resolvedFbo->size ());
250+ }
0 commit comments