Skip to content

Commit db08870

Browse files
committed
Move stamp rendering to RenderedTarget
1 parent 8e8abc1 commit db08870

File tree

5 files changed

+99
-95
lines changed

5 files changed

+99
-95
lines changed

src/irenderedtarget.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ class IRenderedTarget : public QNanoQuickItem
7777

7878
virtual bool mirrorHorizontally() const = 0;
7979

80+
virtual void render(double scale) const = 0;
81+
8082
virtual Texture texture() const = 0;
8183
virtual const Texture &cpuTexture() const = 0;
8284
virtual int costumeWidth() const = 0;

src/penlayer.cpp

Lines changed: 3 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,6 @@ static const double pi = std::acos(-1); // TODO: Use std::numbers::pi in C++20
1515

1616
std::unordered_map<libscratchcpp::IEngine *, IPenLayer *> PenLayer::m_projectPenLayers;
1717

18-
// TODO: Move this to a separate class
19-
template<typename T>
20-
short sgn(T x)
21-
{
22-
return (T(0) < x) - (x < T(0));
23-
}
24-
2518
PenLayer::PenLayer(QNanoQuickItem *parent) :
2619
IPenLayer(parent)
2720
{
@@ -219,101 +212,17 @@ void PenLayer::stamp(IRenderedTarget *target)
219212

220213
Q_ASSERT(m_fbo->isBound());
221214

222-
const float stageWidth = m_engine->stageWidth() * m_scale;
223-
const float stageHeight = m_engine->stageHeight() * m_scale;
224-
225-
libscratchcpp::Rect bounds = target->getFastBounds();
226-
bounds.snapToInt();
227-
228-
if (!bounds.intersects(libscratchcpp::Rect(-stageWidth / 2, stageHeight / 2, stageWidth / 2, -stageHeight / 2)))
229-
return;
230-
231-
float angle = 180;
232-
float scaleX = 1;
233-
float scaleY = 1;
234-
235-
SpriteModel *spriteModel = target->spriteModel();
236-
237-
if (spriteModel) {
238-
libscratchcpp::Sprite *sprite = spriteModel->sprite();
239-
240-
switch (sprite->rotationStyle()) {
241-
case libscratchcpp::Sprite::RotationStyle::AllAround:
242-
angle = 270 - sprite->direction();
243-
break;
244-
245-
case libscratchcpp::Sprite::RotationStyle::LeftRight:
246-
scaleX = sgn(sprite->direction());
247-
break;
248-
249-
default:
250-
break;
251-
}
252-
253-
scaleY = sprite->size() / 100;
254-
scaleX *= scaleY;
255-
}
256-
257-
scaleX *= m_scale;
258-
scaleY *= m_scale;
259-
260-
const Texture &texture = target->cpuTexture();
261-
262-
if (!texture.isValid())
263-
return;
264-
265-
const float textureScale = texture.width() / static_cast<float>(target->costumeWidth());
266-
const float skinWidth = texture.width();
267-
const float skinHeight = texture.height();
268-
269-
// Projection matrix
270-
QMatrix4x4 projectionMatrix;
271-
const float aspectRatio = skinHeight / skinWidth;
272-
projectionMatrix.ortho(1.0f, -1.0f, aspectRatio, -aspectRatio, 0.1f, 0.0f);
273-
projectionMatrix.scale(skinWidth / bounds.width() / m_scale, skinHeight / bounds.height() / m_scale);
274-
275-
// Model matrix
276-
// TODO: This should be calculated and cached by targets
277-
QMatrix4x4 modelMatrix;
278-
modelMatrix.rotate(angle, 0, 0, 1);
279-
modelMatrix.scale(scaleX / textureScale, aspectRatio * scaleY / textureScale);
280215
m_glF->glDisable(GL_SCISSOR_TEST);
281216
m_glF->glDisable(GL_DEPTH_TEST);
282-
m_glF->glEnable(GL_BLEND);
283-
m_glF->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
284-
285-
// Set viewport
286-
m_glF->glViewport((stageWidth / 2) + bounds.left() * m_scale, (stageHeight / 2) + bounds.bottom() * m_scale, bounds.width() * m_scale, bounds.height() * m_scale);
287-
288-
// Get the shader program for the current set of effects
289-
ShaderManager *shaderManager = ShaderManager::instance();
290-
291-
const auto &effects = target->graphicEffects();
292-
QOpenGLShaderProgram *shaderProgram = shaderManager->getShaderProgram(effects);
293-
Q_ASSERT(shaderProgram);
294-
Q_ASSERT(shaderProgram->isLinked());
295217

296218
m_glF->glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
297-
298-
// Render to the target framebuffer
299-
m_glF->glBindFramebuffer(GL_FRAMEBUFFER, m_fbo->handle());
300-
shaderProgram->bind();
301219
m_glF->glBindVertexArray(m_vao);
302-
m_glF->glActiveTexture(GL_TEXTURE0);
303-
m_glF->glBindTexture(GL_TEXTURE_2D, texture.handle());
304-
shaderManager->setUniforms(shaderProgram, 0, texture.size(), effects); // set texture and effect uniforms
305-
shaderProgram->setUniformValue("u_projectionMatrix", projectionMatrix);
306-
shaderProgram->setUniformValue("u_modelMatrix", modelMatrix);
307-
m_glF->glDrawArrays(GL_TRIANGLES, 0, 6);
308-
309-
// Cleanup
310-
shaderProgram->release();
220+
221+
target->render(m_scale);
222+
311223
m_glF->glBindVertexArray(0);
312224
m_glF->glBindBuffer(GL_ARRAY_BUFFER, 0);
313225

314-
// The FBO should remain bound until the frame ends
315-
// m_glF->glBindFramebuffer(GL_FRAMEBUFFER, 0);
316-
317226
m_glF->glEnable(GL_SCISSOR_TEST);
318227
m_glF->glEnable(GL_DEPTH_TEST);
319228

src/renderedtarget.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ using namespace libscratchcpp;
2323
static const double SVG_SCALE_LIMIT = 0.1; // the maximum viewport dimensions are multiplied by this
2424
static const double pi = std::acos(-1); // TODO: Use std::numbers::pi in C++20
2525

26+
// TODO: Move this to a separate class
27+
template<typename T>
28+
short sgn(T x)
29+
{
30+
return (T(0) < x) - (x < T(0));
31+
}
32+
2633
RenderedTarget::RenderedTarget(QQuickItem *parent) :
2734
IRenderedTarget(parent)
2835
{
@@ -507,6 +514,88 @@ void RenderedTarget::mouseMoveEvent(QMouseEvent *event)
507514
}
508515
}
509516

