mirror of
https://github.com/Fledge68/WiiFlow_Lite.git
synced 2024-12-27 12:21:57 +01:00
219 lines
6.8 KiB
C++
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;
|
|
}
|
|
}
|
|
}
|
|
}
|