Fix crash from new brush code when TPTMP is enabled

Okay yeah this is actually a well-camouflaged refactor.
This commit is contained in:
Tamás Bálint Misius 2023-02-28 14:55:57 +01:00
parent 114017d550
commit 369dadf81e
No known key found for this signature in database
GPG Key ID: 5B472A12F6ECA9F2
9 changed files with 80 additions and 172 deletions

View File

@ -3,10 +3,7 @@
#include "Misc.h" #include "Misc.h"
#include <cmath> #include <cmath>
BitmapBrush::BitmapBrush(ui::Point inputSize, unsigned char const *inputBitmap): BitmapBrush::BitmapBrush(ui::Point inputSize, unsigned char const *inputBitmap)
Brush(),
radius(inputSize / 2),
origSize(0, 0)
{ {
ui::Point newSize = inputSize; ui::Point newSize = inputSize;
@ -24,7 +21,11 @@ BitmapBrush::BitmapBrush(ui::Point inputSize, unsigned char const *inputBitmap):
origBitmap[x + y * newSize.X] = inputBitmap[x + y * inputSize.X]; origBitmap[x + y * newSize.X] = inputBitmap[x + y * inputSize.X];
} }
std::pair<ui::Point, std::unique_ptr<unsigned char []>> BitmapBrush::GenerateBitmap() const BitmapBrush::BitmapBrush(const BitmapBrush &other) : BitmapBrush(other.origSize, &other.origBitmap[0])
{
}
std::unique_ptr<unsigned char []> BitmapBrush::GenerateBitmap() const
{ {
ui::Point size = radius * 2 + 1; ui::Point size = radius * 2 + 1;
auto bitmap = std::make_unique<unsigned char []>(size.X * size.Y); auto bitmap = std::make_unique<unsigned char []>(size.X * size.Y);
@ -58,13 +59,10 @@ std::pair<ui::Point, std::unique_ptr<unsigned char []>> BitmapBrush::GenerateBit
} }
} }
} }
return std::make_pair(radius, std::move(bitmap)); return bitmap;
} }
std::unique_ptr<Brush> BitmapBrush::Clone() const std::unique_ptr<Brush> BitmapBrush::Clone() const
{ {
auto into = std::make_unique<BitmapBrush>(origSize, &origBitmap[0]); return std::make_unique<BitmapBrush>(*this);
into->radius = radius;
copyBitmaps(*into);
return into;
} }

View File

@ -1,36 +1,18 @@
/*
* BitmapBrush.h
*
* Created on: Nov 18, 2012
* Author: Simon Robertshaw
*/
#pragma once #pragma once
#include <vector> #include <vector>
#include "Brush.h" #include "Brush.h"
class BitmapBrush: public Brush class BitmapBrush: public Brush
{ {
ui::Point radius; ui::Point origSize{ 0, 0 };
ui::Point origSize;
// 2D array with coords [0, origSize.X) by [0, origSize.Y) // 2D array with coords [0, origSize.X) by [0, origSize.Y)
std::unique_ptr<unsigned char []> origBitmap; std::unique_ptr<unsigned char []> origBitmap;
public: public:
BitmapBrush(ui::Point size, unsigned char const *bitmap); BitmapBrush(ui::Point size, unsigned char const *bitmap);
BitmapBrush(const BitmapBrush &other);
virtual ~BitmapBrush() override = default; virtual ~BitmapBrush() override = default;
std::pair<ui::Point, std::unique_ptr<unsigned char []>> GenerateBitmap() const override; std::unique_ptr<unsigned char []> GenerateBitmap() const override;
ui::Point GetRadius() const override
{
return radius;
}
void SetRadius(ui::Point radius) override
{
this->radius = radius;
InvalidateCache();
}
std::unique_ptr<Brush> Clone() const override; std::unique_ptr<Brush> Clone() const override;
}; };

View File

