From 32e924063440c11ba586d6a39347b5cf8ff39f22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Tue, 10 Sep 2024 21:11:55 +0200 Subject: [PATCH] Fix editor crash when saving maps with RGB mapres Convert mapres to RGBA immediately when loading them, so the image data is always in RGBA format internally, instead of only converting when the map is saved (which was erroneously removed in #8670). This means the `cl_editor_dilate` setting will now also be applied to converted RGB images. --- src/engine/client/graphics_threaded.cpp | 2 +- src/engine/graphics.h | 2 + src/game/editor/editor.cpp | 51 ++++++++++++++++++------- src/game/editor/mapitems/map_io.cpp | 9 +++++ 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 63ea4d10403..21e5687febb 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -300,7 +300,7 @@ void CGraphics_Threaded::UnloadTexture(CTextureHandle *pIndex) FreeTextureIndex(pIndex); } -static bool ConvertToRGBA(uint8_t *pDest, const CImageInfo &SrcImage) +bool ConvertToRGBA(uint8_t *pDest, const CImageInfo &SrcImage) { if(SrcImage.m_Format == CImageInfo::FORMAT_RGBA) { diff --git a/src/engine/graphics.h b/src/engine/graphics.h index 184e907e87b..2528c0d792a 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -124,6 +124,8 @@ class CImageInfo } }; +bool ConvertToRGBA(uint8_t *pDest, const CImageInfo &SrcImage); + /* Structure: CVideoMode */ diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 86c525d0a93..78538e45b66 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -4384,7 +4384,7 @@ bool CEditor::ReplaceImage(const char *pFileName, int StorageType, bool CheckDup } } - CEditorImage ImgInfo(this); + CImageInfo ImgInfo; if(!Graphics()->LoadPng(ImgInfo, pFileName, StorageType)) { ShowFileDialogError("Failed to load image from file '%s'.", pFileName); @@ -4394,21 +4394,33 @@ bool CEditor::ReplaceImage(const char *pFileName, int StorageType, bool CheckDup std::shared_ptr pImg = m_Map.m_vpImages[m_SelectedImage]; Graphics()->UnloadTexture(&(pImg->m_Texture)); pImg->Free(); - *pImg = ImgInfo; + pImg->m_Width = ImgInfo.m_Width; + pImg->m_Height = ImgInfo.m_Height; + pImg->m_Format = ImgInfo.m_Format; + pImg->m_pData = ImgInfo.m_pData; str_copy(pImg->m_aName, aBuf); pImg->m_External = IsVanillaImage(pImg->m_aName); - if(!pImg->m_External && g_Config.m_ClEditorDilate == 1 && pImg->m_Format == CImageInfo::FORMAT_RGBA) + if(!pImg->m_External && pImg->m_Format != CImageInfo::FORMAT_RGBA) { - DilateImage(ImgInfo.m_pData, ImgInfo.m_Width, ImgInfo.m_Height); + uint8_t *pRgbaData = static_cast(malloc((size_t)pImg->m_Width * pImg->m_Height * CImageInfo::PixelSize(CImageInfo::FORMAT_RGBA))); + ConvertToRGBA(pRgbaData, *pImg); + free(pImg->m_pData); + pImg->m_pData = pRgbaData; + pImg->m_Format = CImageInfo::FORMAT_RGBA; + } + + if(!pImg->m_External && g_Config.m_ClEditorDilate == 1) + { + DilateImage(pImg->m_pData, pImg->m_Width, pImg->m_Height); } pImg->m_AutoMapper.Load(pImg->m_aName); int TextureLoadFlag = Graphics()->Uses2DTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE; - if(ImgInfo.m_Width % 16 != 0 || ImgInfo.m_Height % 16 != 0) + if(pImg->m_Width % 16 != 0 || pImg->m_Height % 16 != 0) TextureLoadFlag = 0; - pImg->m_Texture = Graphics()->LoadTextureRaw(ImgInfo, TextureLoadFlag, pFileName); - ImgInfo.m_pData = nullptr; + pImg->m_Texture = Graphics()->LoadTextureRaw(*pImg, TextureLoadFlag, pFileName); + SortImages(); for(size_t i = 0; i < m_Map.m_vpImages.size(); ++i) { @@ -4447,7 +4459,7 @@ bool CEditor::AddImage(const char *pFileName, int StorageType, void *pUser) return false; } - CEditorImage ImgInfo(pEditor); + CImageInfo ImgInfo; if(!pEditor->Graphics()->LoadPng(ImgInfo, pFileName, StorageType)) { pEditor->ShowFileDialogError("Failed to load image from file '%s'.", pFileName); @@ -4455,19 +4467,30 @@ bool CEditor::AddImage(const char *pFileName, int StorageType, void *pUser) } std::shared_ptr pImg = std::make_shared(pEditor); - *pImg = ImgInfo; + pImg->m_Width = ImgInfo.m_Width; + pImg->m_Height = ImgInfo.m_Height; + pImg->m_Format = ImgInfo.m_Format; + pImg->m_pData = ImgInfo.m_pData; pImg->m_External = IsVanillaImage(aBuf); - if(!pImg->m_External && g_Config.m_ClEditorDilate == 1 && pImg->m_Format == CImageInfo::FORMAT_RGBA) + if(pImg->m_Format != CImageInfo::FORMAT_RGBA) + { + uint8_t *pRgbaData = static_cast(malloc((size_t)pImg->m_Width * pImg->m_Height * CImageInfo::PixelSize(CImageInfo::FORMAT_RGBA))); + ConvertToRGBA(pRgbaData, *pImg); + free(pImg->m_pData); + pImg->m_pData = pRgbaData; + pImg->m_Format = CImageInfo::FORMAT_RGBA; + } + + if(!pImg->m_External && g_Config.m_ClEditorDilate == 1) { - DilateImage(ImgInfo.m_pData, ImgInfo.m_Width, ImgInfo.m_Height); + DilateImage(pImg->m_pData, pImg->m_Width, pImg->m_Height); } int TextureLoadFlag = pEditor->Graphics()->Uses2DTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE; - if(ImgInfo.m_Width % 16 != 0 || ImgInfo.m_Height % 16 != 0) + if(pImg->m_Width % 16 != 0 || pImg->m_Height % 16 != 0) TextureLoadFlag = 0; - pImg->m_Texture = pEditor->Graphics()->LoadTextureRaw(ImgInfo, TextureLoadFlag, pFileName); - ImgInfo.m_pData = nullptr; + pImg->m_Texture = pEditor->Graphics()->LoadTextureRaw(*pImg, TextureLoadFlag, pFileName); str_copy(pImg->m_aName, aBuf); pImg->m_AutoMapper.Load(pImg->m_aName); pEditor->m_Map.m_vpImages.push_back(pImg); diff --git a/src/game/editor/mapitems/map_io.cpp b/src/game/editor/mapitems/map_io.cpp index a3346b1a259..a834a3d990d 100644 --- a/src/game/editor/mapitems/map_io.cpp +++ b/src/game/editor/mapitems/map_io.cpp @@ -509,6 +509,15 @@ bool CEditorMap::Load(const char *pFileName, int StorageType, const std::functio pImg->m_Height = ImgInfo.m_Height; pImg->m_Format = ImgInfo.m_Format; pImg->m_pData = ImgInfo.m_pData; + if(pImg->m_Format != CImageInfo::FORMAT_RGBA) + { + uint8_t *pRgbaData = static_cast(malloc((size_t)pImg->m_Width * pImg->m_Height * CImageInfo::PixelSize(CImageInfo::FORMAT_RGBA))); + ConvertToRGBA(pRgbaData, *pImg); + free(pImg->m_pData); + pImg->m_pData = pRgbaData; + pImg->m_Format = CImageInfo::FORMAT_RGBA; + } + int TextureLoadFlag = m_pEditor->Graphics()->Uses2DTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE; if(ImgInfo.m_Width % 16 != 0 || ImgInfo.m_Height % 16 != 0) TextureLoadFlag = 0;