usbloadergx/source/video.cpp
dimok321 1d2854c777 *Fixed issue 1808
*Fixed issue with crashing carousel when switching from empty game list to none empty list.
*Added download for Full HQ & LQ Covers. When both are checked HQ Covers are prioritized.
*Added support for Full HQ & LQ Covers:
Full covers are currently used only in the GameInfo Screen (Press 2). The Box can be rotated in there with the Nunchuck. When the box is clicked it will jump to the midlle of the screen. Here it can be rotated with Nunchuck & Wiimote D-Pad. Also it can be zoomed in/out with the PLUS or MINUS buttons. Zoomed in covers are currently cut off when going too far into the screen because the axis had to be layed to the middle to keep the symmetry. Don't report issues about that. It's known. Another use of full covers might follow with a new layout if we think of something nice ;).
*Added support for different box colors. Box colors are taken from WiiTDB so if you get a wrong color complain at WiiTDB :P.
2011-01-30 16:22:16 +00:00

468 lines
14 KiB
C++

/****************************************************************************
* libwiigui Template
* Tantric 2009
*
* video.cpp
* Video routines
***************************************************************************/
#include <gccore.h>
#include <ogcsys.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wiiuse/wpad.h>
#include <pngu/pngu.h>
#include "input.h"
#include "gecko.h"
#include "libwiigui/gui.h"
#define DEFAULT_FIFO_SIZE 256 * 1024
static unsigned int *xfb[2] = { NULL, NULL }; // Double buffered
static int whichfb = 0; // Switch
static GXRModeObj *vmode; // Menu video mode
static unsigned char gp_fifo[DEFAULT_FIFO_SIZE] ATTRIBUTE_ALIGN ( 32 );
static Mtx GXmodelView2D;
static Mtx44 projection;
int screenheight;
int screenwidth;
u32 frameCount = 0;
u8 * gameScreenTex = NULL; // a GX texture screen capture of the game
u8 * gameScreenTex2 = NULL; // a GX texture screen capture of the game (copy)
/****************************************************************************
* ResetVideo_Menu
*
* Reset the video/rendering mode for the menu
****************************************************************************/
void ResetVideo_Menu()
{
f32 yscale;
u32 xfbHeight;
VIDEO_Configure(vmode);
VIDEO_Flush();
VIDEO_WaitVSync();
if (vmode->viTVMode & VI_NON_INTERLACE)
VIDEO_WaitVSync();
else while (VIDEO_GetNextField())
VIDEO_WaitVSync();
// clears the bg to color and clears the z buffer
GXColor background = { 0, 0, 0, 255 };
GX_SetCopyClear(background, 0x00ffffff);
yscale = GX_GetYScaleFactor(vmode->efbHeight, vmode->xfbHeight);
xfbHeight = GX_SetDispCopyYScale(yscale);
GX_SetScissor(0, 0, vmode->fbWidth, vmode->efbHeight);
GX_SetDispCopySrc(0, 0, vmode->fbWidth, vmode->efbHeight);
GX_SetDispCopyDst(vmode->fbWidth, xfbHeight);
GX_SetCopyFilter(vmode->aa, vmode->sample_pattern, GX_TRUE, vmode->vfilter);
GX_SetFieldMode(vmode->field_rendering, ((vmode->viHeight == 2 * vmode->xfbHeight) ? GX_ENABLE : GX_DISABLE));
if (vmode->aa)
GX_SetPixelFmt(GX_PF_RGB565_Z16, GX_ZC_LINEAR);
else
GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
// setup the vertex descriptor
// tells the flipper to expect direct data
GX_ClearVtxDesc();
GX_InvVtxCache();
GX_InvalidateTexAll();
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);
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);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GX_SetZMode(GX_FALSE, GX_LEQUAL, GX_TRUE);
GX_SetNumChans(1);
GX_SetNumTexGens(1);
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
guMtxIdentity(GXmodelView2D);
guMtxTransApply(GXmodelView2D, GXmodelView2D, 0.0F, 0.0F, -200.0F);
GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0);
guOrtho(projection, 0, 479, 0, 639, 0, 300);
GX_LoadProjectionMtx(projection, GX_ORTHOGRAPHIC);
GX_SetViewport(0.0f, 0.0f, vmode->fbWidth, vmode->efbHeight, 0.0f, 1.0f);
GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
GX_SetAlphaUpdate(GX_TRUE);
}
/****************************************************************************
* InitVideo
*
* This function MUST be called at startup.
* - also sets up menu video mode
***************************************************************************/
void InitVideo()
{
VIDEO_Init();
vmode = VIDEO_GetPreferredMode(NULL); // get default video mode
if (CONF_GetAspectRatio() == CONF_ASPECT_16_9)
{
// widescreen fix
vmode->viWidth = VI_MAX_WIDTH_PAL - 12;
vmode->viXOrigin = ((VI_MAX_WIDTH_PAL - vmode->viWidth) / 2) + 2;
}
VIDEO_Configure(vmode);
screenheight = 480;
screenwidth = vmode->fbWidth;
// Allocate the video buffers
xfb[0] = (u32 *) MEM_K0_TO_K1 ( SYS_AllocateFramebuffer ( vmode ) );
xfb[1] = (u32 *) MEM_K0_TO_K1 ( SYS_AllocateFramebuffer ( vmode ) );
// Clear framebuffers etc.
VIDEO_ClearFrameBuffer(vmode, xfb[0], COLOR_BLACK);
VIDEO_ClearFrameBuffer(vmode, xfb[1], COLOR_BLACK);
VIDEO_SetNextFramebuffer(xfb[0]);
VIDEO_Flush();
VIDEO_WaitVSync();
if (vmode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync();
// Initialize GX
GXColor background = { 0, 0, 0, 0xff };
memset (&gp_fifo, 0, DEFAULT_FIFO_SIZE);
GX_Init (&gp_fifo, DEFAULT_FIFO_SIZE);
GX_SetCopyClear (background, 0x00ffffff);
GX_SetDispCopyGamma (GX_GM_1_0);
GX_SetCullMode (GX_CULL_NONE);
ResetVideo_Menu();
VIDEO_SetBlack(FALSE);
// Finally, the video is up and ready for use :)
// A console is always useful while debugging
//console_init(xfb[0], 80, 100, 500, 350, vmode->fbWidth * 2);
}
void VIDEO_SetWidescreen(bool widescreen)
{
if (widescreen)
{
// widescreen fix
vmode->viWidth = VI_MAX_WIDTH_PAL - 12;
vmode->viXOrigin = ((VI_MAX_WIDTH_PAL - vmode->viWidth) / 2) + 2;
}
else
{
VIDEO_GetPreferredMode(NULL);
}
VIDEO_Configure(vmode);
}
/****************************************************************************
* StopGX
*
* Stops GX (when exiting)
***************************************************************************/
void StopGX()
{
GX_AbortFrame();
GX_Flush();
VIDEO_SetBlack(TRUE);
VIDEO_Flush();
}
/****************************************************************************
* Menu_Render
*
* Renders everything current sent to GX, and flushes video
***************************************************************************/
void Menu_Render()
{
whichfb ^= 1; // flip framebuffer
GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
GX_SetColorUpdate(GX_TRUE);
GX_CopyDisp(xfb[whichfb], GX_TRUE);
GX_DrawDone();
VIDEO_SetNextFramebuffer(xfb[whichfb]);
VIDEO_Flush();
VIDEO_WaitVSync();
frameCount++;
}
/****************************************************************************
* Menu_DrawImg
*
* Draws the specified image on screen using GX
***************************************************************************/
void Menu_DrawImg(f32 xpos, f32 ypos, f32 zpos, f32 width, f32 height, u8 data[], f32 degrees, f32 scaleX, f32 scaleY,
u8 alpha, int XX1, int YY1, int XX2, int YY2, int XX3, int YY3, int XX4, int YY4)
{
if (data == NULL) return;
GX_LoadProjectionMtx(projection, GX_ORTHOGRAPHIC);
GXTexObj texObj;
GX_InitTexObj(&texObj, data, width, height, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
GX_LoadTexObj(&texObj, GX_TEXMAP0);
GX_InvalidateTexAll();
GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
Mtx m, m1, m2, mv;
width *= 0.5f;
height *= 0.5f;
guMtxIdentity(m1);
guMtxScaleApply(m1, m1, scaleX, scaleY, 1.0f);
guVector axis = ( guVector )
{
0 , 0, 1
};
guMtxRotAxisDeg ( m2, &axis, degrees );
// guMtxConcat(m2,m1,m);
guMtxConcat(m1, m2, m);
guMtxTransApply(m, m, xpos + width + 0.5f, ypos + height + 0.5f, zpos);
guMtxConcat(GXmodelView2D, m, mv);
GX_LoadPosMtxImm(mv, GX_PNMTX0);
//
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
GX_Position3f32(-width + XX1, -height + YY1, 0);
GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
GX_TexCoord2f32(0, 0);
GX_Position3f32(width + XX2, -height + YY2, 0);
GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
GX_TexCoord2f32(1, 0);
GX_Position3f32(width + XX3, height + YY3, 0);
GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
GX_TexCoord2f32(1, 1);
GX_Position3f32(-width + XX4, height + YY4, 0);
GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
GX_TexCoord2f32(0, 1);
//
GX_End();
GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0);
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
}
/****************************************************************************
* Menu_DrawRectangle
*
* Draws a rectangle at the specified coordinates using GX
***************************************************************************/
void Menu_DrawRectangle(f32 x, f32 y, f32 width, f32 height, GXColor color, u8 filled)
{
GX_LoadProjectionMtx(projection, GX_ORTHOGRAPHIC);
u8 fmt;
long n;
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 } };
if (!filled)
{
fmt = GX_LINESTRIP;
n = 5;
}
else
{
fmt = GX_TRIANGLEFAN;
n = 4;
}
GX_Begin(fmt, GX_VTXFMT0, n);
for (i = 0; i < n; i++)
{
GX_Position3f32(v[i].x, v[i].y, v[i].z);
GX_Color4u8(color.r, color.g, color.b, color.a);
}
GX_End();
}
void Menu_DrawDiskCover(f32 xpos, f32 ypos, f32 zpos, u16 width, u16 height, u16 distance, u8 data[], f32 deg_alpha,
f32 deg_beta, f32 scaleX, f32 scaleY, u8 alpha, bool shadow)
{
if (data == NULL) return;
GX_LoadProjectionMtx(projection, GX_ORTHOGRAPHIC);
GXTexObj texObj;
GX_InitTexObj(&texObj, data, width, height, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
GX_LoadTexObj(&texObj, GX_TEXMAP0);
GX_InvalidateTexAll();
GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
f32 cos_beta = cos(DegToRad( deg_beta ));
f32 s_offset_y = (zpos + (cos_beta * distance)) * tan(DegToRad( 5 ));
f32 s_offset_x = (cos_beta < 0 ? -cos_beta : cos_beta) * s_offset_y;
f32 s_offset_z = (s_offset_y < 0 ? 0 : s_offset_y) * 2;
Mtx m, m1, m2, m3, m4, mv;
width *= .5;
height *= .5;
guMtxIdentity(m4);
guMtxTransApply(m4, m4, 0, 0, distance);
guMtxIdentity(m1);
guMtxScaleApply(m1, m1, scaleX, scaleY, 1.0);
guVector axis2 = ( guVector )
{
0 , 1, 0
};
guMtxRotAxisDeg ( m2, &axis2, deg_beta );
guVector axis = ( guVector )
{
0 , 0, 1
};
guMtxRotAxisDeg ( m3, &axis, deg_alpha );
// guMtxConcat(m2,m1,m);
guMtxConcat(m3, m4, m3); // move distance then rotate z-axis
guMtxConcat(m2, m3, m2); // rotate y-axis
guMtxConcat(m1, m2, m); // scale
if (shadow)
guMtxTransApply(m, m, xpos + width + 0.5 + s_offset_x, ypos + height + 0.5 + s_offset_y, zpos - s_offset_z);
else
guMtxTransApply(m, m, xpos + width + 0.5, ypos + height + 0.5, zpos);
guMtxConcat(GXmodelView2D, m, mv);
GX_LoadPosMtxImm(mv, GX_PNMTX0);
if (shadow)
{
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
GX_Position3f32(-width, -height, 0);
GX_Color4u8(0, 0, 0, alpha);
GX_TexCoord2f32(0, 0);
GX_Position3f32(width, -height, 0);
GX_Color4u8(0, 0, 0, alpha);
GX_TexCoord2f32(1, 0);
GX_Position3f32(width, height, 0);
GX_Color4u8(0, 0, 0, alpha);
GX_TexCoord2f32(1, 1);
GX_Position3f32(-width, height, 0);
GX_Color4u8(0, 0, 0, alpha);
GX_TexCoord2f32(0, 1);
}
else
{
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
GX_Position3f32(-width, -height, 0);
GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
GX_TexCoord2f32(0, 0);
GX_Position3f32(width, -height, 0);
GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
GX_TexCoord2f32(1, 0);
GX_Position3f32(width, height, 0);
GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
GX_TexCoord2f32(1, 1);
GX_Position3f32(-width, height, 0);
GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
GX_TexCoord2f32(0, 1);
}
GX_End();
GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0);
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
}
void Menu_DrawTPLImg(f32 xpos, f32 ypos, f32 zpos, f32 width, f32 height, GXTexObj *texObj, f32 degrees, f32 scaleX,
f32 scaleY, u8 alpha, int XX1, int YY1, int XX2, int YY2, int XX3, int YY3, int XX4, int YY4)
{
GX_LoadProjectionMtx(projection, GX_ORTHOGRAPHIC);
GX_LoadTexObj(texObj, GX_TEXMAP0);
GX_InvalidateTexAll();
GX_SetTevOp(GX_TEVSTAGE0, GX_REPLACE);
GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
Mtx m, m1, m2, mv;
width *= .5;
height *= .5;
guMtxIdentity(m1);
guMtxScaleApply(m1, m1, scaleX, scaleY, 1.0);
guVector axis = ( guVector )
{
0 , 0, 1
};
guMtxRotAxisDeg ( m2, &axis, degrees );
guMtxConcat(m1, m2, m);
guMtxTransApply(m, m, xpos + width + 0.5, ypos + height + 0.5, zpos);
guMtxConcat(GXmodelView2D, m, mv);
GX_LoadPosMtxImm(mv, GX_PNMTX0);
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
GX_Position3f32(-width + XX1, -height + YY1, 0);
GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
GX_TexCoord2f32(0, 0);
GX_Position3f32(width + XX2, -height + YY2, 0);
GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
GX_TexCoord2f32(1, 0);
GX_Position3f32(width + XX3, height + YY3, 0);
GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
GX_TexCoord2f32(1, 1);
GX_Position3f32(-width + XX4, height + YY4, 0);
GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
GX_TexCoord2f32(0, 1);
GX_End();
GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0);
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
}
/****************************************************************************
* TakeScreenshot
*
* Copies the current screen into a file "path"
***************************************************************************/
s32 TakeScreenshot(const char *path)
{
gprintf("\nTakeScreenshot(%s)", path);
IMGCTX ctx = PNGU_SelectImageFromDevice(path);
s32 ret = PNGU_EncodeFromYCbYCr(ctx, vmode->fbWidth, vmode->efbHeight, xfb[whichfb], 0);
PNGU_ReleaseImageContext(ctx);
gprintf(":%d", ret);
return 1;
}