thug/Code/Sys/ngc/p_display.cpp
2016-02-14 08:39:12 +11:00

2052 lines
55 KiB
C++

/********************************************************************************
* *
* Module: *
* NsDisplay *
* Description: *
* Sets up and manages a triple-buffered display. This code is *
* derived from the Nintendo "frb-triple" example. *
* Take a look at Sony's documentation for more information at: *
* $/DolphinSDK1.0/man/demos/gxdemos/Framebuffer/frb-triple.html *
* Also, check out the original source code at: *
* $/DolphinSDK1.0/build/demos/gxdemo/src/Framebuffer/frb-triple.c *
* Written by: *
* Paul Robinson *
* Copyright: *
* 2001 Neversoft Entertainment - All rights reserved. *
* *
********************************************************************************/
/********************************************************************************
* Includes. *
********************************************************************************/
#include "p_hw.h"
//#include <stdlib.h>
#include "p_display.h"
//#include <dolphin\dtk.h>
#include <sys\timer.h>
#include <sys\ngc\p_render.h>
//#include <sys\ngc\p_screenshot.h>
#include <sys\ngc\p_prim.h>
#include <sys\ngc\p_camera.h>
#include <sys\ngc\p_dvd.h>
#include <gel/scripting/script.h>
#include "gfx/ngc/nx/nx_init.h"
#include <gel/mainloop.h>
#include <sys/ngc/p_display.h>
#include <sys/ngc/p_render.h>
#include <sys/ngc/p_prim.h>
#include <gfx/ngc/nx/nx_init.h>
#include <gfx/ngc/nx/chars.h>
#include <gfx/ngc/nx/render.h>
#include <gfx/nxfontman.h>
#include <gfx/ngc/p_nxfont.h>
#include <gel/scripting/symboltable.h>
#include <core/defines.h>
#include <core/String/stringutils.h>
#include <gfx/NxFontMan.h>
#include <gel/Scripting/script.h>
#include <gel/scripting/struct.h>
#include <gel/scripting/array.h>
#include <gel/scripting/symboltable.h>
#include "gfx\ngc\nx\nx_init.h"
#include "gel\music\ngc\p_music.h"
#include <sys\ngc\p_profile.h>
#include "VIDSimpleAudio.h"
extern GXRenderModeObj *rmode;
extern GXRenderModeObj rmodeobj;
extern int inDrawingContext;
extern DVDCallback last_callback[8];
extern s32 last_callback_length[8];
extern DVDFileInfo* last_callback_fileInfo[8];
extern int last_callback_counter[8];
bool g_need_to_flush = true;
//NsProfile profile_gpu( "gpu", 256 );
//#define __INFO_REPORT__
#define P0_COUNT 35
#define P1_COUNT 22
bool g_legal = false;
#ifdef __INFO_REPORT__
int gp0 = GX_PERF0_XF_WAIT_IN;
int gp1 = GX_PERF1_TX_IDLE;
char g_gp_info0[64*P0_COUNT];
char g_gp_info1[64*P1_COUNT];
int frames = 0;
u32 _p0, _p1;
char * p0_name[] =
{
"GX_PERF0_VERTICES ",
"GX_PERF0_CLIP_VTX ",
"GX_PERF0_CLIP_CLKS ",
"GX_PERF0_XF_WAIT_IN ",
"GX_PERF0_XF_WAIT_OUT ",
"GX_PERF0_XF_XFRM_CLKS ",
"GX_PERF0_XF_LIT_CLKS ",
"GX_PERF0_XF_BOT_CLKS ",
"GX_PERF0_XF_REGLD_CLKS ",
"GX_PERF0_XF_REGRD_CLKS ",
"GX_PERF0_CLIP_RATIO ",
"GX_PERF0_TRIANGLES ",
"GX_PERF0_TRIANGLES_CULLED ",
"GX_PERF0_TRIANGLES_PASSED ",
"GX_PERF0_TRIANGLES_SCISSORED ",
"GX_PERF0_TRIANGLES_0TEX ",
"GX_PERF0_TRIANGLES_1TEX ",
"GX_PERF0_TRIANGLES_2TEX ",
"GX_PERF0_TRIANGLES_3TEX ",
"GX_PERF0_TRIANGLES_4TEX ",
"GX_PERF0_TRIANGLES_5TEX ",
"GX_PERF0_TRIANGLES_6TEX ",
"GX_PERF0_TRIANGLES_7TEX ",
"GX_PERF0_TRIANGLES_8TEX ",
"GX_PERF0_TRIANGLES_0CLR ",
"GX_PERF0_TRIANGLES_1CLR ",
"GX_PERF0_TRIANGLES_2CLR ",
"GX_PERF0_QUAD_0CVG ",
"GX_PERF0_QUAD_NON0CVG ",
"GX_PERF0_QUAD_1CVG ",
"GX_PERF0_QUAD_2CVG ",
"GX_PERF0_QUAD_3CVG ",
"GX_PERF0_QUAD_4CVG ",
"GX_PERF0_AVG_QUAD_CNT ",
"GX_PERF0_CLOCKS ",
"GX_PERF0_NONE "
};
/********************************/
char * p1_name[] =
{
"GX_PERF1_TEXELS ",
"GX_PERF1_TX_IDLE ",
"GX_PERF1_TX_REGS ",
"GX_PERF1_TX_MEMSTALL ",
"GX_PERF1_TC_CHECK1_2 ",
"GX_PERF1_TC_CHECK3_4 ",
"GX_PERF1_TC_CHECK5_6 ",
"GX_PERF1_TC_CHECK7_8 ",
"GX_PERF1_TC_MISS ",
"GX_PERF1_VC_ELEMQ_FULL ",
"GX_PERF1_VC_MISSQ_FULL ",
"GX_PERF1_VC_MEMREQ_FULL ",
"GX_PERF1_VC_STATUS7 ",
"GX_PERF1_VC_MISSREP_FULL ",
"GX_PERF1_VC_STREAMBUF_LOW ",
"GX_PERF1_VC_ALL_STALLS ",
"GX_PERF1_VERTICES ",
"GX_PERF1_FIFO_REQ ",
"GX_PERF1_CALL_REQ ",
"GX_PERF1_VC_MISS_REQ ",
"GX_PERF1_CP_ALL_REQ ",
"GX_PERF1_CLOCKS ",
"GX_PERF1_NONE "
};
#endif // __INFO_REPORT__
/********************************************************************************
* Defines. *
********************************************************************************/
#define QUEUE_MAX 5
#define QUEUE_EMPTY QUEUE_MAX
u8 g_blur = 0;
extern bool gLoadingBarActive;
extern int gLoadBarTotalFrames;
extern int gLoadBarNumFrames;
extern int gLoadBarX;
extern int gLoadBarY;
extern int gLoadBarWidth;
extern int gLoadBarHeight;
extern int gLoadBarStartColor[4];
extern int gLoadBarDeltaColor[4];
extern int gLoadBarBorderWidth;
extern int gLoadBarBorderHeight;
extern int gLoadBarBorderColor[4];
GXColor messageColor = {0,0,0,255};
static float lasty = 0;
static float prevx = 0;
static float prevy = 0;
static int selection = 0;
static int selection_max = 0;
static int reset_enabled_frames = 0;
/********************************************************************************
* Structures. *
********************************************************************************/
typedef struct QItem_
{
void* writePtr;
void* dataPtr;
void* copyXFB;
} NsDisplay_QItem;
typedef struct Queue_
{
NsDisplay_QItem entry[QUEUE_MAX];
u16 top;
u16 bot;
} NsDisplay_Queue;
/********************************************************************************
* Local variables. *
********************************************************************************/
void (*pIconCallback)( void ) = NULL;
static NsDisplay_Queue RenderQ; // Queue for frames in FIFO
static NsDisplay_Queue DoneQ; // Queue for frames finished already
static void * myXFB1; // Pointers to the two XFB's
static void * myXFB2;
static void * copyXFB; // Which XFB to copy to next
static void * dispXFB; // Which XFB is being displayed now
static GXBool BPSet; // Is the FIFO breakpoint set?
static GXBool BPWait; // Is breakpt reset waiting on VBlank?
static GXBool BPGo; // Indicates breakpt should be released
static u16 lastVCBToken; // Last sync token the VBlank callback saw
static u16 newToken; // Value to use for new sync token.
static OSThreadQueue waitingDoneRender; // Threads waiting for frames to finish
static OSThread CUThread; // OS data for clean-up thread
static u8 CUThreadStack[4096]; // Stack for clean-up thread
static OSAlarm s_bg_alarm;
static OSThread s_bg_thread;
static u8 s_bg_thread_stack[4096];
static int initCount = 0; // We can only initialize this once.
static int inDisplayContext = 0;
int resetDown = 0; // Whether the reset button has been pressed.
static int currentBuffer = 0; // Current buffer to use for triple buffering.
/********************************************************************************
* Forward references. *
********************************************************************************/
static void BPCallback ( void );
static void SetNextBreakPt ( void );
static void VIPreCallback ( u32 retraceCount );
static void VIPostCallback ( u32 retraceCount );
static void * CleanupThread ( void * param );
static void * bg_thread_func ( void * param );
static void bg_alarm_handler ( OSAlarm* alarm, OSContext* context );
static void init_queue ( NsDisplay_Queue *q );
static void enqueue ( NsDisplay_Queue *q, NsDisplay_QItem *qitm );
static NsDisplay_QItem dequeue ( NsDisplay_Queue *q );
static NsDisplay_QItem queue_front ( NsDisplay_Queue *q );
static GXBool queue_empty ( NsDisplay_Queue *q );
static u32 queue_length ( NsDisplay_Queue *q );
static NsDisplay_StartRenderingCallback startCB = NULL;
static NsDisplay_EndRenderingCallback endCB = NULL;
/********************************************************************************
* Externs. *
********************************************************************************/
extern void * hwFrameBuffer1; // Where to find XFB info
extern void * hwFrameBuffer2;
extern PADStatus padData[PAD_MAX_CONTROLLERS]; // game pad state
//static void* MyAlloc( u32 size )
//{
// Mem::Manager::sHandle().BottomUpHeap()->PushAlign( 32 );
// void* p = new char[size];
// Mem::Manager::sHandle().BottomUpHeap()->PopAlign();
//
// return p;
//}
//
//static void MyFree( void* block )
//{
// delete (char *)block;
//}
static u32 Update_input( void )
{
int i;
// u32 ResetReq = 0;
// PADStatus Pad[PAD_MAX_CONTROLLERS];
u32 PadButtonDownVal;
static u16 buttonLast[4] ={ 0, 0, 0, 0 };
//
// Read current PAD status and clamp the analog inputs
//
// hwPadRead();
// PADRead(Pad);
// PADClamp(Pad);
// //
// // Do we have an input device handle yet?
// //
//
// for ( i = 0 ; i < PAD_MAX_CONTROLLERS ; i++ )
// {
// if ( padData[i].err == PAD_ERR_TRANSFER )
// {
// return( 0 );
// }
// else if ( padData[i].err == PAD_ERR_NONE )
// {
// break;
// }
// else if ( padData[i].err == PAD_ERR_NO_CONTROLLER )
// {
// ResetReq |= (PAD_CHAN0_BIT >> i);
// }
// }
//
// //
// // A pad isn't plugged in
// //
//
// if ( i == PAD_MAX_CONTROLLERS )
// {
// //
// // Reset pad channels which have been not valid
// //
//
// if ( ResetReq )
// {
// PADReset( ResetReq );
// }
//
// buttonLast[0] = 0;
// buttonLast[1] = 0;
// buttonLast[2] = 0;
// buttonLast[3] = 0;
// return( 0 );
// }
//
// Get the button downs and save the current state
//
PadButtonDownVal = 0;
for ( i = 0 ; i < PAD_MAX_CONTROLLERS ; i++ )
{
PadButtonDownVal |= PADButtonDown ( buttonLast[i], padData[i].button );
buttonLast[i] = padData[i].button;
}
// //
// // Handle the loop control
// //
//
// if ( PadButtonDownVal & PAD_BUTTON_START )
// {
// Loop_current = ! Loop_current;
// }
//
// //
// // Handle the skip to the next files
// //
//
// if ( Pad[i].button & PAD_BUTTON_A )
// {
// return( 1 );
// }
//
// return( 0 );
return PadButtonDownVal;
}
void NsDisplay::Check480P( void )
{
// See if the 480p/widescreen menu should be displayed
u32 buttons = 0;
NxNgc::EngineGlobals.screen_brightness = 0.0f;
for ( int lp = 0; lp < 4; lp++ )
{
NsDisplay::begin();
NsRender::begin();
NsRender::end();
NsDisplay::end( true );
for ( int i = 0 ; i < PAD_MAX_CONTROLLERS ; i++ )
{
buttons |= padData[i].button;
}
}
NxNgc::EngineGlobals.screen_brightness = 1.0f;
// If we have a cable connected, we can continue...
if ( VIGetDTVStatus() )
{
if ( ( buttons & PAD_BUTTON_B ) || OSGetProgressiveMode() )
{
while ( !( buttons & PAD_BUTTON_A ) )
{
// Render the text.
NsDisplay::begin();
NsRender::begin();
NsCamera cam;
cam.orthographic( 0, 0, 640, 448 );
// Draw the screen.
NsPrim::begin();
cam.begin();
GX::SetZMode( GX_FALSE, GX_ALWAYS, GX_TRUE );
NxNgc::set_blend_mode( NxNgc::vBLEND_MODE_BLEND );
Script::RunScript( "ngc_widescreen" );
NsDisplay::setBackgroundColor( messageColor );
cam.end();
NsPrim::end();
NsRender::end();
NsDisplay::end( true );
buttons = Update_input();
if ( buttons & PAD_BUTTON_DOWN ) selection++;
if ( buttons & PAD_BUTTON_UP ) selection--;
if ( selection < 0 ) selection = 0;
if ( selection >= selection_max ) selection = selection_max - 1;
}
// Clear to black.
NsDisplay::setBackgroundColor( (GXColor){0,0,0,0} );
NsDisplay::begin();
NsDisplay::end( true );
NsDisplay::begin();
NsDisplay::end( true );
// Run the selected script.
char buf[32];
sprintf( buf, "ngc_select%d", selection );
Script::RunScript( buf );
}
}
else
{
// No cable, turn off progressive mode.
OSSetProgressiveMode(0);
}
// Must display licensed by nintendo screen.
display_legal();
g_legal = true;
}
void NsDisplay::Check60Hz( void )
{
// See if the 60Hz menu should be displayed
u32 buttons = 0;
NxNgc::EngineGlobals.screen_brightness = 0.0f;
for ( int lp = 0; lp < 4; lp++ )
{
NsDisplay::begin();
NsRender::begin();
NsRender::end();
NsDisplay::end( true );
for ( int i = 0 ; i < PAD_MAX_CONTROLLERS ; i++ )
{
buttons |= padData[i].button;
}
}
NxNgc::EngineGlobals.screen_brightness = 1.0f;
// If we press the B button, or we're already in 60hz mode...
if ( ( buttons & PAD_BUTTON_B ) || OSGetEuRgb60Mode() )
{
while ( !( buttons & PAD_BUTTON_A ) )
{
// Render the text.
NsDisplay::begin();
NsRender::begin();
NsCamera cam;
cam.orthographic( 0, 0, 640, 448 );
// Draw the screen.
NsPrim::begin();
cam.begin();
GX::SetZMode( GX_FALSE, GX_ALWAYS, GX_TRUE );
NxNgc::set_blend_mode( NxNgc::vBLEND_MODE_BLEND );
Script::RunScript( "ngc_pal60" );
NsDisplay::setBackgroundColor( messageColor );
cam.end();
NsPrim::end();
NsRender::end();
NsDisplay::end( true );
buttons = Update_input();
if ( buttons & PAD_BUTTON_DOWN ) selection++;
if ( buttons & PAD_BUTTON_UP ) selection--;
if ( selection < 0 ) selection = 0;
if ( selection >= selection_max ) selection = selection_max - 1;
}
// Clear to black.
NsDisplay::setBackgroundColor( (GXColor){0,0,0,0} );
NsDisplay::begin();
NsDisplay::end( true );
NsDisplay::begin();
NsDisplay::end( true );
// Run the selected script.
char buf[32];
sprintf( buf, "ngc_selectPAL%d", selection );
Script::RunScript( buf );
}
// Must display licensed by nintendo screen.
display_legal();
g_legal = true;
}
/********************************************************************************
* *
* Method: *
* NsDisplay *
* Inputs: *
* <none> *
* Output: *
* <none> *
* Description: *
* Initializes the OS, pad, DVD, video functions from the Nintendo *
* library, using hwInit(). The display defaults to *
* GXNtsc480IntDf. Gamma defaults to GX_GM_1_0. *
* Triple buffering is also set up here, with the display turned *
* off as a default. The display will become visible once the *
* first frame has been rendered. This will happen at some point *
* after the end() function is called. *
* *
********************************************************************************/
void NsDisplay::init( void )
{
// GXFifoObj * fifo;
// GXFifoObj * fifoCPUCurrent;
#define FIFO_SIZE (256*1024)
#define FIFO_DRAWDONE_TOKEN 0xBEEF
#define FIFO_DRAWING_TOKEN 0xCACE
Dbg_MsgAssert ( initCount == 0, ( "Display module can only be instanced once.\nThis is the 2nd instance of this class.\n" ) );
initCount++;
hwInit(NULL); // Init the OS, game pad, graphics and video.
// fifo = (GXFifoObj *)OSAlloc( sizeof(GXFifoObj) );
//
// // get the default fifo and free it
// GXSetDrawDone();
// fifoCPUCurrent = GXGetCPUFifo();
//
// // allocate new fifos
// GXInitFifoBase( fifo, OSAlloc(FIFO_SIZE), FIFO_SIZE );
//
// // set the CPU and GP fifo
// GXSetCPUFifo( fifo );
// GXSetGPFifo( fifo );
//
// // set a drawdone token in the fifo
// GXSetDrawSync( FIFO_DRAWDONE_TOKEN );
//
//// // install a callback so we can capture the GP rendering time
//// GXSetDrawDoneCallback( CheckRenderingTime );
//
// // free the default fifo when we set GP fifo to a different fifo
// OSFree( GXGetFifoBase(fifoCPUCurrent) );
GX::SetDispCopyGamma( GX_GM_1_0 );
BPSet = GX_FALSE;
BPWait = GX_FALSE;
BPGo = GX_FALSE;
lastVCBToken = 0;
newToken = 1;
init_queue(&RenderQ);
init_queue(&DoneQ);
OSInitThreadQueue( &waitingDoneRender );
// Creates a new thread. The thread is suspended by default.
OSCreateThread(
&CUThread, // ptr to the thread to init
CleanupThread, // ptr to the start routine
0, // param passed to start routine
CUThreadStack+sizeof(CUThreadStack),// initial stack address
sizeof CUThreadStack,
14, // scheduling priority
OS_THREAD_ATTR_DETACH); // detached by default
// Starts the thread
OSResumeThread(&CUThread);
myXFB1 = hwFrameBuffer1;
myXFB2 = hwFrameBuffer2;
dispXFB = myXFB1;
copyXFB = myXFB2;
(void) VISetPreRetraceCallback(VIPreCallback);
(void) VISetPostRetraceCallback(VIPostCallback);
(void) GX::SetBreakPtCallback(BPCallback);
// The screen won't actually unblank until the first frame has
// been displayed (until VIFlush is called and retrace occurs).
VISetBlack(FALSE);
// This should move to a target/platform module or something...
// OSInitFastCast();
// Set XF Stall bug to on.
// GXSetMisc( GX_MT_XF_FLUSH, GX_XF_FLUSH_SAFE );
// Create & start the background thread.
OSCreateThread(
&s_bg_thread, // ptr to the thread to init
bg_thread_func, // ptr to the start routine
0, // param passed to start routine
s_bg_thread_stack+sizeof(s_bg_thread_stack),// initial stack address
sizeof s_bg_thread_stack,
14, // scheduling priority
OS_THREAD_ATTR_DETACH); // detached by default
OSSetAlarm( &s_bg_alarm, OSMillisecondsToTicks( (long long int)( 1000.0f / 60.0f ) ), bg_alarm_handler );
// OSResumeThread( &s_bg_thread );
}
/********************************************************************************
* *
* Method: *
* begin *
* Inputs: *
* <none> *
* Output: *
* <none> *
* Description: *
* Calls hwBeforeRender, which sets up the viewport, and *
* invalidates the vertex and texture cache. *
* *
********************************************************************************/
void NsDisplay::begin ( void )
{
NsDisplay::doReset();
if ( inDisplayContext == 1 ) return;
hwBeforeRender();
// We must keep latency down while still keeping the FIFO full.
// We allow only two frames to be in the FIFO at once.
// This is a critical section that requires no interrupts to
// happen in between the "if" and the "sleep". The sleep will
// reenable interrupts, allowing one to wake up this thread.
int enabled = OSDisableInterrupts();
if (queue_length(&RenderQ) > 1)
{
OSSleepThread( &waitingDoneRender );
}
OSRestoreInterrupts(enabled);
// Read PAD data.
// PADRead( padData );
inDisplayContext = 1;
}
/********************************************************************************
* *
* Method: *
* end *
* Inputs: *
* <none> *
* Output: *
* <none> *
* Description: *
* Queues up the current display list for rendering. Also swaps *
* the current draw/display XFB. *
* *
********************************************************************************/
void NsDisplay::end ( bool clear )
{
if ( !gLoadingBarActive ) g_need_to_flush = true;
void* tmp_read;
void* tmp_write;
NsDisplay_QItem qitm;
int enabled;
if ( inDisplayContext == 0 ) return;
// //************************************
//
// GX::SetNumTevStages( 1 );
// GX::SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
// GX::SetTevSwapMode( GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0 );
// GX::SetNumTexGens( 0 );
// GX::SetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV );
// GX::SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV );
// GX::SetBlendMode ( GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR );
// GX::SetTevAlphaIn ( GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_RASA );
// GX::SetTevColorIn ( GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC );
// GX::SetChanCtrl( GX_COLOR0A0, GX_ENABLE, GX_SRC_VTX, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE );
// GX::SetChanMatColor( GX_COLOR0A0, (GXColor){255,255,255,255} );
//
// int dc = inDrawingContext;
// inDrawingContext = 1;
// profile_gpu.histogram( 32, 32, 96, 96, (GXColor){0,128,255,255} );
// inDrawingContext = dc;
//
// //************************************
// End of frame code:
GX::Flush();
GX::GetFifoPtrs(GX::GetCPUFifo(), &tmp_read, &tmp_write);
// Create new render queue item
qitm.writePtr = tmp_write;
qitm.dataPtr = NULL; // pointer to frame-related user data
qitm.copyXFB = copyXFB;
// Technically, you can work this such that you don't
// need the OSDisabled interrupts. You need to rework
// the enqueue/dequeue routines a bit, though, to make
// them non-interfere with each other.
enabled = OSDisableInterrupts();
enqueue(&RenderQ, &qitm);
OSRestoreInterrupts(enabled);
if (BPSet == GX_FALSE) {
BPSet = GX_TRUE;
GX::EnableBreakPt( tmp_write );
if ( startCB ) startCB();
// profile_gpu.start();
#ifdef __INFO_REPORT__
GX::ReadGPMetric( &_p0, &_p1 );
#endif // __INFO_REPORT__
#ifdef __INFO_REPORT__
// GXClearPixMetric();
GX::SetGPMetric( (GXPerf0)gp0, (GXPerf1)gp1 );
GX::ClearGPMetric();
#endif // __INFO_REPORT__
}
GX::SetDrawSync( newToken );
//BEGIN SCREENSHOT CODE
// SCREENSHOTService( hwGetCurrentBuffer(), MyAlloc, MyFree );
//END SCREENSHOT CODE
u8 newFilter[7];
newFilter[0] = 8 + ( ( g_blur * 24 ) / 8 );
newFilter[1] = 8 - ( ( g_blur * 8 ) / 8 );
newFilter[2] = 10 - ( ( g_blur * 10 ) / 8 );
newFilter[3] = 12 - ( ( g_blur * 12 ) / 8 );
newFilter[4] = 10 - ( ( g_blur * 10 ) / 8 );
newFilter[5] = 8 - ( ( g_blur * 8 ) / 8 );
newFilter[6] = 8 + ( ( g_blur * 24 ) / 8 );
for ( int i = 0; i < 7; ++i )
{
newFilter[i] = u8( (float)newFilter[i] * NxNgc::EngineGlobals.screen_brightness );
}
GX::SetCopyFilter( rmode->aa, rmode->sample_pattern, GX_TRUE, newFilter );
GX::CopyDisp( copyXFB, ( clear ) ? GX_TRUE : GX_FALSE );
GX::SetCopyFilter( rmode->aa, rmode->sample_pattern, GX_TRUE, rmode->vfilter );
// GXCopyDisp( copyXFB, ( clear ) ? GX_TRUE : GX_FALSE );
// GXCopyDisp( copyXFB, GX_FALSE );
GX::Flush();
#ifdef __INFO_REPORT__
frames++;
sprintf( &g_gp_info0[gp0*64], "%s: %9d", p0_name[gp0], (int)_p0 / frames );
sprintf( &g_gp_info1[gp1*64], "%s: %9d", p1_name[gp1], (int)_p1 / frames );
// if ( ( p0 > 10 ) || ( p1 > 10 ) ) OSReport( "p0/p1: %8d - %8d\n", p0, p1 );
// gp0++;
// gp1++;
// if ( gp0 >= P0_COUNT ) gp0 = 0;
// if ( gp1 >= P1_COUNT ) gp1 = 0;
#endif // __INFO_REPORT__
newToken++;
copyXFB = (copyXFB == myXFB1) ? myXFB2 : myXFB1;
inDisplayContext = 0;
currentBuffer++;
if ( currentBuffer == 2 ) currentBuffer = 0;
}
/********************************************************************************
* *
* Method: *
* setBackgroundColor *
* Inputs: *
* color The rgba color to set the background to. *
* Output: *
* <none> *
* Description: *
* Sets the background color to the specified color. At the *
* beginning of drawing, the screen is cleared to a specific *
* color - it defaults to 0,0,0,0. *
* *
********************************************************************************/
void NsDisplay::setBackgroundColor ( GXColor color )
{
GX::SetCopyClear ( color, 0x00ffffff );
}
/********************************************************************************
* *
* Method: *
* setRenderStartCallback *
* Inputs: *
* pCB The callback to set - NULL means no callback. *
* Output: *
* <none> *
* Description: *
* Sets up the callback to be called when rendering for a frame *
* actually begins - note that when you call NsDisplay::begin or *
* NsDisplay::End bears no relation to when the rendering actually *
* starts or stops. This function is intended to be useful for *
* profiling the performance of the graphics processor. *
* *
********************************************************************************/
void NsDisplay::setRenderStartCallback ( NsDisplay_StartRenderingCallback pCB )
{
startCB = pCB;
}
/********************************************************************************
* *
* Method: *
* setRenderEndCallback *
* Inputs: *
* pCB The callback to set - NULL means no callback. *
* Output: *
* <none> *
* Description: *
* Sets up the callback to be called when rendering for a frame *
* actually ends - note that when you call NsDisplay::begin or *
* NsDisplay::End bears no relation to when the rendering actually *
* starts or stops. This function is intended to be useful for *
* profiling the performance of the graphics processor. *
* *
********************************************************************************/
void NsDisplay::setRenderEndCallback ( NsDisplay_EndRenderingCallback pCB )
{
endCB = pCB;
}
/********************************************************************************
* *
* Method: *
* flush *
* Inputs: *
* <none> *
* Output: *
* <none> *
* Description: *
* Waits for all queued drawing commands to be executed. Use this *
* if you want to make sure that the graphics processor is not *
* reliant upon a piece of memory you want to free up (such as *
* rendering a loading screen texture, then freeing it). *
* *
********************************************************************************/
void NsDisplay::flush ( void )
{
if ( !g_need_to_flush ) return;
g_need_to_flush = false;
for ( int lp = 0; lp < 3; lp++ ) {
// begin();
hwBeforeRender();
// End of frame code:
GX::Flush();
VIWaitForRetrace();
// GXGetFifoPtrs(GXGetCPUFifo(), &tmp_read, &tmp_write);
//
// // Create new render queue item
// qitm.writePtr = tmp_write;
// qitm.dataPtr = NULL; // pointer to frame-related user data
// qitm.copyXFB = copyXFB;
//
// // Technically, you can work this such that you don't
// // need the OSDisabled interrupts. You need to rework
// // the enqueue/dequeue routines a bit, though, to make
// // them non-interfere with each other.
//
// enabled = OSDisableInterrupts();
// enqueue(&RenderQ, &qitm);
// OSRestoreInterrupts(enabled);
//
// if (BPSet == GX_FALSE) {
//
// BPSet = GX_TRUE;
// GXEnableBreakPt( tmp_write );
// }
//
// GXSetDrawSync( newToken );
// GXCopyDisp( copyXFB, ( clear ) ? GX_TRUE : GX_FALSE );
// GXFlush();
//
// newToken++;
// copyXFB = (copyXFB == myXFB1) ? myXFB2 : myXFB1;
}
int enabled = OSDisableInterrupts();
currentBuffer = 0; // Current buffer to use for triple buffering.
BPSet = GX_FALSE;
BPWait = GX_FALSE;
BPGo = GX_FALSE;
lastVCBToken = 0;
newToken = 1;
myXFB1 = hwFrameBuffer1;
myXFB2 = hwFrameBuffer2;
dispXFB = myXFB1;
copyXFB = myXFB2;
init_queue(&RenderQ);
init_queue(&DoneQ);
OSRestoreInterrupts(enabled);
// GXSetDrawDone();
// GXWaitDrawDone();
}
/********************************************************************************
* *
* Method: *
* getCurrentBufferIndex *
* Inputs: *
* <none> *
* Output: *
* <none> *
* Description: *
* Gets the current buffer index used for triple buffering. *
* *
********************************************************************************/
int NsDisplay::getCurrentBufferIndex ( void )
{
return currentBuffer;
}
/********************************************************************************
* *
* Method: *
* shouldReset *
* Inputs: *
* <none> *
* Output: *
* <none> *
* Description: *
* *
* *
********************************************************************************/
bool NsDisplay::shouldReset( void )
{
return ( ( resetDown == 2 ) || NxNgc::EngineGlobals.resetToIPL );
}
/********************************************************************************
* *
* Method: *
* doReset *
* Inputs: *
* <none> *
* Output: *
* <none> *
* Description: *
* *
* *
********************************************************************************/
//static volatile bool flushComplete;
//
//static void flushCallback( void )
//{
// flushComplete = true;
//}
//
//static void _color( GXColor col )
//{
// NsDisplay::setBackgroundColor( col );
//
// for ( int lp = 0; lp < 4; lp++ )
// {
// NsDisplay::begin();
// NsRender::begin();
// NsRender::end();
// NsDisplay::end(true);
// }
//}
#define _color(a,b,c,d)
void NsDisplay::doReset( bool hard_reset, bool forceMenu )
{
// Reset has to be enabled for 4 frames to be recognized.
if ( reset_enabled_frames < 4 )
{
// Count up if reset is not disabled.
if ( !NxNgc::EngineGlobals.disableReset )
{
reset_enabled_frames++;
}
}
// If reset is disabled, the counting starts again at 0.
if ( NxNgc::EngineGlobals.disableReset )
{
reset_enabled_frames = 0;
}
if ( NsDisplay::shouldReset() && !NxNgc::EngineGlobals.disableReset && ( reset_enabled_frames == 4 ) )
{
// NsDisplay::doReset(false, false);
}
else
{
return;
}
_color( (GXColor){128,128,128,255} );
bool reset = false;
bool hard = false;
bool force = false;
// Reset if we pressed the button, but ony if it's not disabled.
if ( NsDisplay::shouldReset() && !NxNgc::EngineGlobals.disableReset )
{
switch ( DVDError() )
{
case DVD_STATE_COVER_OPEN:
case DVD_STATE_NO_DISK:
case DVD_STATE_WRONG_DISK:
// As per lot-check 4.5.
reset = true;
hard = true;
force = false;
// NsDisplay::doReset( true, false );
break;
default:
// NsDisplay::doReset( false, false );
reset = true;
hard = false;
force = false;
break;
}
}
if ( NxNgc::EngineGlobals.resetToIPL )
{
// NsDisplay::doReset( true, true );
reset = true;
hard = true;
force = true;
}
if ( !reset ) return;
hard_reset = hard;
forceMenu = force;
// DTKFlushTracks( flushCallback );
//while( !flushComplete );
_color( (GXColor){128,0,0,255} );
// Recalibrate pads (also stops motor).
PADRecalibrate( PAD_CHAN0_BIT | PAD_CHAN1_BIT | PAD_CHAN2_BIT | PAD_CHAN3_BIT );
_color( (GXColor){0,128,0,255} );
Pcm::PCMAudio_StopMusic( true );
//#ifndef DVDETH
// DTKFlushTracks( NULL );
//#endif // DVDETH
_color( (GXColor){0,0,128,255} );
VISetBlack( TRUE );
VIFlush();
VIWaitForRetrace();
NxNgc::EngineGlobals.use_60hz = false;
// NsDisplay::setBackgroundColor((GXColor){ 0, 0, 0, 0 });
// for( int i = 0; i < 2; ++i )
// {
// NsDisplay::begin();
// NsRender::begin();
// NsRender::end();
// NsDisplay::end();
// }
// NsDisplay::flush();
// Determine whether the correct disc is in the drive - if not we need to do a hot reset.
// bool disk_okay = DVDCheckDisk();
// Shut down audio libs - flush pending ARQ transfers and wait for DMA to finish.
_color( (GXColor){255,0,0,255} );
ARQFlushQueue();
_color( (GXColor){0,255,0,255} );
while( ARGetDMAStatus() != 0 );
_color( (GXColor){0,0,255,255} );
AXQuit();
_color( (GXColor){255,255,0,255} );
AIReset();
_color( (GXColor){0,255,255,255} );
ARQReset();
_color( (GXColor){255,255,255,255} );
ARReset();
_color( (GXColor){255,0,255,255} );
// Perform reset.
if( hard_reset || forceMenu )
{
OSResetSystem( OS_RESET_HOTRESET, 0, forceMenu ? TRUE : FALSE );
return;
}
// if( disk_okay )
// {
OSResetSystem( OS_RESET_RESTART, 0, FALSE );
// }
// else
// {
// OSResetSystem( OS_RESET_HOTRESET, 0, FALSE );
// }
}
/*---------------------------------------------------------------------------*
Breakpoint Interrupt Callback
*---------------------------------------------------------------------------*/
static void BPCallback ( void )
{
// profile_gpu.stop();
NsDisplay_QItem qitm;
qitm = queue_front(&RenderQ);
// Check whether or not the just-finished frame can be
// copied already or if it must wait (due to lack of a
// free XFB). If it must wait, set a flag for the VBlank
// interrupt callback to take care of it.
if (qitm.copyXFB == dispXFB)
{
BPWait = GX_TRUE;
}
else
{
SetNextBreakPt();
}
if ( endCB ) endCB();
}
/*---------------------------------------------------------------------------*
Routine to move breakpoint ahead, deal with finished frames.
*---------------------------------------------------------------------------*/
static void SetNextBreakPt ( void )
{
NsDisplay_QItem qitm;
// Move entry from RenderQ to DoneQ.
qitm = dequeue(&RenderQ);
enqueue(&DoneQ, &qitm);
OSWakeupThread( &waitingDoneRender );
// Move breakpoint to next entry, if any.
if (queue_empty(&RenderQ))
{
GX::DisableBreakPt();
BPSet = GX_FALSE;
// profile_gpu.start();
}
else
{
qitm = queue_front(&RenderQ);
GX::EnableBreakPt( qitm.writePtr );
if ( startCB ) startCB();
}
}
/*---------------------------------------------------------------------------*
VI Pre Callback (VBlank interrupt)
The VI Pre callback should be kept minimal, since the VI registers
must be set before too much time passes. Additional bookkeeping is
done in the VI Post callback.
*---------------------------------------------------------------------------*/
static void VIPreCallback ( u32 retraceCount )
{
// #pragma unused (retraceCount)
u16 token;
// We don't need to worry about missed tokens, since
// the breakpt holds up the tokens, and the logic only
// allows one token out the gate at a time.
token = GX::ReadDrawSync();
// We actually need to use only 1 bit from the sync token.
if (token == (u16) (lastVCBToken+1))
{
lastVCBToken = token;
dispXFB = (dispXFB == myXFB1) ? myXFB2 : myXFB1;
VISetNextFrameBuffer( dispXFB );
VIFlush();
#ifndef DVDETH
// We swapped the frame buffers. Start audio (if not yet active & waiting)
// (we make sure we get at most 2 active channels (even if the file has more channels to offer))
{
static const u32 mask[1] = {0x00000003};
VIDSimpleAudioStartPlayback(mask,1);
}
#endif // DVDETH
BPGo = GX_TRUE;
}
}
/*---------------------------------------------------------------------------*
VI Post Callback (VBlank interrupt)
*---------------------------------------------------------------------------*/
static void VIPostCallback ( u32 retraceCount )
{
// #pragma unused (retraceCount)
if (BPWait && BPGo)
{
SetNextBreakPt();
BPWait = GX_FALSE;
BPGo = GX_FALSE;
}
// Read PAD data.
hwPadRead();
// // Obtain reset button state.
// if( resetDown == 0 )
// {
// if( OSGetResetButtonState())
// {
// // Wait for the button to be released.
// resetDown = 1;
// }
// }
// else
if( resetDown == 1 )
{
if( !OSGetResetButtonState())
{
// The button has been released.
resetDown = 2;
}
}
if( pIconCallback )
{
pIconCallback();
}
// Call the timer vblank callback.
Tmr::IncrementVblankCounters();
OSResumeThread( &s_bg_thread );
// Issue DVD callback.
for ( int lp = 0; lp < 8; lp++ )
{
if ( last_callback_counter[lp] == 0 )
{
last_callback[lp]( last_callback_length[lp], last_callback_fileInfo[lp] );
}
if ( last_callback_counter[lp] >= 0 ) last_callback_counter[lp]--;
}
}
/*---------------------------------------------------------------------------*
Cleanup Thread
*---------------------------------------------------------------------------*/
static void * CleanupThread ( void* param )
{
// #pragma unused (param)
NsDisplay_QItem qitm;
while(1) {
OSSleepThread( &waitingDoneRender );
qitm = dequeue(&DoneQ);
// Take qitm.dataPtr and do any necessary cleanup.
// That is, free up any data that only needed to be
// around for the GP to read while rendering the frame.
}
}
/*---------------------------------------------------------------------------*
* Quick and dirty queue implementation.
*---------------------------------------------------------------------------*/
static void init_queue(NsDisplay_Queue *q)
{
q->top = QUEUE_EMPTY;
}
static void enqueue(NsDisplay_Queue *q, NsDisplay_QItem *qitm)
{
if (q->top == QUEUE_EMPTY)
{
q->top = q->bot = 0;
}
else
{
q->top = (u16) ((q->top+1) % QUEUE_MAX);
Dbg_MsgAssert ( q->top != q->bot, ( "queue overflow" ) );
}
q->entry[q->top] = *qitm;
}
static NsDisplay_QItem dequeue(NsDisplay_Queue *q)
{
u16 bot = q->bot;
Dbg_MsgAssert ( q->top != QUEUE_EMPTY, ( "queue underflow" ) );
if (q->bot == q->top)
{
q->top = QUEUE_EMPTY;
}
else
{
q->bot = (u16) ((q->bot+1) % QUEUE_MAX);
}
return q->entry[bot];
}
static NsDisplay_QItem queue_front(NsDisplay_Queue *q)
{
Dbg_MsgAssert ( q->top != QUEUE_EMPTY, ( "queue empty" ) );
return q->entry[q->bot];
}
static GXBool queue_empty(NsDisplay_Queue *q)
{
return q->top == QUEUE_EMPTY;
}
static u32 queue_length(NsDisplay_Queue *q)
{
if (q->top == QUEUE_EMPTY) return 0;
if (q->top > q->bot)
return (u32) ((s32) q->top - q->bot + 1);
else
return (u32) ((s32) (q->top + QUEUE_MAX) - q->bot + 1);
}
static void * bg_thread_func ( void* param )
{
// int count = 0;
// int tick = 0;
// bool waiting_for_reset = false;
while( 1 )
{
////
//// if ( NsDisplay::shouldReset() && !waiting_for_reset ) {
//// if ( ( NsDisplay::shouldReset() && NxNgc::EngineGlobals.disableReset ) || ( DVDError() && Script::GetInteger( "allow_dvd_errors" ) ) && !NxNgc::EngineGlobals.gpuBusy ) {
// if ( ( DVDError() && Script::GetInteger( "allow_dvd_errors" ) ) && !NxNgc::EngineGlobals.gpuBusy ) {
// //OSReport( "We have to reset now.\n" );
// waiting_for_reset = true;
//
// NxNgc::EngineGlobals.screen_brightness = 1.0f;
//
// // Render the text.
// NsDisplay::begin();
// NsRender::begin();
//// GX::SetCullMode ( GX_CULL_NONE );
//
// NsCamera cam;
// cam.orthographic( 0, 0, 640, 448 );
//
// // Draw the screen.
// NsPrim::begin();
//
// cam.begin();
//
// GX::SetZMode( GX_FALSE, GX_ALWAYS, GX_TRUE );
//
// NxNgc::set_blend_mode( NxNgc::vBLEND_MODE_ADD );
//
//// if ( NsDisplay::shouldReset() )
//// {
//// // Reset message.
//// Script::RunScript( "ngc_reset" );
//// }
//// else
// {
// // DVD Error message.
// switch ( DVDError() )
// {
// case DVD_STATE_FATAL_ERROR:
// case DVD_STATE_RETRY:
// Script::RunScript( "ngc_dvd_fatal" );
// break;
// case DVD_STATE_COVER_OPEN:
// Script::RunScript( "ngc_dvd_cover_open" );
// break;
// case DVD_STATE_NO_DISK:
// Script::RunScript( "ngc_dvd_no_disk" );
// break;
// case DVD_STATE_WRONG_DISK:
// Script::RunScript( "ngc_dvd_wrong_disk" );
// break;
// default:
// Script::RunScript( "ngc_dvd_unknown" );
// break;
// }
// }
//
// NsDisplay::setBackgroundColor( messageColor );
//
// cam.end();
//
// NsPrim::end();
//
// NsRender::end();
// NsDisplay::end( false );
//
// // Notes:
// // Parameters to set in script:
// //
// // reset_font = "testtitle"
// // reset_text = "RESET"
// // reset_text_col = 255,255,255,255
// // reset_bg_col = 255,0,32,255
// }
if ( !NsDisplay::shouldReset() && !DVDError() ) gLoadBarNumFrames++;
if ( gLoadingBarActive && !NxNgc::EngineGlobals.gpuBusy && !NsDisplay::shouldReset() )
{
NsDisplay::begin();
NsRender::begin();
NsPrim::begin();
NsCamera camera2D;
camera2D.orthographic( 0, 0, 640, 448 );
camera2D.begin();
int cur_width = (gLoadBarWidth - 1);
if (gLoadBarNumFrames < gLoadBarTotalFrames)
{
cur_width = (cur_width * gLoadBarNumFrames) / gLoadBarTotalFrames;
}
int x1 = gLoadBarX;
int y1 = gLoadBarY;
int x2 = x1 + cur_width;
int y2 = y1 + (gLoadBarHeight - 1);
int end_color[4];
if (gLoadBarNumFrames < gLoadBarTotalFrames)
{
end_color[0] = gLoadBarStartColor[0] + ((gLoadBarDeltaColor[0] * gLoadBarNumFrames) / gLoadBarTotalFrames);
end_color[1] = gLoadBarStartColor[1] + ((gLoadBarDeltaColor[1] * gLoadBarNumFrames) / gLoadBarTotalFrames);
end_color[2] = gLoadBarStartColor[2] + ((gLoadBarDeltaColor[2] * gLoadBarNumFrames) / gLoadBarTotalFrames);
end_color[3] = gLoadBarStartColor[3] + ((gLoadBarDeltaColor[3] * gLoadBarNumFrames) / gLoadBarTotalFrames);
} else {
end_color[0] = gLoadBarStartColor[0] + gLoadBarDeltaColor[0];
end_color[1] = gLoadBarStartColor[1] + gLoadBarDeltaColor[1];
end_color[2] = gLoadBarStartColor[2] + gLoadBarDeltaColor[2];
end_color[3] = gLoadBarStartColor[3] + gLoadBarDeltaColor[3];
}
int border_x1 = x1 - gLoadBarBorderWidth;
int border_y1 = y1 - gLoadBarBorderHeight;
int border_x2 = x1 + (gLoadBarWidth - 1) + gLoadBarBorderWidth;
int border_y2 = y2 + gLoadBarBorderHeight;
u32 bc = gLoadBarBorderColor[3]|(gLoadBarBorderColor[2]<<8)|(gLoadBarBorderColor[1]<<16)|(gLoadBarBorderColor[0]<<24);
u32 sc = gLoadBarStartColor[3]|(gLoadBarStartColor[2]<<8)|(gLoadBarStartColor[1]<<16)|(gLoadBarStartColor[0]<<24);
u32 ec = end_color[3]|(end_color[2]<<8)|(end_color[1]<<16)|(end_color[0]<<24);
GX::SetZMode( GX_FALSE, GX_ALWAYS, GX_FALSE );
GX::SetCurrMtxPosTex03( GX_PNMTX0, GX_IDENTITY, GX_IDENTITY, GX_IDENTITY, GX_IDENTITY );
GX::SetTevAlphaInOpSwap( GX_TEVSTAGE0, GX_CA_RASA, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO,
GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_2, GX_ENABLE, GX_TEVPREV,
GX_TEV_SWAP0, GX_TEV_SWAP0 );
GX::SetTevColorInOp( GX_TEVSTAGE0, GX_CC_RASC, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO,
GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_2, GX_ENABLE, GX_TEVPREV );
GX::SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
GX::SetTexChanTevIndCull( 0, 1, 1, 0, GX_CULL_NONE );
GX::SetAlphaCompare(GX_GREATER, 0, GX_AOP_AND, GX_GREATER, 0 );
GX::SetBlendMode( GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_FALSE );
// Set current vertex descriptor to enable position and color0.
// Both use 8b index to access their data arrays.
GX::SetVtxDesc( 2, GX_VA_POS, GX_DIRECT, GX_VA_CLR0, GX_DIRECT );
// Set material color.
GX::SetChanMatColor( GX_COLOR0A0, (GXColor){255,255,255,255} );
GX::SetChanCtrl( GX_COLOR0A0, GX_ENABLE, GX_SRC_VTX, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE );
// Border
GX::Begin( GX_QUADS, GX_VTXFMT0, 4 );
GX::Position3f32( border_x1, border_y1, -1.0f );
GX::Color1u32( bc );
GX::Position3f32( border_x1, border_y2, -1.0f );
GX::Color1u32( bc );
GX::Position3f32( border_x2, border_y2, -1.0f );
GX::Color1u32( bc );
GX::Position3f32( border_x2, border_y1, -1.0f );
GX::Color1u32( bc );
GX::End();
// Bar
GX::Begin( GX_QUADS, GX_VTXFMT0, 4 );
GX::Position3f32( x1, y1, -1.0f );
GX::Color1u32( sc );
GX::Position3f32( x1, y2, -1.0f );
GX::Color1u32( sc );
GX::Position3f32( x2, y2, -1.0f );
GX::Color1u32( ec );
GX::Position3f32( x2, y1, -1.0f );
GX::Color1u32( ec );
GX::End();
camera2D.end();
NsPrim::end();
NsRender::end();
NsDisplay::end( false );
// current_image = ( current_image + 1 ) % p_data->m_NumFrames ;
}
// Vsync callback will resume it.
OSSuspendThread( &s_bg_thread );
}
}
static void bg_alarm_handler( OSAlarm* alarm, OSContext* context )
{
// Check the thread has not been resumed yet...
if( OSIsThreadSuspended( &s_bg_thread ))
{
OSResumeThread( &s_bg_thread );
}
}
void display_legal( void )
{
NsDisplay::flush();
int frames;
if ( !g_legal )
{
frames = 10;
}
else
{
frames = 2;
}
for ( int lp = 0; lp < frames; lp++ )
{
if ( g_legal )
{
NxNgc::EngineGlobals.screen_brightness = 1.0f;
}
else
{
NxNgc::EngineGlobals.screen_brightness = ( 1.0f * (float)lp ) / (float)frames;
}
// Render the text.
NsDisplay::begin();
NsRender::begin();
NsCamera cam;
cam.orthographic( 0, 0, 640, 448 );
// Draw the screen.
NsPrim::begin();
cam.begin();
GX::SetZMode( GX_FALSE, GX_ALWAYS, GX_FALSE );
NxNgc::set_blend_mode( NxNgc::vBLEND_MODE_BLEND );
Script::RunScript( "ngc_license" );
NsDisplay::setBackgroundColor( messageColor );
cam.end();
NsPrim::end();
NsRender::end();
NsDisplay::end( true );
}
}
namespace Nx
{
bool ScriptNgc_BGColor(Script::CScriptStructure *pParams, Script::CScript *pScript)
{
int r = messageColor.r;
int g = messageColor.g;
int b = messageColor.b;
int a = messageColor.a;
pParams->GetInteger("r",&r);
pParams->GetInteger("g",&g);
pParams->GetInteger("b",&b);
pParams->GetInteger("a",&a);
messageColor.r = r;
messageColor.g = g;
messageColor.b = b;
messageColor.a = a;
return true;
}
bool ScriptNgc_Message(Script::CScriptStructure *pParams, Script::CScript *pScript)
{
NxNgc::SText message;
Nx::CFont * p_cfont;
const char * p_font_name = NULL;
const char * p_text = NULL;
if ( !pParams->GetString( "font", &p_font_name ) ) return false;
if ( !pParams->GetString( "text", &p_text ) ) return false;
float y = lasty;
pParams->GetFloat( "y", &y );
// We can only draw a text string if we have a font & a string.
if ( p_font_name && p_text )
{
p_cfont = Nx::CFontManager::sGetFont( p_font_name );
if ( !p_cfont )
{
Nx::CFontManager::sLoadFont( p_font_name );
p_cfont = Nx::CFontManager::sGetFont( p_font_name );
if ( !p_cfont ) return true;
}
message.mp_string = (char *)p_text;
int sr = 128;
int sg = 128;
int sb = 128;
int sa = 255;
pParams->GetInteger( "r", &sr );
pParams->GetInteger( "g", &sg );
pParams->GetInteger( "b", &sb );
pParams->GetInteger( "a", &sa );
message.m_rgba = sa | ( sb << 8 ) | ( sg << 16 ) | ( sr << 24 );
Nx::CNgcFont * p_nfont = static_cast<Nx::CNgcFont*>( p_cfont );
NxNgc::SFont * p_font = p_nfont->GetEngineFont();
message.mp_font = p_font;
float w, h;
if ( p_font )
{
float x = 0.0f;
message.m_ypos = y;
float scale = 1.0f;
pParams->GetFloat( "scale", &scale );
message.m_xscale = scale;
message.m_yscale = scale;
message.m_color_override = false;
p_font->QueryString( message.mp_string, w, h );
if ( pParams->GetFloat( "x", &x ) )
{
message.m_xpos = x;
}
else
{
message.m_xpos = ( 640.0f - ( w * scale ) ) / 2.0f;
}
float appendx = 0.0f;
float appendy = 0.0f;
bool append = false;
if ( pParams->GetFloat( "appendx", &appendx ) || pParams->GetFloat( "appendy", &appendy ) )
{
append = true;
pParams->GetFloat( "appendx", &appendx );
pParams->GetFloat( "appendy", &appendy );
message.m_xpos = prevx + appendx;
message.m_ypos = prevy + appendy;
}
message.DrawSingle();
prevx = message.m_xpos + ( w * scale );
prevy = y;
if ( !append )
{
lasty = y + (float)((int)( h * scale ));
}
}
}
return true;
}
bool ScriptNgc_Menu(Script::CScriptStructure *pParams, Script::CScript *pScript)
{
NxNgc::SText message;
Nx::CFont * p_cfont;
const char * p_font_name = NULL;
int items = 0;
const char * p_item;
char buf[32];
int sr = 128;
int sg = 128;
int sb = 128;
int sa = 255;
int ur = 128;
int ug = 128;
int ub = 128;
int ua = 255;
pParams->GetString( "font", &p_font_name );
pParams->GetInteger( "items", &items );
pParams->GetInteger( "sr", &sr );
pParams->GetInteger( "sg", &sg );
pParams->GetInteger( "sb", &sb );
pParams->GetInteger( "sa", &sa );
pParams->GetInteger( "ur", &ur );
pParams->GetInteger( "ug", &ug );
pParams->GetInteger( "ub", &ub );
pParams->GetInteger( "ua", &ua );
// We can only draw a text string if we have a font & a string.
if ( p_font_name && items )
{
Nx::CFontManager::sLoadFont( p_font_name );
p_cfont = Nx::CFontManager::sGetFont( p_font_name );
for ( int lp = 0; lp < items; lp++ )
{
p_item = NULL;
sprintf( buf, "item%d", lp );
pParams->GetString( buf, &p_item );
if ( p_item )
{
message.mp_string = (char *)p_item;
float scale = 1.0f;
pParams->GetFloat( "scale", &scale );
if ( lp == selection )
{
message.m_rgba = sa | ( sb << 8 ) | ( sg << 16 ) | ( sr << 24 );
}
else
{
message.m_rgba = ua | ( ub << 8 ) | ( ug << 16 ) | ( ur << 24 );
}
Nx::CNgcFont * p_nfont = static_cast<Nx::CNgcFont*>( p_cfont );
NxNgc::SFont * p_font = p_nfont->GetEngineFont();
message.mp_font = p_font;
float w, h;
p_font->QueryString( message.mp_string, w, h );
message.m_xpos = ( 640.0f - ( w * scale ) ) / 2.0f;
message.m_ypos = lasty;
message.m_xscale = scale;
message.m_yscale = scale;
message.m_color_override = false;
message.DrawSingle();
lasty += (float)((int)( h * scale ));
}
}
}
selection_max = items;
return true;
}
bool ScriptNgc_Set480P(Script::CScriptStructure *pParams, Script::CScript *pScript)
{
OSSetProgressiveMode(1);
NxNgc::EngineGlobals.use_480p = true;
hwReInit( NULL );
// Must display screen saying that progressive mode has been set.
for ( int lp = 0; lp < 240; lp++ )
{
// Render the text.
NsDisplay::begin();
NsRender::begin();
NsCamera cam;
cam.orthographic( 0, 0, 640, 448 );
// Draw the screen.
NsPrim::begin();
cam.begin();
GX::SetZMode( GX_FALSE, GX_ALWAYS, GX_TRUE );
NxNgc::set_blend_mode( NxNgc::vBLEND_MODE_BLEND );
if ( lp > 60 ) Script::RunScript( "ngc_progressive" );
NsDisplay::setBackgroundColor( messageColor );
cam.end();
NsPrim::end();
NsRender::end();
NsDisplay::end( true );
}
return true;
}
bool ScriptNgc_Set480I(Script::CScriptStructure *pParams, Script::CScript *pScript)
{
// Already in 480I to display menu. Just set the SRAM bit.
OSSetProgressiveMode(0);
return true;
}
bool ScriptNgc_Set60Hz(Script::CScriptStructure *pParams, Script::CScript *pScript)
{
OSSetEuRgb60Mode(1);
NxNgc::EngineGlobals.use_60hz = true;
hwReInit( NULL );
hwGXInit();
VIConfigure(rmode);
Config::gFPS = 60;
// Must display screen saying that 60hz mode has been set.
for ( int lp = 0; lp < 240; lp++ )
{
// Render the text.
NsDisplay::begin();
NsRender::begin();
NsCamera cam;
cam.orthographic( 0, 0, 640, 448 );
// Draw the screen.
NsPrim::begin();
cam.begin();
GX::SetZMode( GX_FALSE, GX_ALWAYS, GX_TRUE );
NxNgc::set_blend_mode( NxNgc::vBLEND_MODE_BLEND );
if ( lp > 60 ) Script::RunScript( "ngc_60Hz" );
NsDisplay::setBackgroundColor( messageColor );
cam.end();
NsPrim::end();
NsRender::end();
NsDisplay::end( true );
}
return true;
}
bool ScriptNgc_Set50Hz(Script::CScriptStructure *pParams, Script::CScript *pScript)
{
OSSetEuRgb60Mode(0);
NxNgc::EngineGlobals.use_60hz = false;
Config::gFPS = 50;
// Must display screen saying that 50hz mode has been set.
for ( int lp = 0; lp < 240; lp++ )
{
// Render the text.
NsDisplay::begin();
NsRender::begin();
NsCamera cam;
cam.orthographic( 0, 0, 640, 448 );
// Draw the screen.
NsPrim::begin();
cam.begin();
GX::SetZMode( GX_FALSE, GX_ALWAYS, GX_TRUE );
NxNgc::set_blend_mode( NxNgc::vBLEND_MODE_BLEND );
if ( lp > 60 ) Script::RunScript( "ngc_50Hz" );
NsDisplay::setBackgroundColor( messageColor );
cam.end();
NsPrim::end();
NsRender::end();
NsDisplay::end( true );
}
return true;
}
bool ScriptNgc_SetWide(Script::CScriptStructure *pParams, Script::CScript *pScript)
{
NxNgc::EngineGlobals.use_widescreen = true;
return true;
}
bool ScriptNgc_SetStandard(Script::CScriptStructure *pParams, Script::CScript *pScript)
{
NxNgc::EngineGlobals.use_widescreen = false;
return true;
}
bool ScriptNgc_ReduceColors(Script::CScriptStructure *pParams, Script::CScript *pScript)
{
bool truth;
if ( pParams->GetInteger( NONAME, (int*)&truth ) )
{
NxNgc::EngineGlobals.reduceColors = truth;
}
return true;
}
}