thug/Code/Gfx/XBox/NX/sprite.cpp

498 lines
13 KiB
C++
Raw Permalink Normal View History

2016-02-13 21:39:12 +00:00
#include <string.h>
#include <core/defines.h>
#include <core/macros.h>
#include <core/debug.h>
#include <sys/config/config.h>
#include <sys/file/filesys.h>
#include "nx_init.h"
#include "scene.h"
#include "render.h"
#include "sprite.h"
extern DWORD PixelShader4;
extern DWORD PixelShader5;
namespace NxXbox
{
/******************************************************************/
/* */
/* SDraw2D */
/* */
/******************************************************************/
SDraw2D *SDraw2D::sp_2D_draw_list = NULL;
/******************************************************************/
/* */
/* */
/******************************************************************/
SDraw2D::SDraw2D( float pri, bool hide )
{
m_hidden = hide;
m_pri = pri;
m_zvalue = 0.0f;
mp_next = NULL;
// add to draw list
if( !m_hidden )
{
InsertDrawList();
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
SDraw2D::~SDraw2D()
{
// Try removing from draw list
RemoveDrawList();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void SDraw2D::SetPriority( float pri )
{
if( m_pri != pri )
{
m_pri = pri;
// By removing and re-inserting, we re-sort the list
if( !m_hidden )
{
RemoveDrawList();
InsertDrawList();
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void SDraw2D::SetZValue( float z )
{
m_zvalue = z;
if( z > 0.0f )
{
// Set the priority to zero so it will always draw before everything else.
SetPriority( 0.0f );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void SDraw2D::SetHidden( bool hide )
{
if (m_hidden != hide)
{
m_hidden = hide;
if (hide)
{
RemoveDrawList();
} else {
InsertDrawList();
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void SDraw2D::DrawAll( void )
{
static uint32 z_test_required = 0;
set_blend_mode( vBLEND_MODE_BLEND );
set_render_state( RS_UVADDRESSMODE0, 0x00010001UL );
set_render_state( RS_ZBIAS, 0 );
// Set the alpha cutoff value.
set_render_state( RS_ALPHACUTOFF, 1 );
set_render_state( RS_ZWRITEENABLE, 0 );
set_texture( 1, NULL );
set_texture( 2, NULL );
set_texture( 3, NULL );
if( EngineGlobals.color_sign[0] != ( D3DTSIGN_RUNSIGNED | D3DTSIGN_GUNSIGNED | D3DTSIGN_BUNSIGNED ))
{
EngineGlobals.color_sign[0] = ( D3DTSIGN_RUNSIGNED | D3DTSIGN_GUNSIGNED | D3DTSIGN_BUNSIGNED );
D3DDevice_SetTextureStageState( 0, D3DTSS_COLORSIGN, D3DTSIGN_RUNSIGNED | D3DTSIGN_GUNSIGNED | D3DTSIGN_BUNSIGNED );
}
// Unfortunately, now that we have 3D text, we may need to enable the z test for some strings.
set_render_state( RS_ZTESTENABLE, z_test_required );
SDraw2D *pDraw = sp_2D_draw_list;
uint32 z_test = 0;
while( pDraw )
{
if (!pDraw->m_hidden)
{
pDraw->BeginDraw();
pDraw->Draw();
pDraw->EndDraw();
if(( z_test == 0 ) && ( pDraw->GetZValue() > 0.0f ))
{
// There is at least one peice of text with nonzero z, so we need to z test.
z_test = 1;
}
}
pDraw = pDraw->mp_next;
}
z_test_required = z_test;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void SDraw2D::InsertDrawList( void )
{
if( !sp_2D_draw_list || ( m_pri <= sp_2D_draw_list->m_pri ))
{
// Empty or start of list.
mp_next = sp_2D_draw_list;
sp_2D_draw_list = this;
}
else
{
SDraw2D *p_cur = sp_2D_draw_list;
// Find where to insert.
while( p_cur->mp_next )
{
if( m_pri <= p_cur->mp_next->m_pri )
break;
p_cur = p_cur->mp_next;
}
// Insert at this point.
mp_next = p_cur->mp_next;
p_cur->mp_next = this;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void SDraw2D::RemoveDrawList( void )
{
// Take out from draw list
if (sp_2D_draw_list == this)
{
sp_2D_draw_list = mp_next;
}
else if (sp_2D_draw_list)
{
SDraw2D *p_cur = sp_2D_draw_list;
while(p_cur->mp_next)
{
if (p_cur->mp_next == this)
{
p_cur->mp_next = mp_next;
break;
}
p_cur = p_cur->mp_next;
}
}
}
typedef struct
{
float x, y, z;
float rhw;
D3DCOLOR col;
float u, v;
}
sSpriteVert;
/******************************************************************/
/* */
/* */
/******************************************************************/
sSprite::sSprite( float pri ) : SDraw2D( pri, true )
{
mp_texture = NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
sSprite::~sSprite()
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sSprite::BeginDraw( void )
{
set_vertex_shader( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2( 0 ));
if( mp_texture )
{
set_pixel_shader( PixelShader4 );
set_texture( 0, mp_texture->pD3DTexture, mp_texture->pD3DPalette );
}
else
{
set_pixel_shader( PixelShader5 );
set_texture( 0, NULL );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sSprite::Draw( void )
{
// Sprites are based on .img files, which in turn are converted from .png files, which are upside down,
// so reverse the v components of the texture coordinates.
float u0 = 0.0f;
float v0 = 1.0f;
float u1, v1;
if( mp_texture )
{
u1 = (float)mp_texture->ActualWidth / (float)mp_texture->BaseWidth;
v1 = 1.0f - ((float)mp_texture->ActualHeight / (float)mp_texture->BaseHeight );
}
else
{
u1 = 1.0f;
v1 = 0.0f;
}
// Check for flip.
float abs_scale_x = m_scale_x;
float abs_scale_y = m_scale_y;
if( abs_scale_x < 0.0f )
{
float temp = u0;
u0 = u1;
u1 = temp;
abs_scale_x = -abs_scale_x;
}
if( abs_scale_y < 0.0f )
{
float temp = v0;
v0 = v1;
v1 = temp;
abs_scale_y = -abs_scale_y;
}
float x0 = -( m_xhot * abs_scale_x );
float y0 = -( m_yhot * abs_scale_y );
float x1 = x0 + ( m_width * abs_scale_x );
float y1 = y0 + ( m_height * abs_scale_y );
DWORD current_color = ( m_rgba & 0xFF00FF00 ) | (( m_rgba & 0xFF ) << 16 ) | (( m_rgba & 0xFF0000 ) >> 16 );
DWORD* p_push;
if( m_rot != 0.0f )
{
Mth::Vector p0( x0, y0, 0.0f, 0.0f );
Mth::Vector p1( x1, y0, 0.0f, 0.0f );
Mth::Vector p2( x0, y1, 0.0f, 0.0f );
Mth::Vector p3( x1, y1, 0.0f, 0.0f );
p0.RotateZ( m_rot );
p1.RotateZ( m_rot );
p2.RotateZ( m_rot );
p3.RotateZ( m_rot );
p0[X] = SCREEN_CONV_X( p0[X] + m_xpos );
p0[Y] = SCREEN_CONV_Y( p0[Y] + m_ypos );
p1[X] = SCREEN_CONV_X( p1[X] + m_xpos );
p1[Y] = SCREEN_CONV_Y( p1[Y] + m_ypos );
p2[X] = SCREEN_CONV_X( p2[X] + m_xpos );
p2[Y] = SCREEN_CONV_Y( p2[Y] + m_ypos );
p3[X] = SCREEN_CONV_X( p3[X] + m_xpos );
p3[Y] = SCREEN_CONV_Y( p3[Y] + m_ypos );
// Now grab the push buffer space required.
p_push = D3DDevice_BeginPush( 34 );
p_push[0] = D3DPUSH_ENCODE( D3DPUSH_SET_BEGIN_END, 1 );
p_push[1] = D3DPT_QUADLIST;
p_push[2] = D3DPUSH_ENCODE( D3DPUSH_NOINCREMENT_FLAG | D3DPUSH_INLINE_ARRAY, 28 );
// Vertex0.
p_push[3] = *((uint32*)&p0[X] );
p_push[4] = *((uint32*)&p0[Y] );
p_push[5] = 0;
p_push[6] = 0;
p_push[7] = current_color;
p_push[8] = *((uint32*)&u0 );
p_push[9] = *((uint32*)&v0 );
// Vertex1.
p_push[10] = *((uint32*)&p2[X] );
p_push[11] = *((uint32*)&p2[Y] );
p_push[12] = 0;
p_push[13] = 0;
p_push[14] = current_color;
p_push[15] = *((uint32*)&u0 );
p_push[16] = *((uint32*)&v1 );
// Vertex2.
p_push[17] = *((uint32*)&p3[X] );
p_push[18] = *((uint32*)&p3[Y] );
p_push[19] = 0;
p_push[20] = 0;
p_push[21] = current_color;
p_push[22] = *((uint32*)&u1 );
p_push[23] = *((uint32*)&v1 );
// Vertex3.
p_push[24] = *((uint32*)&p1[X] );
p_push[25] = *((uint32*)&p1[Y] );
p_push[26] = 0;
p_push[27] = 0;
p_push[28] = current_color;
p_push[29] = *((uint32*)&u1 );
p_push[30] = *((uint32*)&v0 );
}
else
{
x0 += m_xpos;
y0 += m_ypos;
x1 += m_xpos;
y1 += m_ypos;
// Nasty hack - if the sprite is intended to cover the screen from top to bottom or left to right,
// bypass the addtional offset added by SCREEN_CONV.
if(( x0 <= 0.0f ) && ( x1 >= 640.0f ))
{
x0 = 0.0f;
x1 = (float)NxXbox::EngineGlobals.backbuffer_width;
}
else
{
x0 = SCREEN_CONV_X( x0 );
x1 = SCREEN_CONV_X( x1 );
}
if(( y0 <= 0.0f ) && ( y1 >= 480.0f ))
{
y0 = 0.0f;
y1 = (float)NxXbox::EngineGlobals.backbuffer_height;
}
else
{
y0 = SCREEN_CONV_Y( y0 );
y1 = SCREEN_CONV_Y( y1 );
}
// Now grab the push buffer space required.
p_push = D3DDevice_BeginPush( 34 );
p_push[0] = D3DPUSH_ENCODE( D3DPUSH_SET_BEGIN_END, 1 );
p_push[1] = D3DPT_QUADLIST;
p_push[2] = D3DPUSH_ENCODE( D3DPUSH_NOINCREMENT_FLAG | D3DPUSH_INLINE_ARRAY, 28 );
// Vertex0.
p_push[3] = *((uint32*)&x0 );
p_push[4] = *((uint32*)&y0 );
p_push[5] = 0;
p_push[6] = 0;
p_push[7] = current_color;
p_push[8] = *((uint32*)&u0 );
p_push[9] = *((uint32*)&v0 );
// Vertex1.
p_push[10] = *((uint32*)&x0 );
p_push[11] = *((uint32*)&y1 );
p_push[12] = 0;
p_push[13] = 0;
p_push[14] = current_color;
p_push[15] = *((uint32*)&u0 );
p_push[16] = *((uint32*)&v1 );
// Vertex2.
p_push[17] = *((uint32*)&x1 );
p_push[18] = *((uint32*)&y1 );
p_push[19] = 0;
p_push[20] = 0;
p_push[21] = current_color;
p_push[22] = *((uint32*)&u1 );
p_push[23] = *((uint32*)&v1 );
// Vertex3.
p_push[24] = *((uint32*)&x1 );
p_push[25] = *((uint32*)&y0 );
p_push[26] = 0;
p_push[27] = 0;
p_push[28] = current_color;
p_push[29] = *((uint32*)&u1 );
p_push[30] = *((uint32*)&v0 );
}
// End of vertex data for this sprite.
p_push[31] = D3DPUSH_ENCODE( D3DPUSH_SET_BEGIN_END, 1 );
p_push[32] = 0;
p_push += 33;
D3DDevice_EndPush( p_push );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sSprite::EndDraw( void )
{
// Vertices have been submitted - nothing more to do.
}
} // namespace NxXbox