Skip to content

Commit 93504fb

Browse files
authored
Merge pull request #135 from scratchcpp/hq_pen
Implement HQ pen
2 parents 25c2533 + 985a63b commit 93504fb

8 files changed

+327
-96
lines changed

src/ProjectPlayer.qml

+4-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ ProjectScene {
1616
property alias cloneLimit: loader.cloneLimit
1717
property alias spriteFencing: loader.spriteFencing
1818
property alias mute: loader.mute
19+
property alias hqPen: projectPenLayer.hqPen
1920
property bool showLoadingProgress: true
2021
readonly property bool loading: priv.loading
2122
readonly property int downloadedAssets: loader.downloadedAssets
@@ -141,9 +142,9 @@ ProjectScene {
141142
engine: loader.engine
142143
anchors.top: parent.top
143144
anchors.left: parent.left
144-
width: stageWidth
145-
height: stageHeight
146-
scale: stageScale
145+
width: hqPen ? parent.width : stageWidth
146+
height: hqPen ? parent.height : stageHeight
147+
scale: hqPen ? 1 : stageScale
147148
transformOrigin: Item.TopLeft
148149
visible: !priv.loading
149150
}

src/penlayer.cpp

+70-17
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,7 @@ void PenLayer::setEngine(libscratchcpp::IEngine *newEngine)
5858

5959
if (m_engine && QOpenGLContext::currentContext()) {
6060
m_projectPenLayers[m_engine] = this;
61-
QOpenGLFramebufferObjectFormat fboFormat;
62-
fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
63-
m_fbo = std::make_unique<QOpenGLFramebufferObject>(m_engine->stageWidth(), m_engine->stageHeight(), fboFormat);
64-
Q_ASSERT(m_fbo->isValid());
65-
m_texture = Texture(m_fbo->texture(), m_fbo->size());
61+
createFbo();
6662

6763
if (!m_painter)
6864
m_painter = std::make_unique<QNanoPainter>();
@@ -106,6 +102,21 @@ void PenLayer::setEngine(libscratchcpp::IEngine *newEngine)
106102
emit engineChanged();
107103
}
108104

105+
bool PenLayer::hqPen() const
106+
{
107+
return m_hqPen;
108+
}
109+
110+
void PenLayer::setHqPen(bool newHqPen)
111+
{
112+
if (m_hqPen == newHqPen)
113+
return;
114+
115+
m_hqPen = newHqPen;
116+
createFbo();
117+
emit hqPenChanged();
118+
}
119+
109120
void scratchcpprender::PenLayer::clear()
110121
{
111122
if (!m_fbo)
@@ -138,16 +149,23 @@ void scratchcpprender::PenLayer::drawLine(const PenAttributes &penAttributes, do
138149

139150
m_painter->beginFrame(m_fbo->width(), m_fbo->height());
140151

152+
// Apply scale (HQ pen)
153+
x0 *= m_scale;
154+
y0 *= m_scale;
155+
x1 *= m_scale;
156+
y1 *= m_scale;
157+
141158
// Translate to Scratch coordinate system
142-
double stageWidthHalf = m_engine->stageWidth() / 2;
143-
double stageHeightHalf = m_engine->stageHeight() / 2;
159+
double stageWidthHalf = width() / 2;
160+
double stageHeightHalf = height() / 2;
144161
x0 += stageWidthHalf;
145162
y0 = stageHeightHalf - y0;
146163
x1 += stageWidthHalf;
147164
y1 = stageHeightHalf - y1;
148165

149166
// Set pen attributes
150-
m_painter->setLineWidth(penAttributes.diameter);
167+
const double diameter = penAttributes.diameter * m_scale;
168+
m_painter->setLineWidth(diameter);
151169
m_painter->setStrokeStyle(penAttributes.color);
152170
m_painter->setFillStyle(penAttributes.color);
153171
m_painter->setLineJoin(QNanoPainter::JOIN_ROUND);
@@ -156,11 +174,11 @@ void scratchcpprender::PenLayer::drawLine(const PenAttributes &penAttributes, do
156174
m_painter->beginPath();
157175

158176
// Width 1 and 3 lines need to be offset by 0.5
159-
const double offset = (std::fmod(std::max(4 - penAttributes.diameter, 0.0), 2)) / 2;
177+
const double offset = (std::fmod(std::max(4 - diameter, 0.0), 2)) / 2;
160178

161179
// If the start and end coordinates are the same, draw a point, otherwise draw a line
162180
if (x0 == x1 && y0 == y1) {
163-
m_painter->circle(x0 + offset, y0 + offset, penAttributes.diameter / 2);
181+
m_painter->circle(x0 + offset, y0 + offset, diameter / 2);
164182
m_painter->fill();
165183
} else {
166184
m_painter->moveTo(x0 + offset, y0 + offset);
@@ -223,6 +241,9 @@ void PenLayer::stamp(IRenderedTarget *target)
223241
} else
224242
costume = target->stageModel()->stage()->currentCostume();
225243

244+
// Apply scale (HQ pen)
245+
scale *= m_scale;
246+
226247
const double bitmapRes = costume->bitmapResolution();
227248
const double centerX = costume->rotationCenterX() / bitmapRes;
228249
const double centerY = costume->rotationCenterY() / bitmapRes;
@@ -234,8 +255,11 @@ void PenLayer::stamp(IRenderedTarget *target)
234255

235256
const double textureScale = texture.width() / static_cast<double>(target->costumeWidth());
236257

258+
// Apply scale (HQ pen)
259+
x *= m_scale;
260+
y *= m_scale;
261+
237262
// Translate the coordinates
238-
// TODO: Apply scale (HQ pen)
239263
x = std::floor(x + m_texture.width() / 2.0);
240264
y = std::floor(-y + m_texture.height() / 2.0);
241265

@@ -352,8 +376,11 @@ QRgb PenLayer::colorAtScratchPoint(double x, double y) const
352376
const double width = m_texture.width();
353377
const double height = m_texture.height();
354378

379+
// Apply scale (HQ pen)
380+
x *= m_scale;
381+
y *= m_scale;
382+
355383
// Translate the coordinates
356-
// TODO: Apply scale
357384
x = std::floor(x + width / 2.0);
358385
y = std::floor(-y + height / 2.0);
359386

@@ -393,7 +420,6 @@ const libscratchcpp::Rect &PenLayer::getBounds() const
393420
}
394421

395422
for (const QPointF &point : points) {
396-
// TODO: Apply scale
397423
double x = point.x() - width / 2;
398424
double y = -point.y() + height / 2;
399425

@@ -410,10 +436,10 @@ const libscratchcpp::Rect &PenLayer::getBounds() const
410436
bottom = y;
411437
}
412438

413-
m_bounds.setLeft(left);
414-
m_bounds.setTop(top);
415-
m_bounds.setRight(right + 1);
416-
m_bounds.setBottom(bottom - 1);
439+
m_bounds.setLeft(left / m_scale);
440+
m_bounds.setTop(top / m_scale);
441+
m_bounds.setRight(right / m_scale + 1);
442+
m_bounds.setBottom(bottom / m_scale - 1);
417443
}
418444

419445
return m_bounds;
@@ -439,6 +465,33 @@ QNanoQuickItemPainter *PenLayer::createItemPainter() const
439465
return new PenLayerPainter;
440466
}
441467

468+
void PenLayer::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
469+
{
470+
if (m_hqPen && newGeometry != oldGeometry)
471+
createFbo();
472+
473+
QNanoQuickItem::geometryChange(newGeometry, oldGeometry);
474+
}
475+
476+
void PenLayer::createFbo()
477+
{
478+
if (!QOpenGLContext::currentContext() || !m_engine)
479+
return;
480+
481+
QOpenGLFramebufferObjectFormat fboFormat;
482+
fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
483+
484+
QOpenGLFramebufferObject *newFbo = new QOpenGLFramebufferObject(width(), height(), fboFormat);
485+
Q_ASSERT(newFbo->isValid());
486+
487+
if (m_fbo)
488+
QOpenGLFramebufferObject::blitFramebuffer(newFbo, m_fbo.get());
489+
490+
m_fbo.reset(newFbo);
491+
m_texture = Texture(m_fbo->texture(), m_fbo->size());
492+
m_scale = width() / m_engine->stageWidth();
493+
}
494+
442495
void PenLayer::updateTexture()
443496
{
444497
if (!m_fbo)

src/penlayer.h

+9
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class PenLayer : public IPenLayer
1919
Q_OBJECT
2020
QML_ELEMENT
2121
Q_PROPERTY(libscratchcpp::IEngine *engine READ engine WRITE setEngine NOTIFY engineChanged)
22+
Q_PROPERTY(bool hqPen READ hqPen WRITE setHqPen NOTIFY hqPenChanged)
2223

2324
public:
2425
PenLayer(QNanoQuickItem *parent = nullptr);
@@ -30,6 +31,9 @@ class PenLayer : public IPenLayer
3031
libscratchcpp::IEngine *engine() const override;
3132
void setEngine(libscratchcpp::IEngine *newEngine) override;
3233

34+
bool hqPen() const;
35+
void setHqPen(bool newHqPen);
36+
3337
void clear() override;
3438
void drawPoint(const PenAttributes &penAttributes, double x, double y) override;
3539
void drawLine(const PenAttributes &penAttributes, double x0, double y0, double x1, double y1) override;
@@ -45,17 +49,22 @@ class PenLayer : public IPenLayer
4549

4650
signals:
4751
void engineChanged();
52+
void hqPenChanged();
4853

4954
protected:
5055
QNanoQuickItemPainter *createItemPainter() const override;
56+
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
5157

5258
private:
59+
void createFbo();
5360
void updateTexture();
5461

5562
static std::unordered_map<libscratchcpp::IEngine *, IPenLayer *> m_projectPenLayers;
5663
bool m_antialiasingEnabled = true;
5764
libscratchcpp::IEngine *m_engine = nullptr;
65+
bool m_hqPen = false;
5866
std::unique_ptr<QOpenGLFramebufferObject> m_fbo;
67+
double m_scale = 1;
5968
std::unique_ptr<QNanoPainter> m_painter;
6069
std::unique_ptr<QOpenGLExtraFunctions> m_glF;
6170
Texture m_texture;

test/lines_hq.png

7.23 KB
Loading

0 commit comments

Comments
 (0)