thug/Code/Gfx/XBox/p_NxLoadScreen.cpp

417 lines
14 KiB
C++
Raw Normal View History

2016-02-13 21:39:12 +00:00
/////////////////////////////////////////////////////////////////////////////
// p_NxLoadScreen.cpp - Xbox platform specific interface for the load screen
//
//
#include "gfx\Nx.h"
#include "gfx\NxLoadScreen.h"
#include "gfx\xbox\p_NxTexture.h"
#include "gfx\xbox\p_NxSprite.h"
#include "gfx\xbox\NX\sprite.h"
#include "gfx\xbox\NX\scene.h"
#include "gfx\xbox\NX\render.h"
#include "sys\config\config.h"
#include "core\macros.h"
namespace Nx
{
Nx::CXboxTexture *sp_load_screen_texture;
Nx::CXboxSprite *sp_load_screen_sprite;
static float loadingBarTotalSeconds;
static float loadingBarCurrentSeconds;
static float loadingBarDeltaSeconds;
static int loadingBarStartColor[3]; // r,g,b
static int loadingBarEndColor[3]; // r,g,b
static uint32 loadingBarColors[1280][3]; // r,g,b
static bool loadingBarColorsSet = false;
static int loadingBarWidth;
static uint32 loadingBarBorderColor;
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// Functions
#define USE_SPRITES 0
/******************************************************************/
/* */
/* */
/******************************************************************/
void CALLBACK loadingBarTimerCallback( UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2 )
{
if( NxXbox::EngineGlobals.loadingbar_timer_event != 0 )
{
loadingBarCurrentSeconds += loadingBarDeltaSeconds;
float mult = loadingBarCurrentSeconds / loadingBarTotalSeconds;
mult = ( mult > 1.0f ) ? 1.0f : mult;
int bar_width = (int)( loadingBarWidth * mult );
// Get pointer to front buffer memory.
IDirect3DSurface8 *p_buffer;
D3DLOCKED_RECT locked_rect;
NxXbox::EngineGlobals.p_Device->GetBackBuffer( -1, D3DBACKBUFFER_TYPE_MONO, &p_buffer );
p_buffer->LockRect( &locked_rect, NULL, D3DLOCK_TILED );
uint32 *p_screen = (uint32*)locked_rect.pBits;
// ----------------------------------
// | |||||||||||||||||||||| |
// ----------------------------------
// ^ ^ ^ ^
// a b c d
//
// a = surround start
// b = bar start
// c = bar end
// d = surround end
int bar_start = ( 640 - loadingBarWidth ) / 2;
int surround_start = bar_start - 5;
int bar_end = bar_start + bar_width;
int surround_end = surround_start + loadingBarWidth + 10;
const int HDTV_OFFSET = 48;
bar_start = (int)SCREEN_CONV_X( bar_start );
surround_start = (int)SCREEN_CONV_X( surround_start );
bar_end = (int)SCREEN_CONV_X( bar_end );
surround_end = (int)SCREEN_CONV_X( surround_end );
if( NxXbox::EngineGlobals.backbuffer_width > 640 )
{
bar_start += HDTV_OFFSET;
surround_start += HDTV_OFFSET;
bar_end += HDTV_OFFSET;
surround_end += HDTV_OFFSET;
}
int base_y = (int)SCREEN_CONV_Y( 410 );
for( int i = 0; i < 20; ++i )
{
uint32 *p_loop = p_screen + (( base_y + i ) * NxXbox::EngineGlobals.backbuffer_width );
if(( i < 5 ) || ( i >= 15 ))
{
for( int j = surround_start; j < surround_end; ++j )
p_loop[j] = loadingBarBorderColor;
}
else
{
for( int j = surround_start; j < ( surround_start + 5 ); ++j )
p_loop[j] = loadingBarBorderColor;
for( int j = bar_end; j < surround_end; ++j )
p_loop[j] = loadingBarBorderColor;
for( int j = bar_start; j < bar_end; ++j )
{
uint32 idx = ( j - bar_start >= 1279 ) ? 1279 : ( j - bar_start );
uint32 write_value = 0x80000000UL | ( loadingBarColors[idx][0] << 16 ) | ( loadingBarColors[idx][1] << 8 ) | ( loadingBarColors[idx][2] << 0 );
p_loop[j] = write_value;
}
}
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static bool is_power_of_two( uint32 a )
{
if( a == 0 )
{
return false;
}
return (( a & ( a - 1 )) == 0 );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CLoadScreen::s_plat_display(const char* filename, bool just_freeze, bool blank)
{
// Wait for asyncronous rendering to finish.
NxXbox::EngineGlobals.p_Device->BlockUntilIdle();
if( !just_freeze )
{
if( blank )
{
D3DDevice_Clear( 0, NULL, D3DCLEAR_TARGET, 0x00000000UL, 1.0f, 0 );
D3DDevice_Swap( D3DSWAP_DEFAULT );
}
else
{
// Engine stuff
Dbg_Assert(!sp_load_screen_texture);
Dbg_Assert(!sp_load_screen_sprite);
sp_load_screen_texture = new CXboxTexture();
# ifdef __PAL_BUILD__
switch( Config::GetLanguage())
{
case Config::LANGUAGE_FRENCH:
{
char t_filename[200];
sprintf( t_filename, "PALImages/FRImages/%s", filename );
if( !sp_load_screen_texture->LoadTexture( t_filename, true ))
{
Dbg_Error( "Can't load texture %s", t_filename );
return;
}
break;
}
case Config::LANGUAGE_GERMAN:
{
char t_filename[200];
sprintf( t_filename, "PALImages/GRImages/%s", filename );
if( !sp_load_screen_texture->LoadTexture( t_filename, true ))
{
Dbg_Error( "Can't load texture %s", t_filename );
return;
}
break;
}
default:
{
if( !sp_load_screen_texture->LoadTexture( filename, true ))
{
Dbg_Error( "Can't load texture %s", filename );
return;
}
break;
}
}
# else
if( !sp_load_screen_texture->LoadTexture( filename, true ))
{
Dbg_Error( "Can't load texture %s", filename );
return;
}
# endif // __PAL_BUILD__
// Copy into frame buffer.
float x_offset = 0.0f;
float y_offset = 0.0f;
float x_scale = 1.0f;
float y_scale = 1.0f;
float alpha_level = 1.0f;
D3DDevice_SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
D3DDevice_SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
D3DDevice_SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
D3DDevice_SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
// Store the stage zero minfilter, since it may be anisotropic.
DWORD stage_zero_minfilter;
D3DDevice_GetTextureStageState( 0, D3DTSS_MINFILTER, &stage_zero_minfilter );
// Turn on texture filtering when scaling...
D3DDevice_SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
D3DDevice_SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
// Turn on clamping so that the linear textures work
NxXbox::set_render_state( RS_UVADDRESSMODE0, 0x00010001UL );
D3DDevice_SetRenderState( D3DRS_LIGHTING, FALSE );
// Use a default vertex shader
NxXbox::set_pixel_shader( 0 );
NxXbox::set_vertex_shader( D3DFVF_XYZRHW | D3DFVF_TEX1 );
NxXbox::set_blend_mode( NxXbox::vBLEND_MODE_DIFFUSE );
// Select the texture (flush first, since the screen texture is linear).
NxXbox::set_texture( 0, NULL );
NxXbox::set_texture( 0, sp_load_screen_texture->GetEngineTexture()->pD3DTexture, sp_load_screen_texture->GetEngineTexture()->pD3DPalette );
// Setup up the vertices.
typedef struct
{
float sx,sy,sz;
float rhw;
float tu,tv;
}
LOADSCREEN_VERT;
// Get the width height from the texture itself, since we may be using a texture not designed especially
// for this screen dimension.
float tex_w = (float)sp_load_screen_texture->GetEngineTexture()->ActualWidth;
float tex_h = (float)sp_load_screen_texture->GetEngineTexture()->ActualHeight;
float scr_w = (float)NxXbox::EngineGlobals.backbuffer_width;
float scr_h = (float)NxXbox::EngineGlobals.backbuffer_height;
LOADSCREEN_VERT vertices[4];
// The texture coordinate addressing will differ depending on whether this is a linear texture or not.
if( is_power_of_two( sp_load_screen_texture->GetEngineTexture()->ActualWidth ) &&
is_power_of_two( sp_load_screen_texture->GetEngineTexture()->ActualHeight ))
{
// Not a linear texture, will be swizzled, max uv is (1.0, 1.0).
vertices[0].sx = x_offset;
vertices[0].sy = y_offset;
vertices[0].sz = 0.0f;
vertices[0].rhw = 0.0f;
vertices[0].tu = 0.0f;
vertices[0].tv = 1.0f;
vertices[1] = vertices[0];
vertices[1].sy = y_offset + ( scr_h * y_scale );
vertices[1].tv = 0.0f;
vertices[2] = vertices[0];
vertices[2].sx = x_offset + ( scr_w * x_scale );
vertices[2].tu = 1.0f;
vertices[3] = vertices[2];
vertices[3].sy = vertices[1].sy;
vertices[3].tv = 0.0f;
}
else
{
// Linear texture, won't be swizzled, max uv is (tex_w, tex_h).
vertices[0].sx = x_offset;
vertices[0].sy = y_offset;
vertices[0].sz = 0.0f;
vertices[0].rhw = 0.0f;
vertices[0].tu = -0.5f;
vertices[0].tv = tex_h - 0.5f;
vertices[1] = vertices[0];
vertices[1].sy = y_offset + ( scr_h * y_scale );
vertices[1].tv = -0.5f;
vertices[2] = vertices[0];
vertices[2].sx = x_offset + ( scr_w * x_scale );
vertices[2].tu = tex_w - 0.5f;
vertices[3] = vertices[2];
vertices[3].sy = vertices[1].sy;
vertices[3].tv = -0.5f;
}
// Draw the vertices, and make sure they're displayed.
D3DDevice_DrawVerticesUP( D3DPT_TRIANGLESTRIP, 4, vertices, sizeof( LOADSCREEN_VERT ));
D3DDevice_Swap( D3DSWAP_DEFAULT );
// Done with texture
delete sp_load_screen_texture;
sp_load_screen_texture = NULL;
// Reflush linear texture out.
NxXbox::set_texture( 0, NULL );
// Restore the stage zero minfilter.
D3DDevice_SetTextureStageState( 0, D3DTSS_MINFILTER, stage_zero_minfilter );
}
}
// Indicate that the loading screen is visible, to stop any more rendering until it is hidden.
NxXbox::EngineGlobals.loadingscreen_visible = true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CLoadScreen::s_plat_hide()
{
// Remove the loading bar.
if( NxXbox::EngineGlobals.loadingbar_timer_event != 0 )
{
timeKillEvent( NxXbox::EngineGlobals.loadingbar_timer_event );
NxXbox::EngineGlobals.loadingbar_timer_event = 0;
}
// Indicate that the loading screen is no longer visible.
NxXbox::EngineGlobals.loadingscreen_visible = false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CLoadScreen::s_plat_clear()
{
if( sp_load_screen_sprite )
{
CEngine::sDestroySprite(sp_load_screen_sprite);
sp_load_screen_sprite = NULL;
}
if( sp_load_screen_texture )
{
delete sp_load_screen_texture;
sp_load_screen_texture = NULL;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CLoadScreen::s_plat_start_loading_bar( float seconds )
{
loadingBarTotalSeconds = seconds * 0.6f;
loadingBarCurrentSeconds = 0.0f;
loadingBarDeltaSeconds = 0.03f; // 30 milliseconds.
s_plat_update_bar_properties();
// Set up the timer event.
if( NxXbox::EngineGlobals.loadingbar_timer_event == 0 )
{
NxXbox::EngineGlobals.loadingbar_timer_event = timeSetEvent( (uint32)( loadingBarDeltaSeconds * 1000.0f ), // Delay (ms).
0, // Ignored resolution (ms).
loadingBarTimerCallback, // Callback function.
0, // Callback data.
TIME_PERIODIC | TIME_CALLBACK_FUNCTION );
Dbg_Assert( NxXbox::EngineGlobals.loadingbar_timer_event != 0 );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CLoadScreen::s_plat_update_bar_properties( void )
{
loadingBarStartColor[0] = s_bar_start_color.r;
loadingBarStartColor[1] = s_bar_start_color.g;
loadingBarStartColor[2] = s_bar_start_color.b;
loadingBarEndColor[0] = s_bar_end_color.r;
loadingBarEndColor[1] = s_bar_end_color.g;
loadingBarEndColor[2] = s_bar_end_color.b;
loadingBarWidth = s_bar_width;
loadingBarBorderColor = 0x80000000 | ((uint32)s_bar_border_color.r << 16 ) | ((uint32)s_bar_border_color.g << 8 ) | (uint32)s_bar_border_color.b;
// Build the interpolated color array.
int last_color = (int)( loadingBarWidth * NxXbox::EngineGlobals.screen_conv_x_multiplier );
for( int i = 0; i < last_color; ++i )
{
for( int c = 0; c < 3; ++c )
{
loadingBarColors[i][c] = loadingBarStartColor[c] + ((( loadingBarEndColor[c] - loadingBarStartColor[c] ) * i ) / last_color );
}
}
}
}