Skip to content

Commit

Permalink
Refactor costume loading
Browse files Browse the repository at this point in the history
  • Loading branch information
adazem009 committed Dec 11, 2023
1 parent dbe3f54 commit 8bad035
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 187 deletions.
7 changes: 0 additions & 7 deletions ScratchCPPGui/irenderedtarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,6 @@ class IRenderedTarget : public QNanoQuickItem
virtual qreal height() const = 0;
virtual void setHeight(qreal width) = 0;

virtual double costumeWidth() const = 0;
virtual void setCostumeWidth(double width) = 0;

virtual double costumeHeight() const = 0;
virtual void setCostumeHeight(double width) = 0;

virtual unsigned char *svgBitmap() const = 0;
virtual QBuffer *bitmapBuffer() = 0;
virtual const QString &bitmapUniqueKey() const = 0;

Expand Down
93 changes: 33 additions & 60 deletions ScratchCPPGui/renderedtarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@ RenderedTarget::RenderedTarget(QNanoQuickItem *parent) :
{
}

RenderedTarget::~RenderedTarget()
{
if (m_svgBitmap)
free(m_svgBitmap);
}

void RenderedTarget::loadProperties()
{
Q_ASSERT(!(m_spriteModel && m_stageModel));
Expand Down Expand Up @@ -83,30 +77,12 @@ void RenderedTarget::loadCostume(Costume *costume)
return;

m_costumeMutex.lock();
Target *target = scratchTarget();
m_costume = costume;
m_imageChanged = true;

if (costume->dataFormat() == "svg") {
// TODO: Load SVG here
// In case of rasterizing, write the bitmap to m_svgBitmap
} else {
if (m_svgBitmap) {
free(m_svgBitmap);
m_svgBitmap = nullptr;
}

m_bitmapBuffer.open(QBuffer::WriteOnly);
m_bitmapBuffer.write(static_cast<const char *>(costume->data()), costume->dataSize());
m_bitmapBuffer.close();
m_bitmapUniqueKey = QString::fromStdString(costume->id());

QImageReader reader(&m_bitmapBuffer);
QSize size = reader.size();
calculateSize(target, size.width(), size.height());
m_bitmapBuffer.close();
}

m_costume = costume;
m_costumeMutex.unlock();
}

Expand All @@ -116,8 +92,12 @@ void RenderedTarget::updateProperties()
setVisible(m_visible);

if (m_visible) {
setWidth(m_width);
setHeight(m_height);
if (m_imageChanged) {
doLoadCostume();
update();
m_imageChanged = false;
}

setX(m_x);
setY(m_y);
setZ(m_z);
Expand All @@ -128,11 +108,6 @@ void RenderedTarget::updateProperties()
m_mirrorHorizontally = m_newMirrorHorizontally;
emit mirrorHorizontallyChanged();
}

if (m_imageChanged) {
update();
m_imageChanged = false;
}
}

mutex.unlock();
Expand Down Expand Up @@ -210,38 +185,36 @@ void RenderedTarget::setHeight(qreal height)
QNanoQuickItem::setHeight(height);
}

double RenderedTarget::costumeWidth() const
QNanoQuickItemPainter *RenderedTarget::createItemPainter() const
{
return m_width;
return new TargetPainter();
}

void RenderedTarget::setCostumeWidth(double width)
void RenderedTarget::doLoadCostume()
{
mutex.lock();
m_width = width;
mutex.unlock();
}
m_costumeMutex.lock();

double RenderedTarget::costumeHeight() const
{
return m_height;
}
if (!m_costume) {
m_costumeMutex.unlock();
return;
}

void RenderedTarget::setCostumeHeight(double height)
{
mutex.lock();
m_height = height;
mutex.unlock();
}
Target *target = scratchTarget();

unsigned char *RenderedTarget::svgBitmap() const
{
return m_svgBitmap;
}
if (m_costume->dataFormat() == "svg") {
} else {
m_bitmapBuffer.open(QBuffer::WriteOnly);
m_bitmapBuffer.write(static_cast<const char *>(m_costume->data()), m_costume->dataSize());
m_bitmapBuffer.close();
m_bitmapUniqueKey = QString::fromStdString(m_costume->id());

QNanoQuickItemPainter *RenderedTarget::createItemPainter() const
{
return new TargetPainter();
QImageReader reader(&m_bitmapBuffer);
QSize size = reader.size();
calculateSize(target, size.width(), size.height());
m_bitmapBuffer.close();
}

m_costumeMutex.unlock();
}