@ -1,30 +1,34 @@
#include "Brush.h" #include "Brush.h"
#include "graphics/Renderer.h" #include "graphics/Renderer.h"
void Brush::InvalidateCache() Brush::Brush(const Brush &other)
{ {
size = ui::Point(0, 0); radius = other.radius;
bitmap.reset(); auto size = GetSize();
outline.reset(); if (other.bitmap)
{
bitmap = std::make_unique<unsigned char []>(size.X * size.Y);
std::copy(&other.bitmap[0], &other.bitmap[0] + size.X * size.Y, &bitmap[0]);
}
if (other.outline)
{
outline = std::make_unique<unsigned char []>(size.X * size.Y);
std::copy(&other.outline[0], &other.outline[0] + size.X * size.Y, &outline[0]);
}
} }
void Brush::ensureBitmap() const void Brush::InitBitmap()
{ {
if (bitmap) bitmap = GenerateBitmap();
return;
auto pair = GenerateBitmap();
size = pair.first;
bitmap = std::move(pair.second);
} }
void Brush::ensureOutline() const void Brush::InitOutline()
{ {
if (outline) InitBitmap();
return; ui::Point bounds = GetSize();
ensureBitmap();
ui::Point bounds = size * 2 + 1;
outline = std::make_unique<unsigned char []>(bounds.X * bounds.Y); outline = std::make_unique<unsigned char []>(bounds.X * bounds.Y);
for (int j = 0; j < bounds.Y; j++) for (int j = 0; j < bounds.Y; j++)
{
for (int i = 0; i < bounds.X; i++) for (int i = 0; i < bounds.X; i++)
{ {
bool value = false; bool value = false;
@ -43,6 +47,13 @@ void Brush::ensureOutline() const
} }
outline[i + j * bounds.X] = value ? 0xFF : 0; outline[i + j * bounds.X] = value ? 0xFF : 0;
} }
}
}
void Brush::SetRadius(ui::Point newRadius)
{
radius = newRadius;
InitOutline();
} }
void Brush::AdjustSize(int delta, bool logarithmic, bool keepX, bool keepY) void Brush::AdjustSize(int delta, bool logarithmic, bool keepX, bool keepY)
@ -73,22 +84,6 @@ void Brush::AdjustSize(int delta, bool logarithmic, bool keepX, bool keepY)
SetRadius(newSize); SetRadius(newSize);
} }
void Brush::copyBitmaps(Brush &into) const
{
into.size = size;
size_t bounds = (2 * size.X + 1) * (2 * size.Y + 1);
if (bitmap)
{
into.bitmap = std::make_unique<unsigned char []>(bounds);
std::copy(&bitmap[0], &bitmap[bounds], &into.bitmap[0]);
}
if (outline)
{
into.outline = std::make_unique<unsigned char []>(bounds);
std::copy(&outline[0], &outline[bounds], &into.outline[0]);
}
}
void Brush::RenderRect(Renderer * ren, ui::Point position1, ui::Point position2) const void Brush::RenderRect(Renderer * ren, ui::Point position1, ui::Point position2) const
{ {
int width, height; int width, height;
@ -123,8 +118,7 @@ void Brush::RenderLine(Renderer * ren, ui::Point position1, ui::Point position2)
void Brush::RenderPoint(Renderer * ren, ui::Point position) const void Brush::RenderPoint(Renderer * ren, ui::Point position) const
{ {
ensureOutline(); ren->xor_bitmap(&outline[0], position.X - radius.X, position.Y - radius.Y, 2 * radius.X + 1, 2 * radius.Y + 1);
ren->xor_bitmap(&outline[0], position.X - size.X, position.Y - size.Y, 2 * size.X + 1, 2 * size.Y + 1);
} }
void Brush::RenderFill(Renderer * ren, ui::Point position) const void Brush::RenderFill(Renderer * ren, ui::Point position) const

View File

@ -6,13 +6,12 @@ class Renderer;
class Brush class Brush
{ {
private: private:
ui::Point mutable size; // 2D arrays indexed by coordinates from [-radius.X, radius.X] by [-radius.Y, radius.Y]
// 2D arrays indexed by coordinates from [-size.X, size.X] by [-size.Y, size.Y] std::unique_ptr<unsigned char []> bitmap;
std::unique_ptr<unsigned char []> mutable bitmap; std::unique_ptr<unsigned char []> outline;
std::unique_ptr<unsigned char []> mutable outline;
void ensureBitmap() const; void InitBitmap();
void ensureOutline() const; void InitOutline();
struct iterator struct iterator
{ {
@ -21,14 +20,15 @@ private:
iterator &operator++() iterator &operator++()
{ {
auto radius = parent.GetRadius();
do do
{ {
if (++x > parent.size.X) if (++x > radius.X)
{ {
--y; --y;
x = -parent.size.X; x = -radius.X;
} }
} while (y >= -parent.size.Y && !parent.bitmap[x + parent.size.X + (y + parent.size.Y) * (2 * parent.size.X + 1)]); } while (y >= -radius.Y && !parent.bitmap[x + radius.X + (y + radius.Y) * (2 * radius.X + 1)]);
return *this; return *this;
} }
@ -50,42 +50,42 @@ private:
}; };
protected: protected:
Brush(): ui::Point radius{ 0, 0 };
size(0, 0),
bitmap(),
outline()
{
}
void InvalidateCache(); virtual std::unique_ptr<unsigned char []> GenerateBitmap() const = 0;
virtual std::pair<ui::Point, std::unique_ptr<unsigned char []>> GenerateBitmap() const = 0;
void copyBitmaps(Brush &into) const;
public: public:
Brush() = default;
Brush(const Brush &other);
virtual ~Brush() = default; virtual ~Brush() = default;
virtual ui::Point GetRadius() const = 0;
virtual void SetRadius(ui::Point radius) = 0;
virtual void AdjustSize(int delta, bool logarithmic, bool keepX, bool keepY); virtual void AdjustSize(int delta, bool logarithmic, bool keepX, bool keepY);
virtual std::unique_ptr<Brush> Clone() const = 0; virtual std::unique_ptr<Brush> Clone() const = 0;
ui::Point GetSize() const ui::Point GetSize() const
{ {
return size; return radius * 2 + 1;
}
ui::Point GetRadius() const
{
return radius;
} }
iterator begin() const iterator begin() const
{ {
// bottom to top is the preferred order for Simulation::CreateParts // bottom to top is the preferred order for Simulation::CreateParts
return ++iterator{*this, size.X, size.Y + 1}; return ++iterator{*this, radius.X, radius.Y + 1};
} }
iterator end() const iterator end() const
{ {
return iterator{*this, -size.X, -size.Y - 1}; return iterator{*this, -radius.X, -radius.Y - 1};
} }
void RenderRect(Renderer * ren, ui::Point position1, ui::Point position2) const; void RenderRect(Renderer * ren, ui::Point position1, ui::Point position2) const;
void RenderLine(Renderer * ren, ui::Point position1, ui::Point position2) const; void RenderLine(Renderer * ren, ui::Point position1, ui::Point position2) const;
void RenderPoint(Renderer * ren, ui::Point position) const; void RenderPoint(Renderer * ren, ui::Point position) const;
void RenderFill(Renderer * ren, ui::Point position) const; void RenderFill(Renderer * ren, ui::Point position) const;
void SetRadius(ui::Point newRadius);
}; };

View File

@ -4,19 +4,16 @@
class EllipseBrush: public Brush class EllipseBrush: public Brush
{ {
ui::Point radius;
bool perfectCircle; bool perfectCircle;
public: public:
EllipseBrush(ui::Point radius, bool perfectCircle = true): EllipseBrush(bool newPerfectCircle) :
Brush(), perfectCircle(newPerfectCircle)
radius(radius),
perfectCircle(perfectCircle)
{ {
} }
virtual ~EllipseBrush() override = default; virtual ~EllipseBrush() override = default;
std::pair<ui::Point, std::unique_ptr<unsigned char []>> GenerateBitmap() const override std::unique_ptr<unsigned char []> GenerateBitmap() const override
{ {
ui::Point size = radius * 2 + 1; ui::Point size = radius * 2 + 1;
auto bitmap = std::make_unique<unsigned char []>(size.X * size.Y); auto bitmap = std::make_unique<unsigned char []>(size.X * size.Y);
@ -64,24 +61,11 @@ public:
bitmap[size.X/2] = 255; bitmap[size.X/2] = 255;
bitmap[size.X*size.Y-size.X/2-1] = 255; bitmap[size.X*size.Y-size.X/2-1] = 255;
} }
return std::make_pair(radius, std::move(bitmap)); return bitmap;
}
ui::Point GetRadius() const override
{
return radius;
}
void SetRadius(ui::Point radius) override
{
this->radius = radius;
InvalidateCache();
} }
std::unique_ptr<Brush> Clone() const override std::unique_ptr<Brush> Clone() const override
{ {
auto into = std::make_unique<EllipseBrush>(radius, perfectCircle); return std::make_unique<EllipseBrush>(*this);
copyBitmaps(*into);
return into;
} }
}; };

