2008-08-06 03:09:59 +02:00
/****************************************************************************
2010-01-27 23:20:37 +01:00
* Snes9x Nintendo Wii / Gamecube Port
2008-08-06 03:09:59 +02:00
*
* softdev July 2006
* crunchy2 May 2007
2008-10-22 20:52:51 +02:00
* Michniewski 2008
2018-12-27 00:10:12 +01:00
* Tantric 2008 - 2019
2008-09-11 06:41:58 +02:00
*
* video . cpp
*
* Video routines
2008-09-12 07:28:40 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-08-06 03:09:59 +02:00
# include <gccore.h>
# include <ogcsys.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2008-08-06 03:39:43 +02:00
# include <unistd.h>
2009-01-16 05:48:15 +01:00
# include <ogc/texconv.h>
2009-03-11 18:28:37 +01:00
2010-03-22 00:43:54 +01:00
# include "snes9xgx.h"
2009-03-11 18:28:37 +01:00
# include "menu.h"
2009-01-30 08:25:30 +01:00
# include "filter.h"
2009-03-11 18:28:37 +01:00
# include "filelist.h"
# include "audio.h"
2009-04-13 10:43:50 +02:00
# include "gui/gui.h"
2009-03-16 06:16:20 +01:00
# include "input.h"
2008-09-09 05:02:11 +02:00
2010-03-22 00:43:54 +01:00
# include "snes9x/snes9x.h"
# include "snes9x/memmap.h"
2010-07-15 05:52:42 +02:00
extern void UpdatePlaybackRate ( void ) ;
2008-08-06 03:09:59 +02:00
/*** Snes9x GFX Buffer ***/
2010-01-27 23:08:56 +01:00
# define SNES9XGFX_SIZE (EXT_PITCH*EXT_HEIGHT)
# define FILTERMEM_SIZE (512*MAX_SNES_HEIGHT*4)
2009-03-11 18:28:37 +01:00
2009-04-22 20:21:37 +02:00
static unsigned char * snes9xgfx = NULL ;
unsigned char * filtermem = NULL ; // only want ((512*2) X (239*2))
2008-08-06 03:09:59 +02:00
/*** 2D Video ***/
2018-06-06 16:10:11 +02:00
static u32 * xfb [ 2 ] = { NULL , NULL } ; // Double buffered
2009-03-11 18:28:37 +01:00
static int whichfb = 0 ; // Switch
2010-04-14 01:34:01 +02:00
GXRModeObj * vmode = NULL ; // Current video mode
2009-09-16 09:54:34 +02:00
int screenheight = 480 ;
int screenwidth = 640 ;
2009-06-15 10:23:19 +02:00
static int oldRenderMode = - 1 ; // set to GCSettings.render when changing (temporarily) to another mode
int CheckVideo = 0 ; // for forcing video reset
2008-08-06 03:09:59 +02:00
/*** GX ***/
# define TEX_WIDTH 512
# define TEX_HEIGHT 512
2009-03-11 18:28:37 +01:00
# define TEXTUREMEM_SIZE TEX_WIDTH*(TEX_HEIGHT+8)*2
static unsigned char texturemem [ TEXTUREMEM_SIZE ] ATTRIBUTE_ALIGN ( 32 ) ;
2008-08-06 03:09:59 +02:00
# define DEFAULT_FIFO_SIZE 256 * 1024
2009-03-11 18:28:37 +01:00
static unsigned int copynow = GX_FALSE ;
2008-08-06 03:09:59 +02:00
static unsigned char gp_fifo [ DEFAULT_FIFO_SIZE ] ATTRIBUTE_ALIGN ( 32 ) ;
2009-03-11 18:28:37 +01:00
static GXTexObj texobj ;
static Mtx view ;
static Mtx GXmodelView2D ;
2008-12-30 01:08:17 +01:00
static int vwidth , vheight , oldvwidth , oldvheight ;
2008-08-06 03:09:59 +02:00
2010-06-04 01:15:34 +02:00
u8 * gameScreenPng = NULL ;
int gameScreenPngSize = 0 ;
2009-03-11 18:28:37 +01:00
2008-08-06 03:09:59 +02:00
u32 FrameTimer = 0 ;
2016-02-06 22:40:46 +01:00
bool vmode_60hz = true ;
int timerstyle = 0 ;
2008-09-11 04:23:48 +02:00
bool progressive = 0 ;
2008-08-06 03:39:43 +02:00
2008-08-24 01:15:58 +02:00
# define HASPECT 320
# define VASPECT 240
2008-08-06 03:09:59 +02:00
/* New texture based scaler */
typedef struct tagcamera
{
2009-07-10 23:30:44 +02:00
guVector pos ;
guVector up ;
guVector view ;
2008-08-06 03:09:59 +02:00
}
camera ;
/*** Square Matrix
This structure controls the size of the image on the screen .
Think of the output as a - 80 x 80 by - 60 x 60 graph .
* * */
s16 square [ ] ATTRIBUTE_ALIGN ( 32 ) =
{
/*
* X , Y , Z
* Values set are for roughly 4 : 3 aspect
*/
2008-11-04 21:43:15 +01:00
- HASPECT , VASPECT , 0 , // 0
HASPECT , VASPECT , 0 , // 1
HASPECT , - VASPECT , 0 , // 2
- HASPECT , - VASPECT , 0 // 3
2008-08-06 03:09:59 +02:00
} ;
2008-08-24 01:15:58 +02:00
2008-11-02 00:05:56 +01:00
static camera cam = {
{ 0.0F , 0.0F , 0.0F } ,
2008-11-04 21:43:15 +01:00
{ 0.0F , 0.5F , 0.0F } ,
{ 0.0F , 0.0F , - 0.5F }
2008-08-06 03:09:59 +02:00
} ;
2008-08-24 01:15:58 +02:00
2008-09-10 19:33:35 +02:00
/***
* * * Custom Video modes ( used to emulate original console video modes )
2008-08-24 01:15:58 +02:00
* * */
/** Original SNES PAL Resolutions: **/
/* 239 lines progressive (PAL 50Hz) */
2008-12-30 08:30:31 +01:00
static GXRModeObj TV_239p =
2008-08-24 01:15:58 +02:00
{
VI_TVMODE_PAL_DS , // viDisplayMode
2008-11-04 20:10:23 +01:00
512 , // fbWidth
2008-08-24 01:15:58 +02:00
239 , // efbHeight
239 , // xfbHeight
2008-09-10 23:09:53 +02:00
( VI_MAX_WIDTH_PAL - 640 ) / 2 , // viXOrigin
2008-11-04 20:10:23 +01:00
( VI_MAX_HEIGHT_PAL / 2 - 478 / 2 ) / 2 , // viYOrigin
2008-09-10 23:09:53 +02:00
640 , // viWidth
2008-09-09 18:24:42 +02:00
478 , // viHeight
2008-08-24 01:15:58 +02:00
VI_XFBMODE_SF , // xFBmode
GX_FALSE , // field_rendering
GX_FALSE , // aa
2008-11-04 21:43:15 +01:00
// 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
{
0 , // line n-1
0 , // line n-1
21 , // line n
22 , // line n
21 , // line n
0 , // line n+1
0 // line n+1
}
2008-08-24 01:15:58 +02:00
} ;
/* 478 lines interlaced (PAL 50Hz, Deflicker) */
2008-12-30 08:30:31 +01:00
static GXRModeObj TV_478i =
2008-08-24 01:15:58 +02:00
{
2008-11-04 21:43:15 +01:00
VI_TVMODE_PAL_INT , // viDisplayMode
512 , // fbWidth
478 , // efbHeight
478 , // xfbHeight
( VI_MAX_WIDTH_PAL - 640 ) / 2 , // viXOrigin
( VI_MAX_HEIGHT_PAL - 478 ) / 2 , // viYOrigin
640 , // viWidth
478 , // 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
}
2008-08-24 01:15:58 +02:00
} ;
/** Original SNES NTSC Resolutions: **/
/* 224 lines progressive (NTSC or PAL 60Hz) */
2008-12-30 08:30:31 +01:00
static GXRModeObj TV_224p =
2008-08-24 01:15:58 +02:00
{
VI_TVMODE_EURGB60_DS , // viDisplayMode
2008-11-04 20:10:23 +01:00
512 , // fbWidth
2008-08-24 01:15:58 +02:00
224 , // efbHeight
224 , // xfbHeight
2008-09-10 23:09:53 +02:00
( VI_MAX_WIDTH_NTSC - 640 ) / 2 , // viXOrigin
2008-11-04 20:10:23 +01:00
( VI_MAX_HEIGHT_NTSC / 2 - 448 / 2 ) / 2 , // viYOrigin
2008-09-10 23:09:53 +02:00
640 , // viWidth
2008-09-09 18:24:42 +02:00
448 , // viHeight
2008-08-24 01:15:58 +02:00
VI_XFBMODE_SF , // xFBmode
GX_FALSE , // field_rendering
GX_FALSE , // aa
2008-11-04 21:43:15 +01:00
// 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
{
0 , // line n-1
0 , // line n-1
21 , // line n
22 , // line n
21 , // line n
0 , // line n+1
0 // line n+1
}
2008-08-24 01:15:58 +02:00
} ;
/* 448 lines interlaced (NTSC or PAL 60Hz, Deflicker) */
2008-12-30 08:30:31 +01:00
static GXRModeObj TV_448i =
2008-08-24 01:15:58 +02:00
{
2008-11-04 21:43:15 +01:00
VI_TVMODE_EURGB60_INT , // viDisplayMode
512 , // fbWidth
448 , // efbHeight
448 , // xfbHeight
( VI_MAX_WIDTH_NTSC - 640 ) / 2 , // viXOrigin
( VI_MAX_HEIGHT_NTSC - 448 ) / 2 , // viYOrigin
640 , // viWidth
448 , // 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
}
2008-08-24 01:15:58 +02:00
} ;
2009-01-30 08:25:30 +01:00
static GXRModeObj TV_Custom ;
2008-08-24 01:15:58 +02:00
/* TV Modes table */
2008-12-30 08:30:31 +01:00
static GXRModeObj * tvmodes [ 4 ] = {
2008-08-24 01:15:58 +02:00
& TV_239p , & TV_478i , /* Snes PAL video modes */
& TV_224p , & TV_448i , /* Snes NTSC video modes */
} ;
2008-08-06 03:09:59 +02:00
/****************************************************************************
* VideoThreading
2008-09-12 07:28:40 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-08-06 03:09:59 +02:00
# define TSTACK 16384
2009-03-11 18:28:37 +01:00
static lwp_t vbthread = LWP_THREAD_NULL ;
2008-08-06 03:09:59 +02:00
static unsigned char vbstack [ TSTACK ] ;
/****************************************************************************
* vbgetback
*
* This callback enables the emulator to keep running while waiting for a
2008-08-10 05:14:39 +02:00
* vertical blank .
2008-08-06 03:09:59 +02:00
*
* Putting LWP to good use : )
2008-09-12 07:28:40 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-08-06 03:09:59 +02:00
static void *
vbgetback ( void * arg )
{
2008-08-24 01:15:58 +02:00
while ( 1 )
{
VIDEO_WaitVSync ( ) ; /**< Wait for video vertical blank */
LWP_SuspendThread ( vbthread ) ;
}
return NULL ;
2008-08-06 03:09:59 +02:00
}
/****************************************************************************
* copy_to_xfb
*
* Stock code to copy the GX buffer to the current display mode .
* Also increments the frameticker , as it ' s called for each vb .
2008-09-12 07:28:40 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-05-06 08:33:57 +02:00
static inline void
2008-08-06 03:09:59 +02:00
copy_to_xfb ( u32 arg )
{
2008-08-24 01:15:58 +02:00
if ( copynow = = GX_TRUE )
{
GX_CopyDisp ( xfb [ whichfb ] , GX_TRUE ) ;
GX_Flush ( ) ;
copynow = GX_FALSE ;
}
2009-12-14 02:08:14 +01:00
+ + FrameTimer ;
2008-08-06 03:09:59 +02:00
}
/****************************************************************************
2008-08-24 01:15:58 +02:00
* Scaler Support Functions
2008-09-12 07:28:40 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-05-06 08:33:57 +02:00
static inline void
2008-08-06 03:09:59 +02:00
draw_init ( )
{
2008-08-24 01:15:58 +02:00
GX_ClearVtxDesc ( ) ;
GX_SetVtxDesc ( GX_VA_POS , GX_INDEX8 ) ;
GX_SetVtxDesc ( GX_VA_CLR0 , GX_INDEX8 ) ;
GX_SetVtxDesc ( GX_VA_TEX0 , GX_DIRECT ) ;
GX_SetVtxAttrFmt ( GX_VTXFMT0 , GX_VA_POS , GX_POS_XYZ , GX_S16 , 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_SetArray ( GX_VA_POS , square , 3 * sizeof ( s16 ) ) ;
GX_SetNumTexGens ( 1 ) ;
GX_SetNumChans ( 0 ) ;
2008-09-10 19:33:35 +02:00
2008-08-24 01:15:58 +02:00
GX_SetTexCoordGen ( GX_TEXCOORD0 , GX_TG_MTX2x4 , GX_TG_TEX0 , GX_IDENTITY ) ;
2008-09-23 05:49:57 +02:00
2008-08-24 01:15:58 +02:00
GX_SetTevOp ( GX_TEVSTAGE0 , GX_REPLACE ) ;
GX_SetTevOrder ( GX_TEVSTAGE0 , GX_TEXCOORD0 , GX_TEXMAP0 , GX_COLORNULL ) ;
2008-09-10 19:33:35 +02:00
2008-08-24 01:15:58 +02:00
memset ( & view , 0 , sizeof ( Mtx ) ) ;
guLookAt ( view , & cam . pos , & cam . up , & cam . view ) ;
GX_LoadPosMtxImm ( view , GX_PNMTX0 ) ;
2008-11-04 20:10:23 +01:00
2008-11-04 21:43:15 +01:00
GX_InvVtxCache ( ) ; // update vertex cache
2008-08-06 03:09:59 +02:00
}
2009-05-06 08:33:57 +02:00
static inline void
2008-08-06 03:09:59 +02:00
draw_vert ( u8 pos , u8 c , f32 s , f32 t )
{
2008-08-24 01:15:58 +02:00
GX_Position1x8 ( pos ) ;
GX_Color1x8 ( c ) ;
GX_TexCoord2f32 ( s , t ) ;
2008-08-06 03:09:59 +02:00
}
2009-05-06 08:33:57 +02:00
static inline void
2008-08-06 03:09:59 +02:00
draw_square ( Mtx v )
{
2008-08-24 01:15:58 +02:00
Mtx m ; // model matrix.
Mtx mv ; // modelview matrix.
guMtxIdentity ( m ) ;
guMtxTransApply ( m , m , 0 , 0 , - 100 ) ;
guMtxConcat ( v , m , mv ) ;
GX_LoadPosMtxImm ( mv , GX_PNMTX0 ) ;
GX_Begin ( GX_QUADS , GX_VTXFMT0 , 4 ) ;
draw_vert ( 0 , 0 , 0.0 , 0.0 ) ;
draw_vert ( 1 , 0 , 1.0 , 0.0 ) ;
draw_vert ( 2 , 0 , 1.0 , 1.0 ) ;
draw_vert ( 3 , 0 , 0.0 , 1.0 ) ;
GX_End ( ) ;
2008-08-06 03:09:59 +02:00
}
2009-03-28 20:03:35 +01:00
/****************************************************************************
* StopGX
*
* Stops GX ( when exiting )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-03-11 18:28:37 +01:00
void StopGX ( )
{
GX_AbortFrame ( ) ;
GX_Flush ( ) ;
2008-08-24 01:15:58 +02:00
2009-03-11 18:28:37 +01:00
VIDEO_SetBlack ( TRUE ) ;
VIDEO_Flush ( ) ;
2008-08-06 03:09:59 +02:00
}
/****************************************************************************
2009-09-16 09:54:34 +02:00
* FindVideoMode
2008-08-06 03:09:59 +02:00
*
2009-04-22 20:21:37 +02:00
* Finds the optimal video mode , or uses the user - specified one
* Also configures original video modes
2008-09-12 07:28:40 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-09-16 09:54:34 +02:00
static GXRModeObj * FindVideoMode ( )
2008-08-06 03:09:59 +02:00
{
2009-09-16 09:54:34 +02:00
GXRModeObj * mode ;
2010-08-31 08:14:45 +02:00
2009-04-22 20:21:37 +02:00
// choose the desired video mode
switch ( GCSettings . videomode )
{
case 1 : // NTSC (480i)
2009-09-16 09:54:34 +02:00
mode = & TVNtsc480IntDf ;
2009-04-22 20:21:37 +02:00
break ;
case 2 : // Progressive (480p)
2009-09-16 09:54:34 +02:00
mode = & TVNtsc480Prog ;
2009-04-22 20:21:37 +02:00
break ;
case 3 : // PAL (50Hz)
2012-04-28 18:13:03 +02:00
mode = & TVPal576IntDfScale ;
2009-04-22 20:21:37 +02:00
break ;
case 4 : // PAL (60Hz)
2009-09-16 09:54:34 +02:00
mode = & TVEurgb60Hz480IntDf ;
2009-04-22 20:21:37 +02:00
break ;
default :
2009-09-16 09:54:34 +02:00
mode = VIDEO_GetPreferredMode ( NULL ) ;
2009-04-22 20:21:37 +02:00
# ifdef HW_DOL
/* we have component cables, but the preferred mode is interlaced
* why don ' t we switch into progressive ?
* on the Wii , the user can do this themselves on their Wii Settings */
if ( VIDEO_HaveComponentCable ( ) )
2009-09-16 09:54:34 +02:00
mode = & TVNtsc480Prog ;
2009-04-22 20:21:37 +02:00
# endif
break ;
}
// configure original modes
2009-09-16 09:54:34 +02:00
switch ( mode - > viTVMode > > 2 )
2008-08-06 03:39:43 +02:00
{
2008-09-11 06:41:58 +02:00
case VI_PAL :
2008-09-11 04:23:48 +02:00
// 576 lines (PAL 50Hz)
2010-08-31 08:14:45 +02:00
vmode_60hz = false ;
2008-11-04 20:10:23 +01:00
2009-04-21 23:48:22 +02:00
// Original Video modes (forced to PAL 50Hz)
2009-04-22 20:21:37 +02:00
// set video signal mode
2008-11-04 20:10:23 +01:00
TV_224p . viTVMode = VI_TVMODE_PAL_DS ;
TV_448i . viTVMode = VI_TVMODE_PAL_INT ;
// set VI position
TV_224p . viYOrigin = ( VI_MAX_HEIGHT_PAL / 2 - 448 / 2 ) / 2 ;
2009-04-22 20:21:37 +02:00
TV_448i . viYOrigin = ( VI_MAX_HEIGHT_PAL - 448 ) / 2 ;
2008-08-06 03:39:43 +02:00
break ;
2008-09-11 06:41:58 +02:00
case VI_NTSC :
2009-04-21 23:48:22 +02:00
// 480 lines (NTSC 60Hz)
2010-08-31 08:14:45 +02:00
vmode_60hz = true ;
2008-11-04 20:10:23 +01:00
// Original Video modes (forced to NTSC 60hz)
// set video signal mode
TV_239p . viTVMode = VI_TVMODE_NTSC_DS ;
TV_478i . viTVMode = VI_TVMODE_NTSC_INT ;
TV_224p . viTVMode = VI_TVMODE_NTSC_DS ;
TV_448i . viTVMode = VI_TVMODE_NTSC_INT ;
// set VI position
TV_239p . viYOrigin = ( VI_MAX_HEIGHT_NTSC / 2 - 478 / 2 ) / 2 ;
2009-04-22 20:21:37 +02:00
TV_478i . viYOrigin = ( VI_MAX_HEIGHT_NTSC - 478 ) / 2 ;
2008-11-04 20:10:23 +01:00
TV_224p . viYOrigin = ( VI_MAX_HEIGHT_NTSC / 2 - 448 / 2 ) / 2 ;
2009-04-22 20:21:37 +02:00
TV_448i . viYOrigin = ( VI_MAX_HEIGHT_NTSC - 448 ) / 2 ;
2008-11-04 20:10:23 +01:00
break ;
2008-08-24 01:15:58 +02:00
2008-09-11 06:41:58 +02:00
default :
2008-09-11 04:23:48 +02:00
// 480 lines (PAL 60Hz)
2010-08-31 08:14:45 +02:00
vmode_60hz = true ;
2008-11-04 20:10:23 +01:00
// Original Video modes (forced to PAL 60hz)
// set video signal mode
2009-09-20 03:06:00 +02:00
TV_239p . viTVMode = VI_TVMODE ( mode - > viTVMode > > 2 , VI_NON_INTERLACE ) ;
TV_478i . viTVMode = VI_TVMODE ( mode - > viTVMode > > 2 , VI_INTERLACE ) ;
TV_224p . viTVMode = VI_TVMODE ( mode - > viTVMode > > 2 , VI_NON_INTERLACE ) ;
TV_448i . viTVMode = VI_TVMODE ( mode - > viTVMode > > 2 , VI_INTERLACE ) ;
2008-11-04 20:10:23 +01:00
// set VI position
TV_239p . viYOrigin = ( VI_MAX_HEIGHT_NTSC / 2 - 478 / 2 ) / 2 ;
2009-04-22 20:21:37 +02:00
TV_478i . viYOrigin = ( VI_MAX_HEIGHT_NTSC - 478 ) / 2 ;
2008-11-04 20:10:23 +01:00
TV_224p . viYOrigin = ( VI_MAX_HEIGHT_NTSC / 2 - 448 / 2 ) / 2 ;
2009-04-22 20:21:37 +02:00
TV_448i . viYOrigin = ( VI_MAX_HEIGHT_NTSC - 448 ) / 2 ;
2008-08-06 03:39:43 +02:00
break ;
}
2008-09-10 19:33:35 +02:00
2008-09-09 05:02:11 +02:00
// check for progressive scan
2009-09-16 09:54:34 +02:00
if ( mode - > viTVMode = = VI_TVMODE_NTSC_PROG )
2008-09-11 04:23:48 +02:00
progressive = true ;
2009-04-22 20:21:37 +02:00
else
progressive = false ;
2008-09-11 06:41:58 +02:00
2009-03-11 18:28:37 +01:00
# ifdef HW_RVL
2010-04-14 01:34:01 +02:00
if ( CONF_GetAspectRatio ( ) = = CONF_ASPECT_16_9 )
2010-08-31 08:14:45 +02:00
mode - > viWidth = 678 ;
2010-04-14 01:34:01 +02:00
else
mode - > viWidth = 672 ;
2010-08-31 08:14:45 +02:00
if ( vmode_60hz )
2010-04-14 01:34:01 +02:00
{
2010-08-31 08:14:45 +02:00
mode - > viXOrigin = ( VI_MAX_WIDTH_NTSC - mode - > viWidth ) / 2 ;
mode - > viYOrigin = ( VI_MAX_HEIGHT_NTSC - mode - > viHeight ) / 2 ;
2010-04-14 01:34:01 +02:00
}
else
2008-11-05 18:26:59 +01:00
{
2010-08-31 08:14:45 +02:00
mode - > viXOrigin = ( VI_MAX_WIDTH_PAL - mode - > viWidth ) / 2 ;
mode - > viYOrigin = ( VI_MAX_HEIGHT_PAL - mode - > viHeight ) / 2 ;
2008-11-05 18:26:59 +01:00
}
2009-03-11 18:28:37 +01:00
# endif
2009-09-16 09:54:34 +02:00
return mode ;
2009-04-22 20:21:37 +02:00
}
/****************************************************************************
2009-09-16 09:54:34 +02:00
* SetupVideoMode
2009-04-22 20:21:37 +02:00
*
2009-09-16 09:54:34 +02:00
* Sets up the given video mode
2009-04-22 20:21:37 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-09-16 09:54:34 +02:00
static void SetupVideoMode ( GXRModeObj * mode )
2009-04-22 20:21:37 +02:00
{
2009-09-16 09:54:34 +02:00
if ( vmode = = mode )
return ;
2012-06-28 04:33:17 +02:00
2009-09-16 09:54:34 +02:00
VIDEO_SetPostRetraceCallback ( NULL ) ;
copynow = GX_FALSE ;
VIDEO_Configure ( mode ) ;
VIDEO_Flush ( ) ;
2008-08-10 05:14:39 +02:00
2009-01-02 23:32:16 +01:00
// Clear framebuffers etc.
2009-09-16 09:54:34 +02:00
VIDEO_ClearFrameBuffer ( mode , xfb [ 0 ] , COLOR_BLACK ) ;
VIDEO_ClearFrameBuffer ( mode , xfb [ 1 ] , COLOR_BLACK ) ;
2009-01-02 23:32:16 +01:00
VIDEO_SetNextFramebuffer ( xfb [ 0 ] ) ;
2008-08-10 05:14:39 +02:00
2009-01-02 23:32:16 +01:00
VIDEO_SetBlack ( FALSE ) ;
VIDEO_Flush ( ) ;
VIDEO_WaitVSync ( ) ;
2009-09-16 09:54:34 +02:00
if ( mode - > viTVMode & VI_NON_INTERLACE )
VIDEO_WaitVSync ( ) ;
else
while ( VIDEO_GetNextField ( ) )
VIDEO_WaitVSync ( ) ;
VIDEO_SetPostRetraceCallback ( ( VIRetraceCallback ) copy_to_xfb ) ;
vmode = mode ;
}
2008-08-10 05:14:39 +02:00
2009-09-16 09:54:34 +02:00
/****************************************************************************
* InitGCVideo
*
* This function MUST be called at startup .
* - also sets up menu video mode
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-02-07 04:01:10 +01:00
2009-09-16 09:54:34 +02:00
void
InitGCVideo ( )
{
2009-10-13 06:56:38 +02:00
VIDEO_Init ( ) ;
2010-06-20 02:26:36 +02:00
// Allocate the video buffers
2012-07-07 19:46:28 +02:00
xfb [ 0 ] = ( u32 * ) memalign ( 32 , 640 * 576 * 2 ) ;
xfb [ 1 ] = ( u32 * ) memalign ( 32 , 640 * 576 * 2 ) ;
DCInvalidateRange ( xfb [ 0 ] , 640 * 576 * 2 ) ;
DCInvalidateRange ( xfb [ 1 ] , 640 * 576 * 2 ) ;
2010-11-17 08:27:53 +01:00
xfb [ 0 ] = ( u32 * ) MEM_K0_TO_K1 ( xfb [ 0 ] ) ;
xfb [ 1 ] = ( u32 * ) MEM_K0_TO_K1 ( xfb [ 1 ] ) ;
2010-06-20 02:26:36 +02:00
2009-09-16 09:54:34 +02:00
GXRModeObj * rmode = FindVideoMode ( ) ;
SetupVideoMode ( rmode ) ;
2010-06-23 19:34:19 +02:00
# ifdef HW_RVL
2009-01-30 08:25:30 +01:00
InitLUTs ( ) ; // init LUTs for hq2x
2010-06-23 19:34:19 +02:00
# endif
2009-10-13 06:56:38 +02:00
LWP_CreateThread ( & vbthread , vbgetback , NULL , vbstack , TSTACK , 68 ) ;
2009-10-13 07:09:43 +02:00
// 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 ) ;
vwidth = 100 ;
vheight = 100 ;
2008-08-06 04:31:44 +02:00
}
2012-06-28 04:33:17 +02:00
void ResetFbWidth ( int width , GXRModeObj * rmode )
{
if ( rmode - > fbWidth = = width )
return ;
rmode - > fbWidth = width ;
if ( rmode ! = vmode )
return ;
GX_InvVtxCache ( ) ;
VIDEO_Configure ( rmode ) ;
VIDEO_Flush ( ) ;
}
2008-08-06 03:09:59 +02:00
/****************************************************************************
2008-09-12 07:28:40 +02:00
* ResetVideo_Emu
*
* Reset the video / rendering mode for the emulator rendering
2008-08-24 01:15:58 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-08-06 03:09:59 +02:00
void
2008-08-24 01:15:58 +02:00
ResetVideo_Emu ( )
2008-08-06 03:09:59 +02:00
{
2009-09-16 09:54:34 +02:00
GXRModeObj * rmode ;
2008-12-30 08:30:31 +01:00
Mtx44 p ;
2008-09-23 05:49:57 +02:00
int i = - 1 ;
2009-04-02 07:14:18 +02:00
// original render mode or hq2x
2009-04-02 07:59:36 +02:00
if ( GCSettings . render = = 0 )
2008-08-24 01:15:58 +02:00
{
2009-04-02 07:14:18 +02:00
for ( int j = 0 ; j < 4 ; j + + )
2008-11-04 21:43:15 +01:00
{
2009-04-02 07:14:18 +02:00
if ( tvmodes [ j ] - > efbHeight = = vheight )
{
i = j ;
2008-09-09 05:02:11 +02:00
break ;
2009-04-02 07:14:18 +02:00
}
2008-08-24 01:15:58 +02:00
}
2009-04-02 07:14:18 +02:00
}
if ( i > = 0 ) // we found a matching original mode
{
2008-08-24 01:15:58 +02:00
rmode = tvmodes [ i ] ;
2009-02-07 04:01:10 +01:00
2009-04-22 07:59:37 +02:00
// hack to fix video output for hq2x (only when actually filtering; h<=239, w<=256)
if ( GCSettings . FilterMethod ! = FILTER_NONE & & vheight < = 239 & & vwidth < = 256 )
2009-01-30 08:25:30 +01:00
{
memcpy ( & TV_Custom , tvmodes [ i ] , sizeof ( TV_Custom ) ) ;
rmode = & TV_Custom ;
2009-02-07 04:01:10 +01:00
2009-01-30 08:25:30 +01:00
rmode - > fbWidth = 512 ;
rmode - > efbHeight * = 2 ;
rmode - > xfbHeight * = 2 ;
rmode - > xfbMode = VI_XFBMODE_DF ;
rmode - > viTVMode | = VI_INTERLACE ;
}
2010-07-15 05:52:42 +02:00
Settings . SoundInputRate = 31894 ;
UpdatePlaybackRate ( ) ;
2008-09-10 19:33:35 +02:00
}
2008-11-04 21:43:15 +01:00
else
2009-09-16 09:54:34 +02:00
{
rmode = FindVideoMode ( ) ;
2012-01-11 19:46:55 +01:00
2012-06-28 04:33:17 +02:00
if ( GCSettings . widescreen )
ResetFbWidth ( 640 , rmode ) ;
else
ResetFbWidth ( 512 , rmode ) ;
2018-08-20 17:29:40 +02:00
Settings . SoundInputRate = 31950 ;
2010-07-15 05:52:42 +02:00
UpdatePlaybackRate ( ) ;
2009-09-16 09:54:34 +02:00
}
2008-09-10 19:33:35 +02:00
2009-09-16 09:54:34 +02:00
SetupVideoMode ( rmode ) ; // reconfigure VI
2009-06-27 22:03:15 +02:00
2009-03-11 18:28:37 +01:00
GXColor background = { 0 , 0 , 0 , 255 } ;
GX_SetCopyClear ( background , 0x00ffffff ) ;
2008-08-24 01:15:58 +02:00
GX_SetViewport ( 0 , 0 , rmode - > fbWidth , rmode - > efbHeight , 0 , 1 ) ;
GX_SetDispCopyYScale ( ( f32 ) rmode - > xfbHeight / ( f32 ) rmode - > efbHeight ) ;
GX_SetScissor ( 0 , 0 , rmode - > fbWidth , rmode - > efbHeight ) ;
2008-09-10 19:33:35 +02:00
2008-08-24 01:15:58 +02:00
GX_SetDispCopySrc ( 0 , 0 , rmode - > fbWidth , rmode - > efbHeight ) ;
GX_SetDispCopyDst ( rmode - > fbWidth , rmode - > xfbHeight ) ;
2018-08-16 17:35:24 +02:00
u8 sharp [ 7 ] = { 0 , 0 , 21 , 22 , 21 , 0 , 0 } ;
u8 soft [ 7 ] = { 8 , 8 , 10 , 12 , 10 , 8 , 8 } ;
u8 * vfilter =
GCSettings . render = = 3 ? sharp
: GCSettings . render = = 4 ? soft
: rmode - > vfilter ;
GX_SetCopyFilter ( rmode - > aa , rmode - > sample_pattern , ( rmode - > xfbMode = = VI_XFBMODE_SF ) ? GX_FALSE : GX_TRUE , vfilter ) ;
2008-09-10 19:33:35 +02:00
2008-08-24 01:15:58 +02:00
GX_SetFieldMode ( rmode - > field_rendering , ( ( rmode - > viHeight = = 2 * rmode - > xfbHeight ) ? GX_ENABLE : GX_DISABLE ) ) ;
2009-09-15 08:13:08 +02:00
if ( rmode - > aa )
GX_SetPixelFmt ( GX_PF_RGB565_Z16 , GX_ZC_LINEAR ) ;
else
GX_SetPixelFmt ( GX_PF_RGB8_Z24 , GX_ZC_LINEAR ) ;
2008-08-24 01:15:58 +02:00
2009-03-11 18:28:37 +01:00
GX_SetZMode ( GX_TRUE , GX_LEQUAL , GX_TRUE ) ;
GX_SetColorUpdate ( GX_TRUE ) ;
2009-04-21 23:48:22 +02:00
guOrtho ( p , rmode - > efbHeight / 2 , - ( rmode - > efbHeight / 2 ) , - ( rmode - > fbWidth / 2 ) , rmode - > fbWidth / 2 , 100 , 1000 ) ; // matrix, t, b, l, r, n, f
2008-08-24 01:15:58 +02:00
GX_LoadProjectionMtx ( p , GX_ORTHOGRAPHIC ) ;
2008-09-10 19:33:35 +02:00
2009-03-11 18:28:37 +01:00
draw_init ( ) ;
2008-08-06 03:09:59 +02:00
}
2009-05-22 23:17:06 +02:00
/****************************************************************************
* MakeTexture
*
* Modified for a buffer with an offset ( border )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
MakeTexture ( const void * src , void * dst , s32 width , s32 height )
{
register u32 tmp0 = 0 , tmp1 = 0 , tmp2 = 0 , tmp3 = 0 ;
__asm__ __volatile__ (
" srwi %6,%6,2 \n "
" srwi %7,%7,2 \n "
" subi %3,%4,4 \n "
" mr %4,%3 \n "
" subi %4,%4,4 \n "
" 2: mtctr %6 \n "
" mr %0,%5 \n "
//
" 1: lwz %1,0(%5) \n " //1
" stwu %1,8(%4) \n "
" lwz %2,4(%5) \n " //1
" stwu %2,8(%3) \n "
" lwz %1,1032(%5) \n " //2
" stwu %1,8(%4) \n "
" lwz %2,1036(%5) \n " //2
" stwu %2,8(%3) \n "
" lwz %1,2064(%5) \n " //3
" stwu %1,8(%4) \n "
" lwz %2,2068(%5) \n " //3
" stwu %2,8(%3) \n "
" lwz %1,3096(%5) \n " //4
" stwu %1,8(%4) \n "
" lwz %2,3100(%5) \n " //4
" stwu %2,8(%3) \n "
" addi %5,%5,8 \n "
" bdnz 1b \n "
" addi %5,%0,4128 \n " //5
" subic. %7,%7,1 \n "
" bne 2b "
// 0 1 2 3 4 5 6 7
: " =&b " ( tmp0 ) , " =&b " ( tmp1 ) , " =&b " ( tmp2 ) , " =&b " ( tmp3 ) , " +b " ( dst ) : " b " ( src ) , " b " ( width ) , " b " ( height )
) ;
}
2008-08-06 03:09:59 +02:00
/****************************************************************************
* Update Video
2008-09-12 07:28:40 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-08-25 07:57:43 +02:00
uint32 prevRenderedFrameCount = 0 ;
2010-06-23 19:34:19 +02:00
int fscale = 1 ;
2008-08-25 07:57:43 +02:00
2008-08-06 03:09:59 +02:00
void
update_video ( int width , int height )
{
2008-08-24 01:15:58 +02:00
vwidth = width ;
vheight = height ;
2010-06-01 04:18:28 +02:00
if ( CheckVideo = = 2 & & IPPU . RenderedFramesCount = = prevRenderedFrameCount )
2010-04-13 07:17:30 +02:00
return ; // we haven't rendered any frames yet, so we can't draw anything!
2008-08-06 03:09:59 +02:00
2008-09-11 04:23:48 +02:00
// Ensure previous vb has complete
2008-08-24 01:15:58 +02:00
while ( ( LWP_ThreadIsSuspended ( vbthread ) = = 0 ) | | ( copynow = = GX_TRUE ) )
2008-11-04 21:43:15 +01:00
usleep ( 50 ) ;
2008-08-06 03:09:59 +02:00
2008-08-24 01:15:58 +02:00
whichfb ^ = 1 ;
2010-04-13 07:17:30 +02:00
if ( oldvheight ! = vheight | | oldvwidth ! = vwidth ) // if rendered width/height changes, update scaling
2008-09-09 23:26:12 +02:00
CheckVideo = 1 ;
2008-09-10 19:33:35 +02:00
2010-04-13 07:17:30 +02:00
if ( CheckVideo ) // if we get back from the menu, and have rendered at least 1 frame
2008-08-24 01:15:58 +02:00
{
2008-09-28 04:13:19 +02:00
int xscale , yscale ;
2010-06-23 19:34:19 +02:00
# ifdef HW_RVL
2010-09-08 18:10:36 +02:00
if ( vwidth < = 256 )
fscale = GetFilterScale ( ( RenderFilter ) GCSettings . FilterMethod ) ;
else
fscale = 1 ;
2010-06-23 19:34:19 +02:00
# endif
2008-08-24 01:15:58 +02:00
ResetVideo_Emu ( ) ; // reset video to emulator rendering settings
2018-08-30 19:44:41 +02:00
memset ( filtermem , 0 , FILTERMEM_SIZE ) ;
2008-09-10 19:33:35 +02:00
2008-08-06 03:09:59 +02:00
/** Update scaling **/
2009-03-11 18:28:37 +01:00
if ( GCSettings . render = = 0 ) // original render mode
2009-01-30 08:25:30 +01:00
{
2009-04-22 07:59:37 +02:00
if ( GCSettings . FilterMethod ! = FILTER_NONE & & vheight < = 239 & & vwidth < = 256 )
{ // filters; normal operation
2009-03-11 18:28:37 +01:00
xscale = vwidth ;
yscale = vheight ;
}
else
2009-04-22 07:59:37 +02:00
{ // no filtering
fscale = 1 ;
2009-03-11 18:28:37 +01:00
xscale = 256 ;
yscale = vheight / 2 ;
}
2008-11-04 21:43:15 +01:00
}
else // unfiltered and filtered mode
{
2012-01-11 19:46:55 +01:00
xscale = 256 ;
2010-08-31 08:14:45 +02:00
if ( vheight = = 224 | | vheight = = 448 )
yscale = 224 ;
else
yscale = 239 ;
2008-08-24 01:15:58 +02:00
}
2008-09-10 19:33:35 +02:00
2008-09-11 04:23:48 +02:00
if ( GCSettings . widescreen )
2010-06-23 01:31:14 +02:00
{
if ( GCSettings . render = = 0 )
xscale = ( 3 * xscale ) / 4 ;
else
xscale = 256 ; // match the original console's width for "widescreen" to prevent flickering
}
2008-09-27 09:13:52 +02:00
2009-11-16 09:13:02 +01:00
xscale * = GCSettings . zoomHor ;
yscale * = GCSettings . zoomVert ;
2008-09-10 19:33:35 +02:00
2008-09-28 04:13:19 +02:00
square [ 6 ] = square [ 3 ] = xscale + GCSettings . xshift ;
square [ 0 ] = square [ 9 ] = - xscale + GCSettings . xshift ;
2008-09-30 08:43:34 +02:00
square [ 4 ] = square [ 1 ] = yscale - GCSettings . yshift ;
square [ 7 ] = square [ 10 ] = - yscale - GCSettings . yshift ;
2008-11-07 17:50:42 +01:00
DCFlushRange ( square , 32 ) ; // update memory BEFORE the GPU accesses it!
2008-11-04 20:10:23 +01:00
draw_init ( ) ;
2008-08-24 01:15:58 +02:00
2009-01-30 08:25:30 +01:00
// initialize the texture obj we are going to use
GX_InitTexObj ( & texobj , texturemem , vwidth * fscale , vheight * fscale , GX_TF_RGB565 , GX_CLAMP , GX_CLAMP , GX_FALSE ) ;
2008-09-10 19:33:35 +02:00
2008-09-11 04:23:48 +02:00
if ( GCSettings . render = = 0 | | GCSettings . render = = 2 )
GX_InitTexObjLOD ( & texobj , GX_NEAR , GX_NEAR_MIP_NEAR , 2.5 , 9.0 , 0.0 , GX_FALSE , GX_FALSE , GX_ANISO_1 ) ; // original/unfiltered video mode: force texture filtering OFF
2008-09-11 06:41:58 +02:00
2008-09-11 04:23:48 +02:00
GX_LoadTexObj ( & texobj , GX_TEXMAP0 ) ; // load texture object so its ready to use
2008-09-10 19:33:35 +02:00
2008-08-24 01:15:58 +02:00
oldvwidth = vwidth ;
oldvheight = vheight ;
2008-08-25 07:57:43 +02:00
CheckVideo = 0 ;
2008-08-24 01:15:58 +02:00
}
2010-06-23 19:34:19 +02:00
# ifdef HW_RVL
2009-01-30 08:25:30 +01:00
// convert image to texture
2009-04-22 07:59:37 +02:00
if ( GCSettings . FilterMethod ! = FILTER_NONE & & vheight < = 239 & & vwidth < = 256 ) // don't do filtering on game textures > 256 x 239
2009-01-30 08:25:30 +01:00
{
FilterMethod ( ( uint8 * ) GFX . Screen , EXT_PITCH , ( uint8 * ) filtermem , vwidth * fscale * 2 , vwidth , vheight ) ;
MakeTexture565 ( ( char * ) filtermem , ( char * ) texturemem , vwidth * fscale , vheight * fscale ) ;
2009-03-11 18:28:37 +01:00
}
else
2010-06-23 19:34:19 +02:00
# endif
2009-03-11 18:28:37 +01:00
{
2009-01-30 08:25:30 +01:00
MakeTexture ( ( char * ) GFX . Screen , ( char * ) texturemem , vwidth , vheight ) ;
}
2008-08-06 03:09:59 +02:00
2009-03-11 18:28:37 +01:00
DCFlushRange ( texturemem , TEXTUREMEM_SIZE ) ; // update the texture memory
2008-09-11 04:23:48 +02:00
GX_InvalidateTexAll ( ) ;
2008-08-06 03:09:59 +02:00
2008-09-11 04:23:48 +02:00
draw_square ( view ) ; // draw the quad
2008-08-06 03:09:59 +02:00
2010-04-06 01:15:42 +02:00
GX_DrawDone ( ) ;
2009-06-15 10:23:19 +02:00
if ( ScreenshotRequested )
{
if ( GCSettings . render = = 0 ) // we can't take a screenshot in Original mode
{
oldRenderMode = 0 ;
GCSettings . render = 2 ; // switch to unfiltered mode
CheckVideo = 1 ; // request the switch
}
else
{
ScreenshotRequested = 0 ;
TakeScreenshot ( ) ;
if ( oldRenderMode ! = - 1 )
{
GCSettings . render = oldRenderMode ;
oldRenderMode = - 1 ;
}
ConfigRequested = 1 ;
}
}
2008-08-24 01:15:58 +02:00
VIDEO_SetNextFramebuffer ( xfb [ whichfb ] ) ;
2010-04-06 01:15:42 +02:00
VIDEO_Flush ( ) ;
2008-08-24 01:15:58 +02:00
copynow = GX_TRUE ;
2008-08-06 04:31:44 +02:00
2008-09-11 04:23:48 +02:00
// Return to caller, don't waste time waiting for vb
2008-08-24 01:15:58 +02:00
LWP_ResumeThread ( vbthread ) ;
}
2008-08-06 03:09:59 +02:00
2009-03-11 18:28:37 +01:00
void AllocGfxMem ( )
2008-08-06 03:09:59 +02:00
{
2009-03-11 18:28:37 +01:00
snes9xgfx = ( unsigned char * ) memalign ( 32 , SNES9XGFX_SIZE ) ;
memset ( snes9xgfx , 0 , SNES9XGFX_SIZE ) ;
2010-06-23 19:34:19 +02:00
# ifdef HW_RVL
2009-03-11 18:28:37 +01:00
filtermem = ( unsigned char * ) memalign ( 32 , FILTERMEM_SIZE ) ;
memset ( filtermem , 0 , FILTERMEM_SIZE ) ;
2010-06-23 19:34:19 +02:00
# endif
2009-03-11 18:28:37 +01:00
GFX . Pitch = EXT_PITCH ;
GFX . Screen = ( uint16 * ) ( snes9xgfx + EXT_OFFSET ) ;
2008-08-24 01:15:58 +02:00
}
2008-08-06 03:09:59 +02:00
2008-08-24 01:15:58 +02:00
/****************************************************************************
* setGFX
*
* Setup the global GFX information for Snes9x
2008-09-12 07:28:40 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-08-24 01:15:58 +02:00
void
setGFX ( )
{
2009-01-30 08:25:30 +01:00
GFX . Pitch = EXT_PITCH ;
2009-03-11 18:28:37 +01:00
}
/****************************************************************************
2009-03-28 20:03:35 +01:00
* TakeScreenshot
*
* Copies the current screen into a GX texture
2009-03-11 18:28:37 +01:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void TakeScreenshot ( )
{
2010-06-29 09:48:17 +02:00
IMGCTX pngContext = PNGU_SelectImageFromBuffer ( savebuffer ) ;
if ( pngContext ! = NULL )
{
gameScreenPngSize = PNGU_EncodeFromEFB ( pngContext , vmode - > fbWidth , vmode - > efbHeight ) ;
PNGU_ReleaseImageContext ( pngContext ) ;
gameScreenPng = ( u8 * ) malloc ( gameScreenPngSize ) ;
memcpy ( gameScreenPng , savebuffer , gameScreenPngSize ) ;
}
2009-03-11 18:28:37 +01:00
}
/****************************************************************************
* ResetVideo_Menu
*
* Reset the video / rendering mode for the menu
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
ResetVideo_Menu ( )
{
Mtx44 p ;
f32 yscale ;
u32 xfbHeight ;
2009-09-16 09:54:34 +02:00
GXRModeObj * rmode = FindVideoMode ( ) ;
2009-03-11 18:28:37 +01:00
2009-09-16 09:54:34 +02:00
SetupVideoMode ( rmode ) ; // reconfigure VI
2009-06-27 22:03:15 +02:00
2009-03-11 18:28:37 +01:00
// 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 ) ) ;
2009-02-07 04:01:10 +01:00
2009-03-11 18:28:37 +01:00
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 , - 50.0F ) ;
GX_LoadPosMtxImm ( GXmodelView2D , GX_PNMTX0 ) ;
guOrtho ( p , 0 , 479 , 0 , 639 , 0 , 300 ) ;
GX_LoadProjectionMtx ( p , GX_ORTHOGRAPHIC ) ;
GX_SetViewport ( 0 , 0 , vmode - > fbWidth , vmode - > efbHeight , 0 , 1 ) ;
GX_SetBlendMode ( GX_BM_BLEND , GX_BL_SRCALPHA , GX_BL_INVSRCALPHA , GX_LO_CLEAR ) ;
GX_SetAlphaUpdate ( GX_TRUE ) ;
}
2009-03-28 20:03:35 +01:00
/****************************************************************************
* Menu_Render
*
* Renders everything current sent to GX , and flushes video
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-03-11 18:28:37 +01:00
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 ) ;
2010-04-06 01:15:42 +02:00
GX_DrawDone ( ) ;
2009-03-11 18:28:37 +01:00
VIDEO_SetNextFramebuffer ( xfb [ whichfb ] ) ;
2010-04-06 01:15:42 +02:00
VIDEO_Flush ( ) ;
2009-03-11 18:28:37 +01:00
VIDEO_WaitVSync ( ) ;
}
2009-03-28 20:03:35 +01:00
/****************************************************************************
* Menu_DrawImg
*
* Draws the specified image on screen using GX
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void Menu_DrawImg ( f32 xpos , f32 ypos , u16 width , u16 height , u8 data [ ] ,
f32 degrees , f32 scaleX , f32 scaleY , u8 alpha )
2009-03-11 18:28:37 +01:00
{
if ( data = = NULL )
return ;
GXTexObj texObj ;
GX_InitTexObj ( & texObj , data , width , height , GX_TF_RGBA8 , GX_CLAMP , GX_CLAMP , GX_FALSE ) ;
GX_LoadTexObj ( & texObj , GX_TEXMAP0 ) ;
2009-03-17 06:09:45 +01:00
GX_InvalidateTexAll ( ) ;
2009-03-11 18:28:37 +01:00
GX_SetTevOp ( GX_TEVSTAGE0 , GX_MODULATE ) ;
GX_SetVtxDesc ( GX_VA_TEX0 , GX_DIRECT ) ;
Mtx m , m1 , m2 , mv ;
2009-12-14 02:08:14 +01:00
width > > = 1 ;
height > > = 1 ;
2009-03-11 18:28:37 +01:00
guMtxIdentity ( m1 ) ;
guMtxScaleApply ( m1 , m1 , scaleX , scaleY , 1.0 ) ;
2009-07-10 23:30:44 +02:00
guVector axis = ( guVector ) { 0 , 0 , 1 } ;
2009-03-11 18:28:37 +01:00
guMtxRotAxisDeg ( m2 , & axis , degrees ) ;
guMtxConcat ( m2 , m1 , m ) ;
guMtxTransApply ( m , m , xpos + width , ypos + height , 0 ) ;
guMtxConcat ( GXmodelView2D , m , mv ) ;
GX_LoadPosMtxImm ( mv , GX_PNMTX0 ) ;
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 ) ;
}
2009-03-28 20:03:35 +01:00
/****************************************************************************
* Menu_DrawRectangle
*
* Draws a rectangle at the specified coordinates using GX
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-03-11 18:28:37 +01:00
void Menu_DrawRectangle ( f32 x , f32 y , f32 width , f32 height , GXColor color , u8 filled )
{
2009-12-14 02:08:14 +01:00
long n = 4 ;
2009-03-11 18:28:37 +01:00
f32 x2 = x + width ;
f32 y2 = y + height ;
2009-07-10 23:30:44 +02:00
guVector v [ ] = { { x , y , 0.0f } , { x2 , y , 0.0f } , { x2 , y2 , 0.0f } , { x , y2 , 0.0f } , { x , y , 0.0f } } ;
2009-12-14 02:08:14 +01:00
u8 fmt = GX_TRIANGLEFAN ;
2009-03-11 18:28:37 +01:00
if ( ! filled )
{
fmt = GX_LINESTRIP ;
n = 5 ;
}
GX_Begin ( fmt , GX_VTXFMT0 , n ) ;
2009-12-14 02:08:14 +01:00
for ( long i = 0 ; i < n ; + + i )
2009-03-11 18:28:37 +01:00
{
GX_Position3f32 ( v [ i ] . x , v [ i ] . y , v [ i ] . z ) ;
GX_Color4u8 ( color . r , color . g , color . b , color . a ) ;
}
GX_End ( ) ;
2008-08-06 03:09:59 +02:00
}
2010-04-06 01:15:42 +02:00