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>
|
2008-08-14 17:19:13 +00:00
|
|
|
|
|
|
|
#include <base/system.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <base/math.h>
|
2008-08-14 17:19:13 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <engine/graphics.h>
|
|
|
|
#include <engine/storage.h>
|
|
|
|
#include <engine/shared/engine.h>
|
2008-10-21 18:05:06 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include "skins.h"
|
2008-10-21 18:05:06 +00:00
|
|
|
|
2010-09-24 11:38:03 +00:00
|
|
|
void CSkins::SkinScan(const char *pName, int IsDir, int DirType, void *pUser)
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
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)
|
2007-11-18 12:03:59 +00:00
|
|
|
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))
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
2010-08-17 22:06:00 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf), "failed to load skin from %s", pName);
|
|
|
|
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
|
2007-11-18 12:03:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-18 18:48:49 +00:00
|
|
|
CSkin Skin;
|
|
|
|
Skin.m_OrgTexture = pSelf->Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0);
|
2007-11-18 12:03:59 +00:00
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-18 18:48:49 +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;
|
2008-03-23 12:36:24 +00:00
|
|
|
|
|
|
|
// 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++)
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
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;
|
2007-11-18 12:03:59 +00:00
|
|
|
}
|
2008-03-17 01:41:11 +00:00
|
|
|
|
2007-11-18 12:03:59 +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;
|
2008-03-23 12:36:24 +00:00
|
|
|
|
|
|
|
// 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++)
|
2008-03-23 12:36:24 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(d[y*Pitch+x*4+3] > 128)
|
|
|
|
Freq[d[y*Pitch+x*4]]++;
|
2008-03-23 12:36:24 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2008-03-23 12:36:24 +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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-18 18:48:49 +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);
|
2007-11-18 12:03:59 +00:00
|
|
|
|
|
|
|
// set skin data
|
2010-09-18 18:48:49 +00:00
|
|
|
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);
|
2010-08-17 22:06:00 +00:00
|
|
|
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
|
2010-09-18 18:48:49 +00:00
|
|
|
pSelf->m_aSkins.add(Skin);
|
2007-11-18 12:03:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CSkins::Init()
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
|
|
|
// load skins
|
2010-09-18 18:48:49 +00:00
|
|
|
m_aSkins.clear();
|
2010-05-29 07:25:38 +00:00
|
|
|
Storage()->ListDirectory(IStorage::TYPE_ALL, "skins", SkinScan, this);
|
2011-01-06 21:55:57 +00:00
|
|
|
if(!m_aSkins.size())
|
|
|
|
{
|
|
|
|
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "gameclient", "failed to load skins. folder='skins/'");
|
|
|
|
CSkin DummySkin;
|
|
|
|
DummySkin.m_OrgTexture = -1;
|
|
|
|
DummySkin.m_ColorTexture = -1;
|
|
|
|
str_copy(DummySkin.m_aName, "dummy", sizeof(DummySkin.m_aName));
|
|
|
|
DummySkin.m_BloodColor = vec3(1.0f, 1.0f, 1.0f);
|
|
|
|
m_aSkins.add(DummySkin);
|
|
|
|
}
|
2007-11-18 12:03:59 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
int CSkins::Num()
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
2010-09-18 18:48:49 +00:00
|
|
|
return m_aSkins.size();
|
2007-11-18 12:03:59 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
const CSkins::CSkin *CSkins::Get(int Index)
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
2010-09-18 18:48:49 +00:00
|
|
|
return &m_aSkins[Index%m_aSkins.size()];
|
2007-11-18 12:03:59 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
int CSkins::Find(const char *pName)
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
2010-09-18 18:48:49 +00:00
|
|
|
for(int i = 0; i < m_aSkins.size(); i++)
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(str_comp(m_aSkins[i].m_aName, pName) == 0)
|
2007-11-18 12:03:59 +00:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-11-24 00:11:56 +00:00
|
|
|
vec3 CSkins::GetColorV3(int v)
|
|
|
|
{
|
|
|
|
return HslToRgb(vec3(((v>>16)&0xff)/255.0f, ((v>>8)&0xff)/255.0f, 0.5f+(v&0xff)/255.0f*0.5f));
|
|
|
|
}
|
|
|
|
|
|
|
|
vec4 CSkins::GetColorV4(int v)
|
2007-11-18 14:24:34 +00:00
|
|
|
{
|
2011-01-04 10:58:25 +00:00
|
|
|
vec3 r = GetColorV3(v);
|
2007-11-18 14:24:34 +00:00
|
|
|
return vec4(r.r, r.g, r.b, 1.0f);
|
|
|
|
}
|