ddnet/src/game/client/components/skins.cpp

187 lines
4.3 KiB
C++
Raw Normal View History

2010-11-20 10:37:14 +00:00
/* (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. */
2008-03-17 01:41:11 +00:00
#include <math.h>
#include <base/system.h>
2010-05-29 07:25:38 +00:00
#include <base/math.h>
2010-05-29 07:25:38 +00:00
#include <engine/graphics.h>
#include <engine/storage.h>
#include <engine/shared/engine.h>
2010-05-29 07:25:38 +00:00
#include "skins.h"
void CSkins::SkinScan(const char *pName, int IsDir, int DirType, void *pUser)
{
2010-05-29 07:25:38 +00:00
CSkins *pSelf = (CSkins *)pUser;
int l = str_length(pName);
2010-09-24 11:21:03 +00:00
if(l < 4 || IsDir || str_comp(pName+l-4, ".png") != 0)
return;
2010-05-29 07:25:38 +00:00
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "skins/%s", pName);
CImageInfo Info;
2010-10-06 21:07:35 +00:00
if(!pSelf->Graphics()->LoadPNG(&Info, aBuf, DirType))
{
str_format(aBuf, sizeof(aBuf), "failed to load skin from %s", pName);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
return;
}
CSkin Skin;
Skin.m_OrgTexture = pSelf->Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0);
2010-05-29 07:25:38 +00:00
int BodySize = 96; // body size
unsigned char *d = (unsigned char *)Info.m_pData;
int Pitch = Info.m_Width*4;
2008-03-17 01:41:11 +00:00
// dig out blood color
{
2010-05-29 07:25:38 +00:00
int aColors[3] = {0};
for(int y = 0; y < BodySize; y++)
for(int x = 0; x < BodySize; x++)
2008-03-17 01:41:11 +00:00
{
2010-05-29 07:25:38 +00:00
if(d[y*Pitch+x*4+3] > 128)
2008-03-17 01:41:11 +00:00
{
2010-05-29 07:25:38 +00:00
aColors[0] += d[y*Pitch+x*4+0];
aColors[1] += d[y*Pitch+x*4+1];
aColors[2] += d[y*Pitch+x*4+2];
2008-03-17 01:41:11 +00:00
}
}
Skin.m_BloodColor = normalize(vec3(aColors[0], aColors[1], aColors[2]));
2008-03-17 01:41:11 +00:00
}
// create colorless version
2010-05-29 07:25:38 +00:00
int Step = Info.m_Format == CImageInfo::FORMAT_RGBA ? 4 : 3;
// make the texture gray scale
2010-05-29 07:25:38 +00:00
for(int i = 0; i < Info.m_Width*Info.m_Height; i++)
{
2010-05-29 07:25:38 +00:00
int v = (d[i*Step]+d[i*Step+1]+d[i*Step+2])/3;
d[i*Step] = v;
d[i*Step+1] = v;
d[i*Step+2] = v;
}
2008-03-17 01:41:11 +00:00
2007-11-26 22:26:33 +00:00
if(1)
{
2010-05-29 07:25:38 +00:00
int Freq[256] = {0};
int OrgWeight = 0;
int NewWeight = 192;
// find most common frequence
2010-05-29 07:25:38 +00:00
for(int y = 0; y < BodySize; y++)
for(int x = 0; x < BodySize; x++)
{
2010-05-29 07:25:38 +00:00
if(d[y*Pitch+x*4+3] > 128)
Freq[d[y*Pitch+x*4]]++;
}
2007-11-26 22:26:33 +00:00
for(int i = 1; i < 256; i++)
{
2010-05-29 07:25:38 +00:00
if(Freq[OrgWeight] < Freq[i])
OrgWeight = i;
2007-11-26 22:26:33 +00:00
}
// reorder
2010-05-29 07:25:38 +00:00
int InvOrgWeight = 255-OrgWeight;
int InvNewWeight = 255-NewWeight;
for(int y = 0; y < BodySize; y++)
for(int x = 0; x < BodySize; x++)
2007-11-26 22:26:33 +00:00
{
2010-05-29 07:25:38 +00:00
int v = d[y*Pitch+x*4];
if(v <= OrgWeight)
v = (int)(((v/(float)OrgWeight) * NewWeight));
2007-11-26 22:26:33 +00:00
else
2010-05-29 07:25:38 +00:00
v = (int)(((v-OrgWeight)/(float)InvOrgWeight)*InvNewWeight + NewWeight);
d[y*Pitch+x*4] = v;
d[y*Pitch+x*4+1] = v;
d[y*Pitch+x*4+2] = v;
2007-11-26 22:26:33 +00:00
}
}
Skin.m_ColorTexture = pSelf->Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0);
2010-05-29 07:25:38 +00:00
mem_free(Info.m_pData);
// set skin data
str_copy(Skin.m_aName, pName, min((int)sizeof(Skin.m_aName),l-3));
str_format(aBuf, sizeof(aBuf), "load skin %s", Skin.m_aName);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
pSelf->m_aSkins.add(Skin);
}
2010-05-29 07:25:38 +00:00
void CSkins::Init()
{
// load skins
m_aSkins.clear();
2010-05-29 07:25:38 +00:00
Storage()->ListDirectory(IStorage::TYPE_ALL, "skins", SkinScan, this);
}
2010-05-29 07:25:38 +00:00
int CSkins::Num()
{
return m_aSkins.size();
}
2010-05-29 07:25:38 +00:00
const CSkins::CSkin *CSkins::Get(int Index)
{
return &m_aSkins[Index%m_aSkins.size()];
}
2010-05-29 07:25:38 +00:00
int CSkins::Find(const char *pName)
{
for(int i = 0; i < m_aSkins.size(); i++)
{
2010-05-29 07:25:38 +00:00
if(str_comp(m_aSkins[i].m_aName, pName) == 0)
return i;
}
return -1;
}
// these converter functions were nicked from some random internet pages
2010-05-29 07:25:38 +00:00
static float HueToRgb(float v1, float v2, float h)
{
if(h < 0) h += 1;
if(h > 1) h -= 1;
if((6 * h) < 1) return v1 + ( v2 - v1 ) * 6 * h;
if((2 * h) < 1) return v2;
if((3 * h) < 2) return v1 + ( v2 - v1 ) * ((2.0f/3.0f) - h) * 6;
return v1;
}
2010-05-29 07:25:38 +00:00
static vec3 HslToRgb(vec3 in)
{
float v1, v2;
2010-05-29 07:25:38 +00:00
vec3 Out;
if(in.s == 0)
{
2010-05-29 07:25:38 +00:00
Out.r = in.l;
Out.g = in.l;
Out.b = in.l;
}
else
{
if(in.l < 0.5f)
v2 = in.l * (1 + in.s);
else
v2 = (in.l+in.s) - (in.s*in.l);
v1 = 2 * in.l - v2;
2010-05-29 07:25:38 +00:00
Out.r = HueToRgb(v1, v2, in.h + (1.0f/3.0f));
Out.g = HueToRgb(v1, v2, in.h);
Out.b = HueToRgb(v1, v2, in.h - (1.0f/3.0f));
}
2010-05-29 07:25:38 +00:00
return Out;
}
2010-05-29 07:25:38 +00:00
vec4 CSkins::GetColor(int v)
{
2010-05-29 07:25:38 +00:00
vec3 r = HslToRgb(vec3(((v>>16)&0xff)/255.0f, ((v>>8)&0xff)/255.0f, 0.5f+(v&0xff)/255.0f*0.5f));
return vec4(r.r, r.g, r.b, 1.0f);
}