Skip to content

Commit 7dab0ba

Browse files
authored
Merge pull request #62 from scratchcpp/run_in_gui_thread
Run projects in main thread
2 parents 7557a01 + 3858f42 commit 7dab0ba

20 files changed

+483
-556
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,13 @@ Button {
114114
}
115115
```
116116

117+
Please note that the ScratchCPP renderer only works with the basic scene graph render loop.
118+
Qt 6 uses the threaded render loop by default, so you'll have to disable it by calling this
119+
before constructing your application object:
120+
```cpp
121+
qputenv("QSG_RENDER_LOOP", "basic");
122+
```
123+
117124
<p align="right">(<a href="#readme-top">back to top</a>)</p>
118125
119126

src/ProjectPlayer.qml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ ProjectScene {
4444
else
4545
failedToLoad();
4646
}
47+
onStageChanged: stage.loadCostume();
4748
}
4849

4950
function start() {

src/irenderedtarget.h

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,11 @@
33
#pragma once
44

55
#include <qnanoquickitem.h>
6+
#include <scratchcpp/sprite.h>
67

78
class QBuffer;
89
class QNanoPainter;
9-
10-
namespace libscratchcpp
11-
{
12-
13-
class Costume;
14-
class IEngine;
15-
class Target;
16-
17-
} // namespace libscratchcpp
10+
class QOpenGLContext;
1811

1912
namespace scratchcpprender
2013
{
@@ -33,9 +26,17 @@ class IRenderedTarget : public QNanoQuickItem
3326

3427
virtual ~IRenderedTarget() { }
3528

36-
virtual void loadProperties() = 0;
29+
virtual void updateVisibility(bool visible) = 0;
30+
virtual void updateX(double x) = 0;
31+
virtual void updateY(double y) = 0;
32+
virtual void updateSize(double size) = 0;
33+
virtual void updateDirection(double direction) = 0;
34+
virtual void updateRotationStyle(libscratchcpp::Sprite::RotationStyle style) = 0;
35+
virtual void updateLayerOrder(int layerOrder) = 0;
36+
3737
virtual void loadCostume(libscratchcpp::Costume *costume) = 0;
38-
virtual void updateProperties() = 0;
38+
39+
virtual void beforeRedraw() = 0;
3940

4041
virtual libscratchcpp::IEngine *engine() const = 0;
4142
virtual void setEngine(libscratchcpp::IEngine *newEngine) = 0;

src/projectloader.cpp

Lines changed: 12 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@
1212
using namespace scratchcpprender;
1313
using namespace libscratchcpp;
1414

15-
void runEventLoop(IEngine *engine)
16-
{
17-
engine->runEventLoop();
18-
}
19-
2015
ProjectLoader::ProjectLoader(QObject *parent) :
2116
QObject(parent)
2217
{
@@ -33,12 +28,6 @@ ProjectLoader::ProjectLoader(QObject *parent) :
3328
});
3429

3530
initTimer();
36-
37-
// Update refresh rate when primary screen changes
38-
connect(qApp, &QApplication::primaryScreenChanged, this, [this]() {
39-
killTimer(m_timerId);
40-
initTimer();
41-
});
4231
}
4332

4433
ProjectLoader::~ProjectLoader()
@@ -48,11 +37,6 @@ ProjectLoader::~ProjectLoader()
4837
if (m_loadThread.isRunning())
4938
m_loadThread.waitForFinished();
5039

51-
if (m_engine && m_eventLoopEnabled) {
52-
m_engine->stopEventLoop();
53-
m_eventLoop.waitForFinished();
54-
}
55-
5640
for (SpriteModel *sprite : m_sprites)
5741
sprite->deleteLater();
5842
}
@@ -72,11 +56,6 @@ void ProjectLoader::setFileName(const QString &newFileName)
7256

7357
m_fileName = newFileName;
7458

75-
if (m_engine) {
76-
m_engine->stopEventLoop();
77-
m_eventLoop.waitForFinished();
78-
}
79-
8059
m_project.setScratchVersion(ScratchVersion::Scratch3);
8160
m_project.setFileName(m_fileName.toStdString());
8261
m_loadStatus = false;
@@ -164,17 +143,8 @@ void ProjectLoader::timerEvent(QTimerEvent *event)
164143
if (m_loadThread.isRunning())
165144
return;
166145

167-
auto stageRenderedTarget = m_stage.renderedTarget();
168-
169-
if (stageRenderedTarget)
170-
stageRenderedTarget->updateProperties();
171-
172-
for (auto sprite : m_sprites) {
173-
auto renderedTarget = sprite->renderedTarget();
174-
175-
if (renderedTarget)
176-
renderedTarget->updateProperties();
177-
}
146+
if (m_engine)
147+
m_engine->step();
178148

179149
event->accept();
180150
}
@@ -213,7 +183,7 @@ void ProjectLoader::load()
213183
m_engine->setCloneLimit(m_cloneLimit);
214184
m_engine->setSpriteFencingEnabled(m_spriteFencing);
215185

216-
auto handler = std::bind(&ProjectLoader::emitTick, this);
186+
auto handler = std::bind(&ProjectLoader::redraw, this);
217187
m_engine->setRedrawHandler(std::function<void()>(handler));
218188

219189
// Load targets
@@ -240,12 +210,6 @@ void ProjectLoader::load()
240210
return;
241211
}
242212

243-
// Run event loop
244-
m_engine->setSpriteFencingEnabled(false);
245-
246-
if (m_eventLoopEnabled)
247-
m_eventLoop = QtConcurrent::run(&runEventLoop, m_engine);
248-
249213
m_engineMutex.unlock();
250214

251215
emit loadStatusChanged();
@@ -257,27 +221,24 @@ void ProjectLoader::load()
257221

258222
void ProjectLoader::initTimer()
259223
{
260-
QScreen *screen = qApp->primaryScreen();
261-
262-
if (screen)
263-
m_timerId = startTimer(1000 / screen->refreshRate());
224+
m_timerId = startTimer(1000 / m_fps);
264225
}
265226

266-
void ProjectLoader::emitTick()
227+
void ProjectLoader::redraw()
267228
{
268229
if (m_loadThread.isRunning())
269230
m_loadThread.waitForFinished();
270231

271-
auto stageRenderedTarget = m_stage.renderedTarget();
232+
auto stage = m_stage.renderedTarget();
272233

273-
if (stageRenderedTarget)
274-
stageRenderedTarget->loadProperties();
234+
if (stage)
235+
stage->beforeRedraw();
275236

276237
for (auto sprite : m_sprites) {
277238
auto renderedTarget = sprite->renderedTarget();
278239

279240
if (renderedTarget)
280-
renderedTarget->loadProperties();
241+
renderedTarget->beforeRedraw();
281242
}
282243
}
283244

@@ -299,6 +260,9 @@ void ProjectLoader::setFps(double newFps)
299260
} else
300261
m_fps = newFps;
301262

263+
killTimer(m_timerId);
264+
initTimer();
265+
302266
m_engineMutex.unlock();
303267
emit fpsChanged();
304268
}
@@ -405,32 +369,6 @@ void ProjectLoader::setSpriteFencing(bool newSpriteFencing)
405369
emit spriteFencingChanged();
406370
}
407371

408-
bool ProjectLoader::eventLoopEnabled() const
409-
{
410-
return m_eventLoopEnabled;
411-
}
412-
413-
void ProjectLoader::setEventLoopEnabled(bool newEventLoopEnabled)
414-
{
415-
if (m_eventLoopEnabled == newEventLoopEnabled)
416-
return;
417-
418-
m_eventLoopEnabled = newEventLoopEnabled;
419-
m_engineMutex.lock();
420-
421-
if (m_engine) {
422-
if (m_eventLoopEnabled)
423-
m_eventLoop = QtConcurrent::run(&runEventLoop, m_engine);
424-
else {
425-
m_engine->stopEventLoop();
426-
m_eventLoop.waitForFinished();
427-
}
428-
}
429-
430-
m_engineMutex.unlock();
431-
emit eventLoopEnabledChanged();
432-
}
433-
434372
unsigned int ProjectLoader::downloadedAssets() const
435373
{
436374
return m_downloadedAssets;

src/projectloader.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ class ProjectLoader : public QObject
2929
Q_PROPERTY(unsigned int stageHeight READ stageHeight WRITE setStageHeight NOTIFY stageHeightChanged)
3030
Q_PROPERTY(int cloneLimit READ cloneLimit WRITE setCloneLimit NOTIFY cloneLimitChanged)
3131
Q_PROPERTY(bool spriteFencing READ spriteFencing WRITE setSpriteFencing NOTIFY spriteFencingChanged)
32-
Q_PROPERTY(bool eventLoopEnabled READ eventLoopEnabled WRITE setEventLoopEnabled NOTIFY eventLoopEnabledChanged)
3332
Q_PROPERTY(unsigned int downloadedAssets READ downloadedAssets NOTIFY downloadedAssetsChanged)
3433
Q_PROPERTY(unsigned int assetCount READ assetCount NOTIFY assetCountChanged)
3534

@@ -71,9 +70,6 @@ class ProjectLoader : public QObject
7170
bool spriteFencing() const;
7271
void setSpriteFencing(bool newSpriteFencing);
7372

74-
bool eventLoopEnabled() const;
75-
void setEventLoopEnabled(bool newEventLoopEnabled);
76-
7773
unsigned int downloadedAssets() const;
7874

7975
unsigned int assetCount() const;
@@ -91,7 +87,6 @@ class ProjectLoader : public QObject
9187
void stageHeightChanged();
9288
void cloneLimitChanged();
9389
void spriteFencingChanged();
94-
void eventLoopEnabledChanged();
9590
void downloadedAssetsChanged();
9691
void assetCountChanged();
9792

@@ -102,7 +97,7 @@ class ProjectLoader : public QObject
10297
static void callLoad(ProjectLoader *loader);
10398
void load();
10499
void initTimer();
105-
void emitTick();
100+
void redraw();
106101

107102
int m_timerId = -1;
108103
QString m_fileName;
@@ -113,14 +108,12 @@ class ProjectLoader : public QObject
113108
bool m_loadStatus = false;
114109
StageModel m_stage;
115110
QList<SpriteModel *> m_sprites;
116-
QFuture<void> m_eventLoop;
117111
double m_fps = 30;
118112
bool m_turboMode = false;
119113
unsigned int m_stageWidth = 480;
120114
unsigned int m_stageHeight = 360;
121115
int m_cloneLimit = 300;
122116
bool m_spriteFencing = true;
123-
bool m_eventLoopEnabled = true;
124117
std::atomic<unsigned int> m_downloadedAssets = 0;
125118
std::atomic<unsigned int> m_assetCount = 0;
126119
std::atomic<bool> m_stopLoading = false;

0 commit comments

Comments
 (0)