1097 lines
33 KiB
C++
1097 lines
33 KiB
C++
//-----------------------------------------------------------------------------
|
|
// 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 );
|
|
}
|
|
|