/
dieoska
/
ddnet
Обзор
Документация
Войти
/
dieoska
/
ddnet
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/game/editor/quadart.cpp
223 строки
7 KB
Robert Müller
Add `CEditor::Map` getter, make `CEditor::m_Map` private
20 дек 2025, 14:25
20 дек 2025, 14:25
6eee3c6
Код
Авторство
О чём код?
#include "quadart.h" #include "editor.h" #include "editor_actions.h" #include <game/editor/mapitems/image.h> #include <algorithm> #include <array> #include <vector> CQuadArt::CQuadArt(CQuadArtParameters Parameters, CImageInfo &&Img) : m_Parameters(Parameters), m_Img(std::move(Img)) { m_vVisitedPixels.resize(m_Img.m_Height * m_Img.m_Width, false); } CQuadArt::~CQuadArt() { m_Img.Free(); } ivec2 CQuadArt::GetOptimizedQuadSize(const ColorRGBA &Pixel, const ivec2 &Pos) { ivec2 OptimizedSize(0, 0); ivec2 Size(0, 0); size_t ImgPixelSize = m_Parameters.m_ImagePixelSize; while(IsPixelOptimizable(Pos + Size, Pixel)) { while(IsPixelOptimizable(Pos + Size, Pixel) && (!OptimizedSize.y || Size.y < OptimizedSize.y)) Size.y += ImgPixelSize; if(!OptimizedSize.y || Size.y < OptimizedSize.y) OptimizedSize.y = Size.y; Size.y = 0; Size.x += ImgPixelSize; OptimizedSize.x = Size.x; } MarkPixelAsVisited(Pos, OptimizedSize); Size = OptimizedSize / ImgPixelSize; return Size; } size_t CQuadArt::FindSuperPixelSize(const ColorRGBA &Pixel, const ivec2 &Pos, const size_t CurrentSize) { ivec2 Size(CurrentSize, CurrentSize); if(Pos.x + CurrentSize >= m_Img.m_Width || Pos.y + CurrentSize >= m_Img.m_Height) { MarkPixelAsVisited(Pos, Size); return CurrentSize; } for(int i = 0; i < 2; i++) { for(size_t j = 0; j < CurrentSize + 1; j++) { ivec2 CurrentPos = Pos; CurrentPos.x += i == 0 ? j : CurrentSize; CurrentPos.y += i == 0 ? CurrentSize : j; ColorRGBA CheckPixel = GetPixelClamped(CurrentPos); if(CurrentPos.x >= (int)m_Img.m_Width || CurrentPos.y >= (int)m_Img.m_Height || Pixel != CheckPixel) { MarkPixelAsVisited(Pos, Size); return CurrentSize; } } } return FindSuperPixelSize(Pixel, Pos, CurrentSize + 1); } ColorRGBA CQuadArt::GetPixelClamped(const ivec2 &Pos) const { size_t x = std::clamp<size_t>(Pos.x, 0, m_Img.m_Width - 1); size_t y = std::clamp<size_t>(Pos.y, 0, m_Img.m_Height - 1); return m_Img.PixelColor(x, y); } bool CQuadArt::IsPixelOptimizable(const ivec2 &Pos, const ColorRGBA &Pixel) const { if(Pos.x >= (int)m_Img.m_Width || Pos.y >= (int)m_Img.m_Height) return false; ColorRGBA CheckPixel = m_Img.PixelColor(Pos.x, Pos.y); return !m_vVisitedPixels[Pos.x + Pos.y * m_Img.m_Width] && CheckPixel.a > 0 && Pixel == CheckPixel; } void CQuadArt::MarkPixelAsVisited(const ivec2 &Pos, const ivec2 &Size) { for(int y = Pos.y; y < Pos.y + Size.y; y++) { for(int x = Pos.x; x < Pos.x + Size.x; x++) { size_t Index = (size_t)(x + y * m_Img.m_Width); if(Index < m_vVisitedPixels.size()) m_vVisitedPixels[Index] = true; } } } CQuad CQuadArt::CreateNewQuad(const vec2 &Pos, const ivec2 &Size, const ColorRGBA &Color) const { CQuad Quad; Quad.m_PosEnv = Quad.m_ColorEnv = -1; Quad.m_PosEnvOffset = Quad.m_ColorEnvOffset = 0; int x = f2fx(Pos.x), y = f2fx(Pos.y), w = f2fx(Size.x / 2.f), h = f2fx(Size.y / 2.f); for(int i = 0; i < 2; ++i) { Quad.m_aPoints[i].y = y - h; Quad.m_aPoints[i + 2].y = y + h; Quad.m_aPoints[i * 2].x = x - w; Quad.m_aPoints[i * 2 + 1].x = x + w; } for(auto &QuadColor : Quad.m_aColors) { QuadColor.r = (int)(Color.r * 255); QuadColor.g = (int)(Color.g * 255); QuadColor.b = (int)(Color.b * 255); QuadColor.a = (int)(Color.a * 255); } Quad.m_aPoints[4].x = m_Parameters.m_Centralize ? i2fx(-1) : x; Quad.m_aPoints[4].y = m_Parameters.m_Centralize ? i2fx(-1) : y; for(int i = 0; i < 4; ++i) { Quad.m_aTexcoords[i].x = i2fx(i % 2); Quad.m_aTexcoords[i].y = i2fx(i / 2); } return Quad; } bool CQuadArt::Create(std::shared_ptr<CLayerQuads> &pQuadLayer) { size_t MaxNewQuads = std::ceil((float)(m_Img.m_Width * m_Img.m_Height) / m_Parameters.m_ImagePixelSize); pQuadLayer->m_vQuads.clear(); pQuadLayer->m_vQuads.reserve(MaxNewQuads); size_t ImgPixelSize = m_Parameters.m_ImagePixelSize; ivec2 Scale(1, 1); for(size_t y = 0; y < m_Img.m_Height; y += ImgPixelSize) { for(size_t x = 0; x < m_Img.m_Width; x += ImgPixelSize) { ivec2 ImgPos(x, y); ColorRGBA Pixel = GetPixelClamped(ImgPos); if(m_vVisitedPixels[x + y * m_Img.m_Width] || Pixel.a == 0.f) continue; if(m_Parameters.m_Optimize) Scale = GetOptimizedQuadSize(Pixel, ImgPos); ivec2 Size = Scale * m_Parameters.m_QuadPixelSize; vec2 Pos(((x / (float)ImgPixelSize) + (Scale.x / 2.f)) * m_Parameters.m_QuadPixelSize, ((y / (float)ImgPixelSize) + (Scale.y / 2.f)) * m_Parameters.m_QuadPixelSize); CQuad Quad = CreateNewQuad(Pos, Size, Pixel); pQuadLayer->m_vQuads.emplace_back(Quad); } } pQuadLayer->m_vQuads.shrink_to_fit(); return true; } void CEditor::AddQuadArt(bool IgnoreHistory) { char aQuadArtName[IO_MAX_PATH_LENGTH]; IStorage::StripPathAndExtension(m_QuadArtParameters.m_aFilename, aQuadArtName, sizeof(aQuadArtName)); std::shared_ptr<CLayerGroup> pGroup = Map()->NewGroup(); str_copy(pGroup->m_aName, aQuadArtName); pGroup->m_UseClipping = true; pGroup->m_ClipX = -1; pGroup->m_ClipY = -1; pGroup->m_ClipH = std::ceil(m_QuadArtImageInfo.m_Height * 1.f * m_QuadArtParameters.m_QuadPixelSize / m_QuadArtParameters.m_ImagePixelSize) + 2; pGroup->m_ClipW = std::ceil(m_QuadArtImageInfo.m_Width * 1.f * m_QuadArtParameters.m_QuadPixelSize / m_QuadArtParameters.m_ImagePixelSize) + 2; std::shared_ptr<CLayerQuads> pLayer = std::make_shared<CLayerQuads>(Map()); str_copy(pLayer->m_aName, aQuadArtName); pGroup->AddLayer(pLayer); pLayer->m_Flags |= LAYERFLAG_DETAIL; CQuadArt QuadArt(m_QuadArtParameters, std::move(m_QuadArtImageInfo)); QuadArt.Create(pLayer); if(!IgnoreHistory) Map()->m_EditorHistory.RecordAction(std::make_shared<CEditorActionQuadArt>(Map(), m_QuadArtParameters)); Map()->OnModify(); OnDialogClose(); } bool CEditor::CallbackAddQuadArt(const char *pFilepath, int StorageType, void *pUser) { CEditor *pEditor = (CEditor *)pUser; pEditor->m_QuadArtParameters.m_ImagePixelSize = 1; pEditor->m_QuadArtParameters.m_QuadPixelSize = 4; pEditor->m_QuadArtParameters.m_Optimize = true; pEditor->m_QuadArtParameters.m_Centralize = false; if(!pEditor->Graphics()->LoadPng(pEditor->m_QuadArtImageInfo, pFilepath, StorageType)) { pEditor->ShowFileDialogError("Failed to load image from file '%s'.", pFilepath); return false; } str_copy(pEditor->m_QuadArtParameters.m_aFilename, pFilepath); CUIRect View = *(pEditor->Ui()->Screen()); static SPopupMenuId s_PopupQuadArtId; constexpr float PopupWidth = 400.0f; constexpr float PopupHeight = 120.0f; pEditor->Ui()->DoPopupMenu(&s_PopupQuadArtId, View.w / 2.0f - PopupWidth / 2.0f, View.h / 2.0f - PopupHeight / 2.0f, PopupWidth, PopupHeight, pEditor, PopupQuadArt); return false; }