diff --git a/CMakeLists.txt b/CMakeLists.txt index ec9912fbc..d89e7d580 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1453,6 +1453,8 @@ set_src(ENGINE_SHARED GLOB src/engine/shared datafile.h demo.cpp demo.h + dilate.cpp + dilate.h econ.cpp econ.h engine.cpp diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 4fa3eba2c..aa334a564 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -21,6 +21,7 @@ MACRO_CONFIG_INT(ClRefreshRate, cl_refresh_rate, 0, 0, 10000, CFGFLAG_SAVE | CFG MACRO_CONFIG_INT(ClRefreshRateInactive, cl_refresh_rate_inactive, 120, 0, 10000, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Refresh rate for updating the game when the window is inactive (in Hz)") MACRO_CONFIG_INT(ClEditor, cl_editor, 0, 0, 1, CFGFLAG_CLIENT, "") MACRO_CONFIG_INT(ClEditorUndo, cl_editorundo, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Undo function in editor") +MACRO_CONFIG_INT(ClEditorDilate, cl_editor_dilate, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Automatically dilates embedded images") MACRO_CONFIG_INT(ClLoadCountryFlags, cl_load_country_flags, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Load and show country flags") MACRO_CONFIG_STR(ClSkinFilterString, cl_skin_filter_string, 25, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Skin filtering string") diff --git a/src/engine/shared/dilate.cpp b/src/engine/shared/dilate.cpp new file mode 100644 index 000000000..031537afa --- /dev/null +++ b/src/engine/shared/dilate.cpp @@ -0,0 +1,86 @@ +#include +#include + +static void Dilate(int w, int h, int BPP, unsigned char *pSrc, unsigned char *pDest, unsigned char AlphaThreshold = 30) +{ + int ix, iy; + const int xo[] = {0, -1, 1, 0}; + const int yo[] = {-1, 0, 0, 1}; + + int AlphaCompIndex = BPP - 1; + + int m = 0; + for(int y = 0; y < h; y++) + { + for(int x = 0; x < w; x++, m += BPP) + { + for(int i = 0; i < BPP; ++i) + pDest[m + i] = pSrc[m + i]; + if(pSrc[m + AlphaCompIndex] > AlphaThreshold) + continue; + + int SumOfOpaque[] = {0, 0, 0}; + int Counter = 0; + for(int c = 0; c < 4; c++) + { + ix = clamp(x + xo[c], 0, w - 1); + iy = clamp(y + yo[c], 0, h - 1); + int k = iy * w * BPP + ix * BPP; + if(pSrc[k + AlphaCompIndex] > AlphaThreshold) + { + for(int p = 0; p < BPP - 1; ++p) + SumOfOpaque[p] += pSrc[k + p]; + ++Counter; + break; + } + } + + if(Counter > 0) + { + for(int i = 0; i < BPP - 1; ++i) + { + SumOfOpaque[i] /= Counter; + pDest[m + i] = (unsigned char)SumOfOpaque[i]; + } + + pDest[m + AlphaCompIndex] = 255; + } + } + } +} + +static void CopyColorValues(int w, int h, int BPP, unsigned char *pSrc, unsigned char *pDest) +{ + int m = 0; + for(int y = 0; y < h; y++) + { + for(int x = 0; x < w; x++, m += BPP) + { + for(int i = 0; i < BPP - 1; ++i) + pDest[m + i] = pSrc[m + i]; + } + } +} + +void DilateImage(unsigned char *pImageBuff, int w, int h, int BPP) +{ + unsigned char *pBuffer[2] = {NULL, NULL}; + + pBuffer[0] = (unsigned char *)malloc(w * h * sizeof(unsigned char) * BPP); + pBuffer[1] = (unsigned char *)malloc(w * h * sizeof(unsigned char) * BPP); + + unsigned char *pPixelBuff = (unsigned char *)pImageBuff; + + Dilate(w, h, BPP, pPixelBuff, pBuffer[0]); + + for(int i = 0; i < 5; i++) + { + Dilate(w, h, BPP, pBuffer[0], pBuffer[1]); + Dilate(w, h, BPP, pBuffer[1], pBuffer[0]); + } + + CopyColorValues(w, h, BPP, pBuffer[0], pPixelBuff); + + free(pBuffer[0]); + free(pBuffer[1]); +} diff --git a/src/engine/shared/dilate.h b/src/engine/shared/dilate.h new file mode 100644 index 000000000..368a6b35d --- /dev/null +++ b/src/engine/shared/dilate.h @@ -0,0 +1,6 @@ +#ifndef ENGINE_SHARED_DILATE_H +#define ENGINE_SHARED_DILATE_H + +void DilateImage(unsigned char *pImageBuff, int w, int h, int BPP); + +#endif diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index b2992ba95..484234d41 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -30,6 +30,8 @@ #include #include +#include + #include "auto_map.h" #include "editor.h" @@ -3606,6 +3608,20 @@ void CEditor::ReplaceImage(const char *pFileName, int StorageType, void *pUser) *pImg = ImgInfo; IStorage::StripPathAndExtension(pFileName, pImg->m_aName, sizeof(pImg->m_aName)); pImg->m_External = IsVanillaImage(pImg->m_aName); + + if(!pImg->m_External && g_Config.m_ClEditorDilate == 1) + { + int ColorChannelCount = 0; + if(ImgInfo.m_Format == CImageInfo::FORMAT_ALPHA) + ColorChannelCount = 1; + else if(ImgInfo.m_Format == CImageInfo::FORMAT_RGB) + ColorChannelCount = 3; + else if(ImgInfo.m_Format == CImageInfo::FORMAT_RGBA) + ColorChannelCount = 4; + + DilateImage((unsigned char *)ImgInfo.m_pData, ImgInfo.m_Width, ImgInfo.m_Height, ColorChannelCount); + } + pImg->m_AutoMapper.Load(pImg->m_aName); pImg->m_Texture = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0); ImgInfo.m_pData = 0; @@ -3643,9 +3659,23 @@ void CEditor::AddImage(const char *pFileName, int StorageType, void *pUser) CEditorImage *pImg = new CEditorImage(pEditor); *pImg = ImgInfo; + pImg->m_External = IsVanillaImage(aBuf); + + if(!pImg->m_External && g_Config.m_ClEditorDilate == 1) + { + int ColorChannelCount = 0; + if(ImgInfo.m_Format == CImageInfo::FORMAT_ALPHA) + ColorChannelCount = 1; + else if(ImgInfo.m_Format == CImageInfo::FORMAT_RGB) + ColorChannelCount = 3; + else if(ImgInfo.m_Format == CImageInfo::FORMAT_RGBA) + ColorChannelCount = 4; + + DilateImage((unsigned char *)ImgInfo.m_pData, ImgInfo.m_Width, ImgInfo.m_Height, ColorChannelCount); + } + pImg->m_Texture = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0); ImgInfo.m_pData = 0; - pImg->m_External = IsVanillaImage(aBuf); str_copy(pImg->m_aName, aBuf, sizeof(pImg->m_aName)); pImg->m_AutoMapper.Load(pImg->m_aName); pEditor->m_Map.m_lImages.add(pImg); diff --git a/src/tools/dilate.cpp b/src/tools/dilate.cpp index 38de84eef..76bdf1d63 100644 --- a/src/tools/dilate.cpp +++ b/src/tools/dilate.cpp @@ -1,57 +1,13 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ -#include #include +#include +#include #include -typedef struct -{ - unsigned char r, g, b, a; -} CPixel; - -static void Dilate(int w, int h, CPixel *pSrc, CPixel *pDest) -{ - int ix, iy; - const int xo[] = {0, -1, 1, 0}; - const int yo[] = {-1, 0, 0, 1}; - - int m = 0; - for(int y = 0; y < h; y++) - { - for(int x = 0; x < w; x++, m++) - { - pDest[m] = pSrc[m]; - if(pSrc[m].a) - continue; - - for(int c = 0; c < 4; c++) - { - ix = clamp(x + xo[c], 0, w-1); - iy = clamp(y + yo[c], 0, h-1); - int k = iy*w+ix; - if(pSrc[k].a) - { - pDest[m] = pSrc[k]; - pDest[m].a = 255; - break; - } - } - } - } -} - -static void CopyAlpha(int w, int h, CPixel *pSrc, CPixel *pDest) -{ - int m = 0; - for(int y = 0; y < h; y++) - for(int x = 0; x < w; x++, m++) - pDest[m].a = pSrc[m].a; -} - int DilateFile(const char *pFileName) { png_t Png; - CPixel *pBuffer[3] = {0,0,0}; png_init(0, 0); int Error = png_open_file(&Png, pFileName); @@ -69,29 +25,23 @@ int DilateFile(const char *pFileName) return 1; } - pBuffer[0] = (CPixel *)malloc(Png.width * Png.height * sizeof(CPixel)); - pBuffer[1] = (CPixel *)malloc(Png.width * Png.height * sizeof(CPixel)); - pBuffer[2] = (CPixel *)malloc(Png.width * Png.height * sizeof(CPixel)); - png_get_data(&Png, (unsigned char *)pBuffer[0]); + unsigned char *pBuffer = (unsigned char *)malloc(Png.width * Png.height * sizeof(unsigned char) * 4); + + png_get_data(&Png, pBuffer); png_close_file(&Png); int w = Png.width; int h = Png.height; - Dilate(w, h, pBuffer[0], pBuffer[1]); - for(int i = 0; i < 5; i++) - { - Dilate(w, h, pBuffer[1], pBuffer[2]); - Dilate(w, h, pBuffer[2], pBuffer[1]); - } - - CopyAlpha(w, h, pBuffer[0], pBuffer[1]); + DilateImage(pBuffer, w, h, 4); // save here png_open_file_write(&Png, pFileName); - png_set_data(&Png, w, h, 8, PNG_TRUECOLOR_ALPHA, (unsigned char *)pBuffer[1]); + png_set_data(&Png, w, h, 8, PNG_TRUECOLOR_ALPHA, (unsigned char *)pBuffer); png_close_file(&Png); + free(pBuffer); + return 0; }