|
|
//-----------------------------------------------------------------------------
// 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 ); }
|