Improve editor append (fixes #7625)

Fix broken editor append.
Check for image data when image names are identical. In such case, appended image is renamed until its name is unique.
This commit is contained in:
Corantin H 2023-12-27 17:44:52 +01:00
parent 083c8c77bf
commit f3fc85cfbb
3 changed files with 67 additions and 8 deletions

View file

@ -8832,31 +8832,63 @@ bool CEditor::Append(const char *pFileName, int StorageType, bool IgnoreHistory)
(int)m_Map.m_vpSounds.size(),
(int)m_Map.m_vpEnvelopes.size()};
// Keep a map to check if specific indices have already been replaced to prevent
// replacing those indices again when transfering images
static std::map<int *, bool> s_ReplacedMap;
static const auto &&s_ReplaceIndex = [](int ToReplace, int ReplaceWith) {
return [ToReplace, ReplaceWith](int *pIndex) {
if(*pIndex == ToReplace)
if(*pIndex == ToReplace && !s_ReplacedMap[pIndex])
{
*pIndex = ReplaceWith;
s_ReplacedMap[pIndex] = true;
}
};
};
//Transfer non-duplicate images
const auto &&Rename = [&](const std::shared_ptr<CEditorImage> &pImage) {
char aRenamed[IO_MAX_PATH_LENGTH];
int DuplicateCount = 1;
str_copy(aRenamed, pImage->m_aName);
while(std::find_if(m_Map.m_vpImages.begin(), m_Map.m_vpImages.end(), [aRenamed](const std::shared_ptr<CEditorImage> &OtherImage) { return str_comp(OtherImage->m_aName, aRenamed) == 0; }) != m_Map.m_vpImages.end())
str_format(aRenamed, sizeof(aRenamed), "%s (%d)", pImage->m_aName, DuplicateCount++); // Rename to "image_name (%d)"
str_copy(pImage->m_aName, aRenamed);
};
// Transfer non-duplicate images
s_ReplacedMap.clear();
for(auto NewMapIt = NewMap.m_vpImages.begin(); NewMapIt != NewMap.m_vpImages.end(); ++NewMapIt)
{
auto pNewImage = *NewMapIt;
auto NameIsTaken = [pNewImage](const std::shared_ptr<CEditorImage> &OtherImage) { return str_comp(pNewImage->m_aName, OtherImage->m_aName) == 0; };
auto MatchInCurrentMap = std::find_if(begin(m_Map.m_vpImages), end(m_Map.m_vpImages), NameIsTaken);
auto MatchInCurrentMap = std::find_if(m_Map.m_vpImages.begin(), m_Map.m_vpImages.end(), NameIsTaken);
const bool IsDuplicate = MatchInCurrentMap != std::end(m_Map.m_vpImages);
const bool IsDuplicate = MatchInCurrentMap != m_Map.m_vpImages.end();
const int IndexToReplace = NewMapIt - NewMap.m_vpImages.begin();
if(IsDuplicate)
{
const int IndexToReplaceWith = MatchInCurrentMap - m_Map.m_vpImages.begin();
// Check for image data
const bool ImageDataEquals = (*MatchInCurrentMap)->DataEquals(*pNewImage);
dbg_msg("editor", "map contains image %s already, removing duplicate", pNewImage->m_aName);
if(ImageDataEquals)
{
const int IndexToReplaceWith = MatchInCurrentMap - m_Map.m_vpImages.begin();
//In the new map, replace the index of the duplicate image to the index of the same in the current map.
NewMap.ModifyImageIndex(s_ReplaceIndex(IndexToReplace, IndexToReplaceWith));
dbg_msg("editor", "map already contains image %s with the same data, removing duplicate", pNewImage->m_aName);
// In the new map, replace the index of the duplicate image to the index of the same in the current map.
NewMap.ModifyImageIndex(s_ReplaceIndex(IndexToReplace, IndexToReplaceWith));
}
else
{
// Rename image and add it
Rename(pNewImage);
dbg_msg("editor", "map already contains image %s but contents of appended image is different. Renaming to %s", (*MatchInCurrentMap)->m_aName, pNewImage->m_aName);
NewMap.ModifyImageIndex(s_ReplaceIndex(IndexToReplace, m_Map.m_vpImages.size()));
m_Map.m_vpImages.push_back(pNewImage);
}
}
else
{

View file

@ -54,3 +54,29 @@ void CEditorImage::AnalyseTileFlags()
}
}
}
bool CEditorImage::DataEquals(const CEditorImage &Other) const
{
// If height, width or pixel size don't match, then data cannot be equal
const size_t ImgPixelSize = PixelSize();
if(Other.m_Height != m_Height || Other.m_Width != m_Width || Other.PixelSize() != ImgPixelSize)
return false;
const auto &&GetPixel = [&](void *pData, int x, int y, size_t p) -> uint8_t {
return ((uint8_t *)pData)[x * ImgPixelSize + (m_Width * ImgPixelSize * y) + p];
};
// Look through every pixel and check if there are any difference
for(int y = 0; y < m_Height; y += ImgPixelSize)
{
for(int x = 0; x < m_Width; x += ImgPixelSize)
{
for(size_t p = 0; p < ImgPixelSize; p++)
if(GetPixel(m_pData, x, y, p) != GetPixel(Other.m_pData, x, y, p))
return false;
}
}
return true;
}

View file

@ -14,6 +14,7 @@ public:
void Init(CEditor *pEditor) override;
void AnalyseTileFlags();
bool DataEquals(const CEditorImage &Other) const;
IGraphics::CTextureHandle m_Texture;
int m_External = 0;