44
55#include " penlayer.h"
66#include " penlayerpainter.h"
7- #include " penattributes.h"
87#include " irenderedtarget.h"
98#include " spritemodel.h"
109#include " stagemodel.h"
1110
1211using namespace scratchcpprender ;
1312
1413static const double pi = std::acos(-1 ); // TODO: Use std::numbers::pi in C++20
14+ static const int PEN_LINES_RESERVE = 10240 ;
1515
1616std::unordered_map<libscratchcpp::IEngine *, IPenLayer *> PenLayer::m_projectPenLayers;
1717
1818PenLayer::PenLayer (QNanoQuickItem *parent) :
1919 IPenLayer(parent)
2020{
2121 setSmooth (false );
22+
23+ // Reserve space for pen lines
24+ m_penLines.reserve (PEN_LINES_RESERVE);
25+
26+ for (int i = 0 ; i < PEN_LINES_RESERVE; i++) {
27+ m_penLines.push_back (PenLine ());
28+ }
2229}
2330
2431PenLayer::~PenLayer ()
@@ -119,14 +126,34 @@ void PenLayer::setEngine(libscratchcpp::IEngine *newEngine)
119126void PenLayer::beginFrame ()
120127{
121128 m_fbo->bind ();
122- beginPainterFrame ();
123- m_frameChanged = false ;
129+ m_glF->glDisable (GL_SCISSOR_TEST);
130+ m_glF->glDisable (GL_DEPTH_TEST);
131+
132+ m_glF->glBindBuffer (GL_ARRAY_BUFFER, m_vbo);
133+ m_glF->glBindVertexArray (m_vao);
134+
135+ m_penLineAdded = false ;
136+ m_stampAdded = false ;
124137}
125138
126139void PenLayer::endFrame ()
127140{
141+ m_glF->glBindVertexArray (0 );
142+ m_glF->glBindBuffer (GL_ARRAY_BUFFER, 0 );
143+
144+ beginPainterFrame ();
145+ renderLines ();
128146 endPainterFrame ();
147+
129148 m_fbo->release ();
149+ m_glF->glEnable (GL_SCISSOR_TEST);
150+ m_glF->glEnable (GL_DEPTH_TEST);
151+
152+ if (m_penLineAdded || m_stampAdded) {
153+ update ();
154+ m_penLineAdded = false ;
155+ m_stampAdded = false ;
156+ }
130157}
131158
132159bool PenLayer::hqPen () const
@@ -151,16 +178,12 @@ void scratchcpprender::PenLayer::clear()
151178
152179 Q_ASSERT (m_fbo->isBound ());
153180
154- if (m_frameChanged) {
155- endPainterFrame ();
156- beginPainterFrame ();
157- m_frameChanged = false ;
158- }
181+ m_penLineCount = 0 ;
182+ m_penLineAdded = false ;
183+ m_stampAdded = false ;
159184
160- m_glF->glDisable (GL_SCISSOR_TEST);
161185 m_glF->glClearColor (0 .0f , 0 .0f , 0 .0f , 0 .0f );
162186 m_glF->glClear (GL_COLOR_BUFFER_BIT);
163- m_glF->glEnable (GL_SCISSOR_TEST);
164187
165188 m_textureDirty = true ;
166189 m_boundsDirty = true ;
@@ -193,33 +216,25 @@ void scratchcpprender::PenLayer::drawLine(const PenAttributes &penAttributes, do
193216 x1 += stageWidthHalf;
194217 y1 = stageHeightHalf - y1;
195218
196- // Set pen attributes
197- const double diameter = penAttributes.diameter * m_scale;
198- m_painter->setLineWidth (diameter);
199- m_painter->setStrokeStyle (penAttributes.color );
200- m_painter->setFillStyle (penAttributes.color );
201- m_painter->setLineJoin (QNanoPainter::JOIN_ROUND);
202- m_painter->setLineCap (QNanoPainter::CAP_ROUND);
203- m_painter->setAntialias (m_antialiasingEnabled ? 1 .0f : 0 .0f );
204- m_painter->beginPath ();
205-
206- // Width 1 and 3 lines need to be offset by 0.5
207- const double offset = (std::fmod (std::max (4 - diameter, 0.0 ), 2 )) / 2 ;
219+ // Render the line later
220+ if (m_penLineCount == m_penLines.size ()) {
221+ m_penLines.reserve (m_penLineCount * 2 );
208222
209- // If the start and end coordinates are the same, draw a point, otherwise draw a line
210- if (x0 == x1 && y0 == y1) {
211- m_painter->circle (x0 + offset, y0 + offset, diameter / 2 );
212- m_painter->fill ();
213- } else {
214- m_painter->moveTo (x0 + offset, y0 + offset);
215- m_painter->lineTo (x1 + offset, y1 + offset);
216- m_painter->stroke ();
223+ for (size_t i = m_penLineCount; i < m_penLineCount * 2 ; i++) {
224+ m_penLines.push_back (PenLine ());
225+ }
217226 }
218227
228+ PenLine &line = m_penLines[m_penLineCount++];
229+ line.x0 = x0;
230+ line.y0 = y0;
231+ line.x1 = x1;
232+ line.y1 = y1;
233+ line.attributes = penAttributes;
234+
219235 m_textureDirty = true ;
220236 m_boundsDirty = true ;
221- m_frameChanged = true ;
222- update ();
237+ m_penLineAdded = true ;
223238}
224239
225240void PenLayer::stamp (IRenderedTarget *target)
@@ -229,31 +244,24 @@ void PenLayer::stamp(IRenderedTarget *target)
229244
230245 Q_ASSERT (m_fbo->isBound ());
231246
232- if (m_frameChanged)
233- endPainterFrame ();
247+ if (m_penLineAdded) {
248+ m_glF->glBindVertexArray (0 );
249+ m_glF->glBindBuffer (GL_ARRAY_BUFFER, 0 );
234250
235- m_glF->glDisable (GL_SCISSOR_TEST);
236- m_glF->glDisable (GL_DEPTH_TEST);
251+ beginPainterFrame ();
252+ renderLines ();
253+ endPainterFrame ();
254+ m_penLineAdded = false ;
237255
238- m_glF->glBindBuffer (GL_ARRAY_BUFFER, m_vbo);
239- m_glF->glBindVertexArray (m_vao);
256+ m_glF->glBindBuffer (GL_ARRAY_BUFFER, m_vbo);
257+ m_glF->glBindVertexArray (m_vao);
258+ }
240259
241260 target->render (m_scale);
242261
243- m_glF->glBindVertexArray (0 );
244- m_glF->glBindBuffer (GL_ARRAY_BUFFER, 0 );
245-
246- m_glF->glEnable (GL_SCISSOR_TEST);
247- m_glF->glEnable (GL_DEPTH_TEST);
248-
249- if (m_frameChanged) {
250- beginPainterFrame ();
251- m_frameChanged = false ;
252- }
253-
254262 m_textureDirty = true ;
255263 m_boundsDirty = true ;
256- update () ;
264+ m_stampAdded = true ;
257265}
258266
259267void PenLayer::refresh ()
@@ -451,3 +459,38 @@ void PenLayer::updateTexture()
451459 m_textureDirty = false ;
452460 m_textureManager.removeTexture (m_texture);
453461}
462+
463+ void PenLayer::renderLines ()
464+ {
465+ for (size_t i = 0 ; i < m_penLineCount; i++) {
466+ renderLine (m_penLines[i]);
467+ }
468+
469+ m_penLineCount = 0 ;
470+ }
471+
472+ void PenLayer::renderLine (const PenLine &line)
473+ {
474+ // Set pen attributes
475+ const double diameter = line.attributes .diameter * m_scale;
476+ m_painter->setLineWidth (diameter);
477+ m_painter->setStrokeStyle (line.attributes .color );
478+ m_painter->setFillStyle (line.attributes .color );
479+ m_painter->setLineJoin (QNanoPainter::JOIN_ROUND);
480+ m_painter->setLineCap (QNanoPainter::CAP_ROUND);
481+ m_painter->setAntialias (m_antialiasingEnabled ? 1 .0f : 0 .0f );
482+ m_painter->beginPath ();
483+
484+ // Width 1 and 3 lines need to be offset by 0.5
485+ const double offset = (std::fmod (std::max (4 - diameter, 0.0 ), 2 )) / 2 ;
486+
487+ // If the start and end coordinates are the same, draw a point, otherwise draw a line
488+ if (line.x0 == line.x1 && line.y0 == line.y1 ) {
489+ m_painter->circle (line.x0 + offset, line.y0 + offset, diameter / 2 );
490+ m_painter->fill ();
491+ } else {
492+ m_painter->moveTo (line.x0 + offset, line.y0 + offset);
493+ m_painter->lineTo (line.x1 + offset, line.y1 + offset);
494+ m_painter->stroke ();
495+ }
496+ }
0 commit comments