void RenderedTarget::calculateSize(Target *target, double costumeWidth, double costumeHeight)
Expand All @@ -252,11 +225,11 @@ void RenderedTarget::calculateSize(Target *target, double costumeWidth, double c

if (sprite) {
double size = sprite->size();
m_width = costumeWidth * size / 100 / bitmapRes;
m_height = costumeHeight * size / 100 / bitmapRes;
setWidth(costumeWidth * size / 100 / bitmapRes);
setHeight(costumeHeight * size / 100 / bitmapRes);
} else {
m_width = costumeWidth / bitmapRes;
m_height = costumeHeight / bitmapRes;
setWidth(costumeWidth / bitmapRes);
setHeight(costumeHeight / bitmapRes);
}
}
}
Expand Down
12 changes: 1 addition & 11 deletions ScratchCPPGui/renderedtarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class RenderedTarget : public IRenderedTarget

public:
RenderedTarget(QNanoQuickItem *parent = nullptr);
~RenderedTarget();

Q_INVOKABLE void loadProperties() override;
void loadCostume(libscratchcpp::Costume *costume) override;
Expand All @@ -48,13 +47,6 @@ class RenderedTarget : public IRenderedTarget
qreal height() const override;
void setHeight(qreal height) override;

double costumeWidth() const override;
void setCostumeWidth(double width) override;

double costumeHeight() const override;
void setCostumeHeight(double height) override;

unsigned char *svgBitmap() const override;
QBuffer *bitmapBuffer() override;
const QString &bitmapUniqueKey() const override;

Expand All @@ -74,21 +66,19 @@ class RenderedTarget : public IRenderedTarget
QNanoQuickItemPainter *createItemPainter() const override;

private:
void doLoadCostume();
void calculateSize(libscratchcpp::Target *target, double costumeWidth, double costumeHeight);

libscratchcpp::IEngine *m_engine = nullptr;
libscratchcpp::Costume *m_costume = nullptr;
StageModel *m_stageModel = nullptr;
SpriteModel *m_spriteModel = nullptr;
unsigned char *m_svgBitmap = nullptr;
QBuffer m_bitmapBuffer;
QString m_bitmapUniqueKey;
QMutex m_costumeMutex;
QMutex mutex;
bool m_imageChanged = false;
bool m_visible = true;
double m_width = 0;
double m_height = 0;
double m_x = 0;
double m_y = 0;
double m_z = 0;
Expand Down
23 changes: 2 additions & 21 deletions ScratchCPPGui/targetpainter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,11 @@ TargetPainter::~TargetPainter()
void TargetPainter::paint(QNanoPainter *painter)
{
m_target->lockCostume();
unsigned char *svgBitmap = m_target->svgBitmap();
double width = m_target->width();
double height = m_target->height();

if (svgBitmap) {
// TODO: Paint shapes from SVG directly instead of painting rasterized SVG
for (int i = 0; i < width * height; ++i) {
int pixelIndex = i * 4; // Each pixel has four values (R, G, B, A)

uchar red = svgBitmap[pixelIndex];
uchar green = svgBitmap[pixelIndex + 1];
uchar blue = svgBitmap[pixelIndex + 2];
uchar alpha = svgBitmap[pixelIndex + 3];

int x = i % static_cast<int>(width);
int y = i / static_cast<int>(width);

painter->setFillStyle(QNanoColor(red, green, blue, alpha));
painter->fillRect(x, y, 1, 1);
}
} else {
QNanoImage image = QNanoImage::fromCache(painter, m_target->bitmapBuffer(), m_target->bitmapUniqueKey());
painter->drawImage(image, 0, 0, width, height);
}
QNanoImage image = QNanoImage::fromCache(painter, m_target->bitmapBuffer(), m_target->bitmapUniqueKey());
painter->drawImage(image, 0, 0, width, height);

m_target->unlockCostume();
}
Expand Down
7 changes: 0 additions & 7 deletions test/mocks/renderedtargetmock.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,6 @@ class RenderedTargetMock : public IRenderedTarget
MOCK_METHOD(qreal, height, (), (const, override));
MOCK_METHOD(void, setHeight, (qreal), (override));

MOCK_METHOD(double, costumeWidth, (), (const, override));
MOCK_METHOD(void, setCostumeWidth, (double), (override));

MOCK_METHOD(double, costumeHeight, (), (const, override));
MOCK_METHOD(void, setCostumeHeight, (double), (override));

MOCK_METHOD(unsigned char *, svgBitmap, (), (const, override));
MOCK_METHOD(QBuffer *, bitmapBuffer, (), (override));
MOCK_METHOD(const QString &, bitmapUniqueKey, (), (const, override));

Expand Down
54 changes: 20 additions & 34 deletions test/renderedtarget/renderedtarget_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ TEST(RenderedTargetTest, LoadAndUpdateProperties)
stage.setInterface(&stageModel);
target.setStageModel(&stageModel);
Costume costume("", "", "");
std::string costumeData = readFileStr("image.png");
costume.setData(costumeData.size(), static_cast<void *>(costumeData.data()));
costume.setRotationCenterX(-23);
costume.setRotationCenterY(72);
EngineMock engine;
target.loadCostume(&costume);
target.setEngine(&engine);
target.setCostumeWidth(102.3);
target.setCostumeHeight(80.7);

