//----------------------------------------------------------------------------- // 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; iInitDeviceObjects( 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; im_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; iRender(); pThread++; } return S_OK; } //----------------------------------------------------------------------------- // Name: // Desc: //----------------------------------------------------------------------------- HRESULT STATE::InvalidateDeviceObjects() { int i; // Cleanup threads DRAW_THREAD* pThread = m_drawThreads; for( i=0; iInvalidateDeviceObjects(); pThread->DeleteDeviceObjects(); pThread++; } SAFE_RELEASE( m_pClearVB ); // Cleanup textures for( i=0; iKillPipe(); 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; ibDefaultTexture ) { 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; iKillPipe(); 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; iLoadIdentity(); 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; im_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 ); }