diff --git a/src/gui/game/BitmapBrush.cpp b/src/gui/game/BitmapBrush.cpp index 0ff418d84..b3aa735ca 100644 --- a/src/gui/game/BitmapBrush.cpp +++ b/src/gui/game/BitmapBrush.cpp @@ -22,7 +22,7 @@ BitmapBrush::BitmapBrush(ui::Point inputSize, unsigned char const *inputBitmap): for (int y = 0; y < inputSize.Y; y++) for (int x = 0; x < inputSize.X; x++) origBitmap[x + y * newSize.X] = inputBitmap[x + y * inputSize.X]; -}; +} std::pair> BitmapBrush::GenerateBitmap() const { @@ -60,3 +60,11 @@ std::pair> BitmapBrush::GenerateBit } return std::make_pair(radius, std::move(bitmap)); } + +std::unique_ptr BitmapBrush::Clone() const +{ + auto into = std::make_unique(origSize, &origBitmap[0]); + into->radius = radius; + copyBitmaps(*into); + return into; +} diff --git a/src/gui/game/BitmapBrush.h b/src/gui/game/BitmapBrush.h index 1eece024e..36bc4041d 100644 --- a/src/gui/game/BitmapBrush.h +++ b/src/gui/game/BitmapBrush.h @@ -31,4 +31,6 @@ public: this->radius = radius; InvalidateCache(); } + + std::unique_ptr Clone() const override; }; diff --git a/src/gui/game/Brush.cpp b/src/gui/game/Brush.cpp index 8ab47461b..ef1a6b16c 100644 --- a/src/gui/game/Brush.cpp +++ b/src/gui/game/Brush.cpp @@ -73,6 +73,22 @@ void Brush::AdjustSize(int delta, bool logarithmic, bool keepX, bool keepY) 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(bounds); + std::copy(&bitmap[0], &bitmap[bounds], &into.bitmap[0]); + } + if (outline) + { + into.outline = std::make_unique(bounds); + std::copy(&outline[0], &outline[bounds], &into.outline[0]); + } +} + void Brush::RenderRect(Renderer * ren, ui::Point position1, ui::Point position2) const { int width, height; diff --git a/src/gui/game/Brush.h b/src/gui/game/Brush.h index 86f10cfec..6c5b281e0 100644 --- a/src/gui/game/Brush.h +++ b/src/gui/game/Brush.h @@ -42,7 +42,6 @@ private: return x != other.x || y != other.y; } - public: using difference_type = void; using value_type = ui::Point; using pointer = void; @@ -60,12 +59,14 @@ protected: void InvalidateCache(); virtual std::pair> GenerateBitmap() const = 0; + void copyBitmaps(Brush &into) const; public: 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 std::unique_ptr Clone() const = 0; ui::Point GetSize() const { diff --git a/src/gui/game/EllipseBrush.h b/src/gui/game/EllipseBrush.h index 9b4633aac..99e7e06af 100644 --- a/src/gui/game/EllipseBrush.h +++ b/src/gui/game/EllipseBrush.h @@ -77,4 +77,11 @@ public: this->radius = radius; InvalidateCache(); } + + std::unique_ptr Clone() const override + { + auto into = std::make_unique(radius, perfectCircle); + copyBitmaps(*into); + return into; + } }; diff --git a/src/gui/game/GameModel.cpp b/src/gui/game/GameModel.cpp index 5ff5e9ca5..ddb2e15ba 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -472,19 +472,18 @@ void GameModel::BuildBrushList() brushList.push_back(std::make_unique(ui::Point(4, 4))); //Load more from brushes folder - std::vector brushFiles = Platform::DirectorySearch(BRUSH_DIR, "", { ".ptb" }); - for (size_t i = 0; i < brushFiles.size(); i++) + for (ByteString brushFile : Platform::DirectorySearch(BRUSH_DIR, "", { ".ptb" })) { std::vector brushData; - if (!Platform::ReadFile(brushData, ByteString::Build(BRUSH_DIR, PATH_SEP_CHAR, brushFiles[i]))) + if (!Platform::ReadFile(brushData, ByteString::Build(BRUSH_DIR, PATH_SEP_CHAR, brushFile))) { - std::cout << "Brushes: Skipping " << brushFiles[i] << ". Could not open" << std::endl; + std::cout << "Brushes: Skipping " << brushFile << ". Could not open" << std::endl; continue; } - auto dimension = size_t(std::sqrt(float(brushData.size()))); + auto dimension = size_t(std::sqrt(brushData.size())); if (dimension * dimension != brushData.size()) { - std::cout << "Brushes: Skipping " << brushFiles[i] << ". Invalid bitmap size" << std::endl; + std::cout << "Brushes: Skipping " << brushFile << ". Invalid bitmap size" << std::endl; continue; } brushList.push_back(std::make_unique(ui::Point(dimension, dimension), reinterpret_cast(brushData.data()))); @@ -812,9 +811,12 @@ Brush &GameModel::GetBrush() return *brushList[currentBrush]; } -std::vector> const &GameModel::GetBrushList() +Brush *GameModel::GetBrushByID(int i) { - return brushList; + if (i >= 0 && i < (int)brushList.size()) + return brushList[i].get(); + else + return nullptr; } int GameModel::GetBrushID() diff --git a/src/gui/game/GameModel.h b/src/gui/game/GameModel.h index d06a23e5a..17a3135e1 100644 --- a/src/gui/game/GameModel.h +++ b/src/gui/game/GameModel.h @@ -176,7 +176,7 @@ public: std::vector GetUnlistedTools(); Brush &GetBrush(); - std::vector> const &GetBrushList(); + Brush *GetBrushByID(int i); int GetBrushID(); void SetBrushID(int i); diff --git a/src/gui/game/RectangleBrush.h b/src/gui/game/RectangleBrush.h index 5f26e1ac3..309e1db8e 100644 --- a/src/gui/game/RectangleBrush.h +++ b/src/gui/game/RectangleBrush.h @@ -32,4 +32,11 @@ public: this->radius = radius; InvalidateCache(); } + + std::unique_ptr Clone() const override + { + auto into = std::make_unique(radius); + copyBitmaps(*into); + return into; + } }; diff --git a/src/gui/game/TriangleBrush.h b/src/gui/game/TriangleBrush.h index 14056952a..771c71eaf 100644 --- a/src/gui/game/TriangleBrush.h +++ b/src/gui/game/TriangleBrush.h @@ -56,4 +56,11 @@ public: this->radius = radius; InvalidateCache(); } + + std::unique_ptr Clone() const override + { + auto into = std::make_unique(radius); + copyBitmaps(*into); + return into; + } }; diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index de66d43cb..49ac36428 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -1469,17 +1469,16 @@ int LuaScriptInterface::simulation_createParts(lua_State * l) int rx = luaL_optint(l,3,5); int ry = luaL_optint(l,4,5); int c = luaL_optint(l,5,luacon_model->GetActiveTool(0)->GetToolID()); - int brush = luaL_optint(l,6,CIRCLE_BRUSH); + int brushID = luaL_optint(l,6,CIRCLE_BRUSH); int flags = luaL_optint(l,7,luacon_sim->replaceModeFlags); - auto &brushList = luacon_model->GetBrushList(); - if (brush < 0 || brush >= (int)brushList.size()) - return luaL_error(l, "Invalid brush id '%d'", brush); - ui::Point tempRadius = brushList[brush]->GetRadius(); - brushList[brush]->SetRadius(ui::Point(rx, ry)); + Brush *brush = luacon_model->GetBrushByID(brushID); + if (!brush) + return luaL_error(l, "Invalid brush id '%d'", brushID); + auto newBrush = brush->Clone(); + newBrush->SetRadius(ui::Point(rx, ry)); - int ret = luacon_sim->CreateParts(x, y, c, *brushList[brush], flags); - brushList[brush]->SetRadius(tempRadius); + int ret = luacon_sim->CreateParts(x, y, c, *newBrush, flags); lua_pushinteger(l, ret); return 1; } @@ -1493,17 +1492,16 @@ int LuaScriptInterface::simulation_createLine(lua_State * l) int rx = luaL_optint(l,5,5); int ry = luaL_optint(l,6,5); int c = luaL_optint(l,7,luacon_model->GetActiveTool(0)->GetToolID()); - int brush = luaL_optint(l,8,CIRCLE_BRUSH); + int brushID = luaL_optint(l,8,CIRCLE_BRUSH); int flags = luaL_optint(l,9,luacon_sim->replaceModeFlags); - auto &brushList = luacon_model->GetBrushList(); - if (brush < 0 || brush >= (int)brushList.size()) - return luaL_error(l, "Invalid brush id '%d'", brush); - ui::Point tempRadius = brushList[brush]->GetRadius(); - brushList[brush]->SetRadius(ui::Point(rx, ry)); + Brush *brush = luacon_model->GetBrushByID(brushID); + if (!brush) + return luaL_error(l, "Invalid brush id '%d'", brushID); + auto newBrush = brush->Clone(); + newBrush->SetRadius(ui::Point(rx, ry)); - luacon_sim->CreateLine(x1, y1, x2, y2, c, *brushList[brush], flags); - brushList[brush]->SetRadius(tempRadius); + luacon_sim->CreateLine(x1, y1, x2, y2, c, *newBrush, flags); return 0; } @@ -1527,10 +1525,10 @@ int LuaScriptInterface::simulation_floodParts(lua_State * l) int c = luaL_optint(l,3,luacon_model->GetActiveTool(0)->GetToolID()); int cm = luaL_optint(l,4,-1); int flags = luaL_optint(l,5,luacon_sim->replaceModeFlags); - + if (x < 0 || x >= XRES || y < 0 || y >= YRES) return luaL_error(l, "coordinates out of range (%d,%d)", x, y); - + int ret = luacon_sim->FloodParts(x, y, c, cm, flags); lua_pushinteger(l, ret); return 1; @@ -1617,7 +1615,7 @@ int LuaScriptInterface::simulation_toolBrush(lua_State * l) int rx = luaL_optint(l,3,5); int ry = luaL_optint(l,4,5); int tool = luaL_optint(l,5,0); - int brush = luaL_optint(l,6,CIRCLE_BRUSH); + int brushID = luaL_optint(l,6,CIRCLE_BRUSH); float strength = luaL_optnumber(l,7,1.0f); if (tool == (int)luacon_sim->tools.size()) { @@ -1627,14 +1625,13 @@ int LuaScriptInterface::simulation_toolBrush(lua_State * l) else if (tool < 0 || tool > (int)luacon_sim->tools.size()) return luaL_error(l, "Invalid tool id '%d'", tool); - auto &brushList = luacon_model->GetBrushList(); - if (brush < 0 || brush >= (int)brushList.size()) - return luaL_error(l, "Invalid brush id '%d'", brush); - ui::Point tempRadius = brushList[brush]->GetRadius(); - brushList[brush]->SetRadius(ui::Point(rx, ry)); + Brush *brush = luacon_model->GetBrushByID(brushID); + if (!brush) + return luaL_error(l, "Invalid brush id '%d'", brushID); + auto newBrush = brush->Clone(); + newBrush->SetRadius(ui::Point(rx, ry)); - int ret = luacon_sim->ToolBrush(x, y, tool, *brushList[brush], strength); - brushList[brush]->SetRadius(tempRadius); + int ret = luacon_sim->ToolBrush(x, y, tool, *newBrush, strength); lua_pushinteger(l, ret); return 1; } @@ -1648,31 +1645,30 @@ int LuaScriptInterface::simulation_toolLine(lua_State * l) int rx = luaL_optint(l,5,5); int ry = luaL_optint(l,6,5); int tool = luaL_optint(l,7,0); - int brush = luaL_optint(l,8,CIRCLE_BRUSH); + int brushID = luaL_optint(l,8,CIRCLE_BRUSH); float strength = luaL_optnumber(l,9,1.0f); - + if (x1 < 0 || x2 < 0 || x1 >= XRES || x2 >= XRES || y1 < 0 || y2 < 0 || y1 >= YRES || y2 >= YRES) return luaL_error(l, "coordinates out of range (%d,%d),(%d,%d)", x1, y1, x2, y2); if (tool < 0 || tool >= (int)luacon_sim->tools.size()+1) return luaL_error(l, "Invalid tool id '%d'", tool); - auto &brushList = luacon_model->GetBrushList(); - if (brush < 0 || brush >= (int)brushList.size()) - return luaL_error(l, "Invalid brush id '%d'", brush); - ui::Point tempRadius = brushList[brush]->GetRadius(); - brushList[brush]->SetRadius(ui::Point(rx, ry)); + Brush *brush = luacon_model->GetBrushByID(brushID); + if (!brush) + return luaL_error(l, "Invalid brush id '%d'", brushID); + auto newBrush = brush->Clone(); + newBrush->SetRadius(ui::Point(rx, ry)); if (tool == (int)luacon_sim->tools.size()) { Tool *windTool = luacon_model->GetToolFromIdentifier("DEFAULT_UI_WIND"); float oldStrength = windTool->GetStrength(); windTool->SetStrength(strength); - windTool->DrawLine(luacon_sim, *brushList[brush], ui::Point(x1, y1), ui::Point(x2, y2)); + windTool->DrawLine(luacon_sim, *newBrush, ui::Point(x1, y1), ui::Point(x2, y2)); windTool->SetStrength(oldStrength); } else - luacon_sim->ToolLine(x1, y1, x2, y2, tool, *brushList[brush], strength); - brushList[brush]->SetRadius(tempRadius); + luacon_sim->ToolLine(x1, y1, x2, y2, tool, *newBrush, strength); return 0; } @@ -1709,16 +1705,15 @@ int LuaScriptInterface::simulation_decoBrush(lua_State * l) int b = luaL_optint(l,7,255); int a = luaL_optint(l,8,255); int tool = luaL_optint(l,9,DECO_DRAW); - int brush = luaL_optint(l,10,CIRCLE_BRUSH); + int brushID = luaL_optint(l,10,CIRCLE_BRUSH); - auto &brushList = luacon_model->GetBrushList(); - if (brush < 0 || brush >= (int)brushList.size()) - return luaL_error(l, "Invalid brush id '%d'", brush); - ui::Point tempRadius = brushList[brush]->GetRadius(); - brushList[brush]->SetRadius(ui::Point(rx, ry)); + Brush *brush = luacon_model->GetBrushByID(brushID); + if (!brush) + return luaL_error(l, "Invalid brush id '%d'", brushID); + auto newBrush = brush->Clone(); + newBrush->SetRadius(ui::Point(rx, ry)); - luacon_sim->ApplyDecorationPoint(x, y, r, g, b, a, tool, *brushList[brush]); - brushList[brush]->SetRadius(tempRadius); + luacon_sim->ApplyDecorationPoint(x, y, r, g, b, a, tool, *newBrush); return 0; } @@ -1735,19 +1730,18 @@ int LuaScriptInterface::simulation_decoLine(lua_State * l) int b = luaL_optint(l,9,255); int a = luaL_optint(l,10,255); int tool = luaL_optint(l,11,DECO_DRAW); - int brush = luaL_optint(l,12,CIRCLE_BRUSH); + int brushID = luaL_optint(l,12,CIRCLE_BRUSH); if (x1 < 0 || x2 < 0 || x1 >= XRES || x2 >= XRES || y1 < 0 || y2 < 0 || y1 >= YRES || y2 >= YRES) return luaL_error(l, "coordinates out of range (%d,%d),(%d,%d)", x1, y1, x2, y2); - auto &brushList = luacon_model->GetBrushList(); - if (brush < 0 || brush >= (int)brushList.size()) - return luaL_error(l, "Invalid brush id '%d'", brush); - ui::Point tempRadius = brushList[brush]->GetRadius(); - brushList[brush]->SetRadius(ui::Point(rx, ry)); + Brush *brush = luacon_model->GetBrushByID(brushID); + if (!brush) + return luaL_error(l, "Invalid brush id '%d'", brushID); + auto newBrush = brush->Clone(); + newBrush->SetRadius(ui::Point(rx, ry)); - luacon_sim->ApplyDecorationLine(x1, y1, x2, y2, r, g, b, a, tool, *brushList[brush]); - brushList[brush]->SetRadius(tempRadius); + luacon_sim->ApplyDecorationLine(x1, y1, x2, y2, r, g, b, a, tool, *newBrush); return 0; } @@ -2200,22 +2194,19 @@ int LuaScriptInterface::simulation_brush(lua_State * l) } int brushID = luaL_optint(l, 5, luacon_model->GetBrushID()); - auto &brushList = luacon_model->GetBrushList(); - if (brushID < 0 || brushID >= (int)brushList.size()) + Brush *brush = luacon_model->GetBrushByID(brushID); + if (!brush) return luaL_error(l, "Invalid brush id '%d'", brushID); - - Brush &brush = *brushList[brushID]; - ui::Point tempRadius = brush.GetRadius(); - brush.SetRadius(ui::Point(brushradiusX, brushradiusY)); + auto newBrush = brush->Clone(); + newBrush->SetRadius(ui::Point(brushradiusX, brushradiusY)); lua_pushnumber(l, positionX); lua_pushnumber(l, positionY); std::vector points; - std::copy(brush.begin(), brush.end(), std::back_inserter(points)); + std::copy(brush->begin(), brush->end(), std::back_inserter(points)); lua_pushnumber(l, 0); // index lua_pushnumber(l, points.size()); auto points_ud = reinterpret_cast(lua_newuserdata(l, points.size() * sizeof(ui::Point))); std::copy(points.begin(), points.end(), points_ud); - brush.SetRadius(tempRadius); lua_pushcclosure(l, BrushClosure, 5); return 1;