517+
void RenderedTarget::render(double scale) const
518+
{
519+
if (!m_glF) {
520+
m_glF = std::make_unique<QOpenGLFunctions>();
521+
m_glF->initializeOpenGLFunctions();
522+
}
523+
524+
const float stageWidth = m_engine->stageWidth() * scale;
525+
const float stageHeight = m_engine->stageHeight() * scale;
526+
527+
libscratchcpp::Rect bounds = getFastBounds();
528+
bounds.snapToInt();
529+
530+
if (!bounds.intersects(libscratchcpp::Rect(-stageWidth / 2, stageHeight / 2, stageWidth / 2, -stageHeight / 2)))
531+
return;
532+
533+
float angle = 180;
534+
float scaleX = 1;
535+
float scaleY = 1;
536+
537+
if (m_spriteModel) {
538+
libscratchcpp::Sprite *sprite = m_spriteModel->sprite();
539+
540+
switch (sprite->rotationStyle()) {
541+
case libscratchcpp::Sprite::RotationStyle::AllAround:
542+
angle = 270 - sprite->direction();
543+
break;
544+
545+
case libscratchcpp::Sprite::RotationStyle::LeftRight:
546+
scaleX = sgn(sprite->direction());
547+
break;
548+
549+
default:
550+
break;
551+
}
552+
553+
scaleY = sprite->size() / 100;
554+
scaleX *= scaleY;
555+
}
556+
557+
scaleX *= scale;
558+
scaleY *= scale;
559+
560+
const Texture &texture = cpuTexture();
561+
562+
if (!texture.isValid())
563+
return;
564+
565+
const float textureScale = texture.width() / static_cast<float>(costumeWidth());
566+
const float skinWidth = texture.width();
567+
const float skinHeight = texture.height();
568+
569+
QMatrix4x4 projectionMatrix;
570+
const float aspectRatio = skinHeight / skinWidth;
571+
projectionMatrix.ortho(1.0f, -1.0f, aspectRatio, -aspectRatio, 0.1f, 0.0f);
572+
projectionMatrix.scale(skinWidth / bounds.width() / scale, skinHeight / bounds.height() / scale);
573+
574+
QMatrix4x4 modelMatrix;
575+
modelMatrix.rotate(angle, 0, 0, 1);
576+
modelMatrix.scale(scaleX / textureScale, aspectRatio * scaleY / textureScale);
577+
578+
m_glF->glEnable(GL_BLEND);
579+
m_glF->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
580+
581+
m_glF->glViewport((stageWidth / 2) + bounds.left() * scale, (stageHeight / 2) + bounds.bottom() * scale, bounds.width() * scale, bounds.height() * scale);
582+
583+
ShaderManager *shaderManager = ShaderManager::instance();
584+
QOpenGLShaderProgram *shaderProgram = shaderManager->getShaderProgram(m_graphicEffects);
585+
Q_ASSERT(shaderProgram);
586+
Q_ASSERT(shaderProgram->isLinked());
587+
588+
shaderProgram->bind();
589+
m_glF->glActiveTexture(GL_TEXTURE0);
590+
m_glF->glBindTexture(GL_TEXTURE_2D, texture.handle());
591+
shaderManager->setUniforms(shaderProgram, 0, texture.size(), m_graphicEffects);
592+
shaderProgram->setUniformValue("u_projectionMatrix", projectionMatrix);
593+
shaderProgram->setUniformValue("u_modelMatrix", modelMatrix);
594+
m_glF->glDrawArrays(GL_TRIANGLES, 0, 6);
595+
596+
shaderProgram->release();
597+
}
598+
510599
Texture RenderedTarget::texture() const
511600
{
512601
return m_texture;

src/renderedtarget.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ class RenderedTarget : public IRenderedTarget
8585

8686
bool mirrorHorizontally() const override;
8787

88+
void render(double scale) const override;
89+
8890
Texture texture() const override;
8991
const Texture &cpuTexture() const override;
9092
int costumeWidth() const override;
@@ -157,7 +159,7 @@ class RenderedTarget : public IRenderedTarget
157159
Texture m_oldTexture;
158160
Texture m_cpuTexture; // without stage scale
159161
mutable std::shared_ptr<CpuTextureManager> m_textureManager; // NOTE: Use textureManager()!
160-
std::unique_ptr<QOpenGLFunctions> m_glF;
162+
mutable std::unique_ptr<QOpenGLFunctions> m_glF;
161163
mutable std::unordered_map<ShaderManager::Effect, double> m_graphicEffects;
162164
mutable ShaderManager::Effect m_graphicEffectMask = ShaderManager::Effect::NoEffect;
163165
double m_size = 1;

test/mocks/renderedtargetmock.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ class RenderedTargetMock : public IRenderedTarget
6161

6262
MOCK_METHOD(bool, mirrorHorizontally, (), (const, override));
6363

64+
MOCK_METHOD(void, render, (double), (const, override));
65+
6466
MOCK_METHOD(Texture, texture, (), (const, override));
6567
MOCK_METHOD(const Texture &, cpuTexture, (), (const, override));
6668
MOCK_METHOD(int, costumeWidth, (), (const, override));

0 commit comments

Comments
 (0)