diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index d8b4022c0..2b9a97717 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -785,6 +786,61 @@ bool CEditor::CallbackSaveCopyMap(const char *pFileName, int StorageType, void * } } +bool CEditor::CallbackSaveImage(const char *pFileName, int StorageType, void *pUser) +{ + dbg_assert(StorageType == IStorage::TYPE_SAVE, "Saving only allowed for IStorage::TYPE_SAVE"); + + CEditor *pEditor = static_cast(pUser); + char aBuf[IO_MAX_PATH_LENGTH]; + + // add file extension + if(!str_endswith(pFileName, ".png")) + { + str_format(aBuf, sizeof(aBuf), "%s.png", pFileName); + pFileName = aBuf; + } + + std::shared_ptr pImg = pEditor->m_Map.m_vpImages[pEditor->m_SelectedImage]; + + EImageFormat OutputFormat; + switch(pImg->m_Format) + { + case CImageInfo::FORMAT_RGB: + OutputFormat = IMAGE_FORMAT_RGB; + break; + case CImageInfo::FORMAT_RGBA: + OutputFormat = IMAGE_FORMAT_RGBA; + break; + case CImageInfo::FORMAT_SINGLE_COMPONENT: + OutputFormat = IMAGE_FORMAT_R; + break; + default: + pEditor->ShowFileDialogError("Image has invalid format."); + return false; + }; + + TImageByteBuffer ByteBuffer; + SImageByteBuffer ImageByteBuffer(&ByteBuffer); + if(SavePNG(OutputFormat, static_cast(pImg->m_pData), ImageByteBuffer, pImg->m_Width, pImg->m_Height)) + { + IOHANDLE File = pEditor->Storage()->OpenFile(pFileName, IOFLAG_WRITE, StorageType); + if(File) + { + io_write(File, &ByteBuffer.front(), ByteBuffer.size()); + io_close(File); + pEditor->m_Dialog = DIALOG_NONE; + return true; + } + pEditor->ShowFileDialogError("Failed to open file '%s'.", pFileName); + return false; + } + else + { + pEditor->ShowFileDialogError("Failed to write image to file."); + return false; + } +} + void CEditor::DoToolbarLayers(CUIRect ToolBar) { const bool ModPressed = Input()->ModifierIsPressed(); @@ -4119,7 +4175,7 @@ void CEditor::RenderImagesList(CUIRect ToolBox) if(Result == 2) { const std::shared_ptr pImg = m_Map.m_vpImages[m_SelectedImage]; - const int Height = pImg->m_External || IsVanillaImage(pImg->m_aName) ? 73 : 56; + const int Height = !pImg->m_External && IsVanillaImage(pImg->m_aName) ? 90 : 73; static SPopupMenuId s_PopupImageId; UI()->DoPopupMenu(&s_PopupImageId, UI()->MouseX(), UI()->MouseY(), 120, Height, this, PopupImage); } @@ -4743,7 +4799,12 @@ void CEditor::RenderFileDialog() str_append(m_aFileSaveName, FILETYPE_EXTENSIONS[m_FileDialogFileType]); if(!str_comp(m_pFileDialogButtonText, "Save") && Storage()->FileExists(m_aFileSaveName, StorageType)) { - m_PopupEventType = m_pfnFileDialogFunc == &CallbackSaveCopyMap ? POPEVENT_SAVE_COPY : POPEVENT_SAVE; + if(m_pfnFileDialogFunc == &CallbackSaveMap) + m_PopupEventType = POPEVENT_SAVE; + else if(m_pfnFileDialogFunc == &CallbackSaveCopyMap) + m_PopupEventType = POPEVENT_SAVE_COPY; + else + m_PopupEventType = POPEVENT_SAVE_IMG; m_PopupEventActivated = true; } else if(m_pfnFileDialogFunc) diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 2ca9712cf..9f08c4b78 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -994,6 +994,7 @@ public: POPEVENT_NEW, POPEVENT_SAVE, POPEVENT_SAVE_COPY, + POPEVENT_SAVE_IMG, POPEVENT_LARGELAYER, POPEVENT_PREVENTUNUSEDTILES, POPEVENT_IMAGEDIV16, @@ -1286,6 +1287,7 @@ public: static bool CallbackSaveMap(const char *pFileName, int StorageType, void *pUser); static bool CallbackSaveCopyMap(const char *pFileName, int StorageType, void *pUser); static bool CallbackAddTileart(const char *pFilepath, int StorageType, void *pUser); + static bool CallbackSaveImage(const char *pFileName, int StorageType, void *pUser); void PopupSelectImageInvoke(int Current, float x, float y); int PopupSelectImageResult(); diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp index e99d24c6d..ed7744890 100644 --- a/src/game/editor/popups.cpp +++ b/src/game/editor/popups.cpp @@ -1459,6 +1459,7 @@ CUI::EPopupMenuFunctionResult CEditor::PopupImage(void *pContext, CUIRect View, static int s_ReaddButton = 0; static int s_ReplaceButton = 0; static int s_RemoveButton = 0; + static int s_ExportButton = 0; CUIRect Slot; View.HSplitTop(12.0f, &Slot, &View); @@ -1538,6 +1539,17 @@ CUI::EPopupMenuFunctionResult CEditor::PopupImage(void *pContext, CUIRect View, return CUI::POPUP_CLOSE_CURRENT; } + if(!pImg->m_External) + { + View.HSplitTop(5.0f, nullptr, &View); + View.HSplitTop(12.0f, &Slot, &View); + if(pEditor->DoButton_MenuItem(&s_ExportButton, "Export", 0, &Slot, 0, "Export the image")) + { + pEditor->InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_IMG, "Save image", "Save", "mapres", false, CallbackSaveImage, pEditor); + return CUI::POPUP_CLOSE_CURRENT; + } + } + return CUI::POPUP_KEEP_OPEN; } @@ -1750,6 +1762,11 @@ CUI::EPopupMenuFunctionResult CEditor::PopupEvent(void *pContext, CUIRect View, pTitle = "Save map"; pMessage = "The file already exists.\n\nDo you want to overwrite the map?"; } + else if(pEditor->m_PopupEventType == POPEVENT_SAVE_IMG) + { + pTitle = "Save image"; + pMessage = "The file already exists.\n\nDo you want to overwrite the image?"; + } else if(pEditor->m_PopupEventType == POPEVENT_LARGELAYER) { pTitle = "Large layer"; @@ -1869,6 +1886,11 @@ CUI::EPopupMenuFunctionResult CEditor::PopupEvent(void *pContext, CUIRect View, CallbackSaveCopyMap(pEditor->m_aFileSaveName, IStorage::TYPE_SAVE, pEditor); return CUI::POPUP_CLOSE_CURRENT; } + else if(pEditor->m_PopupEventType == POPEVENT_SAVE_IMG) + { + CallbackSaveImage(pEditor->m_aFileSaveName, IStorage::TYPE_SAVE, pEditor); + return CUI::POPUP_CLOSE_CURRENT; + } else if(pEditor->m_PopupEventType == POPEVENT_PLACE_BORDER_TILES) { pEditor->PlaceBorderTiles();