Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1096 lines
32 KiB

//-----------------------------------------------------------------------------
// File: state.cpp
//
// Desc: STATE
//
// Copyright (c) 2000 Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#include "stdafx.h"
//-----------------------------------------------------------------------------
// Name: STATE constructor
// Desc: global state init
// translates variables set from the dialog boxes
//-----------------------------------------------------------------------------
STATE::STATE( CONFIG* pConfig )
{
ZeroMemory( &m_textureInfo, sizeof(TEXTUREINFO)*MAX_TEXTURES );
m_pConfig = pConfig;
m_resetStatus = 0;
m_pClearVB = NULL;
m_pNState = NULL;
m_pd3dDevice = NULL;
m_pWorldMatrixStack = NULL;
m_pLeadPipe = NULL;
m_nodes = NULL;
m_pFState = NULL;
m_maxDrawThreads = 0;
m_nTextures = 0;
m_bUseTexture = FALSE;
m_nSlices = 0;
m_radius = 0;
m_drawMode = 0;
m_maxPipesPerFrame = 0;
m_nPipesDrawn = 0;
m_nDrawThreads = 0;
m_fLastTime = 0.0f;
m_drawScheme = FRAME_SCHEME_RANDOM; // default draw scheme
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT STATE::InitDeviceObjects( IDirect3DDevice8* pd3dDevice )
{
m_pd3dDevice = pd3dDevice;
if( m_view.SetWinSize( g_pMyPipesScreensaver->GetSurfaceDesc()->Width,
g_pMyPipesScreensaver->GetSurfaceDesc()->Height ) )
m_resetStatus |= RESET_RESIZE_BIT;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT STATE::RestoreDeviceObjects()
{
int anDefaultResource[1];
anDefaultResource[0] = IDB_DEFTEX;
m_bUseTexture = FALSE;
if( m_pConfig->bTextured )
{
if( SUCCEEDED( LoadTextureFiles( 1, m_pConfig->strTextureName, anDefaultResource ) ) )
m_bUseTexture = TRUE;
}
DRAW_THREAD* pThread = m_drawThreads;
for( int i=0; i<m_maxDrawThreads; i++ )
{
pThread->InitDeviceObjects( m_pd3dDevice );
pThread->RestoreDeviceObjects();
pThread++;
}
D3DXCreateMatrixStack( 0, &m_pWorldMatrixStack );
m_view.SetProjMatrix( m_pd3dDevice );
D3DCAPS8 d3d8caps;
ZeroMemory( &d3d8caps, sizeof(D3DCAPS8) );
m_pd3dDevice->GetDeviceCaps( &d3d8caps );
if( d3d8caps.TextureOpCaps & D3DTEXOPCAPS_MODULATE )
{
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
}
else if( d3d8caps.TextureOpCaps & D3DTEXOPCAPS_SELECTARG1 )
{
if( m_bUseTexture )
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
else
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
}
if( d3d8caps.TextureFilterCaps & D3DPTFILTERCAPS_MINFLINEAR )
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
else if( d3d8caps.TextureFilterCaps & D3DPTFILTERCAPS_MINFPOINT )
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_POINT );
if( d3d8caps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR )
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
else if( d3d8caps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFPOINT )
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_POINT );
if( d3d8caps.TextureAddressCaps & D3DPTADDRESSCAPS_WRAP )
{
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP );
m_pd3dDevice->SetRenderState( D3DRS_WRAP0, D3DWRAP_U | D3DWRAP_V );
}
else if( d3d8caps.TextureAddressCaps & D3DPTADDRESSCAPS_CLAMP )
{
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP );
}
m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF, 0x00 );
m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATER );
m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE );
if( d3d8caps.PrimitiveMiscCaps & D3DPMISCCAPS_CULLCW )
m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );
else
m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
// Set up the lighting states
ZeroMemory( &m_light, sizeof(D3DLIGHT8) );
m_light.Type = D3DLIGHT_DIRECTIONAL;
m_light.Diffuse.r = 1.0f;
m_light.Diffuse.g = 1.0f;
m_light.Diffuse.b = 1.0f;
m_light.Diffuse.a = 1.0f;
if( m_bUseTexture )
{
m_light.Specular.r = 0.0f;
m_light.Specular.g = 0.0f;
m_light.Specular.b = 0.0f;
}
else
{
m_light.Specular.r = 0.6f;
m_light.Specular.g = 0.6f;
m_light.Specular.b = 0.6f;
}
m_light.Specular.a = 1.0f;
m_light.Position.x = 0.0f;
m_light.Position.y = -50.0f;
m_light.Position.z = -150.0f;
m_light.Ambient.r = 0.1f;
m_light.Ambient.g = 0.1f;
m_light.Ambient.b = 0.1f;
m_light.Ambient.a = 1.1f;
D3DXVec3Normalize( (D3DXVECTOR3*)&m_light.Direction, &D3DXVECTOR3(m_light.Position.x, m_light.Position.y, m_light.Position.z) );
m_light.Range = 1000.0f;
m_pd3dDevice->SetLight( 0, &m_light );
m_pd3dDevice->LightEnable( 0, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
if( m_bUseTexture )
m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xFF2F2F2F );
else
m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xFFFFFFFF );
InitMaterials();
// set 'reference' radius value
m_radius = 1.0f;
// convert tesselation from dwTesselFact(0.0-2.0) to tessLevel(0-MAX_TESS)
int tessLevel = (int) (m_pConfig->dwTesselFact * (MAX_TESS+1) / 2.0001f);
m_nSlices = (tessLevel+2) * 4;
// Allocate basic NODE_ARRAY
// NODE_ARRAY size is determined in Reshape (based on window size)
m_nodes = new NODE_ARRAY;
// Set drawing mode, and initialize accordingly. For now, either all normal
// or all flex pipes are drawn, but they could be combined later.
// Can assume here that if there's any possibility that normal pipes
// will be drawn, NORMAL_STATE will be initialized so that dlists are
// built
// Again, since have either NORMAL or FLEX, set maxPipesPerFrame,
// maxDrawThreads
if( m_pConfig->bMultiPipes )
m_maxDrawThreads = MAX_DRAW_THREADS;
else
m_maxDrawThreads = 1;
m_nDrawThreads = 0; // no active threads yet
m_nPipesDrawn = 0;
// maxPipesPerFrame is set in Reset()
// Create a square for rendering the clear transition
SAFE_RELEASE( m_pClearVB );
m_pd3dDevice->CreateVertexBuffer( 4*sizeof(D3DTLVERTEX),
D3DUSAGE_WRITEONLY, D3DFVF_TLVERTEX,
D3DPOOL_MANAGED, &m_pClearVB );
// Size the background image
D3DTLVERTEX* vBackground;
m_pClearVB->Lock( 0, 0, (BYTE**)&vBackground, 0 );
for( i=0; i<4; i ++ )
{
vBackground[i].p = D3DXVECTOR4( 0.0f, 0.0f, 0.95f, 1.0f );
vBackground[i].color = 0x20000000;
}
vBackground[0].p.y = (FLOAT)m_view.m_winSize.height;
vBackground[1].p.y = (FLOAT)m_view.m_winSize.height;
vBackground[1].p.x = (FLOAT)m_view.m_winSize.width;
vBackground[3].p.x = (FLOAT)m_view.m_winSize.width;
m_pClearVB->Unlock();
if( m_pConfig->bFlexMode )
{
m_drawMode = DRAW_FLEX;
m_pFState = new FLEX_STATE( this );
m_pNState = NULL;
}
else
{
m_drawMode = DRAW_NORMAL;
m_pNState = new NORMAL_STATE( this );
m_pFState = NULL;
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT STATE::FrameMove( FLOAT fElapsedTime )
{
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: Render
// Desc: - Top-level pipe drawing routine
// - Each pipe thread keeps drawing new pipes until we reach maximum number
// of pipes per frame - then each thread gets killed as soon as it gets
// stuck. Once number of drawing threads reaches 0, we start a new
// frame
//-----------------------------------------------------------------------------
HRESULT STATE::Render()
{
int i;
int nKilledThreads = 0;
BOOL bChooseNewLead = FALSE;
DRAW_THREAD* pThread;
// Reset the frame if its time
if( m_resetStatus != 0 )
{
if( FALSE == FrameReset() )
return S_OK;
}
// Check each pipe's status
pThread = m_drawThreads;
for( i=0; i<m_nDrawThreads; i++ )
{
if( pThread->m_pPipe->IsStuck() )
{
m_nPipesDrawn++;
if( m_nPipesDrawn > m_maxPipesPerFrame )
{
// Reaching pipe saturation - kill this pipe thread
if( (m_drawScheme == FRAME_SCHEME_CHASE) &&
(pThread->m_pPipe == m_pLeadPipe) )
bChooseNewLead = TRUE;
pThread->KillPipe();
nKilledThreads++;
}
else
{
// Start up another pipe
if( ! pThread->StartPipe() )
{
// we won't be able to draw any more pipes this frame
// (probably out of nodes)
m_maxPipesPerFrame = m_nPipesDrawn;
}
}
}
pThread++;
}
// Whenever one or more pipes are killed, compact the thread list
if( nKilledThreads )
{
CompactThreadList();
m_nDrawThreads -= nKilledThreads;
}
if( m_nDrawThreads == 0 )
{
// This frame is finished - mark for reset on next Draw
m_resetStatus |= RESET_NORMAL_BIT;
return S_OK;
}
if( bChooseNewLead )
{
// We're in 'chase mode' and need to pick a new lead pipe
ChooseNewLeadPipe();
}
// Draw each pipe
pThread = m_drawThreads;
for( i=0; i<m_nDrawThreads; i++ )
{
pThread->Render();
pThread++;
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT STATE::InvalidateDeviceObjects()
{
int i;
// Cleanup threads
DRAW_THREAD* pThread = m_drawThreads;
for( i=0; i<m_maxDrawThreads; i++ )
{
pThread->InvalidateDeviceObjects();
pThread->DeleteDeviceObjects();
pThread++;
}
SAFE_RELEASE( m_pClearVB );
// Cleanup textures
for( i=0; i<m_nTextures; i++ )
{
SAFE_RELEASE( m_textureInfo[i].pTexture );
}
SAFE_RELEASE( m_pWorldMatrixStack );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT STATE::DeleteDeviceObjects()
{
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: STATE destructor
// Desc:
//-----------------------------------------------------------------------------
STATE::~STATE()
{
SAFE_DELETE( m_pNState );
SAFE_DELETE( m_pFState );
SAFE_DELETE( m_nodes );
// Delete any RC's - should be done by ~THREAD, but since common lib
// deletes shareRC, have to do it here
DRAW_THREAD* pThread = m_drawThreads;
for( int i=0; i<m_maxDrawThreads; i++ )
{
pThread->KillPipe();
pThread++;
}
}
//-----------------------------------------------------------------------------
// Name: CalcTexRepFactors
// Desc:
//-----------------------------------------------------------------------------
void STATE::CalcTexRepFactors()
{
ISIZE winSize;
D3DXVECTOR2 texFact;
winSize = m_view.m_winSize;
// Figure out repetition factor of texture, based on bitmap size and
// screen size.
//
// We arbitrarily decide to repeat textures that are smaller than
// 1/8th of screen width or height.
for( int i = 0; i < m_nTextures; i++ )
{
m_texRep[i].x = m_texRep[i].y = 1;
if( (texFact.x = winSize.width / m_textureInfo[i].width / 8.0f) >= 1.0f)
m_texRep[i].x = (int) (texFact.x+0.5f);
if( (texFact.y = winSize.height / m_textureInfo[i].height / 8.0f) >= 1.0f)
m_texRep[i].y = (int) (texFact.y+0.5f);
}
// ! If display list based normal pipes, texture repetition is embedded
// in the dlists and can't be changed. So use the smallest rep factors.
// mf: Should change this so smaller textures are replicated close to
// the largest texture, then same rep factor will work well for all
if( m_pNState )
{
//put smallest rep factors in texRep[0]; (mf:this is ok for now, as
// flex pipes and normal pipes don't coexist)
for( i = 1; i < m_nTextures; i++ )
{
if( m_texRep[i].x < m_texRep[0].x )
m_texRep[0].x = m_texRep[i].x;
if( m_texRep[i].y < m_texRep[0].y )
m_texRep[0].y = m_texRep[i].y;
}
}
}
//-----------------------------------------------------------------------------
// Name: LoadTextureFiles
// Desc: - Load user texture files. If texturing on but no user textures, or
// problems loading them, load default texture resource
// mf: later, may want to have > 1 texture resource
//-----------------------------------------------------------------------------
HRESULT STATE::LoadTextureFiles( int nTextures, TCHAR strTextureFileNames[MAX_PATH][MAX_TEXTURES], int* anDefaultTextureResource )
{
HRESULT hr;
m_nTextures = 0;
for( int i=0; i<nTextures; i++ )
{
SAFE_RELEASE( m_textureInfo[i].pTexture );
if( !m_pConfig->bDefaultTexture )
{
WIN32_FIND_DATA findFileData;
HANDLE hFind = FindFirstFile( strTextureFileNames[i], &findFileData);
if (hFind != INVALID_HANDLE_VALUE)
{
// Load texture in strTextureFileNames[i] using D3DX
hr = D3DXCreateTextureFromFileEx( m_pd3dDevice, strTextureFileNames[i],
D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8,
D3DPOOL_MANAGED, D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR,
D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR, 0, NULL, NULL, &m_textureInfo[i].pTexture );
if( FAILED( hr ) )
{
SAFE_RELEASE( m_textureInfo[i].pTexture );
}
}
}
if( m_textureInfo[i].pTexture == NULL )
{
// Load default texture in resource anDefaultTextureResource[i]
hr = D3DXCreateTextureFromResourceEx( m_pd3dDevice, NULL, MAKEINTRESOURCE( anDefaultTextureResource[i] ),
D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8,
D3DPOOL_MANAGED, D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR,
D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR, 0, NULL, NULL, &m_textureInfo[i].pTexture );
if( FAILED( hr ) )
{
SAFE_RELEASE( m_textureInfo[i].pTexture );
}
}
if( m_textureInfo[i].pTexture == NULL )
{
// Couldn't load texture
return E_FAIL;
}
else
{
D3DSURFACE_DESC d3dDesc;
ZeroMemory( &d3dDesc, sizeof(D3DSURFACE_DESC) );
m_textureInfo[i].pTexture->GetLevelDesc( 0, &d3dDesc );
m_textureInfo[i].width = d3dDesc.Width;
m_textureInfo[i].height = d3dDesc.Height;
}
}
m_nTextures = nTextures;
CalcTexRepFactors();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: Repaint
// Desc: This is called when a WM_PAINT msg has been sent to the window. The paint
// will overwrite the frame buffer, screwing up the scene if pipes is in single
// buffer mode. We set resetStatus accordingly to clear things up on next
// draw.
//-----------------------------------------------------------------------------
void STATE::Repaint()
{
m_resetStatus |= RESET_REPAINT_BIT;
}
//-----------------------------------------------------------------------------
// Name: Reshape
// Desc: - called on resize, expose
// - always called on app startup
// - set new window size for VIEW object, and set resetStatus for validation
// at draw time
//-----------------------------------------------------------------------------
void STATE::Reshape( int width, int height )
{
}
//-----------------------------------------------------------------------------
// Name: ResetView
// Desc: Called on FrameReset resulting from change in viewing paramters (e.g. from
// a Resize event).
//-----------------------------------------------------------------------------
void STATE::ResetView()
{
IPOINT3D numNodes;
// Have VIEW calculate the node array size based on view params
m_view.CalcNodeArraySize( &numNodes );
// Resize the node array
m_nodes->Resize( &numNodes );
}
//-----------------------------------------------------------------------------
// Name: FrameReset
// Desc: Start a new frame of pipes
// The resetStatus parameter indicates what triggered the Reset.
//-----------------------------------------------------------------------------
BOOL STATE::FrameReset()
{
int i;
float xRot = 0.0f;
float zRot = 0.0f;
// Kill off any active pipes ! (so they can shut down ok)
DRAW_THREAD* pThread = m_drawThreads;
for( i=0; i<m_nDrawThreads; i++ )
{
pThread->KillPipe();
pThread++;
}
m_nDrawThreads = 0;
// Clear the screen
if( FALSE == Clear() )
return FALSE;
// Check for window resize status
if( m_resetStatus & RESET_RESIZE_BIT )
{
ResetView();
}
// Reset the node states to empty
m_nodes->Reset();
// Call any pipe-specific state resets, and get any recommended
// pipesPerFrame counts
if( m_pNState )
{
m_pNState->Reset();
}
if( m_pFState )
{
m_pFState->Reset();
//mf: maybe should figure out min spherical view dist
xRot = CPipesScreensaver::fRand(-5.0f, 5.0f);
zRot = CPipesScreensaver::fRand(-5.0f, 5.0f);
}
m_maxPipesPerFrame = CalcMaxPipesPerFrame();
// Set new number of drawing threads
if( m_maxDrawThreads > 1 )
{
// Set maximum # of pipes per frame
m_maxPipesPerFrame = (int) (m_maxPipesPerFrame * 1.5);
// Set # of draw threads
m_nDrawThreads = SS_MIN( m_maxPipesPerFrame, CPipesScreensaver::iRand2( 2, m_maxDrawThreads ) );
// Set chase mode if applicable, every now and then
BOOL bUseChase = m_pNState || (m_pFState && m_pFState->OKToUseChase());
if( bUseChase && (!CPipesScreensaver::iRand(5)) )
{
m_drawScheme = FRAME_SCHEME_CHASE;
}
}
else
{
m_nDrawThreads = 1;
}
m_nPipesDrawn = 0;
// for now, either all NORMAL or all FLEX for each frame
pThread = m_drawThreads;
for( i=0; i<m_nDrawThreads; i++ )
{
PIPE* pNewPipe;
// Rotate Scene
D3DXVECTOR3 xAxis = D3DXVECTOR3(1.0f,0.0f,0.0f);
D3DXVECTOR3 yAxis = D3DXVECTOR3(0.0f,1.0f,0.0f);
D3DXVECTOR3 zAxis = D3DXVECTOR3(0.0f,0.0f,1.0f);
// Set up the modeling view
m_pWorldMatrixStack->LoadIdentity();
m_pWorldMatrixStack->RotateAxis( &yAxis, m_view.m_yRot );
// create approppriate pipe for this thread slot
switch( m_drawMode )
{
case DRAW_NORMAL:
pNewPipe = (PIPE*) new NORMAL_PIPE(this);
break;
case DRAW_FLEX:
// There are several kinds of FLEX pipes
// so have FLEX_STATE decide which one to create
pNewPipe = m_pFState->NewPipe( this );
break;
}
pThread->SetPipe( pNewPipe );
if( m_drawScheme == FRAME_SCHEME_CHASE )
{
if( i == 0 )
{
// this will be the lead pipe
m_pLeadPipe = pNewPipe;
pNewPipe->SetChooseDirectionMethod( CHOOSE_DIR_RANDOM_WEIGHTED );
}
else
{
pNewPipe->SetChooseDirectionMethod( CHOOSE_DIR_CHASE );
}
}
// If texturing, pick a random texture for this thread
if( m_bUseTexture )
{
int index = PickRandomTexture( i, m_nTextures );
pThread->SetTexture( &m_textureInfo[index] );
// Flex pipes need to be informed of the texture, so they
// can dynamically calculate various texture params
if( m_pFState )
((FLEX_PIPE *) pNewPipe)->SetTexParams( &m_textureInfo[index],
&m_texRep[index] );
}
// Launch the pipe (assumed: always more nodes than pipes starting, so
// StartPipe cannot fail)
// ! All pipe setup needs to be done before we call StartPipe, as this
// is where the pipe starts drawing
pThread->StartPipe();
// Kind of klugey, but if in chase mode, I set chooseStartPos here,
// since first startPos used in StartPipe() should be random
if( (i == 0) && (m_drawScheme == FRAME_SCHEME_CHASE) )
pNewPipe->SetChooseStartPosMethod( CHOOSE_STARTPOS_FURTHEST );
pThread++;
m_nPipesDrawn++;
}
// Increment scene rotation for normal reset case
if( m_resetStatus & RESET_NORMAL_BIT )
m_view.IncrementSceneRotation();
// clear reset status
m_resetStatus = 0;
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: CalcMaxPipesPerFrame
// Desc:
//-----------------------------------------------------------------------------
int STATE::CalcMaxPipesPerFrame()
{
int nCount=0, fCount=0;
if( m_pFState )
fCount = m_pFState->GetMaxPipesPerFrame();
if( m_pNState )
nCount = m_bUseTexture ? NORMAL_TEX_PIPE_COUNT : NORMAL_PIPE_COUNT;
return SS_MAX( nCount, fCount );
}
//-----------------------------------------------------------------------------
// Name: PickRandomTexture
// Desc: Pick a random texture index from a list. Remove entry from list as it
// is picked. Once all have been picked, or starting a new frame, reset.
//-----------------------------------------------------------------------------
int STATE::PickRandomTexture( int iThread, int nTextures )
{
if( nTextures == 0 )
return 0;
static int pickSet[MAX_TEXTURES] = {0};
static int nPicked = 0;
int i, index;
if( iThread == 0 )
{
// new frame - force reset
nPicked = nTextures;
}
// reset condition
if( ++nPicked > nTextures )
{
for( i = 0; i < nTextures; i ++ ) pickSet[i] = 0;
nPicked = 1; // cuz
}
// Pick a random texture index
index = CPipesScreensaver::iRand( nTextures );
while( pickSet[index] )
{
// this index has alread been taken, try the next one
if( ++index >= nTextures )
index = 0;
}
// Hopefully, the above loop will exit :). This means that we have
// found a texIndex that is available
pickSet[index] = 1; // mark as taken
return index;
}
//-----------------------------------------------------------------------------
// Name: Clear
// Desc: Clear the screen. Depending on resetStatus, use normal clear or
// fancy transitional clear.
//-----------------------------------------------------------------------------
BOOL STATE::Clear()
{
if( m_resetStatus & RESET_NORMAL_BIT )
{
// do the normal transitional clear
static DWORD s_dwCount = 0;
static FLOAT s_fLastStepTime = DXUtil_Timer( TIMER_GETAPPTIME );
if( s_dwCount == 0 )
s_dwCount = 30;
float fCurTime = DXUtil_Timer( TIMER_GETAPPTIME );
if( fCurTime - s_fLastStepTime > 0.016 )
{
s_fLastStepTime = fCurTime;
s_dwCount--;
if( s_dwCount == 0 )
{
m_pd3dDevice->SetTexture( 0, NULL );
m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
0x00000000, 1.0f, 0L );
return TRUE;
}
else
{
m_pd3dDevice->SetTexture( 0, NULL );
m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
m_pd3dDevice->SetVertexShader( D3DFVF_TLVERTEX );
m_pd3dDevice->SetStreamSource( 0, m_pClearVB, sizeof(D3DTLVERTEX) );
m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
return FALSE;
}
}
else
{
return FALSE;
}
}
else
{
// do a fast one-shot clear
m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
0x00000000, 1.0f, 0L );
return TRUE;
}
}
//-----------------------------------------------------------------------------
// Name: DrawValidate
// Desc: Validation done before every Draw
// For now, this just involves checking resetStatus
//-----------------------------------------------------------------------------
void STATE::DrawValidate()
{
}
//-----------------------------------------------------------------------------
// Name: CompactThreadList
// Desc: - Compact the thread list according to number of pipe threads killed
// - The pipes have been killed, but the RC's in each slot are still valid
// and reusable. So we swap up entries with valid pipes. This means that
// the ordering of the RC's in the thread list will change during the life
// of the program. This should be OK.
//-----------------------------------------------------------------------------
#define SWAP_SLOT( a, b ) \
DRAW_THREAD pTemp; \
pTemp = *(a); \
*(a) = *(b); \
*(b) = pTemp;
void STATE::CompactThreadList()
{
if( m_nDrawThreads <= 1 )
// If only one active thread, it must be in slot 0 from previous
// compactions - so nothing to do
return;
int iEmpty = 0;
DRAW_THREAD* pThread = m_drawThreads;
for( int i=0; i<m_nDrawThreads; i++ )
{
if( pThread->m_pPipe )
{
if( iEmpty < i )
{
// swap active pipe thread and empty slot
SWAP_SLOT( &(m_drawThreads[iEmpty]), pThread );
}
iEmpty++;
}
pThread++;
}
}
//-----------------------------------------------------------------------------
// Name: ChooseNewLeadPipe
// Desc: Choose a new lead pipe for chase mode.
//-----------------------------------------------------------------------------
void STATE::ChooseNewLeadPipe()
{
// Pick one of the active pipes at random to become the new lead
int iLead = CPipesScreensaver::iRand( m_nDrawThreads );
m_pLeadPipe = m_drawThreads[iLead].m_pPipe;
m_pLeadPipe->SetChooseStartPosMethod( CHOOSE_STARTPOS_FURTHEST );
m_pLeadPipe->SetChooseDirectionMethod( CHOOSE_DIR_RANDOM_WEIGHTED );
}
//-----------------------------------------------------------------------------
// Name: DRAW_THREAD constructor
// Desc:
//-----------------------------------------------------------------------------
DRAW_THREAD::DRAW_THREAD()
{
m_pd3dDevice = NULL;
m_pPipe = NULL;
m_pTextureInfo = NULL;
}
//-----------------------------------------------------------------------------
// Name: DRAW_THREAD destructor
// Desc:
//-----------------------------------------------------------------------------
DRAW_THREAD::~DRAW_THREAD()
{
}
//-----------------------------------------------------------------------------
// Name: SetPipe
// Desc:
//-----------------------------------------------------------------------------
void DRAW_THREAD::SetPipe( PIPE* pPipe )
{
m_pPipe = pPipe;
}
//-----------------------------------------------------------------------------
// Name: SetTexture
// Desc:
//-----------------------------------------------------------------------------
void DRAW_THREAD::SetTexture( TEXTUREINFO* pTextureInfo )
{
m_pTextureInfo = pTextureInfo;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT DRAW_THREAD::InitDeviceObjects( IDirect3DDevice8* pd3dDevice )
{
m_pd3dDevice = pd3dDevice;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT DRAW_THREAD::RestoreDeviceObjects()
{
return S_OK;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT DRAW_THREAD::FrameMove( FLOAT fElapsedTime )
{
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: Render()
// Desc: - Draw pipe in thread slot, according to its type
//-----------------------------------------------------------------------------
HRESULT DRAW_THREAD::Render()
{
m_pPipe->Draw();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT DRAW_THREAD::InvalidateDeviceObjects()
{
return S_OK;
}
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT DRAW_THREAD::DeleteDeviceObjects()
{
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: StartPipe
// Desc: Starts up pipe of the approppriate type. If can't find an empty node
// for the pipe to start on, returns FALSE;
//-----------------------------------------------------------------------------
BOOL DRAW_THREAD::StartPipe()
{
// call pipe-type specific Start function
m_pPipe->Start();
// check status
if( m_pPipe->NowhereToRun() )
return FALSE;
else
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: KillPipe
// Desc:
//-----------------------------------------------------------------------------
void DRAW_THREAD::KillPipe()
{
SAFE_DELETE( m_pPipe );
}