WiiFlow_Lite/source/gui/video.cpp

838 lines
26 KiB
C++
Raw Normal View History

2012-01-21 21:57:41 +01:00
#include <string.h>
#include <unistd.h>
#include <malloc.h>
#include <ogc/machine/processor.h>
#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"
2012-01-21 21:57:41 +01:00
#define DEFAULT_FIFO_SIZE (256 * 1024)
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;
vector<TexData> m_defaultWaitMessages;
2012-01-21 21:57:41 +01:00
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
}
};
struct movieP normalMoviePos = { 410, 31, 610, 181 };
struct movieP zoomedMoviePos = { 0, 0, 640, 480 };
neek2o changes: - re made it possible to use SD emunands with sNeek2o r96. - added vwii r96 beta 9.6 support. wiiflow lite will now look for vwiikernal.bin and emunands must be in a subfolder of vwiinands on USB only. - when exiting a emunand game using neek2o if on wii it will use the back2nand channel to return you to wii system menu or if on wiiu it will return you to wiiu system channel because returning to the vwii system menu isn't possible. - when using wiiflow lite and exit to neek2o it will just launch neek2o system menu. from there you can launch wiiflow or wiiflow lite (if installed on emunand) to use cheats on a emunand game. otherwise cheats do not work when using neek2o to launch a game. banner changes: - now when moving from banner to banner the background music will not play and you will not see coverflow (for a second) when using full screen banners. - now on game selected categories menu the banner will change when you change games using '+' or '-' buttons - added custom banners for plugin games. no longer using trialer thp videos as banners for plugin games. put your custom banners in the custom banner folder plus the plugin cover folder and name them the same as the rom with extension plus .bnr just like how you do for the covers. to make a plugin game banner i suggest downloading one of abdallahterro's custom gamecube dios mios booter channels and use customizemii to change the images (and sound if you want). make sure the images match exactly the size of the one's already there. when changes are done extract the banner and rename it and put it in the proper folder as previously mentioned. other changes: - trailer videos still work even for plugin games. again for plugins rename the thp and ogg file to match the rom plus extension and .thp or .ogg. on game selected screen press '-' to start or quit a trailer video if one is available. pressing 'B' or 'Home' will quit the video and return you to the main screen. - when flipping a cover none of the buttons are available and the mini banner is not shown until you press 'B' to de flip the cover to normal front view. - fixed game info menu - in case a custom channel is selected and is not included in gametdb it will display a message 'no game info' instead of random stuff from the last game viewed. tested on wiiflow lite forwarder channel. - now stopping sounds and music early when exiting wiiflow to prevent music from stuttering when exiting. - other minor coding changes.
2017-05-15 19:50:24 +02:00
struct movieP currentMoviePos = zoomedMoviePos;
2012-01-21 21:57:41 +01:00
const int CVideo::_stencilWidth = 128;
const int CVideo::_stencilHeight = 128;
static lwp_t waitThread = LWP_THREAD_NULL;
CVideo m_vid;
u8 CVideo::waitMessageStack[2048] ATTRIBUTE_ALIGN(32);
const u32 CVideo::waitMessageStackSize = 2048;
2012-01-21 21:57:41 +01:00
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)
2012-01-21 21:57:41 +01:00
{
memset(m_frameBuf, 0, sizeof m_frameBuf);
}
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;
}
}
void CVideo::init(void)
{
/* General Video Init */
VIDEO_Init();
2012-01-21 21:57:41 +01:00
m_wide = CONF_GetAspectRatio() == CONF_ASPECT_16_9;
m_rmode = VIDEO_GetPreferredMode(NULL);
2012-01-21 21:57:41 +01:00
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)
2012-01-21 21:57:41 +01:00
{
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)
2012-01-21 21:57:41 +01:00
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);
2012-01-21 21:57:41 +01:00
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();
2012-01-21 21:57:41 +01:00
}
void CVideo::_clearScreen()
{
VIDEO_ClearFrameBuffer(m_rmode, m_frameBuf[0], COLOR_BLACK);
VIDEO_ClearFrameBuffer(m_rmode, m_frameBuf[1], COLOR_BLACK);
render();
render();
}
2012-01-21 21:57:41 +01:00
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);
2012-01-21 21:57:41 +01:00
m_x2D = std::min(std::max(-50, x), 50);
m_y2D = std::min(std::max(-50, y), 50);
}
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;
2012-01-21 21:57:41 +01:00
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::renderToTexture(TexData &tex, bool clear)
2012-01-21 21:57:41 +01:00
{
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;
}
2012-01-21 21:57:41 +01:00
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);
2012-01-21 21:57:41 +01:00
GX_PixModeSync();
GX_SetCopyFilter(m_rmode->aa, m_rmode->sample_pattern, GX_TRUE, m_rmode->vfilter);
DCFlushRange(tex.data, tex.dataSize);
2012-01-21 21:57:41 +01:00
GX_SetScissor(0, 0, m_rmode->fbWidth, m_rmode->efbHeight);
}
void CVideo::prepare(void)
{
GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
_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::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;
2012-01-21 21:57:41 +01:00
}
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);
_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)
2012-01-21 21:57:41 +01:00
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);
2012-01-21 21:57:41 +01:00
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;
2012-01-21 21:57:41 +01:00
for (aa = 0; aa < m_aa; ++aa)
if (!m_aaBuffer[aa])
break;
if (aa == 7)
aa = 6;
2012-01-21 21:57:41 +01:00
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);
2012-01-21 21:57:41 +01:00
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);
2012-01-21 21:57:41 +01:00
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);
2012-01-21 21:57:41 +01:00
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::_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);
}
static inline u32 coordsI8(u32 x, u32 y, u32 w)
{
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];
2012-01-21 21:57:41 +01:00
}
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);
2012-01-21 21:57:41 +01:00
GX_PixModeSync();
DCFlushRange(m_stencil, CVideo::_stencilWidth * CVideo::_stencilHeight);
2012-01-21 21:57:41 +01:00
GX_SetCopyFilter(m_rmode->aa, m_rmode->sample_pattern, GX_TRUE, m_rmode->vfilter);
}
void CVideo::render(void)
{
GX_DrawDone();
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);
VIDEO_SetNextFramebuffer(m_frameBuf[m_curFB]);
VIDEO_Flush();
VIDEO_WaitVSync();
2012-01-21 21:57:41 +01:00
m_curFB ^= 1;
GX_InvalidateTexAll();
}
void * CVideo::_showWaitMessages(void *obj)
2012-01-21 21:57:41 +01:00
{
CVideo *m = static_cast<CVideo *>(obj);
2012-01-21 21:57:41 +01:00
m->m_showingWaitMessages = true;
u32 frames = m->m_waitMessageDelay * 50;
u32 waitFrames = frames;
2012-01-21 21:57:41 +01:00
s8 fadeDirection = 1;
s8 PNGfadeDirection = 1;
2012-01-21 21:57:41 +01:00
s16 currentLightLevel = 0;
vector<TexData>::iterator waitItr = m->m_waitMessages.begin();
m->_clearScreen();
2012-01-21 21:57:41 +01:00
m->prepare();
m->setup2DProjection();
//gprintf("Wait Message Thread: Start\nDelay: %d, Images: %d\n", waitFrames, m->m_waitMessages.size());
while(m->m_showWaitMessage)
2012-01-21 21:57:41 +01:00
{
currentLightLevel += fadeDirection * 5;
if(currentLightLevel >= 255)
{
currentLightLevel = 255;
fadeDirection = -1;
}
else if(currentLightLevel <= 0)
2012-01-21 21:57:41 +01:00
{
currentLightLevel = 0;
fadeDirection = 1;
2012-01-21 21:57:41 +01:00
}
wiiLightSetLevel(currentLightLevel);
if(waitFrames == 0)
2012-01-21 21:57:41 +01:00
{
m->waitMessage(*waitItr);
waitItr += PNGfadeDirection;
if(waitItr + 1 == m->m_waitMessages.end() || waitItr == m->m_waitMessages.begin())
PNGfadeDirection *= (-1);
2012-01-21 21:57:41 +01:00
waitFrames = frames;
m->render();
2012-01-21 21:57:41 +01:00
}
else
VIDEO_WaitVSync();
waitFrames--;
2012-01-21 21:57:41 +01:00
}
//gprintf("Wait Message Thread: End\n");
2012-01-21 21:57:41 +01:00
m->m_showingWaitMessages = false;
return NULL;
2012-01-21 21:57:41 +01:00
}
void CVideo::hideWaitMessage()
2012-01-21 21:57:41 +01:00
{
m_showWaitMessage = false;
if(waitThread != LWP_THREAD_NULL)
2012-01-21 21:57:41 +01:00
{
/* 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;
2012-01-21 21:57:41 +01:00
}
waitThread = LWP_THREAD_NULL;
2012-01-21 21:57:41 +01:00
}
void CVideo::waitMessage(float delay)
{
if(m_defaultWaitMessages.size() == 0)
{
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(vector<TexData>(), delay);
2012-01-21 21:57:41 +01:00
}
void CVideo::waitMessage(const vector<TexData> &tex, float delay)
2012-01-21 21:57:41 +01:00
{
hideWaitMessage();
m_WaitThreadRunning = true;
if(tex.size() == 0)
2012-01-21 21:57:41 +01:00
{
m_waitMessages = m_defaultWaitMessages;
m_waitMessageDelay = 0.15f;
2012-01-21 21:57:41 +01:00
}
else
{
m_waitMessages = tex;
m_waitMessageDelay = delay;
}
if(m_waitMessages.size() == 1)
2012-01-21 21:57:41 +01:00
waitMessage(m_waitMessages[0]);
else if(m_waitMessages.size() > 1)
2012-01-21 21:57:41 +01:00
{
/* changing light */
wiiLightSetLevel(0);
wiiLightStartThread();
/* onscreen animation */
2012-01-21 21:57:41 +01:00
m_showWaitMessage = true;
LWP_CreateThread(&waitThread, _showWaitMessages, this, waitMessageStack, waitMessageStackSize, LWP_PRIO_HIGHEST);
2012-01-21 21:57:41 +01:00
}
}
void CVideo::waitMessage(const TexData &tex)
2012-01-21 21:57:41 +01:00
{
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);
GX_Position3f32((float)((640 - tex.width) / 2), (float)((480 - tex.height) / 2), 0.f);
GX_TexCoord2f32(0.f, 0.f);
GX_Position3f32((float)((640 + tex.width) / 2), (float)((480 - tex.height) / 2), 0.f);
GX_TexCoord2f32(1.f, 0.f);
GX_Position3f32((float)((640 + tex.width) / 2), (float)((480 + tex.height) / 2), 0.f);
GX_TexCoord2f32(1.f, 1.f);
GX_Position3f32((float)((640 - tex.width) / 2), (float)((480 + tex.height) / 2), 0.f);
GX_TexCoord2f32(0.f, 1.f);
GX_End();
2012-01-21 21:57:41 +01:00
}
s32 CVideo::TakeScreenshot(const char *path)
{
IMGCTX ctx = PNGU_SelectImageFromDevice(path);
2012-01-21 21:57:41 +01:00
s32 ret = PNGU_EncodeFromYCbYCr(ctx, m_rmode->fbWidth, m_rmode->efbHeight, m_frameBuf[m_curFB], 1);
PNGU_ReleaseImageContext (ctx);
return ret;
}
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();
}
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 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();
}
void CVideo::screensaver(u32 no_input, u32 max_no_input)
{
if(no_input == 0)
{
m_screensaver_alpha = 0;
return;
}
if(no_input > max_no_input)
{
DrawRectangle(0, 0, 640, 480, (GXColor){0,0,0,m_screensaver_alpha});
if(m_screensaver_alpha < 150)
m_screensaver_alpha+=2;
}
}