Reorganize RageDisplay
Add Direct3D renderer (separate project configuration) Add Xbox project config (doesn't yet compile)
This commit is contained in:
@@ -0,0 +1,802 @@
|
||||
#include "global.h"
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
Class: RageDisplay
|
||||
|
||||
Desc: See header.
|
||||
|
||||
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
|
||||
Chris Danford
|
||||
Glenn Maynard
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "RageDisplay.h"
|
||||
#include "D3D8.h"
|
||||
#include "RageUtil.h"
|
||||
#include "RageLog.h"
|
||||
#include "RageTimer.h"
|
||||
#include "RageException.h"
|
||||
#include "RageTexture.h"
|
||||
#include "RageTextureManager.h"
|
||||
#include "RageMath.h"
|
||||
#include "RageTypes.h"
|
||||
#include "GameConstantsAndTypes.h"
|
||||
#include "StepMania.h"
|
||||
#include "RageUtil.h"
|
||||
#include "D3dx8math.h"
|
||||
#include "SDL_video.h" // for SDL_Surface
|
||||
#include "SDL_utils.h"
|
||||
|
||||
#include "arch/arch.h"
|
||||
|
||||
#pragma comment(lib, "D3d8.lib")
|
||||
#pragma comment(lib, "D3dx8.lib")
|
||||
|
||||
#include <math.h>
|
||||
|
||||
RageDisplay* DISPLAY = NULL;
|
||||
|
||||
//
|
||||
// Globals
|
||||
//
|
||||
LPDIRECT3D8 g_pd3d = NULL;
|
||||
LPDIRECT3DDEVICE8 g_pd3dDevice = NULL;
|
||||
D3DCAPS8 g_DeviceCaps;
|
||||
D3DDISPLAYMODE g_DesktopMode;
|
||||
D3DPRESENT_PARAMETERS g_d3dpp;
|
||||
int g_ModelMatrixCnt=0;
|
||||
bool g_Windowed;
|
||||
int g_CurrentHeight, g_CurrentWidth, g_CurrentBPP;
|
||||
|
||||
/* Direct3D doesn't associate a palette with textures.
|
||||
* Instead, we load a palette into a slot. We need to keep track
|
||||
* of which texture's palette is stored in what slot. */
|
||||
map<unsigned,int> g_TexResourceToPaletteIndex;
|
||||
int GetUnusedPaletteIndex()
|
||||
{
|
||||
for( int i=0; i<256; i++ )
|
||||
{
|
||||
bool bFreeToUse = true;
|
||||
for( map<unsigned,int>::const_iterator iter=g_TexResourceToPaletteIndex.begin();
|
||||
iter!=g_TexResourceToPaletteIndex.end();
|
||||
iter++ )
|
||||
{
|
||||
if( iter->second == i )
|
||||
{
|
||||
bFreeToUse = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( bFreeToUse )
|
||||
return i;
|
||||
}
|
||||
ASSERT( 0 ); // couldn't find a free palette index. Resource leak?
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define D3DFVF_RAGEVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_TEX1) // D3D FVF flags which describe our vertex structure
|
||||
|
||||
|
||||
const PixelFormatDesc PIXEL_FORMAT_DESC[NUM_PIX_FORMATS] = {
|
||||
{
|
||||
/* A8B8G8R8 */
|
||||
32,
|
||||
{ 0x00FF0000,
|
||||
0x0000FF00,
|
||||
0x000000FF,
|
||||
0xFF000000 }
|
||||
}, {
|
||||
/* A4R4G4B4 */
|
||||
16,
|
||||
{ 0x0F00,
|
||||
0x00F0,
|
||||
0x000F,
|
||||
0xF000 },
|
||||
}, {
|
||||
/* A1B5G5R5 */
|
||||
16,
|
||||
{ 0x7C00,
|
||||
0x03E0,
|
||||
0x001F,
|
||||
0x8000 },
|
||||
}, {
|
||||
/* X1R5G5R5 */
|
||||
16,
|
||||
{ 0x7C00,
|
||||
0x03E0,
|
||||
0x001F,
|
||||
0x0000 },
|
||||
}, {
|
||||
/* B8G8R8 */
|
||||
24,
|
||||
{ 0xFF0000,
|
||||
0x00FF00,
|
||||
0x0000FF,
|
||||
0x000000 }
|
||||
}, {
|
||||
/* Paletted */
|
||||
8,
|
||||
{ 0,0,0,0 } /* N/A */
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
RageDisplay::RageDisplay( bool windowed, int width, int height, int bpp, int rate, bool vsync )
|
||||
{
|
||||
LOG->Trace( "RageDisplay::RageDisplay()" );
|
||||
|
||||
if(!SDL_WasInit(SDL_INIT_VIDEO))
|
||||
SDL_InitSubSystem(SDL_INIT_VIDEO);
|
||||
|
||||
/* By default, ignore all SDL events. We'll enable them as we need them.
|
||||
* We must not enable any events we don't actually want, since we won't
|
||||
* query for them and they'll fill up the event queue.
|
||||
*
|
||||
* This needs to be done after we initialize video, since it's really part
|
||||
* of the SDL video system--it'll be reinitialized on us if we do this first. */
|
||||
SDL_EventState(0xFF /*SDL_ALLEVENTS*/, SDL_IGNORE);
|
||||
|
||||
SDL_EventState(SDL_VIDEORESIZE, SDL_ENABLE);
|
||||
|
||||
g_Windowed = false;
|
||||
|
||||
|
||||
g_pd3d = Direct3DCreate8( D3D_SDK_VERSION );
|
||||
|
||||
if( FAILED( g_pd3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &g_DeviceCaps) ) )
|
||||
throw RageException(
|
||||
"There was an error while initializing your video card.\n\n"
|
||||
"Your system is reporting that Direct3D8 hardware acceleration\n"
|
||||
"is not available. In most cases, you can download an updated\n"
|
||||
"driver from your card's manufacturer."
|
||||
);
|
||||
|
||||
D3DADAPTER_IDENTIFIER8 identifier;
|
||||
g_pd3d->GetAdapterIdentifier( D3DADAPTER_DEFAULT, 0, &identifier );
|
||||
|
||||
LOG->Trace(
|
||||
"Driver: %s\n"
|
||||
"Description: %s\n"
|
||||
"Max texture size: %d\n",
|
||||
identifier.Driver,
|
||||
identifier.Description,
|
||||
g_DeviceCaps.MaxTextureWidth
|
||||
);
|
||||
|
||||
LOG->Trace( "This display adaptor supports the following modes:" );
|
||||
D3DDISPLAYMODE mode;
|
||||
for( UINT u=0; u<g_pd3d->GetAdapterModeCount(D3DADAPTER_DEFAULT); u++ )
|
||||
if( SUCCEEDED( g_pd3d->EnumAdapterModes( D3DADAPTER_DEFAULT, u, &mode ) ) )
|
||||
LOG->Trace( " %ux%u %uHz, format %d", mode.Width, mode.Height, mode.RefreshRate, mode.Format );
|
||||
|
||||
// Save the original desktop format.
|
||||
g_pd3d->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &g_DesktopMode );
|
||||
|
||||
SetVideoMode( windowed, width, height, bpp, rate, vsync );
|
||||
}
|
||||
|
||||
void RageDisplay::Update(float fDeltaTime)
|
||||
{
|
||||
SDL_Event event;
|
||||
while(SDL_GetEvent(event, SDL_VIDEORESIZEMASK))
|
||||
{
|
||||
switch(event.type)
|
||||
{
|
||||
case SDL_VIDEORESIZE:
|
||||
g_CurrentWidth = event.resize.w;
|
||||
g_CurrentHeight = event.resize.h;
|
||||
|
||||
/* Let DISPLAY know that our resolution has changed. */
|
||||
ResolutionChanged();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RageDisplay::IsSoftwareRenderer()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RageDisplay::~RageDisplay()
|
||||
{
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
SDL_EventState(SDL_VIDEORESIZE, SDL_IGNORE);
|
||||
|
||||
g_pd3dDevice->Release();
|
||||
g_pd3d->Release();
|
||||
}
|
||||
|
||||
D3DFORMAT FindBackBufferType(bool bWindowed, int iBPP)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
// If windowed, then bpp is ignored. Use whatever works.
|
||||
vector<D3DFORMAT> vBackBufferFormats; // throw all possibilities in here
|
||||
|
||||
/* When windowed, add all formats; otherwise add only formats that match dwBPP. */
|
||||
if( iBPP == 16 || bWindowed )
|
||||
{
|
||||
vBackBufferFormats.push_back( D3DFMT_R5G6B5 );
|
||||
vBackBufferFormats.push_back( D3DFMT_X1R5G5B5 );
|
||||
vBackBufferFormats.push_back( D3DFMT_A1R5G5B5 );
|
||||
}
|
||||
if( iBPP == 32 || bWindowed )
|
||||
{
|
||||
#ifndef _XBOX
|
||||
vBackBufferFormats.push_back( D3DFMT_R8G8B8 );
|
||||
#endif
|
||||
vBackBufferFormats.push_back( D3DFMT_X8R8G8B8 );
|
||||
vBackBufferFormats.push_back( D3DFMT_A8R8G8B8 );
|
||||
}
|
||||
if( !bWindowed && iBPP != 16 && iBPP != 32 )
|
||||
throw RageException( ssprintf("Invalid BPP '%u' specified", iBPP) );
|
||||
|
||||
// Test each back buffer format until we find something that works.
|
||||
for( unsigned i=0; i < vBackBufferFormats.size(); i++ )
|
||||
{
|
||||
D3DFORMAT fmtBackBuffer = vBackBufferFormats[i];
|
||||
|
||||
D3DFORMAT fmtDisplay;
|
||||
if( bWindowed )
|
||||
fmtDisplay = g_DesktopMode.Format;
|
||||
else // Fullscreen
|
||||
fmtDisplay = vBackBufferFormats[i];
|
||||
|
||||
LOG->Trace( "Testing format: display %d, back buffer %d, windowed %d...",
|
||||
fmtDisplay, fmtBackBuffer, bWindowed );
|
||||
|
||||
hr = g_pd3d->CheckDeviceType( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
|
||||
fmtDisplay, fmtBackBuffer, bWindowed );
|
||||
|
||||
if( FAILED(hr) )
|
||||
continue; // skip
|
||||
|
||||
// done searching
|
||||
LOG->Trace( "This will work." );
|
||||
return fmtBackBuffer;
|
||||
}
|
||||
|
||||
RageException::Throw( "Couldn't find an appropriate back buffer format." );
|
||||
return D3DFMT_UNKNOWN;
|
||||
}
|
||||
|
||||
#ifndef _XBOX
|
||||
HWND GetHwnd()
|
||||
{
|
||||
SDL_SysWMinfo info;
|
||||
SDL_VERSION(&info.version);
|
||||
if( SDL_GetWMInfo(&info) < 0 )
|
||||
RageException::Throw( "SDL_GetWMInfo failed" );
|
||||
return info.window;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set the video mode. */
|
||||
bool RageDisplay::SetVideoMode( bool windowed, int width, int height, int bpp, int rate, bool vsync )
|
||||
{
|
||||
int flags = SDL_RESIZABLE;
|
||||
if( !windowed )
|
||||
flags |= SDL_FULLSCREEN;
|
||||
|
||||
g_Windowed = windowed;
|
||||
SDL_ShowCursor( g_Windowed );
|
||||
|
||||
SDL_Surface *screen = SDL_SetVideoMode(width, height, bpp, flags);
|
||||
if(!screen)
|
||||
RageException::Throw("SDL_SetVideoMode failed: %s", SDL_GetError());
|
||||
|
||||
g_CurrentWidth = screen->w;
|
||||
g_CurrentHeight = screen->h;
|
||||
g_CurrentBPP = bpp;
|
||||
|
||||
|
||||
ZeroMemory( &g_d3dpp, sizeof(g_d3dpp) );
|
||||
g_d3dpp.BackBufferWidth = width;
|
||||
g_d3dpp.BackBufferHeight = height;
|
||||
g_d3dpp.BackBufferFormat = FindBackBufferType( windowed, bpp );
|
||||
g_d3dpp.BackBufferCount = 1;
|
||||
g_d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
|
||||
g_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
#ifndef _XBOX
|
||||
g_d3dpp.hDeviceWindow = GetHwnd();
|
||||
#endif
|
||||
g_d3dpp.Windowed = windowed;
|
||||
g_d3dpp.EnableAutoDepthStencil = TRUE;
|
||||
g_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
|
||||
g_d3dpp.Flags = 0;
|
||||
g_d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
|
||||
|
||||
/* Windowed must always use D3DPRESENT_INTERVAL_DEFAULT. */
|
||||
g_d3dpp.FullScreen_PresentationInterval =
|
||||
(windowed || vsync) ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE;
|
||||
|
||||
if( g_pd3dDevice == NULL ) // device is not yet created. We need to create it
|
||||
{
|
||||
g_pd3d->CreateDevice(
|
||||
D3DADAPTER_DEFAULT,
|
||||
D3DDEVTYPE_HAL,
|
||||
#ifndef _XBOX
|
||||
GetHwnd(),
|
||||
D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED,
|
||||
#else
|
||||
NULL,
|
||||
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
|
||||
#endif
|
||||
&g_d3dpp,
|
||||
&g_pd3dDevice );
|
||||
ASSERT( g_pd3dDevice );
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pd3dDevice->Reset( &g_d3dpp );
|
||||
}
|
||||
|
||||
ResolutionChanged();
|
||||
|
||||
this->SetDefaultRenderStates();
|
||||
|
||||
g_pd3dDevice->BeginScene();
|
||||
|
||||
return false; // we can always reuse the D3D device
|
||||
}
|
||||
|
||||
void RageDisplay::ResolutionChanged()
|
||||
{
|
||||
// no need to clear because D3D uses an overlay
|
||||
// SetViewport(0,0);
|
||||
//
|
||||
// /* Clear any junk that's in the framebuffer. */
|
||||
// Clear();
|
||||
// Flip();
|
||||
}
|
||||
|
||||
void RageDisplay::SetViewport(int shift_left, int shift_down)
|
||||
{
|
||||
/* left and down are on a 0..SCREEN_WIDTH, 0..SCREEN_HEIGHT scale.
|
||||
* Scale them to the actual viewport range. */
|
||||
shift_left = int( shift_left * float(g_CurrentWidth) / SCREEN_WIDTH );
|
||||
shift_down = int( shift_down * float(g_CurrentWidth) / SCREEN_WIDTH );
|
||||
|
||||
D3DVIEWPORT8 viewData = { shift_left, -shift_down, g_CurrentWidth, g_CurrentHeight, 0.f, 1.f };
|
||||
g_pd3dDevice->SetViewport( &viewData );
|
||||
}
|
||||
|
||||
int RageDisplay::GetMaxTextureSize() const
|
||||
{
|
||||
return g_DeviceCaps.MaxTextureWidth;
|
||||
}
|
||||
|
||||
void RageDisplay::Clear()
|
||||
{
|
||||
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
|
||||
D3DCOLOR_XRGB(0,0,0), 1.0f, 0x00000000 );
|
||||
}
|
||||
|
||||
void RageDisplay::Flip()
|
||||
{
|
||||
g_pd3dDevice->EndScene();
|
||||
g_pd3dDevice->Present( 0, 0, 0, 0 );
|
||||
g_pd3dDevice->BeginScene();
|
||||
ProcessStatsOnFlip();
|
||||
}
|
||||
|
||||
D3DFORMAT D3DFORMATS[NUM_PIX_FORMATS] =
|
||||
{
|
||||
D3DFMT_A8R8G8B8,
|
||||
D3DFMT_A4R4G4B4,
|
||||
D3DFMT_A1R5G5B5,
|
||||
D3DFMT_X1R5G5B5,
|
||||
#ifndef _XBOX
|
||||
D3DFMT_R8G8B8,
|
||||
#else
|
||||
D3DFMT_A8R8G8B8,
|
||||
#endif
|
||||
D3DFMT_P8
|
||||
};
|
||||
|
||||
bool RageDisplay::SupportsTextureFormat( PixelFormat pixfmt )
|
||||
{
|
||||
D3DFORMAT d3dfmt = D3DFORMATS[pixfmt];
|
||||
HRESULT hr = g_pd3d->CheckDeviceFormat(
|
||||
D3DADAPTER_DEFAULT,
|
||||
D3DDEVTYPE_HAL,
|
||||
g_d3dpp.BackBufferFormat,
|
||||
0,
|
||||
D3DRTYPE_TEXTURE,
|
||||
d3dfmt);
|
||||
return SUCCEEDED( hr );
|
||||
}
|
||||
|
||||
void RageDisplay::SaveScreenshot( CString sPath )
|
||||
{
|
||||
#ifndef _XBOX
|
||||
IDirect3DSurface8* pSurface;
|
||||
g_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pSurface );
|
||||
D3DXSaveSurfaceToFile( sPath, D3DXIFF_BMP, pSurface, 0, NULL );
|
||||
pSurface->Release();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool RageDisplay::IsWindowed() const { return g_Windowed; }
|
||||
int RageDisplay::GetWidth() const { return g_CurrentWidth; }
|
||||
int RageDisplay::GetHeight() const { return g_CurrentHeight; }
|
||||
int RageDisplay::GetBPP() const { return g_CurrentBPP; }
|
||||
|
||||
#define SEND_CURRENT_MATRICES \
|
||||
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, (D3DMATRIX*)GetProjection() ); \
|
||||
RageMatrix m; \
|
||||
/* Convert to OpenGL-style "pixel-centered" coords */ \
|
||||
RageMatrixTranslation( &m, -0.5f, -0.5f, 0 ); \
|
||||
RageMatrixMultiply( &m, &m, GetModelViewTop() ); \
|
||||
g_pd3dDevice->SetTransform( D3DTS_WORLD, (D3DMATRIX*)&m );
|
||||
|
||||
|
||||
void RageDisplay::DrawQuads( const RageVertex v[], int iNumVerts )
|
||||
{
|
||||
ASSERT( (iNumVerts%4) == 0 );
|
||||
|
||||
if(iNumVerts == 0)
|
||||
return;
|
||||
|
||||
// there isn't a quad primitive in D3D, so we have to fake it with indexed triangles
|
||||
int iNumQuads = iNumVerts/4;
|
||||
int iNumTriangles = iNumQuads*2;
|
||||
int iNumIndices = iNumTriangles*3;
|
||||
|
||||
// make a temporary index buffer
|
||||
static vector<Uint16> vIndices;
|
||||
unsigned uOldSize = vIndices.size();
|
||||
unsigned uNewSize = max(uOldSize,(unsigned)iNumIndices);
|
||||
vIndices.resize( uNewSize );
|
||||
for( Uint16 i=(Uint16)uOldSize/6; i<(Uint16)iNumQuads; i++ )
|
||||
{
|
||||
vIndices[i*6+0] = i*4+0;
|
||||
vIndices[i*6+1] = i*4+1;
|
||||
vIndices[i*6+2] = i*4+2;
|
||||
vIndices[i*6+3] = i*4+2;
|
||||
vIndices[i*6+4] = i*4+3;
|
||||
vIndices[i*6+5] = i*4+0;
|
||||
}
|
||||
|
||||
g_pd3dDevice->SetVertexShader( D3DFVF_RAGEVERTEX );
|
||||
SEND_CURRENT_MATRICES;
|
||||
g_pd3dDevice->DrawIndexedPrimitiveUP(
|
||||
D3DPT_TRIANGLELIST, // PrimitiveType
|
||||
0, // MinIndex
|
||||
iNumVerts, // NumVertices
|
||||
iNumTriangles, // PrimitiveCount,
|
||||
&vIndices[0], // pIndexData,
|
||||
D3DFMT_INDEX16, // IndexDataFormat,
|
||||
v, // pVertexStreamZeroData,
|
||||
sizeof(RageVertex) // VertexStreamZeroStride
|
||||
);
|
||||
|
||||
StatsAddVerts( iNumVerts );
|
||||
}
|
||||
void RageDisplay::DrawFan( const RageVertex v[], int iNumVerts )
|
||||
{
|
||||
ASSERT( iNumVerts >= 3 );
|
||||
g_pd3dDevice->SetVertexShader( D3DFVF_RAGEVERTEX );
|
||||
SEND_CURRENT_MATRICES;
|
||||
g_pd3dDevice->DrawPrimitiveUP(
|
||||
D3DPT_TRIANGLEFAN, // PrimitiveType
|
||||
iNumVerts-2, // PrimitiveCount,
|
||||
v, // pVertexStreamZeroData,
|
||||
sizeof(RageVertex)
|
||||
);
|
||||
StatsAddVerts( iNumVerts );
|
||||
}
|
||||
|
||||
void RageDisplay::DrawStrip( const RageVertex v[], int iNumVerts )
|
||||
{
|
||||
ASSERT( iNumVerts >= 3 );
|
||||
g_pd3dDevice->SetVertexShader( D3DFVF_RAGEVERTEX );
|
||||
SEND_CURRENT_MATRICES;
|
||||
g_pd3dDevice->DrawPrimitiveUP(
|
||||
D3DPT_TRIANGLESTRIP, // PrimitiveType
|
||||
iNumVerts-2, // PrimitiveCount,
|
||||
v, // pVertexStreamZeroData,
|
||||
sizeof(RageVertex)
|
||||
);
|
||||
StatsAddVerts( iNumVerts );
|
||||
}
|
||||
|
||||
void RageDisplay::DrawTriangles( const RageVertex v[], int iNumVerts )
|
||||
{
|
||||
if( iNumVerts == 0 )
|
||||
return;
|
||||
ASSERT( iNumVerts >= 3 );
|
||||
g_pd3dDevice->SetVertexShader( D3DFVF_RAGEVERTEX );
|
||||
SEND_CURRENT_MATRICES;
|
||||
g_pd3dDevice->DrawPrimitiveUP(
|
||||
D3DPT_TRIANGLELIST, // PrimitiveType
|
||||
iNumVerts/3, // PrimitiveCount,
|
||||
v, // pVertexStreamZeroData,
|
||||
sizeof(RageVertex)
|
||||
);
|
||||
StatsAddVerts( iNumVerts );
|
||||
}
|
||||
|
||||
void RageDisplay::DrawIndexedTriangles( const RageVertex v[], const Uint16 pIndices[], int iNumIndices )
|
||||
{
|
||||
if( iNumIndices == 0 )
|
||||
return;
|
||||
g_pd3dDevice->SetVertexShader( D3DFVF_RAGEVERTEX );
|
||||
SEND_CURRENT_MATRICES;
|
||||
g_pd3dDevice->DrawIndexedPrimitiveUP(
|
||||
D3DPT_TRIANGLELIST, // PrimitiveType
|
||||
0, // MinIndex
|
||||
iNumIndices, // NumVertices
|
||||
iNumIndices/3, // PrimitiveCount,
|
||||
pIndices, // pIndexData,
|
||||
D3DFMT_INDEX16, // IndexDataFormat,
|
||||
v, // pVertexStreamZeroData,
|
||||
sizeof(RageVertex) // VertexStreamZeroStride
|
||||
);
|
||||
StatsAddVerts( iNumIndices );
|
||||
}
|
||||
|
||||
void RageDisplay::DrawLineStrip( const RageVertex v[], int iNumVerts, float LineWidth )
|
||||
{
|
||||
ASSERT( iNumVerts >= 2 );
|
||||
g_pd3dDevice->SetRenderState( D3DRS_POINTSIZE, *((DWORD*)&LineWidth) ); // funky cast. See D3DRENDERSTATETYPE doc
|
||||
g_pd3dDevice->SetVertexShader( D3DFVF_RAGEVERTEX );
|
||||
SEND_CURRENT_MATRICES;
|
||||
g_pd3dDevice->DrawPrimitiveUP(
|
||||
D3DPT_LINESTRIP, // PrimitiveType
|
||||
iNumVerts-1, // PrimitiveCount,
|
||||
v, // pVertexStreamZeroData,
|
||||
sizeof(RageVertex)
|
||||
);
|
||||
StatsAddVerts( iNumVerts );
|
||||
}
|
||||
|
||||
void RageDisplay::SetTexture( RageTexture* pTexture )
|
||||
{
|
||||
if( pTexture == NULL )
|
||||
{
|
||||
g_pd3dDevice->SetTexture( 0, NULL );
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned uTexHandle = pTexture->GetTexHandle();
|
||||
IDirect3DTexture8* pTex = (IDirect3DTexture8*)uTexHandle;
|
||||
g_pd3dDevice->SetTexture( 0, pTex );
|
||||
|
||||
// Set palette (if any)
|
||||
if( g_TexResourceToPaletteIndex.find(uTexHandle) != g_TexResourceToPaletteIndex.end() )
|
||||
{
|
||||
int iPaletteIndex = g_TexResourceToPaletteIndex.find(uTexHandle)->second;
|
||||
#ifndef _XBOX
|
||||
g_pd3dDevice->SetCurrentTexturePalette( iPaletteIndex );
|
||||
#else
|
||||
ASSERT(0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void RageDisplay::SetTextureModeModulate()
|
||||
{
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
|
||||
}
|
||||
|
||||
void RageDisplay::SetTextureModeGlow(GlowMode m)
|
||||
{
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
|
||||
|
||||
}
|
||||
|
||||
void RageDisplay::SetTextureFiltering( bool b )
|
||||
{
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, b ? D3DTEXF_LINEAR : D3DTEXF_POINT );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, b ? D3DTEXF_LINEAR : D3DTEXF_POINT );
|
||||
}
|
||||
|
||||
void RageDisplay::SetBlendMode( BlendMode mode )
|
||||
{
|
||||
g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
|
||||
switch( mode )
|
||||
{
|
||||
case BLEND_NORMAL:
|
||||
g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
|
||||
g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
|
||||
break;
|
||||
case BLEND_ADD:
|
||||
g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
|
||||
g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
|
||||
break;
|
||||
case BLEND_NO_EFFECT:
|
||||
g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ZERO );
|
||||
g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool RageDisplay::IsZBufferEnabled() const
|
||||
{
|
||||
DWORD b;
|
||||
g_pd3dDevice->GetRenderState( D3DRS_ZENABLE, &b );
|
||||
return b!=0;
|
||||
}
|
||||
|
||||
void RageDisplay::SetZBuffer( bool b )
|
||||
{
|
||||
g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, b );
|
||||
g_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, b );
|
||||
}
|
||||
void RageDisplay::ClearZBuffer()
|
||||
{
|
||||
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0x00000000 );
|
||||
}
|
||||
|
||||
void RageDisplay::SetTextureWrapping( bool b )
|
||||
{
|
||||
int mode = b ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP;
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSU, mode );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSV, mode );
|
||||
}
|
||||
|
||||
void RageDisplay::SetMaterial(
|
||||
float emissive[4],
|
||||
float ambient[4],
|
||||
float diffuse[4],
|
||||
float specular[4],
|
||||
float shininess
|
||||
)
|
||||
{
|
||||
D3DMATERIAL8 mat;
|
||||
memcpy( &mat.Diffuse, diffuse, sizeof(diffuse) );
|
||||
memcpy( &mat.Ambient, ambient, sizeof(ambient) );
|
||||
memcpy( &mat.Specular, specular, sizeof(specular) );
|
||||
memcpy( &mat.Emissive, emissive, sizeof(emissive) );
|
||||
mat.Power = shininess;
|
||||
g_pd3dDevice->SetMaterial( &mat );
|
||||
}
|
||||
|
||||
void RageDisplay::SetLighting( bool b )
|
||||
{
|
||||
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, b );
|
||||
}
|
||||
|
||||
void RageDisplay::SetLightOff( int index )
|
||||
{
|
||||
g_pd3dDevice->LightEnable( index, false );
|
||||
}
|
||||
void RageDisplay::SetLightDirectional(
|
||||
int index,
|
||||
RageColor ambient,
|
||||
RageColor diffuse,
|
||||
RageColor specular,
|
||||
RageVector3 dir )
|
||||
{
|
||||
g_pd3dDevice->LightEnable( index, true );
|
||||
|
||||
D3DLIGHT8 light;
|
||||
ZERO( light );
|
||||
memcpy( &light.Direction, &dir, sizeof(dir) );
|
||||
memcpy( &light.Direction, &dir, sizeof(dir) );
|
||||
memcpy( &light.Diffuse, diffuse, sizeof(diffuse) );
|
||||
memcpy( &light.Ambient, ambient, sizeof(ambient) );
|
||||
memcpy( &light.Specular, specular, sizeof(specular) );
|
||||
|
||||
g_pd3dDevice->SetLight( index, &light );
|
||||
}
|
||||
|
||||
void RageDisplay::SetBackfaceCull( bool b )
|
||||
{
|
||||
g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, b ? D3DCULL_CCW : D3DCULL_NONE );
|
||||
}
|
||||
|
||||
void RageDisplay::DeleteTexture( unsigned uTexHandle )
|
||||
{
|
||||
IDirect3DTexture8* pTex = (IDirect3DTexture8*) uTexHandle;
|
||||
pTex->Release();
|
||||
|
||||
// Delete palette (if any)
|
||||
if( g_TexResourceToPaletteIndex.find(uTexHandle) != g_TexResourceToPaletteIndex.end() )
|
||||
g_TexResourceToPaletteIndex.erase( g_TexResourceToPaletteIndex.find(uTexHandle) );
|
||||
}
|
||||
|
||||
|
||||
unsigned RageDisplay::CreateTexture(
|
||||
PixelFormat pixfmt,
|
||||
SDL_Surface*& img )
|
||||
{
|
||||
// texture must be power of two
|
||||
ASSERT( img->w == power_of_two(img->w) );
|
||||
ASSERT( img->h == power_of_two(img->h) );
|
||||
|
||||
|
||||
HRESULT hr;
|
||||
IDirect3DTexture8* pTex;
|
||||
hr = g_pd3dDevice->CreateTexture( img->w, img->h, 1, 0, D3DFORMATS[pixfmt], D3DPOOL_MANAGED, &pTex );
|
||||
|
||||
unsigned uTexHandle = (unsigned)pTex;
|
||||
|
||||
if( pixfmt == FMT_PAL )
|
||||
{
|
||||
int iPalIndex = GetUnusedPaletteIndex();
|
||||
|
||||
// Save palette
|
||||
PALETTEENTRY pal[256];
|
||||
memset( pal, 0, sizeof(pal) );
|
||||
for( int i=0; i<img->format->palette->ncolors; i++ )
|
||||
{
|
||||
SDL_Color c = img->format->palette->colors[i];
|
||||
pal[i].peRed = c.r;
|
||||
pal[i].peGreen = c.g;
|
||||
pal[i].peBlue = c.b;
|
||||
bool bIsColorKey = img->flags & SDL_SRCCOLORKEY && (unsigned)i == img->format->colorkey;
|
||||
pal[i].peFlags = bIsColorKey ? 0x00 : 0xFF;
|
||||
}
|
||||
#ifndef _XBOX
|
||||
g_pd3dDevice->SetPaletteEntries( iPalIndex, pal );
|
||||
#else
|
||||
ASSERT(0);
|
||||
#endif
|
||||
|
||||
ASSERT( g_TexResourceToPaletteIndex.find(uTexHandle) == g_TexResourceToPaletteIndex.end() );
|
||||
g_TexResourceToPaletteIndex[uTexHandle] = iPalIndex;
|
||||
}
|
||||
|
||||
UpdateTexture( uTexHandle, pixfmt, img, 0, 0, img->w, img->h );
|
||||
|
||||
return uTexHandle;
|
||||
}
|
||||
|
||||
void RageDisplay::UpdateTexture(
|
||||
unsigned uTexHandle,
|
||||
PixelFormat pixfmt,
|
||||
SDL_Surface*& img,
|
||||
int xoffset, int yoffset, int width, int height )
|
||||
{
|
||||
IDirect3DTexture8* pTex = (IDirect3DTexture8*)uTexHandle;
|
||||
|
||||
RECT rect;
|
||||
rect.left = xoffset;
|
||||
rect.top = yoffset;
|
||||
rect.right = width - xoffset;
|
||||
rect.bottom = height - yoffset;
|
||||
|
||||
D3DLOCKED_RECT lr;
|
||||
pTex->LockRect( 0, &lr, &rect, 0 );
|
||||
|
||||
// copy each row
|
||||
int bytes_per_pixel = img->format->BytesPerPixel;
|
||||
for( int y=rect.top; y<rect.bottom; y++ )
|
||||
{
|
||||
char* src = (char*)img->pixels + y*img->pitch + rect.left*bytes_per_pixel;
|
||||
char* dst = (char*)lr.pBits + y*lr.Pitch + rect.left*bytes_per_pixel;
|
||||
memcpy( dst, src, (rect.right-rect.left)*bytes_per_pixel );
|
||||
}
|
||||
pTex->UnlockRect( 0 );
|
||||
|
||||
// SDL_SaveBMP( (SDL_Surface*)img, "testing-SDL.bmp" );
|
||||
|
||||
// D3DXSaveTextureToFile(
|
||||
// "testing-D3D.bmp",
|
||||
// D3DXIFF_BMP,
|
||||
// pTex,
|
||||
// NULL );
|
||||
}
|
||||
|
||||
void RageDisplay::SetAlphaTest( bool b )
|
||||
{
|
||||
g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, b );
|
||||
g_pd3dDevice->SetRenderState( D3DRS_ALPHAREF, 0 );
|
||||
g_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATER );
|
||||
}
|
||||
Reference in New Issue
Block a user