@@ -76,6 +76,8 @@ void scratchcpprender::PenLayer::clear()
76
76
m_glF->glEnable (GL_SCISSOR_TEST);
77
77
m_fbo->release ();
78
78
79
+ m_textureDirty = true ;
80
+ m_boundsDirty = true ;
79
81
update ();
80
82
}
81
83
@@ -121,6 +123,8 @@ void scratchcpprender::PenLayer::drawLine(const PenAttributes &penAttributes, do
121
123
painter.end ();
122
124
m_fbo->release ();
123
125
126
+ m_textureDirty = true ;
127
+ m_boundsDirty = true ;
124
128
update ();
125
129
}
126
130
@@ -129,6 +133,84 @@ QOpenGLFramebufferObject *PenLayer::framebufferObject() const
129
133
return m_fbo.get ();
130
134
}
131
135
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
+
132
214
IPenLayer *PenLayer::getProjectPenLayer (libscratchcpp::IEngine *engine)
133
215
{
134
216
auto it = m_projectPenLayers.find (engine);
@@ -148,3 +230,21 @@ QNanoQuickItemPainter *PenLayer::createItemPainter() const
148
230
{
149
231
return new PenLayerPainter;
150
232
}
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