View File

@ -462,14 +462,14 @@ void GameModel::BuildFavoritesMenu()
void GameModel::BuildBrushList() void GameModel::BuildBrushList()
{ {
std::optional<ui::Point> radius; ui::Point radius{ 4, 4 };
if (brushList.size()) if (brushList.size())
radius = brushList[currentBrush]->GetRadius(); radius = brushList[currentBrush]->GetRadius();
brushList.clear(); brushList.clear();
brushList.push_back(std::make_unique<EllipseBrush>(ui::Point(4, 4), perfectCircle)); brushList.push_back(std::make_unique<EllipseBrush>(perfectCircle));
brushList.push_back(std::make_unique<RectangleBrush>(ui::Point(4, 4))); brushList.push_back(std::make_unique<RectangleBrush>());
brushList.push_back(std::make_unique<TriangleBrush>(ui::Point(4, 4))); brushList.push_back(std::make_unique<TriangleBrush>());
//Load more from brushes folder //Load more from brushes folder
for (ByteString brushFile : Platform::DirectorySearch(BRUSH_DIR, "", { ".ptb" })) for (ByteString brushFile : Platform::DirectorySearch(BRUSH_DIR, "", { ".ptb" }))
@ -489,8 +489,7 @@ void GameModel::BuildBrushList()
brushList.push_back(std::make_unique<BitmapBrush>(ui::Point(dimension, dimension), reinterpret_cast<unsigned char const *>(brushData.data()))); brushList.push_back(std::make_unique<BitmapBrush>(ui::Point(dimension, dimension), reinterpret_cast<unsigned char const *>(brushData.data())));
} }
if (radius && (size_t)currentBrush < brushList.size()) brushList[currentBrush]->SetRadius(radius);
brushList[currentBrush]->SetRadius(*radius);
notifyBrushChanged(); notifyBrushChanged();
} }

