WiiFlow_Lite/source/gui/video.cpp
Fledge68 ee14187e2d - fixed missing cache covers for real nand channels if you add covers manually and do reload cache. Thanks blackb0x!
- fixed crash when pressing 1/x or 2/y buttons (change coverflow layout) when no covers are loaded.
- fixed hiding the wait loading animation when using source menu on start.
- fixed exiting source menu on start via B button so covers show properly.
- fixed using homebrew icon.png's with transparency as covers for smallbox by restoring some old code I didn't understand. But ... sometimes the icon.png textures (.wfc) are saved as empty black boxes.
- if you get an empty black box for your homebrew cover image you can select the cover and click the 'X' delete icon. it will not delete your homebrew app but will instead delete the cover texture file (.wfc). Then you can do reload cache and hopefully your cover will be fixed.
- tried fixing cacheing covers after downloading them. works sometimes. It's a low free mem2 error if using rhapsodii shima theme and having a lot of games. if covers do not appear after downloading then i suggest rebooting wiiflow and doing reload cache first thing or switch to wiiflow's default theme and then download the covers and then switch back to rhapsodii shima theme.
2020-04-08 12:06:21 -05:00

935 lines
30 KiB
C++

#include <string.h>
#include <unistd.h>
#include <malloc.h>
#include <ogc/machine/processor.h>
#include <algorithm>
#include "memory/mem2.hpp"
#include "video.hpp"
#include "pngu.h"
#include "hw/Gekko.h"
#include "WiiMovie.hpp"
#include "gecko/gecko.hpp"
#include "loader/sys.h"
#include "loader/utils.h"
#include "list/ListGenerator.hpp"
#include "text.hpp"
#include "fileOps/fileOps.h"
#define DEFAULT_FIFO_SIZE (256 * 1024)
const float CVideo::_jitter2[2][2] = {
{ 0.246490f, 0.249999f },
{ -0.246490f, -0.249999f }
};
const float CVideo::_jitter3[3][2] = {
{ -0.373411f, -0.250550f },
{ 0.256263f, 0.368119f },
{ 0.117148f, -0.117570f }
};
const float CVideo::_jitter4[4][2] = {
{ -0.208147f, 0.353730f },
{ 0.203849f, -0.353780f },
{ -0.292626f, -0.149945f },
{ 0.296924f, 0.149994f }
};
const float CVideo::_jitter5[5][2] = {
{ 0.5f, 0.5f },
{ 0.3f, 0.1f },
{ 0.7f, 0.9f },
{ 0.9f, 0.3f },
{ 0.1f, 0.7f }
};
const float CVideo::_jitter6[6][2] = {
{ 0.4646464646f, 0.4646464646f },
{ 0.1313131313f, 0.7979797979f },
{ 0.5353535353f, 0.8686868686f },
{ 0.8686868686f, 0.5353535353f },
{ 0.7979797979f, 0.1313131313f },
{ 0.2020202020f, 0.2020202020f }
};
const float CVideo::_jitter8[8][2] = {
{ -0.334818f, 0.435331f },
{ 0.286438f, -0.393495f },
{ 0.459462f, 0.141540f },
{ -0.414498f, -0.192829f },
{ -0.183790f, 0.082102f },
{ -0.079263f, -0.317383f },
{ 0.102254f, 0.299133f },
{ 0.164216f, -0.054399f }
};
GXRModeObj TVPal574IntDfScale =
{
VI_TVMODE_PAL_INT, // viDisplayMode
640, // fbWidth
480, // efbHeight
574, // xfbHeight
(VI_MAX_WIDTH_PAL - 640)/2, // viXOrigin
(VI_MAX_HEIGHT_PAL - 574)/2, // viYOrigin
640, // viWidth
574, // viHeight
VI_XFBMODE_DF, // xFBmode
GX_FALSE, // field_rendering
GX_FALSE, // aa
// sample points arranged in increasing Y order
{
{6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each
{6,6},{6,6},{6,6}, // pix 1
{6,6},{6,6},{6,6}, // pix 2
{6,6},{6,6},{6,6} // pix 3
},
// vertical filter[7], 1/64 units, 6 bits each
{
8, // line n-1
8, // line n-1
10, // line n
12, // line n
10, // line n
8, // line n+1
8 // line n+1
}
};
vector<TexData> m_defaultWaitMessages;
CVideo m_vid;
CVideo::CVideo(void) :
m_rmode(NULL), m_frameBuf(), m_curFB(0), m_fifo(NULL),
m_yScale(0.0f), m_xfbHeight(0), m_wide(false),
m_width2D(640), m_height2D(480), m_x2D(0), m_y2D(0), m_aa(0), m_aaAlpha(false),
m_aaWidth(0), m_aaHeight(0), m_screensaver_alpha(0), m_showWaitMessage(false),
m_WaitThreadRunning(false), m_showingWaitMessages(false)
{
memset(m_frameBuf, 0, sizeof m_frameBuf);
}
void CVideo::init(void)
{
/* General Video Init */
VIDEO_Init();
m_wide = CONF_GetAspectRatio() == CONF_ASPECT_16_9;
m_rmode = VIDEO_GetPreferredMode(NULL);
u32 type = CONF_GetVideo();
m_50hz = false;
if(m_rmode == &TVPal528IntDf)
{
m_rmode= &TVPal574IntDfScale;
m_50hz = true;
}
m_rmode->viWidth = m_wide ? 700 : 672;
//CONF_VIDEO_NTSC and CONF_VIDEO_MPAL and m_rmode TVEurgb60Hz480IntDf are the same max height and width.
if(type == CONF_VIDEO_PAL && m_rmode != &TVEurgb60Hz480IntDf)
{
m_rmode->viHeight = VI_MAX_HEIGHT_PAL;
m_rmode->viXOrigin = (VI_MAX_WIDTH_PAL - m_rmode->viWidth) / 2;
m_rmode->viYOrigin = (VI_MAX_HEIGHT_PAL - m_rmode->viHeight) / 2;
}
else
{
m_rmode->viHeight = VI_MAX_HEIGHT_NTSC;
m_rmode->viXOrigin = (VI_MAX_WIDTH_NTSC - m_rmode->viWidth) / 2;
m_rmode->viYOrigin = (VI_MAX_HEIGHT_NTSC - m_rmode->viHeight) / 2;
}
s8 hoffset = 0; //Use horizontal offset set in wii menu.
if(CONF_GetDisplayOffsetH(&hoffset) == 0)
m_rmode->viXOrigin += hoffset;
/* Widescreen Fix by tueidj, WiiU Check by crediar, thanks alot */
if(m_wide && AHBPROT_Patched() && IsOnWiiU())
{
write32(0xd8006a0, 0x30000004);
mask32(0xd8006a8, 0, 2);
}
/* GX Init */
m_frameBuf[0] = MEM_K0_TO_K1(MEM1_memalign(32, VIDEO_GetFrameBufferSize(m_rmode)));
m_frameBuf[1] = MEM_K0_TO_K1(MEM1_memalign(32, VIDEO_GetFrameBufferSize(m_rmode)));
m_curFB = 0;
m_fifo = MEM1_memalign(32, DEFAULT_FIFO_SIZE);
memset(m_fifo, 0, DEFAULT_FIFO_SIZE);
GX_Init(m_fifo, DEFAULT_FIFO_SIZE);
GX_SetCopyClear(CColor(0), 0x00FFFFFF);
_setViewPort(0, 0, m_rmode->fbWidth, m_rmode->efbHeight);
m_yScale = GX_GetYScaleFactor(m_rmode->efbHeight, m_rmode->xfbHeight);
m_xfbHeight = GX_SetDispCopyYScale(m_yScale);
GX_SetScissor(0, 0, m_rmode->fbWidth, m_rmode->efbHeight);
GX_SetDispCopySrc(0, 0, m_rmode->fbWidth, m_rmode->efbHeight);
GX_SetDispCopyDst(m_rmode->fbWidth, m_xfbHeight);
GX_SetCopyFilter(m_rmode->aa, m_rmode->sample_pattern, GX_TRUE, m_rmode->vfilter);
GX_SetFieldMode(m_rmode->field_rendering, ((m_rmode->viHeight == 2 * m_rmode->xfbHeight) ? GX_ENABLE : GX_DISABLE));
GX_SetCullMode(GX_CULL_NONE);
GX_CopyDisp(m_frameBuf[m_curFB], GX_TRUE);
GX_SetDispCopyGamma(GX_GM_1_0);
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_RGB8, 0);
GX_SetNumTexGens(0);
GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORDNULL, GX_TEXMAP_NULL, GX_COLOR0A0);
GX_SetNumChans(0);
GX_SetZCompLoc(GX_ENABLE);
setup2DProjection();
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
for(u32 i = 0; i < 8; i++)
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0+i, GX_TEX_ST, GX_F32, 0);
m_stencil = MEM1_memalign(32, CVideo::_stencilWidth * CVideo::_stencilHeight);
memset(m_stencil, 0, CVideo::_stencilWidth * CVideo::_stencilHeight);
/* Configure Video */
VIDEO_Configure(m_rmode);
_clearScreen();
VIDEO_SetBlack(FALSE);
VIDEO_Flush();
VIDEO_WaitVSync();
if(m_rmode->viTVMode & VI_NON_INTERLACE)
VIDEO_WaitVSync();
}
void CVideo::cleanup(void)
{
//gprintf("Cleaning up video...\n");
hideWaitMessage();
_clearScreen();
VIDEO_SetBlack(TRUE);
VIDEO_Flush();
GX_DrawDone();
GX_AbortFrame();
for(u8 i = 0; i < sizeof m_aaBuffer / sizeof m_aaBuffer[0]; ++i)
{
if(m_aaBuffer[i])
free(m_aaBuffer[i]);
m_aaBuffer[i] = NULL;
m_aaBufferSize[i] = 0;
}
for(u8 i = 0; i < m_defaultWaitMessages.size(); i++)
{
if(m_defaultWaitMessages[i].data != NULL)
free(m_defaultWaitMessages[i].data);
m_defaultWaitMessages[i].data = NULL;
}
MEM1_free(MEM_K1_TO_K0(m_frameBuf[0]));
m_frameBuf[0] = NULL;
MEM1_free(MEM_K1_TO_K0(m_frameBuf[1]));
m_frameBuf[1] = NULL;
MEM1_free(m_stencil);
m_stencil = NULL;
MEM1_free(m_fifo);
m_fifo = NULL;
}
void CVideo::_clearScreen()
{
VIDEO_ClearFrameBuffer(m_rmode, m_frameBuf[0], COLOR_BLACK);
VIDEO_ClearFrameBuffer(m_rmode, m_frameBuf[1], COLOR_BLACK);
render();
render();
}
void CVideo::prepare(void)
{
if(m_rmode->aa)
GX_SetPixelFmt(GX_PF_RGB565_Z16, GX_ZC_LINEAR);// 16 bit color (565)
else
GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);// 24 bit color (888)
_setViewPort(0.f, 0.f, (float)m_rmode->fbWidth, (float)m_rmode->efbHeight);
GX_SetScissor(0, 0, m_rmode->fbWidth, m_rmode->efbHeight);
GX_InvVtxCache();
GX_InvalidateTexAll();
}
void CVideo::setup2DProjection(bool setViewPort, bool noScale)
{
Mtx44 projMtx;
float width2D = noScale ? 640.f : (float)m_width2D;
float height2D = noScale ? 480.f : (float)m_height2D;
float x = noScale ? 0.f : (float)(640 - width2D) * 0.5f + (float)m_x2D;
float y = noScale ? 0.f : (float)(480 - height2D) * 0.5f + (float)m_y2D;
if (setViewPort)
_setViewPort(0, 0, m_rmode->fbWidth, m_rmode->efbHeight);
guOrtho(projMtx, y, height2D + y, x, width2D + x, 0.f, 1000.0f);
GX_LoadProjectionMtx(projMtx, GX_ORTHOGRAPHIC);
}
void CVideo::_setViewPort(float x, float y, float w, float h)
{
m_vpX = x;
m_vpY = y;
m_vpW = w;
m_vpH = h;
GX_SetViewport(x, y, w, h, 0.f, 1.f);
}
void CVideo::shiftViewPort(float x, float y)
{
GX_SetViewport(m_vpX + x, m_vpY + y, m_vpW, m_vpH, 0.f, 1.f);
}
void CVideo::set2DViewport(u32 w, u32 h, int x, int y)
{
m_width2D = std::min(std::max(512ul, w), 800ul);
m_height2D = std::min(std::max(384ul, h), 600ul);
m_x2D = std::min(std::max(-50, x), 50);
m_y2D = std::min(std::max(-50, y), 50);
}
/* this takes what is drawn in the frame buffer and copies it to make a new texture/image set as whatever TexData &tex is */
/* this is used by updatebg to fade old bg into new bg */
/* and coverflow after drawing bg and covers to make mirror bg with blur */
void CVideo::renderToTexture(TexData &tex, bool clear)
{
if(tex.data == NULL)
{
tex.dataSize = GX_GetTexBufferSize(tex.width, tex.height, tex.format, GX_FALSE, 0);
tex.data = (u8*)MEM2_alloc(tex.dataSize);
if(tex.data == NULL)
return;
}
GX_DrawDone();
GX_SetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL);
GX_SetTexCopySrc(0, 0, tex.width, tex.height);
GX_SetTexCopyDst(tex.width, tex.height, tex.format, GX_FALSE);
GX_CopyTex(tex.data, clear ? GX_TRUE : GX_FALSE);
GX_PixModeSync();
GX_SetCopyFilter(m_rmode->aa, m_rmode->sample_pattern, GX_TRUE, m_rmode->vfilter);
DCFlushRange(tex.data, tex.dataSize);
GX_SetScissor(0, 0, m_rmode->fbWidth, m_rmode->efbHeight);
}
void CVideo::prepareAAPass(int aaStep)
{
float x = 0.f;
float y = 0.f;
u32 w = m_aaWidth <= 0 ? m_rmode->fbWidth : (u32)m_aaWidth;
u32 h = m_aaHeight <= 0 ? m_rmode->efbHeight: (u32)m_aaHeight;
switch (m_aa)
{
case 2:
x += CVideo::_jitter2[aaStep][0];
y += CVideo::_jitter2[aaStep][1];
break;
case 3:
x += CVideo::_jitter3[aaStep][0];
y += CVideo::_jitter3[aaStep][1];
break;
case 4:
x += CVideo::_jitter4[aaStep][0];
y += CVideo::_jitter4[aaStep][1];
break;
case 5:
x += CVideo::_jitter5[aaStep][0];
y += CVideo::_jitter5[aaStep][1];
break;
case 6:
x += CVideo::_jitter6[aaStep][0];
y += CVideo::_jitter6[aaStep][1];
break;
case 8:
x += CVideo::_jitter8[aaStep][0];
y += CVideo::_jitter8[aaStep][1];
break;
}
GX_SetPixelFmt(m_aaAlpha ? GX_PF_RGBA6_Z24 : GX_PF_RGB8_Z24, GX_ZC_LINEAR);//rgba6 is 6 bit color with 6 bit alpha = 24bit (6666)
_setViewPort(x, y, (float)w, (float)h);
GX_SetScissor(0, 0, w, h);
GX_InvVtxCache();
GX_InvalidateTexAll();
}
void CVideo::renderAAPass(int aaStep)
{
u8 texFmt = GX_TF_RGBA8;
u32 w = m_aaWidth <= 0 ? m_rmode->fbWidth : (u32)m_aaWidth;
u32 h = m_aaHeight <= 0 ? m_rmode->efbHeight: (u32)m_aaHeight;
u32 bufLen = GX_GetTexBufferSize(w, h, texFmt, GX_FALSE, 0);
if (!m_aaBuffer[aaStep] || m_aaBufferSize[aaStep] < bufLen)
{
m_aaBuffer[aaStep] = (u8*)MEM2_alloc(bufLen);
if (m_aaBuffer[aaStep] != NULL)
m_aaBufferSize[aaStep] = bufLen;
}
if (!m_aaBuffer[aaStep] || m_aaBufferSize[aaStep] < bufLen)
return;
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_TRUE);
GX_DrawDone();
GX_SetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL);
GX_SetTexCopySrc(0, 0, w, h);
GX_SetTexCopyDst(w, h, texFmt, GX_FALSE);
GX_CopyTex(m_aaBuffer[aaStep], GX_TRUE);
GX_PixModeSync();
GX_SetCopyFilter(m_rmode->aa, m_rmode->sample_pattern, GX_TRUE, m_rmode->vfilter);
}
void CVideo::drawAAScene(bool fs)
{
GXTexObj texObj[8];
Mtx modelViewMtx;
u8 texFmt = GX_TF_RGBA8;
u32 tw = m_aaWidth <= 0 ? m_rmode->fbWidth : (u32)m_aaWidth;
u32 th = m_aaHeight <= 0 ? m_rmode->efbHeight: (u32)m_aaHeight;
float w = fs ? 640.f : (float)tw;
float h = fs ? 480.f : (float)th;
float x = 0.f;
float y = 0.f;
int aa;
if (m_aa <= 0 || m_aa > 8)
return;
for (aa = 0; aa < m_aa; ++aa)
if (!m_aaBuffer[aa])
break;
if (aa == 7)
aa = 6;
GX_SetNumChans(0);
for (int i = 0; i < aa; ++i)
{
GX_InitTexObj(&texObj[i], m_aaBuffer[i], tw , th, texFmt, GX_CLAMP, GX_CLAMP, GX_FALSE);
GX_LoadTexObj(&texObj[i], GX_TEXMAP0 + i);
}
GX_SetNumTexGens(1);
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GX_SetTevKColor(GX_KCOLOR0, CColor(0xFF / 1, 0xFF / 5, 0xFF, 0xFF)); // Renders better gradients than 0xFF / aa
GX_SetTevKColor(GX_KCOLOR1, CColor(0xFF / 2, 0xFF / 6, 0xFF, 0xFF));
GX_SetTevKColor(GX_KCOLOR2, CColor(0xFF / 3, 0xFF / 7, 0xFF, 0xFF));
GX_SetTevKColor(GX_KCOLOR3, CColor(0xFF / 4, 0xFF / 8, 0xFF, 0xFF));
for (int i = 0; i < aa; ++i)
{
GX_SetTevKColorSel(GX_TEVSTAGE0 + i, GX_TEV_KCSEL_K0_R + i);
GX_SetTevKAlphaSel(GX_TEVSTAGE0 + i, GX_TEV_KASEL_K0_R + i);
GX_SetTevOrder(GX_TEVSTAGE0 + i, GX_TEXCOORD0, GX_TEXMAP0 + i, GX_COLORNULL);
GX_SetTevColorIn(GX_TEVSTAGE0 + i, i == 0 ? GX_CC_ZERO : GX_CC_CPREV, GX_CC_TEXC, GX_CC_KONST, GX_CC_ZERO);
GX_SetTevAlphaIn(GX_TEVSTAGE0 + i, i == 0 ? GX_CA_ZERO : GX_CA_APREV, GX_CA_TEXA, GX_CA_KONST, GX_CA_ZERO);
GX_SetTevColorOp(GX_TEVSTAGE0 + i, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GX_SetTevAlphaOp(GX_TEVSTAGE0 + i, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
}
GX_SetNumTevStages(aa);
GX_SetAlphaUpdate(GX_TRUE);
GX_SetCullMode(GX_CULL_NONE);
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_FALSE);
GX_SetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
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_TEX0, GX_DIRECT);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
guMtxIdentity(modelViewMtx);
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
GX_Position3f32(x, y, 0.f);
GX_TexCoord2f32(0.f, 0.f);
GX_Position3f32(x + w, y, 0.f);
GX_TexCoord2f32(1.f, 0.f);
GX_Position3f32(x + w, y + h, 0.f);
GX_TexCoord2f32(1.f, 1.f);
GX_Position3f32(x, y + h, 0.f);
GX_TexCoord2f32(0.f, 1.f);
GX_End();
GX_SetNumChans(1);
GX_SetNumTexGens(1);
GX_SetNumTevStages(1);
}
void CVideo::render(void)
{
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_TRUE);
GX_SetColorUpdate(GX_TRUE);
GX_CopyDisp(MEM_K1_TO_K0(m_frameBuf[m_curFB]), GX_TRUE);
DCFlushRange(m_frameBuf[m_curFB], 2 * m_rmode->fbWidth * m_rmode->xfbHeight);
GX_DrawDone();
VIDEO_SetNextFramebuffer(m_frameBuf[m_curFB]);
VIDEO_Flush();
VIDEO_WaitVSync();
m_curFB ^= 1;
GX_InvalidateTexAll();
}
/* wait animation control */
extern const u8 wfsplash_jpg[];
extern const u32 wfsplash_jpg_size;
extern const u8 wflsplash_jpg[];
extern const u32 wflsplash_jpg_size;
extern const u8 wait_01_jpg[];
extern const u32 wait_01_jpg_size;
extern const u8 wait_02_jpg[];
extern const u32 wait_02_jpg_size;
extern const u8 wait_03_jpg[];
extern const u32 wait_03_jpg_size;
extern const u8 wait_04_jpg[];
extern const u32 wait_04_jpg_size;
extern const u8 wait_05_jpg[];
extern const u32 wait_05_jpg_size;
extern const u8 wait_06_jpg[];
extern const u32 wait_06_jpg_size;
extern const u8 wait_07_jpg[];
extern const u32 wait_07_jpg_size;
extern const u8 wait_08_jpg[];
extern const u32 wait_08_jpg_size;
static lwp_t waitThread = LWP_THREAD_NULL;
u8 CVideo::waitMessageStack[2048] ATTRIBUTE_ALIGN(32);
const u32 CVideo::waitMessageStackSize = 2048;
bool custom = false;
bool waitLoop = false;
static vector<string> waitImgs;
static void GrabWaitFiles(char *FullPath)
{
waitImgs.push_back(FullPath);
}
void CVideo::setCustomWaitImgs(const char *path, bool wait_loop)
{
waitImgs.clear();
if(path != NULL && fsop_FolderExist(path))
{
GetFiles(path, stringToVector(".png|.jpg", '|'), GrabWaitFiles, false, 1);
if(waitImgs.size() > 0)
{
sort(waitImgs.begin(), waitImgs.end());
custom = true;
waitLoop = wait_loop;
}
}
}
void CVideo::waitMessage(float delay)// set wait images from custom or internal
{
if(m_defaultWaitMessages.size() == 0)
{
if(custom)
{
u8 waitImgs_cnt = waitImgs.size();
TexData m_wTextures[waitImgs_cnt];
for(u8 i = 0; i < waitImgs_cnt; i++)
{
TexHandle.fromImageFile(m_wTextures[i], waitImgs[i].c_str());
}
for(u8 i = 0; i < waitImgs_cnt; i++)
m_defaultWaitMessages.push_back(m_wTextures[i]);
}
else
{
TexData m_wTextures[8];
TexHandle.fromJPG(m_wTextures[0], wait_01_jpg, wait_01_jpg_size);
TexHandle.fromJPG(m_wTextures[1], wait_02_jpg, wait_02_jpg_size);
TexHandle.fromJPG(m_wTextures[2], wait_03_jpg, wait_03_jpg_size);
TexHandle.fromJPG(m_wTextures[3], wait_04_jpg, wait_04_jpg_size);
TexHandle.fromJPG(m_wTextures[4], wait_05_jpg, wait_05_jpg_size);
TexHandle.fromJPG(m_wTextures[5], wait_06_jpg, wait_06_jpg_size);
TexHandle.fromJPG(m_wTextures[6], wait_07_jpg, wait_07_jpg_size);
TexHandle.fromJPG(m_wTextures[7], wait_08_jpg, wait_08_jpg_size);
for(int i = 0; i < 8; i++)
m_defaultWaitMessages.push_back(m_wTextures[i]);
}
}
waitMessage(m_defaultWaitMessages, delay);
}
void CVideo::waitMessage(const vector<TexData> &tex, float delay)// start wait images and wii slot light threads
{
hideWaitMessage();
if(tex.size() == 0)
{
m_waitMessages = m_defaultWaitMessages;
m_waitMessageDelay = 0.15f;
}
else
{
m_waitMessages = tex;
m_waitMessageDelay = delay;
}
if(m_waitMessages.size() == 1)
{
waitMessage(m_waitMessages[0]);// draws frame image using function below (for one frame image only) but no render?
render();
}
else if(m_waitMessages.size() > 1)// if more than one frame
{
m_WaitThreadRunning = true;
/* changing light */
//wiiLightSetLevel(0);
//wiiLightStartThread();// start thread in gekko.c that pulses the wii disc slot light on and off
/* onscreen animation */
m_showWaitMessage = true;// start wait images thread to animate them
LWP_CreateThread(&waitThread, _showWaitMessages, this, waitMessageStack, waitMessageStackSize, LWP_PRIO_HIGHEST);
}
}
void * CVideo::_showWaitMessages(void *obj)// wait images thread
{
CVideo *m = static_cast<CVideo *>(obj);
m->m_showingWaitMessages = true;
u32 frames = m->m_waitMessageDelay * 50;// set delay start
u32 waitFrames = frames;// set delay counter to delay start
//s8 fadeDirection = 1;
s8 PNGfadeDirection = 1;// set frames movement direction
//s16 currentLightLevel = 0;
vector<TexData>::iterator waitItr = m->m_waitMessages.begin();// set start frame image
m->_clearScreen();
m->prepare();
m->setup2DProjection();
//gprintf("Wait Message Thread: Start\nDelay: %d, Images: %d\n", waitFrames, m->m_waitMessages.size());
while(m->m_showWaitMessage)
{
/*currentLightLevel += fadeDirection * 5;
if(currentLightLevel >= 255)
{
currentLightLevel = 255;
fadeDirection = -1;
}
else if(currentLightLevel <= 0)
{
currentLightLevel = 0;
fadeDirection = 1;
}*/
//wiiLightSetLevel(currentLightLevel);
if(waitFrames == 0)// if delay count reaches 0
{
m->waitMessage(*waitItr);// draw frame image
waitItr += PNGfadeDirection;// move to next image
if(waitLoop && waitItr == m->m_waitMessages.end())
waitItr = m->m_waitMessages.begin();
else if(!waitLoop && (waitItr + 1 == m->m_waitMessages.end() || waitItr == m->m_waitMessages.begin()))
PNGfadeDirection *= (-1);// change direction if at beginning or end
waitFrames = frames;// reset delay count
m->render();
}
else
VIDEO_WaitVSync();
waitFrames--;// decrement delay count
}
//gprintf("Wait Message Thread: End\n");
m->m_showingWaitMessages = false;
return NULL;
}
void CVideo::hideWaitMessage()// stop wait images thread and wii disc slot light thread
{
m_showWaitMessage = false;
if(waitThread != LWP_THREAD_NULL)
{
/* end animation */
if(LWP_ThreadIsSuspended(waitThread))
LWP_ResumeThread(waitThread);
while(m_showingWaitMessages)
usleep(50);
LWP_JoinThread(waitThread, NULL);
/* end light thread */
//wiiLightEndThread();
m_WaitThreadRunning = false;
}
waitThread = LWP_THREAD_NULL;
}
/* draws wait animation image centered on screen */
/* can be used to draw any texture centered on screen */
void CVideo::waitMessage(const TexData &tex)
{
Mtx modelViewMtx;
GXTexObj texObj;
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_TEX0, GX_DIRECT);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GX_SetNumTexGens(1);
GX_SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC);
GX_SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA);
GX_SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GX_SetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLORNULL);
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GX_SetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
GX_SetAlphaUpdate(GX_TRUE);
GX_SetCullMode(GX_CULL_NONE);
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_FALSE);
guMtxIdentity(modelViewMtx);
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
GX_InitTexObj(&texObj, tex.data, tex.width, tex.height, tex.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
GX_LoadTexObj(&texObj, GX_TEXMAP0);
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
u32 texWidth = m_wide ? tex.width * .75 : tex.width;
GX_Position3f32((float)((640 - texWidth) / 2), (float)((480 - tex.height) / 2), 0.f);
GX_TexCoord2f32(0.f, 0.f);
GX_Position3f32((float)((640 + texWidth) / 2), (float)((480 - tex.height) / 2), 0.f);
GX_TexCoord2f32(1.f, 0.f);
GX_Position3f32((float)((640 + texWidth) / 2), (float)((480 + tex.height) / 2), 0.f);
GX_TexCoord2f32(1.f, 1.f);
GX_Position3f32((float)((640 - texWidth) / 2), (float)((480 + tex.height) / 2), 0.f);
GX_TexCoord2f32(0.f, 1.f);
GX_End();
}
/* draw and render startup splash screen */
void CVideo::startImage(void)
{
TexData splashTex;
TexHandle.fromJPG(splashTex, wfsplash_jpg, wfsplash_jpg_size);
waitMessage(splashTex);
render();
TexHandle.Cleanup(splashTex);
}
/* save screenshot */
s32 CVideo::TakeScreenshot(const char *path)
{
IMGCTX ctx = PNGU_SelectImageFromDevice(path);
s32 ret = PNGU_EncodeFromYCbYCr(ctx, m_rmode->fbWidth, m_rmode->efbHeight, m_frameBuf[m_curFB], 1);
PNGU_ReleaseImageContext (ctx);
return ret;
}
/* used by coverflow to draw cover texture. used in mainloopcommon() in menu.cpp */
/* this draws a texture in the upper left at 0,0 */
void DrawTexture(TexData * &tex)
{
if(tex == NULL)
return;
Mtx modelViewMtx;
GXTexObj texObj;
GX_SetNumChans(1);
GX_ClearVtxDesc();
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, 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);
guMtxIdentity(modelViewMtx);
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
GX_InitTexObj(&texObj, tex->data, tex->width, tex->height, tex->format, GX_CLAMP, GX_CLAMP, GX_FALSE);
GX_LoadTexObj(&texObj, GX_TEXMAP0);
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
GX_Position2f32(0.f, 0.f);
GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF);
GX_TexCoord2f32(0.f, 0.f);
GX_Position2f32(tex->width, 0.f);
GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF);
GX_TexCoord2f32(1.f, 0.f);
GX_Position2f32(tex->width, tex->height);
GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF);
GX_TexCoord2f32(1.f, 1.f);
GX_Position2f32(0.f, tex->height);
GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF);
GX_TexCoord2f32(0.f, 1.f);
GX_End();
}
/* draws movie frame texture when playing movie in menu_game.cpp */
struct movieP normalMoviePos = { 410, 31, 610, 181 };
struct movieP zoomedMoviePos = { 0, 0, 640, 480 };
struct movieP currentMoviePos = zoomedMoviePos;
/* draws a texture/image at a position and width and height specified by struct movieP currentMoviePos */
/* set currentMoviePos before calling this. example - {x, y, x+w, y+h} */
void DrawTexturePos(const TexData *tex)
{
Mtx modelViewMtx;
GXTexObj texObj;
GX_ClearVtxDesc();
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 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_SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC);
GX_SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLORNULL);
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GX_SetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
GX_SetAlphaUpdate(GX_FALSE);
GX_SetCullMode(GX_CULL_NONE);
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_FALSE);
guMtxIdentity(modelViewMtx);
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
GX_InitTexObj(&texObj, tex->data, tex->width, tex->height, tex->format, GX_CLAMP, GX_CLAMP, GX_FALSE);
GX_LoadTexObj(&texObj, GX_TEXMAP0);
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
GX_Position2f32(currentMoviePos.x1, currentMoviePos.y1);
GX_TexCoord2f32(0.f, 0.f);
GX_Position2f32(currentMoviePos.x2, currentMoviePos.y1);
GX_TexCoord2f32(1.f, 0.f);
GX_Position2f32(currentMoviePos.x2, currentMoviePos.y2);
GX_TexCoord2f32(1.f, 1.f);
GX_Position2f32(currentMoviePos.x1, currentMoviePos.y2);
GX_TexCoord2f32(0.f, 1.f);
GX_End();
}
/* screen saver and full banner frame */
void DrawRectangle(f32 x, f32 y, f32 width, f32 height, GXColor color)
{
Mtx modelViewMtx;
guMtxIdentity(modelViewMtx);
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
GX_ClearVtxDesc();
GX_InvVtxCache();
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
int i;
f32 x2 = x + width;
f32 y2 = y + height;
guVector v[] = { { x, y, 0.0f }, { x2, y, 0.0f }, { x2, y2, 0.0f }, { x, y2, 0.0f }, { x, y, 0.0f } };
GX_Begin(GX_TRIANGLEFAN, GX_VTXFMT0, 4);
for(i = 0; i < 4; i++)
{
GX_Position3f32(v[i].x, v[i].y, v[i].z);
GX_Color4u8(color.r, color.g, color.b, color.a);
}
GX_End();
GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
}
void CVideo::screensaver(u32 no_input, u32 max_no_input)
{
if(no_input == 0)// no idle time so reset alpha to 0 for next time and don't draw the rectangle on this pass
{
m_screensaver_alpha = 0;
return;
}
if(no_input > max_no_input)// if idle time > max idle draw rectangle full screen increasing alpha each time
{
DrawRectangle(0, 0, 640, 480, (GXColor){0,0,0,m_screensaver_alpha});
if(m_screensaver_alpha < 150)
m_screensaver_alpha+=2;
}
}
/* misc settings */
void CColor::blend(const CColor &src)
{
if (src.a == 0) return;
r = (u8)(((int)src.r * (int)src.a + (int)r * (0xFF - (int)src.a)) / 0xFF);
g = (u8)(((int)src.g * (int)src.a + (int)g * (0xFF - (int)src.a)) / 0xFF);
b = (u8)(((int)src.b * (int)src.a + (int)b * (0xFF - (int)src.a)) / 0xFF);
}
CColor CColor::interpolate(const CColor &c1, const CColor &c2, u8 n)
{
CColor c;
c.r = (u8)(((int)c2.r * (int)n + (int)c1.r * (0xFF - (int)n)) / 0xFF);
c.g = (u8)(((int)c2.g * (int)n + (int)c1.g * (0xFF - (int)n)) / 0xFF);
c.b = (u8)(((int)c2.b * (int)n + (int)c1.b * (0xFF - (int)n)) / 0xFF);
c.a = (u8)(((int)c2.a * (int)n + (int)c1.a * (0xFF - (int)n)) / 0xFF);
return c;
}
void CVideo::setAA(u8 aa, bool alpha, int width, int height)
{
if (aa <= 8 && aa != 7 && width <= m_rmode->fbWidth && height <= m_rmode->efbHeight && ((width | height) & 3) == 0)
{
m_aa = aa;
m_aaAlpha = alpha;
m_aaWidth = width;
m_aaHeight = height;
}
}
/* stencil used by coverflow */
const int CVideo::_stencilWidth = 128;
const int CVideo::_stencilHeight = 128;
static inline u32 coordsI8(u32 x, u32 y, u32 w)// used by stencilval below
{
return (((y >> 2) * (w >> 3) + (x >> 3)) << 5) + ((y & 3) << 3) + (x & 7);
}
int CVideo::stencilVal(int x, int y)
{
if ((u32)x >= m_rmode->fbWidth || (u32)y >= m_rmode->efbHeight)
return 0;
x = x * CVideo::_stencilWidth / 640;
y = y * CVideo::_stencilHeight / 480;
u32 i = coordsI8(x, y, (u32)CVideo::_stencilWidth);
if (i >= (u32)(CVideo::_stencilWidth * CVideo::_stencilHeight))
return 0;
return ((u8*)m_stencil)[i];
}
void CVideo::prepareStencil(void)
{
GX_SetPixelFmt(GX_PF_Y8, GX_ZC_LINEAR);
_setViewPort(0.f, 0.f, (float)CVideo::_stencilWidth, (float)CVideo::_stencilHeight);
GX_SetScissor(0, 0, CVideo::_stencilWidth, CVideo::_stencilHeight);
GX_InvVtxCache();
GX_InvalidateTexAll();
}
void CVideo::renderStencil(void)
{
GX_DrawDone();
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_TRUE);
GX_SetColorUpdate(GX_TRUE);
GX_SetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL);
GX_SetTexCopySrc(0, 0, CVideo::_stencilWidth, CVideo::_stencilHeight);
GX_SetTexCopyDst(CVideo::_stencilWidth, CVideo::_stencilHeight, GX_CTF_R8, GX_FALSE);
GX_CopyTex(m_stencil, GX_TRUE);
GX_PixModeSync();
DCFlushRange(m_stencil, CVideo::_stencilWidth * CVideo::_stencilHeight);
GX_SetCopyFilter(m_rmode->aa, m_rmode->sample_pattern, GX_TRUE, m_rmode->vfilter);
}