WiiFlow_Lite/source/gui/cursor.cpp
2012-01-21 20:57:41 +00:00

219 lines
6.8 KiB
C++

#include "cursor.hpp"
#include "pngu.h"
#include <algorithm>
using namespace std;
extern const u8 player1_point_png[];
extern const u8 player2_point_png[];
extern const u8 player3_point_png[];
extern const u8 player4_point_png[];
static inline u32 coordsI8(u32 x, u32 y, u32 w)
{
return (((y >> 2) * (w >> 3) + (x >> 3)) << 5) + ((y & 3) << 3) + (x & 7);
}
static inline u32 coordsRGBA8(u32 x, u32 y, u32 w)
{
return ((((y >> 2) * (w >> 2) + (x >> 2)) << 5) + ((y & 3) << 2) + (x & 3)) << 1;
}
bool CCursor::init(const char *png, bool wideFix, CColor shadowColor, float shadowX, float shadowY, bool blur, int chan)
{
bool ok = true;
bool shadow = shadowColor.a > 0;
m_wideFix = wideFix;
m_x = -1;
m_y = -1;
if (STexture::TE_OK != m_texture.fromPNGFile(png, GX_TF_RGBA8))
{
if (chan == 0)
ok = STexture::TE_OK == m_texture.fromPNG(player1_point_png, GX_TF_RGBA8);
else if (chan == 1)
ok = STexture::TE_OK == m_texture.fromPNG(player2_point_png, GX_TF_RGBA8);
else if (chan == 2)
ok = STexture::TE_OK == m_texture.fromPNG(player3_point_png, GX_TF_RGBA8);
else if (chan == 3)
ok = STexture::TE_OK == m_texture.fromPNG(player4_point_png, GX_TF_RGBA8);
}
if (ok && shadow)
{
m_shadowColor = shadowColor;
m_shadowX = shadowX;
m_shadowY = shadowY;
m_shadow.width = m_texture.width;
m_shadow.height = m_texture.height;
m_shadow.maxLOD = 0;
m_shadow.format = GX_TF_I8;
m_shadow.data = smartMem2Alloc(GX_GetTexBufferSize(m_shadow.width, m_shadow.height, m_shadow.format, GX_FALSE, 0));
if (!!m_shadow.data)
{
const u8 *src = m_texture.data.get();
u8 *dst = m_shadow.data.get();
u32 w = m_shadow.width;
for (u32 yy = 0; yy < m_shadow.height; ++yy)
for (u32 xx = 0; xx < m_shadow.width; ++xx)
dst[coordsI8(xx, yy, w)] = src[coordsRGBA8(xx, yy, w)];
if (blur) _blur();
}
}
return ok;
}
void CCursor::draw(int x, int y, float a)
{
GXTexObj texObj;
float w = (float)m_texture.width * 0.5f;
float h = (float)m_texture.height * 0.5f;
Mtx modelViewMtx;
Vector3D v;
float xScale = m_wideFix ? 0.75f : 1.f;
m_x = x - m_texture.width / 2;
m_y = y - m_texture.height / 2;
//
GX_SetNumChans(1);
GX_ClearVtxDesc();
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GX_SetNumTexGens(1);
GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
GX_SetAlphaUpdate(GX_TRUE);
GX_SetCullMode(GX_CULL_NONE);
GX_SetZMode(GX_DISABLE, GX_LEQUAL, GX_TRUE);
// Shadow
if (!!m_shadow.data)
{
guMtxIdentity(modelViewMtx);
guMtxTransApply(modelViewMtx, modelViewMtx, (float)x - w + m_shadowX * xScale, (float)y - h + m_shadowY, 0.f);
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
GX_InitTexObj(&texObj, m_shadow.data.get(), m_shadow.width, m_shadow.height, m_shadow.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
GX_LoadTexObj(&texObj, GX_TEXMAP0);
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
v = Vector3D(w, h, 0.f).rotateZ(a);
GX_Position3f32(v.x * xScale, v.y, v.z);
GX_Color4u8(m_shadowColor.r, m_shadowColor.g, m_shadowColor.b, m_shadowColor.a);
GX_TexCoord2f32(1.f, 1.f);
v = Vector3D(-w, h, 0.f).rotateZ(a);
GX_Position3f32(v.x * xScale, v.y, v.z);
GX_Color4u8(m_shadowColor.r, m_shadowColor.g, m_shadowColor.b, m_shadowColor.a);
GX_TexCoord2f32(0.f, 1.f);
v = Vector3D(-w, -h, 0.f).rotateZ(a);
GX_Position3f32(v.x * xScale, v.y, v.z);
GX_Color4u8(m_shadowColor.r, m_shadowColor.g, m_shadowColor.b, m_shadowColor.a);
GX_TexCoord2f32(0.f, 0.f);
v = Vector3D(w, -h, 0.f).rotateZ(a);
GX_Position3f32(v.x * xScale, v.y, v.z);
GX_Color4u8(m_shadowColor.r, m_shadowColor.g, m_shadowColor.b, m_shadowColor.a);
GX_TexCoord2f32(1.f, 0.f);
GX_End();
}
//
guMtxIdentity(modelViewMtx);
guMtxTransApply(modelViewMtx, modelViewMtx, (float)x - w, (float)y - h, 0.f);
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
GX_InitTexObj(&texObj, m_texture.data.get(), m_texture.width, m_texture.height, m_texture.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
GX_LoadTexObj(&texObj, GX_TEXMAP0);
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
v = Vector3D(w, h, 0.f).rotateZ(a);
GX_Position3f32(v.x * xScale, v.y, v.z);
GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF);
GX_TexCoord2f32(1.f, 1.f);
v = Vector3D(-w, h, 0.f).rotateZ(a);
GX_Position3f32(v.x * xScale, v.y, v.z);
GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF);
GX_TexCoord2f32(0.f, 1.f);
v = Vector3D(-w, -h, 0.f).rotateZ(a);
GX_Position3f32(v.x * xScale, v.y, v.z);
GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF);
GX_TexCoord2f32(0.f, 0.f);
v = Vector3D(w, -h, 0.f).rotateZ(a);
GX_Position3f32(v.x * xScale, v.y, v.z);
GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF);
GX_TexCoord2f32(1.f, 0.f);
GX_End();
}
void CCursor::_blur(void)
{
int radius = 3;
int w = m_shadow.width;
int h = m_shadow.height;
int div = 2 * radius + 1;
u8 *r = 0;
u8 *pic = m_shadow.data.get();
int sum;
int yp;
int yi;
int pass = 2;
SmartBuf xMinBuf = smartMem2Alloc(w * sizeof (int));
SmartBuf xMaxBuf = smartMem2Alloc(w * sizeof (int));
SmartBuf yMinBuf = smartMem2Alloc(h * sizeof (int));
SmartBuf yMaxBuf = smartMem2Alloc(h * sizeof (int));
SmartBuf buf = smartMem2Alloc(m_shadow.width * m_shadow.height);
if (!xMinBuf || !xMaxBuf || !yMinBuf || !yMaxBuf || !buf)
return;
int *xmin = (int *)xMinBuf.get();
int *xmax = (int *)xMaxBuf.get();
int *ymin = (int *)yMinBuf.get();
int *ymax = (int *)yMaxBuf.get();
r = buf.get();
for (int i = 0; i < w; ++i)
{
xmax[i] = min(i + radius + 1, w - 1);
xmin[i] = max(i - radius, 0);
}
for (int i = 0; i < h; ++i)
{
ymax[i] = min(i + radius + 1, h - 1) * w;
ymin[i] = max(i - radius, 0) * w;
}
for (int k = 0; k < pass; ++k) // 2 passes for much better quality
{
yi = 0;
for (int y = 0; y < h; ++y)
{
sum = 0;
for (int i = -radius; i <= radius; ++i)
sum += pic[coordsI8(min(max(0, i), w - 1), y, w)];
for (int x = 0; x < w; ++x)
{
r[yi] = sum / div;
sum += pic[coordsI8(xmax[x], y, w)];
sum -= pic[coordsI8(xmin[x], y, w)];
++yi;
}
}
for (int x = 0; x < w; ++x)
{
sum = 0;
yp = -radius * w;
for (int i = -radius; i <= radius; ++i)
{
yi = max(0, yp) + x;
sum += r[yi];
yp += w;
}
yi = x;
for (int y = 0; y < h; ++y)
{
pic[coordsI8(x, y, w)] = sum / div;
sum += r[x + ymax[y]] - r[x + ymin[y]];
yi += w;
}
}
}
}