From df4c7a08c8f73e6a27efc75395aa155fec5633a0 Mon Sep 17 00:00:00 2001 From: Jupeyy Date: Sun, 8 Nov 2020 06:39:16 +0100 Subject: [PATCH] Add skin metrics --- src/game/client/components/chat.cpp | 11 +- src/game/client/components/chat.h | 1 + src/game/client/components/ghost.cpp | 3 + src/game/client/components/killmessages.cpp | 34 +++++- src/game/client/components/killmessages.h | 2 + src/game/client/components/menus_settings.cpp | 2 + src/game/client/components/players.cpp | 2 + src/game/client/components/skins.cpp | 72 +++++++++++- src/game/client/gameclient.cpp | 5 + src/game/client/render.cpp | 103 +++++++++++++++++- src/game/client/render.h | 12 ++ src/game/client/skin.h | 67 ++++++++++++ 12 files changed, 304 insertions(+), 10 deletions(-) diff --git a/src/game/client/components/chat.cpp b/src/game/client/components/chat.cpp index 2fe23b9d8..4ebad8dfb 100644 --- a/src/game/client/components/chat.cpp +++ b/src/game/client/components/chat.cpp @@ -810,6 +810,8 @@ void CChat::AddLine(int ClientID, int Team, const char *pLine) str_copy(pCurrentLine->m_aSkinName, m_pClient->m_aClients[pCurrentLine->m_ClientID].m_aSkinName, sizeof(pCurrentLine->m_aSkinName)); pCurrentLine->m_ColorBody = m_pClient->m_aClients[pCurrentLine->m_ClientID].m_RenderInfo.m_ColorBody; pCurrentLine->m_ColorFeet = m_pClient->m_aClients[pCurrentLine->m_ClientID].m_RenderInfo.m_ColorFeet; + + pCurrentLine->m_RenderSkinMetrics = m_pClient->m_aClients[pCurrentLine->m_ClientID].m_RenderInfo.m_SkinMetrics; pCurrentLine->m_HasRenderTee = true; } } @@ -883,6 +885,8 @@ void CChat::RefindSkins() m_aLines[r].m_RenderSkin = pSkin->m_ColorableSkin; else m_aLines[r].m_RenderSkin = pSkin->m_OriginalSkin; + + m_aLines[r].m_RenderSkinMetrics = pSkin->m_Metrics; } } } @@ -1281,6 +1285,7 @@ void CChat::OnRender() RenderInfo.m_ColorableRenderSkin = m_aLines[r].m_RenderSkin; else RenderInfo.m_OriginalRenderSkin = m_aLines[r].m_RenderSkin; + RenderInfo.m_SkinMetrics = m_aLines[r].m_RenderSkinMetrics; RenderInfo.m_ColorBody = m_aLines[r].m_ColorBody; RenderInfo.m_ColorFeet = m_aLines[r].m_ColorFeet; @@ -1289,10 +1294,12 @@ void CChat::OnRender() float RowHeight = FONT_SIZE + RealMsgPaddingY; float OffsetTeeY = MESSAGE_TEE_SIZE / 2.0f; float FullHeightMinusTee = RowHeight - MESSAGE_TEE_SIZE; - float TWSkinUnreliableOffset = 1.0f; // teeworlds skins were always a bit in the ground CAnimState *pIdleState = CAnimState::GetIdle(); - RenderTools()->RenderTee(pIdleState, &RenderInfo, EMOTE_NORMAL, vec2(1, 0.1f), vec2(x + (RealMsgPaddingX + MESSAGE_TEE_SIZE) / 2.0f, y + OffsetTeeY + FullHeightMinusTee / 2.0f + TWSkinUnreliableOffset), Blend); + vec2 OffsetToMid; + RenderTools()->GetRenderTeeOffsetToRenderedTee(pIdleState, &RenderInfo, OffsetToMid); + vec2 TeeRenderPos(x + (RealMsgPaddingX + MESSAGE_TEE_SIZE) / 2.0f, y + OffsetTeeY + FullHeightMinusTee / 2.0f + OffsetToMid.y); + RenderTools()->RenderTee(pIdleState, &RenderInfo, EMOTE_NORMAL, vec2(1, 0.1f), TeeRenderPos, Blend); } STextRenderColor TextOutline(0.f, 0.f, 0.f, 0.3f * Blend); diff --git a/src/game/client/components/chat.h b/src/game/client/components/chat.h index 1d1342756..9eac76efd 100644 --- a/src/game/client/components/chat.h +++ b/src/game/client/components/chat.h @@ -41,6 +41,7 @@ class CChat : public CComponent char m_aSkinName[sizeof(g_Config.m_ClPlayerSkin) / sizeof(g_Config.m_ClPlayerSkin[0])]; CSkin::SSkinTextures m_RenderSkin; + CSkin::SSkinMetrics m_RenderSkinMetrics; bool m_CustomColoredSkin; ColorRGBA m_ColorBody; ColorRGBA m_ColorFeet; diff --git a/src/game/client/components/ghost.cpp b/src/game/client/components/ghost.cpp index 20065117d..5b64317f6 100644 --- a/src/game/client/components/ghost.cpp +++ b/src/game/client/components/ghost.cpp @@ -357,6 +357,7 @@ void CGhost::InitRenderInfos(CGhostItem *pGhost) pRenderInfo->m_OriginalRenderSkin = pSkin->m_OriginalSkin; pRenderInfo->m_ColorableRenderSkin = pSkin->m_ColorableSkin; pRenderInfo->m_BloodColor = pSkin->m_BloodColor; + pRenderInfo->m_SkinMetrics = pSkin->m_Metrics; pRenderInfo->m_CustomColoredSkin = pGhost->m_Skin.m_UseCustomColor; if(pGhost->m_Skin.m_UseCustomColor) { @@ -642,6 +643,7 @@ void CGhost::RefindSkin() const CSkin *pSkin = m_pClient->m_pSkins->Get(SkinId); pRenderInfo->m_OriginalRenderSkin = pSkin->m_OriginalSkin; pRenderInfo->m_ColorableRenderSkin = pSkin->m_ColorableSkin; + pRenderInfo->m_SkinMetrics = pSkin->m_Metrics; } } IntsToStr(&m_CurGhost.m_Skin.m_Skin0, 6, aSkinName); @@ -653,5 +655,6 @@ void CGhost::RefindSkin() const CSkin *pSkin = m_pClient->m_pSkins->Get(SkinId); pRenderInfo->m_OriginalRenderSkin = pSkin->m_OriginalSkin; pRenderInfo->m_ColorableRenderSkin = pSkin->m_ColorableSkin; + pRenderInfo->m_SkinMetrics = pSkin->m_Metrics; } } diff --git a/src/game/client/components/killmessages.cpp b/src/game/client/components/killmessages.cpp index 4768e325f..8ac49134c 100644 --- a/src/game/client/components/killmessages.cpp +++ b/src/game/client/components/killmessages.cpp @@ -196,7 +196,8 @@ void CKillMessages::OnRender() } } - RenderTools()->RenderTee(CAnimState::GetIdle(), &m_aKillmsgs[r].m_VictimRenderInfo, EMOTE_PAIN, vec2(-1, 0), vec2(x, y + 28)); + if(m_aKillmsgs[r].m_VictimID >= 0) + RenderTools()->RenderTee(CAnimState::GetIdle(), &m_aKillmsgs[r].m_VictimRenderInfo, EMOTE_PAIN, vec2(-1, 0), vec2(x, y + 28)); x -= 32.0f; // render weapon @@ -229,7 +230,8 @@ void CKillMessages::OnRender() // render killer tee x -= 24.0f; - RenderTools()->RenderTee(CAnimState::GetIdle(), &m_aKillmsgs[r].m_KillerRenderInfo, EMOTE_ANGRY, vec2(1, 0), vec2(x, y + 28)); + if(m_aKillmsgs[r].m_KillerID >= 0) + RenderTools()->RenderTee(CAnimState::GetIdle(), &m_aKillmsgs[r].m_KillerRenderInfo, EMOTE_ANGRY, vec2(1, 0), vec2(x, y + 28)); x -= 32.0f; // render killer name @@ -242,3 +244,31 @@ void CKillMessages::OnRender() y += 46.0f; } } + +void CKillMessages::RefindSkins() +{ + for(int i = 0; i < MAX_KILLMSGS; i++) + { + int r = i % MAX_KILLMSGS; + if(Client()->GameTick(g_Config.m_ClDummy) > m_aKillmsgs[r].m_Tick + 50 * 10) + continue; + + if(m_aKillmsgs[r].m_KillerID >= 0) + { + CGameClient::CClientData &Client = GameClient()->m_aClients[m_aKillmsgs[r].m_KillerID]; + if(Client.m_aSkinName[0] != '\0') + m_aKillmsgs[r].m_KillerRenderInfo = Client.m_RenderInfo; + else + m_aKillmsgs[r].m_KillerID = -1; + } + + if(m_aKillmsgs[r].m_VictimID >= 0) + { + CGameClient::CClientData &Client = GameClient()->m_aClients[m_aKillmsgs[r].m_VictimID]; + if(Client.m_aSkinName[0] != '\0') + m_aKillmsgs[r].m_VictimRenderInfo = Client.m_RenderInfo; + else + m_aKillmsgs[r].m_VictimID = -1; + } + } +} diff --git a/src/game/client/components/killmessages.h b/src/game/client/components/killmessages.h index 3cfbf5c20..5a29b8422 100644 --- a/src/game/client/components/killmessages.h +++ b/src/game/client/components/killmessages.h @@ -52,6 +52,8 @@ public: virtual void OnRender(); virtual void OnMessage(int MsgType, void *pRawMsg); virtual void OnInit(); + + void RefindSkins(); }; #endif diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index f830b52cb..81c387601 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -469,6 +469,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView) const CSkin *pSkin = m_pClient->m_pSkins->Get(m_pClient->m_pSkins->Find(Skin)); OwnSkinInfo.m_OriginalRenderSkin = pSkin->m_OriginalSkin; OwnSkinInfo.m_ColorableRenderSkin = pSkin->m_ColorableSkin; + OwnSkinInfo.m_SkinMetrics = pSkin->m_Metrics; OwnSkinInfo.m_CustomColoredSkin = *UseCustomColor; if(*UseCustomColor) { @@ -649,6 +650,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView) Info.m_OriginalRenderSkin = s->m_OriginalSkin; Info.m_ColorableRenderSkin = s->m_ColorableSkin; + Info.m_SkinMetrics = s->m_Metrics; Item.m_Rect.HSplitTop(5.0f, 0, &Item.m_Rect); // some margin from the top RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, 0, vec2(1.0f, 0.0f), vec2(Item.m_Rect.x + 30, Item.m_Rect.y + Item.m_Rect.h / 2)); diff --git a/src/game/client/components/players.cpp b/src/game/client/components/players.cpp index f3d81b6ee..cc2501bf3 100644 --- a/src/game/client/components/players.cpp +++ b/src/game/client/components/players.cpp @@ -654,6 +654,7 @@ void CPlayers::OnRender() m_aRenderInfo[i].m_OriginalRenderSkin = pSkin->m_OriginalSkin; m_aRenderInfo[i].m_ColorableRenderSkin = pSkin->m_ColorableSkin; m_aRenderInfo[i].m_BloodColor = pSkin->m_BloodColor; + m_aRenderInfo[i].m_SkinMetrics = pSkin->m_Metrics; m_aRenderInfo[i].m_CustomColoredSkin = IsTeamplay; if(!IsTeamplay) { @@ -668,6 +669,7 @@ void CPlayers::OnRender() m_RenderInfoSpec.m_OriginalRenderSkin = pSkin->m_OriginalSkin; m_RenderInfoSpec.m_ColorableRenderSkin = pSkin->m_ColorableSkin; m_RenderInfoSpec.m_BloodColor = pSkin->m_BloodColor; + m_RenderInfoSpec.m_SkinMetrics = pSkin->m_Metrics; m_RenderInfoSpec.m_CustomColoredSkin = false; m_RenderInfoSpec.m_Size = 64.0f; diff --git a/src/game/client/components/skins.cpp b/src/game/client/components/skins.cpp index 461f32204..9c2cd4f58 100644 --- a/src/game/client/components/skins.cpp +++ b/src/game/client/components/skins.cpp @@ -78,24 +78,49 @@ int CSkins::LoadSkin(const char *pName, const char *pPath, int DirType) for(int i = 0; i < 6; ++i) Skin.m_OriginalSkin.m_Eyes[i] = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_EYE_NORMAL + i]); - int BodySize = 96; // body size + int FeetGridPixelsWidth = (Info.m_Width / g_pData->m_aSprites[SPRITE_TEE_FOOT].m_pSet->m_Gridx); + int FeetGridPixelsHeight = (Info.m_Height / g_pData->m_aSprites[SPRITE_TEE_FOOT].m_pSet->m_Gridy); + int FeetWidth = g_pData->m_aSprites[SPRITE_TEE_FOOT].m_W * FeetGridPixelsWidth; + int FeetHeight = g_pData->m_aSprites[SPRITE_TEE_FOOT].m_H * FeetGridPixelsHeight; + + 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 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}; for(int y = 0; y < BodySize; y++) for(int x = 0; x < BodySize; x++) { - if(d[y * Pitch + x * 4 + 3] > 128) + uint8_t AlphaValue = d[y * Pitch + x * 4 + 3]; + if(AlphaValue > 128) { aColors[0] += d[y * Pitch + x * 4 + 0]; 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]))); @@ -103,6 +128,49 @@ 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); + + Skin.m_Metrics.m_BodyMaxWidth = BodySize; + Skin.m_Metrics.m_BodyMaxHeight = BodySize; + + // get feet size + { + int MaxFeetY = -1; + int MinFeetY = FeetHeight + 1; + int MaxFeetX = -1; + int MinFeetX = FeetWidth + 1; + + 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; + } + // create colorless version int Step = Info.m_Format == CImageInfo::FORMAT_RGBA ? 4 : 3; diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 7f05d7eda..03d3bd26f 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -1252,6 +1252,7 @@ void CGameClient::OnNewSnapshot() const CSkin *pSkin = m_pSkins->Get(m_pSkins->Find(pClient->m_aSkinName)); pClient->m_SkinInfo.m_OriginalRenderSkin = pSkin->m_OriginalSkin; pClient->m_SkinInfo.m_ColorableRenderSkin = pSkin->m_ColorableSkin; + pClient->m_SkinInfo.m_SkinMetrics = pSkin->m_Metrics; pClient->m_SkinInfo.m_BloodColor = pSkin->m_BloodColor; pClient->m_SkinInfo.m_CustomColoredSkin = pClient->m_UseCustomColor; @@ -1974,6 +1975,7 @@ void CGameClient::CClientData::Reset() m_SkinInfo.m_CustomColoredSkin = false; m_SkinInfo.m_ColorBody = ColorRGBA(1, 1, 1); m_SkinInfo.m_ColorFeet = ColorRGBA(1, 1, 1); + m_SkinInfo.m_SkinMetrics.Reset(); m_Solo = false; m_Jetpack = false; @@ -2888,6 +2890,8 @@ void CGameClient::RefindSkins() { for(auto &Client : m_aClients) { + Client.m_SkinInfo.m_OriginalRenderSkin.Reset(); + Client.m_SkinInfo.m_ColorableRenderSkin.Reset(); if(Client.m_aSkinName[0] != '\0') { const CSkin *pSkin = m_pSkins->Get(m_pSkins->Find(Client.m_aSkinName)); @@ -2898,6 +2902,7 @@ void CGameClient::RefindSkins() } m_pGhost->RefindSkin(); m_pChat->RefindSkins(); + gs_KillMessages.RefindSkins(); } void CGameClient::LoadMapSettings() diff --git a/src/game/client/render.cpp b/src/game/client/render.cpp index 00ad48678..3ac70ca9e 100644 --- a/src/game/client/render.cpp +++ b/src/game/client/render.cpp @@ -540,6 +540,100 @@ void CRenderTools::DrawCircle(float x, float y, float r, int Segments) Graphics()->QuadsDrawFreeform(Array, NumItems); } +void CRenderTools::GetRenderTeeAnimScaleAndBaseSize(CAnimState *pAnim, CTeeRenderInfo *pInfo, float &AnimScale, float &BaseSize) +{ + AnimScale = pInfo->m_Size * 1.0f / 64.0f; + BaseSize = pInfo->m_Size; +} + +void CRenderTools::GetRenderTeeBodyScale(float BaseSize, float &BodyScale) +{ + BodyScale = g_Config.m_ClFatSkins ? BaseSize * 1.3f : BaseSize; + BodyScale /= 64.0f; +} + +void CRenderTools::GetRenderTeeFeetScale(float BaseSize, float &FeetScaleWidth, float &FeetScaleHeight) +{ + FeetScaleWidth = BaseSize / 64.0f; + FeetScaleHeight = (BaseSize / 2) / 32.0f; +} + +void CRenderTools::GetRenderTeeBodySize(CAnimState *pAnim, CTeeRenderInfo *pInfo, vec2 &BodyOffset, float &Width, float &Height) +{ + float AnimScale, BaseSize; + GetRenderTeeAnimScaleAndBaseSize(pAnim, pInfo, AnimScale, BaseSize); + + 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; +} + +void CRenderTools::GetRenderTeeFeetSize(CAnimState *pAnim, CTeeRenderInfo *pInfo, vec2 &FeetOffset, float &Width, float &Height) +{ + float AnimScale, BaseSize; + GetRenderTeeAnimScaleAndBaseSize(pAnim, pInfo, AnimScale, BaseSize); + + 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; +} + +void CRenderTools::GetRenderTeeOffsetToRenderedTee(CAnimState *pAnim, CTeeRenderInfo *pInfo, vec2 &TeeOffsetToMid) +{ + float AnimScale, BaseSize; + GetRenderTeeAnimScaleAndBaseSize(pAnim, pInfo, AnimScale, BaseSize); + vec2 BodyPos = vec2(pAnim->GetBody()->m_X, pAnim->GetBody()->m_Y) * AnimScale; + + float AssumedScale = BaseSize / 64.0f; + + // just use the lowest feet + vec2 FeetPos; + CAnimKeyframe *pFoot = pAnim->GetFrontFoot(); + FeetPos = vec2(pFoot->m_X * AnimScale, pFoot->m_Y * AnimScale); + pFoot = pAnim->GetBackFoot(); + FeetPos = vec2(FeetPos.x, maximum(FeetPos.y, pFoot->m_Y * AnimScale)); + + vec2 BodyOffset; + float BodyWidth, BodyHeight; + GetRenderTeeBodySize(pAnim, pInfo, BodyOffset, BodyWidth, BodyHeight); + + // -32 is the assumed min relative position for the quad + float MinY = -32.0f * AssumedScale; + // the body pos shifts the body away from center + MinY += BodyPos.y; + // the actual body is smaller tho, bcs it doesnt use the full skin image in most cases + MinY += BodyOffset.y; + + vec2 FeetOffset; + float FeetWidth, FeetHeight; + GetRenderTeeFeetSize(pAnim, pInfo, FeetOffset, FeetWidth, FeetHeight); + + // MaxY builds up from the MinY + float MaxY = MinY + BodyHeight; + // if the body is smaller than the total feet offset, use feet + // since feets are smaller in height, respect the assumed relative position + MaxY = maximum(MaxY, (-16.0f * AssumedScale + FeetPos.y) + FeetOffset.y + FeetHeight); + + // now we got the full rendered size + float FullHeight = (MaxY - MinY); + + // next step is to calculate the offset that was created compared to the assumed relative positon + float MidOfRendered = MinY + FullHeight / 2.0f; + + // TODO: x coordinate is ignored for now, bcs it's not really used yet anyway + TeeOffsetToMid.x = 0; + // negative value, because the calculation that uses this offset should work with addition. + TeeOffsetToMid.y = -MidOfRendered; +} + void CRenderTools::RenderTee(CAnimState *pAnim, CTeeRenderInfo *pInfo, int Emote, vec2 Dir, vec2 Pos, float Alpha) { vec2 Direction = Dir; @@ -555,8 +649,8 @@ void CRenderTools::RenderTee(CAnimState *pAnim, CTeeRenderInfo *pInfo, int Emote for(int f = 0; f < 2; f++) { - float AnimScale = pInfo->m_Size * 1.0f / 64.0f; - float BaseSize = pInfo->m_Size; + float AnimScale, BaseSize; + GetRenderTeeAnimScaleAndBaseSize(pAnim, pInfo, AnimScale, BaseSize); if(f == 1) { Graphics()->QuadsSetRotation(pAnim->GetBody()->m_Angle * pi * 2); @@ -564,9 +658,10 @@ void CRenderTools::RenderTee(CAnimState *pAnim, CTeeRenderInfo *pInfo, int Emote // draw body Graphics()->SetColor(pInfo->m_ColorBody.r, pInfo->m_ColorBody.g, pInfo->m_ColorBody.b, Alpha); vec2 BodyPos = Position + vec2(pAnim->GetBody()->m_X, pAnim->GetBody()->m_Y) * AnimScale; - float BodySize = g_Config.m_ClFatSkins ? BaseSize * 1.3f : BaseSize; + float BodyScale; + GetRenderTeeBodyScale(BaseSize, BodyScale); Graphics()->TextureSet(OutLine == 1 ? pSkinTextures->m_BodyOutline : pSkinTextures->m_Body); - Graphics()->RenderQuadContainerAsSprite(m_TeeQuadContainerIndex, OutLine, BodyPos.x, BodyPos.y, BodySize / 64.f, BodySize / 64.f); + Graphics()->RenderQuadContainerAsSprite(m_TeeQuadContainerIndex, OutLine, BodyPos.x, BodyPos.y, BodyScale, BodyScale); // draw eyes if(p == 1) diff --git a/src/game/client/render.h b/src/game/client/render.h index d88ee34b6..867785551 100644 --- a/src/game/client/render.h +++ b/src/game/client/render.h @@ -23,6 +23,9 @@ public: CSkin::SSkinTextures m_OriginalRenderSkin; CSkin::SSkinTextures m_ColorableRenderSkin; + + CSkin::SSkinMetrics m_SkinMetrics; + bool m_CustomColoredSkin; ColorRGBA m_BloodColor; @@ -50,6 +53,10 @@ class CRenderTools { int m_TeeQuadContainerIndex; + void GetRenderTeeAnimScaleAndBaseSize(class CAnimState *pAnim, CTeeRenderInfo *pInfo, float &AnimScale, float &BaseSize); + void GetRenderTeeBodyScale(float BaseSize, float &BodyScale); + void GetRenderTeeFeetScale(float BaseSize, float &FeetScaleWidth, float &FeetScaleHeight); + public: class IGraphics *m_pGraphics; class CUI *m_pUI; @@ -95,6 +102,11 @@ public: // larger rendering methods void RenderTilemapGenerateSkip(class CLayers *pLayers); + void GetRenderTeeBodySize(class CAnimState *pAnim, CTeeRenderInfo *pInfo, vec2 &BodyOffset, float &Width, float &Height); + void GetRenderTeeFeetSize(class CAnimState *pAnim, CTeeRenderInfo *pInfo, vec2 &FeetOffset, float &Width, float &Height); + + // returns the offset to use, to render the tee with @see RenderTee exactly in the mid + void GetRenderTeeOffsetToRenderedTee(class CAnimState *pAnim, CTeeRenderInfo *pInfo, vec2 &TeeOffsetToMid); // object render methods (gc_render_obj.cpp) void RenderTee(class CAnimState *pAnim, CTeeRenderInfo *pInfo, int Emote, vec2 Dir, vec2 Pos, float Alpha = 1.0f); diff --git a/src/game/client/skin.h b/src/game/client/skin.h index 978430806..d5d7cf31d 100644 --- a/src/game/client/skin.h +++ b/src/game/client/skin.h @@ -42,6 +42,73 @@ struct CSkin char m_aName[24]; ColorRGBA m_BloodColor; + struct SSkinMetrics + { + int m_BodyWidth; + int m_BodyHeight; + int m_BodyOffsetX; + int m_BodyOffsetY; + + // these can be used to normalize the metrics + int m_BodyMaxWidth; + int m_BodyMaxHeight; + + int m_FeetWidth; + int m_FeetHeight; + int m_FeetOffsetX; + int m_FeetOffsetY; + + // these can be used to normalize the metrics + int m_FeetMaxWidth; + int m_FeetMaxHeight; + + void Reset() + { + m_BodyWidth = m_BodyHeight = m_BodyOffsetX = m_BodyOffsetY = m_FeetWidth = m_FeetHeight = m_FeetOffsetX = m_FeetOffsetY = -1; + } + + float BodyWidthNormalized() + { + 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; + } + }; + SSkinMetrics m_Metrics; + bool operator<(const CSkin &Other) const { return str_comp_nocase(m_aName, Other.m_aName) < 0; } bool operator<(const char *pOther) const { return str_comp_nocase(m_aName, pOther) < 0; }