Skip to content

Commit e266511

Browse files
authored
Merge pull request #120 from scratchcpp/touching_color
Implement touching color
2 parents c055d42 + 9129e7e commit e266511

18 files changed

+826
-61
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ int main(int argc, char **argv) {
145145
- [x] Clones
146146
- [x] Sprite dragging
147147
- [x] Touching sprite block
148-
- [ ] Touching color blocks
148+
- [ ] Touching color blocks (color is touching color is not implemented yet)
149149
- [ ] Pen blocks (all blocks except the stamp block are implemented)
150150
- [x] Monitors
151151
- [ ] Graphics effects (color, brightness and ghost are implemented)

src/cputexturemanager.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,21 @@ const std::vector<QPoint> &CpuTextureManager::getTextureConvexHullPoints(const T
5151
return it->second;
5252
}
5353

54+
void CpuTextureManager::removeTexture(const Texture &texture)
55+
{
56+
if (!texture.isValid())
57+
return;
58+
59+
const GLuint handle = texture.handle();
60+
auto it = m_textureData.find(handle);
61+
62+
if (it != m_textureData.cend()) {
63+
delete it->second;
64+
m_textureData.erase(it);
65+
m_convexHullPoints.erase(handle);
66+
}
67+
}
68+
5469
bool CpuTextureManager::addTexture(const Texture &texture)
5570
{
5671
if (!texture.isValid())

src/cputexturemanager.h

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class CpuTextureManager
2020
GLubyte *getTextureData(const Texture &texture);
2121
const std::vector<QPoint> &getTextureConvexHullPoints(const Texture &texture);
2222

23+
void removeTexture(const Texture &texture);
24+
2325
private:
2426
bool addTexture(const Texture &texture);
2527

src/ipenlayer.h

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#pragma once
44

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

78
namespace libscratchcpp
89
{
@@ -37,6 +38,9 @@ class IPenLayer : public QNanoQuickItem
3738
virtual void drawLine(const PenAttributes &penAttributes, double x0, double y0, double x1, double y1) = 0;
3839

3940
virtual QOpenGLFramebufferObject *framebufferObject() const = 0;
41+
virtual QRgb colorAtScratchPoint(double x, double y) const = 0;
42+
43+
virtual const libscratchcpp::Rect &getBounds() const = 0;
4044
};
4145

4246
} // namespace scratchcpprender

src/irenderedtarget.h

+2
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,10 @@ class IRenderedTarget : public QNanoQuickItem
8686
virtual const std::vector<QPoint> &hullPoints() const = 0;
8787

8888
virtual bool containsScratchPoint(double x, double y) const = 0;
89+
virtual QRgb colorAtScratchPoint(double x, double y) const = 0;
8990

9091
virtual bool touchingClones(const std::vector<libscratchcpp::Sprite *> &clones) const = 0;
92+
virtual bool touchingColor(const libscratchcpp::Value &color) const = 0;
9193
};
9294

9395
} // namespace scratchcpprender

src/penlayer.cpp

+100
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ void scratchcpprender::PenLayer::clear()
7676
m_glF->glEnable(GL_SCISSOR_TEST);
7777
m_fbo->release();
7878

79+
m_textureDirty = true;
80+
m_boundsDirty = true;
7981
update();
8082
}
8183

@@ -121,6 +123,8 @@ void scratchcpprender::PenLayer::drawLine(const PenAttributes &penAttributes, do
121123
painter.end();
122124
m_fbo->release();
123125

126+
m_textureDirty = true;
127+
m_boundsDirty = true;
124128
update();
125129
}
126130

@@ -129,6 +133,84 @@ QOpenGLFramebufferObject *PenLayer::framebufferObject() const
129133
return m_fbo.get();
130134
}
131135

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+
132214
IPenLayer *PenLayer::getProjectPenLayer(libscratchcpp::IEngine *engine)
133215
{
134216
auto it = m_projectPenLayers.find(engine);
@@ -148,3 +230,21 @@ QNanoQuickItemPainter *PenLayer::createItemPainter() const
148230
{
149231
return new PenLayerPainter;
150232
}
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+
}

src/penlayer.h

+15-1
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
#pragma once
44

5-
#include <ipenlayer.h>
65
#include <QOpenGLFramebufferObject>
76
#include <QOpenGLPaintDevice>
87
#include <QOpenGLFunctions>
98
#include <QPainter>
109
#include <scratchcpp/iengine.h>
1110

11+
#include "ipenlayer.h"
12+
#include "texture.h"
13+
#include "cputexturemanager.h"
14+
1215
namespace scratchcpprender
1316
{
1417

@@ -33,6 +36,9 @@ class PenLayer : public IPenLayer
3336
void drawLine(const PenAttributes &penAttributes, double x0, double y0, double x1, double y1) override;
3437

3538
QOpenGLFramebufferObject *framebufferObject() const override;
39+
QRgb colorAtScratchPoint(double x, double y) const override;
40+
41+
const libscratchcpp::Rect &getBounds() const override;
3642

3743
static IPenLayer *getProjectPenLayer(libscratchcpp::IEngine *engine);
3844
static void addPenLayer(libscratchcpp::IEngine *engine, IPenLayer *penLayer); // for tests
@@ -44,13 +50,21 @@ class PenLayer : public IPenLayer
4450
QNanoQuickItemPainter *createItemPainter() const override;
4551

4652
private:
53+
void updateTexture();
54+
4755
static std::unordered_map<libscratchcpp::IEngine *, IPenLayer *> m_projectPenLayers;
4856
bool m_antialiasingEnabled = true;
4957
libscratchcpp::IEngine *m_engine = nullptr;
5058
std::unique_ptr<QOpenGLFramebufferObject> m_fbo;
59+
std::unique_ptr<QOpenGLFramebufferObject> m_resolvedFbo;
5160
std::unique_ptr<QOpenGLPaintDevice> m_paintDevice;
5261
QOpenGLFramebufferObjectFormat m_fboFormat;
5362
std::unique_ptr<QOpenGLFunctions> m_glF;
63+
Texture m_texture;
64+
bool m_textureDirty = true;
65+
mutable CpuTextureManager m_textureManager;
66+
mutable bool m_boundsDirty = true;
67+
mutable libscratchcpp::Rect m_bounds;
5468
};
5569

5670
} // namespace scratchcpprender

0 commit comments

Comments
 (0)