From 0c231c36680cf59be130dd039156d46dfa964679 Mon Sep 17 00:00:00 2001 From: Jupeyy Date: Thu, 12 Nov 2020 08:35:07 +0100 Subject: [PATCH] Respect outline in skin metrics --- src/game/client/components/skins.cpp | 110 ++++++++++++------------ src/game/client/render.cpp | 16 ++-- src/game/client/skin.h | 121 +++++++++++++++++---------- 3 files changed, 140 insertions(+), 107 deletions(-) diff --git a/src/game/client/components/skins.cpp b/src/game/client/components/skins.cpp index 9c2cd4f58..73cae21f3 100644 --- a/src/game/client/components/skins.cpp +++ b/src/game/client/components/skins.cpp @@ -55,6 +55,41 @@ int CSkins::SkinScan(const char *pName, int IsDir, int DirType, void *pUser) return pSelf->LoadSkin(aNameWithoutPng, aBuf, DirType); } +static void CheckMetrics(CSkin::SSkinMetricVariable &Metrics, uint8_t *pImg, int ImgWidth, int ImgX, int ImgY, int CheckWidth, int CheckHeight) +{ + int MaxY = -1; + int MinY = CheckHeight + 1; + int MaxX = -1; + int MinX = CheckWidth + 1; + + for(int y = 0; y < CheckHeight; y++) + { + for(int x = 0; x < CheckWidth; x++) + { + int OffsetAlpha = (y + ImgY) * ImgWidth + (x + ImgX) * 4 + 3; + uint8_t AlphaValue = pImg[OffsetAlpha]; + if(AlphaValue > 0) + { + if(MaxY < y) + MaxY = y; + if(MinY > y) + MinY = y; + if(MaxX < x) + MaxX = x; + if(MinX > x) + MinX = x; + } + } + } + + Metrics.m_Width = clamp((MaxX - MinX) + 1, 1, CheckWidth); + Metrics.m_Height = clamp((MaxY - MinY) + 1, 1, CheckHeight); + Metrics.m_OffsetX = clamp(MinX, 0, CheckWidth - 1); + Metrics.m_OffsetY = clamp(MinY, 0, CheckHeight - 1); + Metrics.m_MaxWidth = CheckWidth; + Metrics.m_MaxHeight = CheckHeight; +} + int CSkins::LoadSkin(const char *pName, const char *pPath, int DirType) { char aBuf[512]; @@ -86,17 +121,27 @@ int CSkins::LoadSkin(const char *pName, const char *pPath, int DirType) int FeetOffsetX = g_pData->m_aSprites[SPRITE_TEE_FOOT].m_X * FeetGridPixelsWidth; int FeetOffsetY = g_pData->m_aSprites[SPRITE_TEE_FOOT].m_Y * FeetGridPixelsHeight; + int FeetOutlineGridPixelsWidth = (Info.m_Width / g_pData->m_aSprites[SPRITE_TEE_FOOT_OUTLINE].m_pSet->m_Gridx); + int FeetOutlineGridPixelsHeight = (Info.m_Height / g_pData->m_aSprites[SPRITE_TEE_FOOT_OUTLINE].m_pSet->m_Gridy); + int FeetOutlineWidth = g_pData->m_aSprites[SPRITE_TEE_FOOT_OUTLINE].m_W * FeetOutlineGridPixelsWidth; + int FeetOutlineHeight = g_pData->m_aSprites[SPRITE_TEE_FOOT_OUTLINE].m_H * FeetOutlineGridPixelsHeight; + + int FeetOutlineOffsetX = g_pData->m_aSprites[SPRITE_TEE_FOOT_OUTLINE].m_X * FeetOutlineGridPixelsWidth; + int FeetOutlineOffsetY = g_pData->m_aSprites[SPRITE_TEE_FOOT_OUTLINE].m_Y * FeetOutlineGridPixelsHeight; + + int BodyOutlineGridPixelsWidth = (Info.m_Width / g_pData->m_aSprites[SPRITE_TEE_BODY_OUTLINE].m_pSet->m_Gridx); + int BodyOutlineGridPixelsHeight = (Info.m_Height / g_pData->m_aSprites[SPRITE_TEE_BODY_OUTLINE].m_pSet->m_Gridy); + int BodyOutlineSize = g_pData->m_aSprites[SPRITE_TEE_BODY_OUTLINE].m_H * BodyOutlineGridPixelsHeight; + + int BodyOutlineOffsetX = g_pData->m_aSprites[SPRITE_TEE_BODY_OUTLINE].m_X * BodyOutlineGridPixelsWidth; + int BodyOutlineOffsetY = g_pData->m_aSprites[SPRITE_TEE_BODY_OUTLINE].m_Y * BodyOutlineGridPixelsHeight; + int BodySize = g_pData->m_aSprites[SPRITE_TEE_BODY].m_H * (Info.m_Height / g_pData->m_aSprites[SPRITE_TEE_BODY].m_pSet->m_Gridy); // body size if(BodySize > Info.m_Height) return 0; unsigned char *d = (unsigned char *)Info.m_pData; int Pitch = Info.m_Width * 4; - int MaxBodyY = -1; - int MinBodyY = BodySize + 1; - int MaxBodyX = -1; - int MinBodyX = BodySize + 1; - // dig out blood color { int aColors[3] = {0}; @@ -110,17 +155,6 @@ int CSkins::LoadSkin(const char *pName, const char *pPath, int DirType) aColors[1] += d[y * Pitch + x * 4 + 1]; aColors[2] += d[y * Pitch + x * 4 + 2]; } - if(AlphaValue > 0) - { - if(MaxBodyY < y) - MaxBodyY = y; - if(MinBodyY > y) - MinBodyY = y; - if(MaxBodyX < x) - MaxBodyX = x; - if(MinBodyX > x) - MinBodyX = x; - } } if(aColors[0] != 0 && aColors[1] != 0 && aColors[2] != 0) Skin.m_BloodColor = ColorRGBA(normalize(vec3(aColors[0], aColors[1], aColors[2]))); @@ -128,48 +162,16 @@ int CSkins::LoadSkin(const char *pName, const char *pPath, int DirType) Skin.m_BloodColor = ColorRGBA(0, 0, 0, 1); } - Skin.m_Metrics.m_BodyHeight = clamp((MaxBodyY - MinBodyY) + 1, 1, BodySize); - Skin.m_Metrics.m_BodyWidth = clamp((MaxBodyX - MinBodyX) + 1, 1, BodySize); - Skin.m_Metrics.m_BodyOffsetX = clamp(MinBodyX, 0, BodySize - 1); - Skin.m_Metrics.m_BodyOffsetY = clamp(MinBodyY, 0, BodySize - 1); + CheckMetrics(Skin.m_Metrics.m_Body, d, Pitch, 0, 0, BodySize, BodySize); - Skin.m_Metrics.m_BodyMaxWidth = BodySize; - Skin.m_Metrics.m_BodyMaxHeight = BodySize; + // body outline metrics + CheckMetrics(Skin.m_Metrics.m_Body, d, Pitch, BodyOutlineOffsetX, BodyOutlineOffsetY, BodyOutlineSize, BodyOutlineSize); // get feet size - { - int MaxFeetY = -1; - int MinFeetY = FeetHeight + 1; - int MaxFeetX = -1; - int MinFeetX = FeetWidth + 1; + CheckMetrics(Skin.m_Metrics.m_Feet, d, Pitch, FeetOffsetX, FeetOffsetY, FeetWidth, FeetHeight); - for(int y = 0; y < FeetHeight; y++) - { - for(int x = 0; x < FeetWidth; x++) - { - int OffsetAlpha = (y + FeetOffsetY) * Pitch + (x + FeetOffsetX) * 4 + 3; - uint8_t AlphaValue = d[OffsetAlpha]; - if(AlphaValue > 0) - { - if(MaxFeetY < y) - MaxFeetY = y; - if(MinFeetY > y) - MinFeetY = y; - if(MaxFeetX < x) - MaxFeetX = x; - if(MinFeetX > x) - MinFeetX = x; - } - } - } - - Skin.m_Metrics.m_FeetWidth = clamp((MaxFeetX - MinFeetX) + 1, 1, FeetWidth); - Skin.m_Metrics.m_FeetHeight = clamp((MaxFeetY - MinFeetY) + 1, 1, FeetHeight); - Skin.m_Metrics.m_FeetOffsetX = clamp(MinFeetX, 0, FeetWidth - 1); - Skin.m_Metrics.m_FeetOffsetY = clamp(MinFeetY, 0, FeetHeight - 1); - Skin.m_Metrics.m_FeetMaxWidth = FeetWidth; - Skin.m_Metrics.m_FeetMaxHeight = FeetHeight; - } + // get feet outline size + CheckMetrics(Skin.m_Metrics.m_Feet, d, Pitch, FeetOutlineOffsetX, FeetOutlineOffsetY, FeetOutlineWidth, FeetOutlineHeight); // create colorless version int Step = Info.m_Format == CImageInfo::FORMAT_RGBA ? 4 : 3; diff --git a/src/game/client/render.cpp b/src/game/client/render.cpp index 3ac70ca9e..b18d2d85e 100644 --- a/src/game/client/render.cpp +++ b/src/game/client/render.cpp @@ -566,10 +566,10 @@ void CRenderTools::GetRenderTeeBodySize(CAnimState *pAnim, CTeeRenderInfo *pInfo float BodyScale; GetRenderTeeBodyScale(BaseSize, BodyScale); - Width = pInfo->m_SkinMetrics.BodyWidthNormalized() * 64.0f * BodyScale; - Height = pInfo->m_SkinMetrics.BodyHeightNormalized() * 64.0f * BodyScale; - BodyOffset.x = pInfo->m_SkinMetrics.BodyOffsetXNormalized() * 64.0f * BodyScale; - BodyOffset.y = pInfo->m_SkinMetrics.BodyOffsetYNormalized() * 64.0f * BodyScale; + Width = pInfo->m_SkinMetrics.m_Body.WidthNormalized() * 64.0f * BodyScale; + Height = pInfo->m_SkinMetrics.m_Body.HeightNormalized() * 64.0f * BodyScale; + BodyOffset.x = pInfo->m_SkinMetrics.m_Body.OffsetXNormalized() * 64.0f * BodyScale; + BodyOffset.y = pInfo->m_SkinMetrics.m_Body.OffsetYNormalized() * 64.0f * BodyScale; } void CRenderTools::GetRenderTeeFeetSize(CAnimState *pAnim, CTeeRenderInfo *pInfo, vec2 &FeetOffset, float &Width, float &Height) @@ -580,10 +580,10 @@ void CRenderTools::GetRenderTeeFeetSize(CAnimState *pAnim, CTeeRenderInfo *pInfo float FeetScaleWidth, FeetScaleHeight; GetRenderTeeFeetScale(BaseSize, FeetScaleWidth, FeetScaleHeight); - Width = pInfo->m_SkinMetrics.FeetWidthNormalized() * 64.0f * FeetScaleWidth; - Height = pInfo->m_SkinMetrics.FeetHeightNormalized() * 32.0f * FeetScaleHeight; - FeetOffset.x = pInfo->m_SkinMetrics.FeetOffsetXNormalized() * 64.0f * FeetScaleWidth; - FeetOffset.y = pInfo->m_SkinMetrics.FeetOffsetYNormalized() * 32.0f * FeetScaleHeight; + Width = pInfo->m_SkinMetrics.m_Feet.WidthNormalized() * 64.0f * FeetScaleWidth; + Height = pInfo->m_SkinMetrics.m_Feet.HeightNormalized() * 32.0f * FeetScaleHeight; + FeetOffset.x = pInfo->m_SkinMetrics.m_Feet.OffsetXNormalized() * 64.0f * FeetScaleWidth; + FeetOffset.y = pInfo->m_SkinMetrics.m_Feet.OffsetYNormalized() * 32.0f * FeetScaleHeight; } void CRenderTools::GetRenderTeeOffsetToRenderedTee(CAnimState *pAnim, CTeeRenderInfo *pInfo, vec2 &TeeOffsetToMid) diff --git a/src/game/client/skin.h b/src/game/client/skin.h index d5d7cf31d..03b61809d 100644 --- a/src/game/client/skin.h +++ b/src/game/client/skin.h @@ -5,6 +5,7 @@ #include #include #include +#include // do this better and nicer struct CSkin @@ -42,16 +43,80 @@ struct CSkin char m_aName[24]; ColorRGBA m_BloodColor; - struct SSkinMetrics + template + struct SSkinMetricVariableInt { - int m_BodyWidth; - int m_BodyHeight; - int m_BodyOffsetX; - int m_BodyOffsetY; + int m_Value; + operator int() { return m_Value; } + SSkinMetricVariableInt &operator=(int NewVal) + { + if(IsSizeType) + m_Value = maximum(m_Value, NewVal); + else + m_Value = minimum(m_Value, NewVal); + return *this; + } + + SSkinMetricVariableInt() + { + Reset(); + } + + void Reset() + { + if(IsSizeType) + m_Value = std::numeric_limits::lowest(); + else + m_Value = std::numeric_limits::max(); + } + }; + + struct SSkinMetricVariable + { + SSkinMetricVariableInt m_Width; + SSkinMetricVariableInt m_Height; + SSkinMetricVariableInt m_OffsetX; + SSkinMetricVariableInt m_OffsetY; // these can be used to normalize the metrics - int m_BodyMaxWidth; - int m_BodyMaxHeight; + SSkinMetricVariableInt m_MaxWidth; + SSkinMetricVariableInt m_MaxHeight; + + float WidthNormalized() + { + return (float)m_Width / (float)m_MaxWidth; + } + + float HeightNormalized() + { + return (float)m_Height / (float)m_MaxHeight; + } + + float OffsetXNormalized() + { + return (float)m_OffsetX / (float)m_MaxWidth; + } + + float OffsetYNormalized() + { + return (float)m_OffsetY / (float)m_MaxHeight; + } + + void Reset() + { + m_Width.Reset(); + m_Height.Reset(); + m_OffsetX.Reset(); + m_OffsetY.Reset(); + m_MaxWidth.Reset(); + m_MaxHeight.Reset(); + } + }; + + struct SSkinMetrics + { + SSkinMetricVariable m_Body; + SSkinMetricVariable m_Feet; int m_FeetWidth; int m_FeetHeight; @@ -64,47 +129,13 @@ struct CSkin void Reset() { - m_BodyWidth = m_BodyHeight = m_BodyOffsetX = m_BodyOffsetY = m_FeetWidth = m_FeetHeight = m_FeetOffsetX = m_FeetOffsetY = -1; + m_Body.Reset(); + m_Feet.Reset(); } - float BodyWidthNormalized() + SSkinMetrics() { - return (float)m_BodyWidth / (float)m_BodyMaxWidth; - } - - float BodyHeightNormalized() - { - return (float)m_BodyHeight / (float)m_BodyMaxHeight; - } - - float BodyOffsetXNormalized() - { - return (float)m_BodyOffsetX / (float)m_BodyMaxWidth; - } - - float BodyOffsetYNormalized() - { - return (float)m_BodyOffsetY / (float)m_BodyMaxHeight; - } - - float FeetWidthNormalized() - { - return (float)m_FeetWidth / (float)m_FeetMaxWidth; - } - - float FeetHeightNormalized() - { - return (float)m_FeetHeight / (float)m_FeetMaxHeight; - } - - float FeetOffsetXNormalized() - { - return (float)m_FeetOffsetX / (float)m_FeetMaxWidth; - } - - float FeetOffsetYNormalized() - { - return (float)m_FeetOffsetY / (float)m_FeetMaxHeight; + Reset(); } }; SSkinMetrics m_Metrics;