Play-/Source/ui_win32/IconMesh.cpp
2015-10-13 22:42:49 -04:00

179 lines
4.1 KiB
C++

#include "IconMesh.h"
#include <gl/glew.h>
#include <math.h>
CIconMesh::CIconMesh(const IconPtr& icon)
: m_icon(icon)
, m_time(0)
, m_texture(0)
, m_animLength(0)
{
m_frameInfluences.reserve(m_icon->GetFrameCount());
//Compute animation length
for(unsigned int i = 0; i < m_icon->GetFrameCount(); i++)
{
const CIcon::FRAME* frame = m_icon->GetFrame(i);
for(unsigned int j = 0; j < frame->nKeyCount; j++)
{
const CIcon::KEY& key = frame->pKeys[j];
m_animLength = std::max<float>(m_animLength, key.nTime);
}
}
LoadTexture();
ComputeFrameInfluences();
}
CIconMesh::~CIconMesh()
{
glDeleteTextures(1, &m_texture);
}
void CIconMesh::Render() const
{
const CIcon::TEXCOORD* pTexCoords = m_icon->GetTexCoords();
unsigned int nVertexCount = m_icon->GetVertexCount();
glBindTexture(GL_TEXTURE_2D, m_texture);
glBegin(GL_TRIANGLES);
for(unsigned int i = 0; i < nVertexCount; i++)
{
glTexCoord2f(pTexCoords[i].nS, pTexCoords[i].nT);
float totalX = 0;
float totalY = 0;
float totalZ = 0;
for(unsigned int j = 0; j < m_frameInfluences.size(); j++)
{
const auto& influence(m_frameInfluences[j]);
auto shape = m_icon->GetShape(influence.shapeId);
if(!shape) continue;
totalX += shape[i].nX * influence.amplitude;
totalY += shape[i].nY * influence.amplitude;
totalZ += shape[i].nZ * influence.amplitude;
}
glVertex3f(totalX, totalY, totalZ);
}
glEnd();
glBindTexture(GL_TEXTURE_2D, NULL);
}
void CIconMesh::Update(float dt)
{
ComputeFrameInfluences();
m_time += (dt * 133);
if(m_time > m_animLength)
{
m_time -= m_animLength;
}
}
void CIconMesh::ComputeFrameInfluences()
{
m_frameInfluences.resize(0);
for(unsigned int i = 0; i < m_icon->GetFrameCount(); i++)
{
//We need to check if this frame influences the mesh at the current time
const CIcon::FRAME* frame = m_icon->GetFrame(i);
float frameAmp = 0;
for(unsigned int j = 0; j < frame->nKeyCount; j++)
{
const CIcon::KEY& key = frame->pKeys[j];
//Check end and start cases
if(
((j == 0) && m_time <= key.nTime) ||
((j == frame->nKeyCount - 1))
)
{
frameAmp = key.nAmplitude;
break;
}
assert((j + 1) != frame->nKeyCount);
const CIcon::KEY& key0 = frame->pKeys[j + 0];
const CIcon::KEY& key1 = frame->pKeys[j + 1];
if(m_time >= key0.nTime && m_time <= key1.nTime)
{
float insideTime = m_time - key0.nTime;
float slope = (key1.nAmplitude - key0.nAmplitude) / (key1.nTime - key0.nTime);
frameAmp = (insideTime * slope) + key0.nAmplitude;
break;
}
}
if(frameAmp != 0)
{
//GTA San Andreas' icon references an invalid shape id.
//If it's invalid, reference the first shape
uint32 shapeId = frame->nShapeId;
if(shapeId >= m_icon->GetShapeCount()) shapeId = 0;
FRAMEINFLUENCE influence;
influence.shapeId = shapeId;
influence.amplitude = frameAmp;
m_frameInfluences.push_back(influence);
}
}
if(
(m_frameInfluences.size() == 0) &&
(m_icon->GetFrameCount() == 1))
{
const CIcon::FRAME* frame = m_icon->GetFrame(0);
FRAMEINFLUENCE influence;
influence.shapeId = frame->nShapeId;
influence.amplitude = 1;
m_frameInfluences.push_back(influence);
}
}
void CIconMesh::LoadTexture()
{
uint32* pCvtBuffer = new uint32[128 * 128];
const uint16* pTexture = m_icon->GetTexture();
for(unsigned int i = 0; i < (128 * 128); i++)
{
uint16 nPixel = pTexture[i];
uint8 nR = ((nPixel & 0x001F) >> 0) << 3;
uint8 nG = ((nPixel & 0x03E0) >> 5) << 3;
uint8 nB = ((nPixel & 0x7C00) >> 10) << 3;
uint8 nA = (nPixel & 0x8000) != 0 ? 0xFF : 0x00;
((uint8*)&pCvtBuffer[i])[0] = nR;
((uint8*)&pCvtBuffer[i])[1] = nG;
((uint8*)&pCvtBuffer[i])[2] = nB;
((uint8*)&pCvtBuffer[i])[3] = nA;
}
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, 4, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, pCvtBuffer);
glBindTexture(GL_TEXTURE_2D, NULL);
delete [] pCvtBuffer;
}