WiiFlow_Lite/source/gui/cursor.cpp
Fledge68 12d21fa0a7 - now compiled with devkitppc r39-2 (GCC 11) and libogc 2.3.1-1
- updated libwolfssl
- many thanks to blackb0x
2021-09-06 14:16:45 -05:00

224 lines
6.8 KiB
C++

#include "cursor.hpp"
#include "pngu.h"
#include "memory/mem2.hpp"
#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(TexHandle.fromImageFile(m_texture, png) != TE_OK)
{
if(chan == 0)
ok = (TexHandle.fromPNG(m_texture, player1_point_png) == TE_OK);
else if(chan == 1)
ok = (TexHandle.fromPNG(m_texture, player2_point_png) == TE_OK);
else if(chan == 2)
ok = (TexHandle.fromPNG(m_texture, player3_point_png) == TE_OK);
else if(chan == 3)
ok = (TexHandle.fromPNG(m_texture, player4_point_png) == TE_OK);
}
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 = (u8*)MEM2_alloc(GX_GetTexBufferSize(m_shadow.width, m_shadow.height, m_shadow.format, GX_FALSE, 0));
if(m_shadow.data != NULL)
{
const u8 *src = m_texture.data;
u8 *dst = m_shadow.data;
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::cleanup(void)
{
TexHandle.Cleanup(m_texture);
if(m_shadow.data != NULL)
TexHandle.Cleanup(m_shadow);
}
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 != NULL)
{
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, 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, 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 *pic = m_shadow.data;
int sum;
int yp;
int yi;
int pass = 2;
s32 *xmin = (s32*)MEM2_alloc(w * sizeof(s32));
s32 *xmax = (s32*)MEM2_alloc(w * sizeof(s32));
s32 *ymin = (s32*)MEM2_alloc(h * sizeof(s32));
s32 *ymax = (s32*)MEM2_alloc(h * sizeof(s32));
u8 *r = (u8*)MEM2_alloc(m_shadow.width * m_shadow.height);
if(!xmin || !xmax || !ymin || !ymax || !r)
return;
for (int i = 0; i < w; ++i)
{
xmax[i] = std::min(i + radius + 1, w - 1);
xmin[i] = std::max(i - radius, 0);
}
for (int i = 0; i < h; ++i)
{
ymax[i] = std::min(i + radius + 1, h - 1) * w;
ymin[i] = std::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(std::min(std::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 = std::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;
}
}
}
free(xmin);
free(xmax);
free(ymin);
free(ymax);
free(r);
}