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;
}