WiiFlow_Lite/source/gui/cursor.cpp
fix94.1 e8c66b7278 -added jpg file support for game covers and themes, if no .png
is found, it will just replace the filename extension with .jpg
and try it again, the jpg file width and height need to be
divisable with 4, otherwise wiiflow will just ignore the cover
2012-07-22 22:10:17 +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.fromImageFile(png))
{
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;
}
}
}
}