target.setWidth(14.3);
target.setHeight(5.8);
Expand All @@ -61,8 +61,8 @@ TEST(RenderedTargetTest, LoadAndUpdateProperties)
ASSERT_EQ(target.transformOriginPoint(), QPointF(3.4, 9.7));

target.updateProperties();
ASSERT_EQ(target.width(), 102.3);
ASSERT_EQ(target.height(), 80.7);
ASSERT_EQ(target.width(), 4);
ASSERT_EQ(target.height(), 6);
ASSERT_EQ(target.x(), 283.5);
ASSERT_EQ(target.y(), 88.5);
ASSERT_EQ(target.z(), 0);
Expand Down Expand Up @@ -105,8 +105,8 @@ TEST(RenderedTargetTest, LoadAndUpdateProperties)
ASSERT_EQ(target.transformOriginPoint(), QPointF(3.4, 9.7));

target.updateProperties();
ASSERT_EQ(target.width(), 102.3);
ASSERT_EQ(target.height(), 80.7);
ASSERT_EQ(target.width(), 14.3);
ASSERT_EQ(target.height(), 5.8);
ASSERT_EQ(std::round(target.x() * 100) / 100, 220.62);
ASSERT_EQ(std::round(target.y() * 100) / 100, -49.09);
ASSERT_EQ(target.z(), 3);
Expand Down Expand Up @@ -163,17 +163,19 @@ TEST(RenderedTargetTest, LoadJpegCostume)
costume.setId("abc");

RenderedTarget target;
ASSERT_EQ(target.costumeWidth(), 0);
ASSERT_EQ(target.costumeHeight(), 0);

target.loadCostume(&costume);
ASSERT_EQ(target.costumeWidth(), 4 / 3.0);
ASSERT_EQ(target.costumeHeight(), 2);
ASSERT_FALSE(target.bitmapBuffer()->isOpen());
target.bitmapBuffer()->open(QBuffer::ReadOnly);
ASSERT_TRUE(target.bitmapBuffer()->readAll().toStdString().empty());
ASSERT_TRUE(target.bitmapUniqueKey().toStdString().empty());
target.bitmapBuffer()->close();

target.updateProperties();
ASSERT_FALSE(target.bitmapBuffer()->isOpen());
target.bitmapBuffer()->open(QBuffer::ReadOnly);
ASSERT_EQ(target.bitmapBuffer()->readAll().toStdString(), str);
ASSERT_EQ(target.bitmapUniqueKey().toStdString(), costume.id());
ASSERT_EQ(target.svgBitmap(), nullptr);
}

TEST(RenderedTargetTest, LoadPngCostume)
Expand All @@ -185,17 +187,19 @@ TEST(RenderedTargetTest, LoadPngCostume)
costume.setId("abc");

RenderedTarget target;
ASSERT_EQ(target.costumeWidth(), 0);
ASSERT_EQ(target.costumeHeight(), 0);

target.loadCostume(&costume);
ASSERT_EQ(target.costumeWidth(), 4 / 3.0);
ASSERT_EQ(target.costumeHeight(), 2);
ASSERT_FALSE(target.bitmapBuffer()->isOpen());
target.bitmapBuffer()->open(QBuffer::ReadOnly);
ASSERT_TRUE(target.bitmapBuffer()->readAll().toStdString().empty());
ASSERT_TRUE(target.bitmapUniqueKey().toStdString().empty());
target.bitmapBuffer()->close();

target.updateProperties();
ASSERT_FALSE(target.bitmapBuffer()->isOpen());
target.bitmapBuffer()->open(QBuffer::ReadOnly);
ASSERT_EQ(target.bitmapBuffer()->readAll().toStdString(), str);
ASSERT_EQ(target.bitmapUniqueKey().toStdString(), costume.id());
ASSERT_EQ(target.svgBitmap(), nullptr);
}

TEST(RenderedTargetTest, Engine)
Expand Down Expand Up @@ -246,21 +250,3 @@ TEST(RenderedTargetTest, ScratchTarget)
target.setSpriteModel(&spriteModel);
ASSERT_EQ(target.scratchTarget(), &sprite);
}

TEST(RenderedTargetTest, CostumeWidth)
{
RenderedTarget target;
ASSERT_EQ(target.costumeWidth(), 0);

target.setCostumeWidth(64.15);
ASSERT_EQ(target.costumeWidth(), 64.15);
}

TEST(RenderedTargetTest, CostumeHeight)
{
RenderedTarget target;
ASSERT_EQ(target.costumeHeight(), 0);

target.setCostumeHeight(46.48);
ASSERT_EQ(target.costumeHeight(), 46.48);
}
Loading

0 comments on commit 8bad035

Please sign in to comment.