View File

@ -3,40 +3,19 @@
class RectangleBrush: public Brush class RectangleBrush: public Brush
{ {
ui::Point radius;
public: public:
RectangleBrush(ui::Point radius):
Brush(),
radius(radius)
{
}
virtual ~RectangleBrush() override = default; virtual ~RectangleBrush() override = default;
std::pair<ui::Point, std::unique_ptr<unsigned char []>> GenerateBitmap() const override std::unique_ptr<unsigned char []> GenerateBitmap() const override
{ {
ui::Point size = radius * 2 + 1; auto size = GetSize();
auto bitmap = std::make_unique<unsigned char []>(size.X * size.Y); auto bitmap = std::make_unique<unsigned char []>(size.X * size.Y);
std::fill(&bitmap[0], &bitmap[size.X * size.Y], 0xFF); std::fill(&bitmap[0], &bitmap[0] + size.X * size.Y, 0xFF);
return std::make_pair(radius, std::move(bitmap)); return bitmap;
}
ui::Point GetRadius() const override
{
return radius;
}
void SetRadius(ui::Point radius) override
{
this->radius = radius;
InvalidateCache();
} }
std::unique_ptr<Brush> Clone() const override std::unique_ptr<Brush> Clone() const override
{ {
auto into = std::make_unique<RectangleBrush>(radius); return std::make_unique<RectangleBrush>(*this);
copyBitmaps(*into);
return into;
} }
}; };

View File

@ -1,28 +1,13 @@
/*
* TriangleBrush.h
*
* Created on: Jan 26, 2012
* Author: Savely Skresanov
*/
#pragma once #pragma once
#include "Brush.h" #include "Brush.h"
#include <cmath> #include <cmath>
class TriangleBrush: public Brush class TriangleBrush: public Brush
{ {
ui::Point radius;
public: public:
TriangleBrush(ui::Point radius):
Brush(),
radius(radius)
{
}
virtual ~TriangleBrush() override = default; virtual ~TriangleBrush() override = default;
std::pair<ui::Point, std::unique_ptr<unsigned char []>> GenerateBitmap() const override std::unique_ptr<unsigned char []> GenerateBitmap() const override
{ {
ui::Point size = radius * 2 + 1; ui::Point size = radius * 2 + 1;
auto bitmap = std::make_unique<unsigned char []>(size.X * size.Y); auto bitmap = std::make_unique<unsigned char []>(size.X * size.Y);
@ -43,24 +28,11 @@ public:
} }
} }
} }
return std::make_pair(radius, std::move(bitmap)); return bitmap;
}
ui::Point GetRadius() const override
{
return radius;
}
void SetRadius(ui::Point radius) override
{
this->radius = radius;
InvalidateCache();
} }
std::unique_ptr<Brush> Clone() const override std::unique_ptr<Brush> Clone() const override
{ {
auto into = std::make_unique<RectangleBrush>(radius); return std::make_unique<TriangleBrush>(*this);
copyBitmaps(*into);
return into;
} }
}; };

View File

@ -2202,7 +2202,7 @@ int LuaScriptInterface::simulation_brush(lua_State * l)
lua_pushnumber(l, positionX); lua_pushnumber(l, positionX);
lua_pushnumber(l, positionY); lua_pushnumber(l, positionY);
std::vector<ui::Point> points; std::vector<ui::Point> points;
std::copy(brush->begin(), brush->end(), std::back_inserter(points)); std::copy(newBrush->begin(), newBrush->end(), std::back_inserter(points));
lua_pushnumber(l, 0); // index lua_pushnumber(l, 0); // index
lua_pushnumber(l, points.size()); lua_pushnumber(l, points.size());
auto points_ud = reinterpret_cast<ui::Point *>(lua_newuserdata(l, points.size() * sizeof(ui::Point))); auto points_ud = reinterpret_cast<ui::Point *>(lua_newuserdata(l, points.size() * sizeof(ui::Point)));