//---------------------------------------------------------------------------- // File: BltAlpha.h // // Desc: DirectShow sample code // Header file and class description for CAlphaBlt, // texture surface to be used in PresentImage of the // customized allocator-presenter // // Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- #ifndef __INITDDSTRUCT_DEFINED #define __INITDDSTRUCT_DEFINED #include #include #include "d3dtextr.h" #include "d3dfont.h" #include "utils.h" #include "resrc1.h" #include "d3dutil.h" extern struct SceneSettings g_ss; template __inline void INITDDSTRUCT(T& dd) { ZeroMemory(&dd, sizeof(dd)); dd.dwSize = sizeof(dd); } #endif #ifndef __RELEASE_DEFINED #define __RELEASE_DEFINED template __inline void RELEASE( T* &p ) { if( p ) { p->Release(); p = NULL; } } #endif #ifndef CHECK_HR #define CHECK_HR(expr) do { if (FAILED(expr)) __leave; } while(0); #endif #define COMPLVERTSIZE 640 // must be divisible by 4!!! #define pi 3.1415926535f //---------------------------------------------------------------------------- // CAlphaBlt // // Desc: texture surface to be used in PresentImage of the // customized allocator-presenter //---------------------------------------------------------------------------- class CAlphaBlt { private: LPDIRECTDRAW7 m_pDD; LPDIRECT3D7 m_pD3D; LPDIRECT3DDEVICE7 m_pD3DDevice; LPDIRECTDRAWSURFACE7 m_lpDDBackBuffer; LPDIRECTDRAWSURFACE7 m_lpDDMirror; LPDIRECTDRAWSURFACE7 m_lpDDM32; LPDIRECTDRAWSURFACE7 m_lpDDM16; DDSURFACEDESC2 m_ddsdM32; DDSURFACEDESC2 m_ddsdM16; bool m_fPowerOf2; bool m_fSquare; bool m_bNeedToRestoreMenu; TextureContainer * m_ptxtrMenu; CD3DFont * m_pFont; typedef struct Vertex { float x, y, z, rhw; D3DCOLOR clr; float tu, tv; } Vertex; Vertex pVertices[4]; // primitive for rotating effect Vertex pVComplex[COMPLVERTSIZE];// primitive for twisting effect Vertex pVMenu[4]; // primitive for menu effect //---------------------------------------------------------------------------- // CAlphaBlt::Rotate // // Desc: 3D transformation of pVertices that provide rotation around Z and Y // // Parameters: // theta - angle of rotation around Z axis // thetaY - angle of rotation around Y axis // pVertices - array of (Vertex*) to be transformed // nSize - number of vertices // (cx2, cy2) - center of rotation //---------------------------------------------------------------------------- void Rotate(float theta, float thetaY, CAlphaBlt::Vertex * pVertices, int nSize, float cx2, float cy2) { D3DXMATRIX mtrV; D3DXMATRIX mtrRotZ; D3DXMATRIX mtrRotY; D3DXMATRIX mtrPrs; D3DXMATRIX mtrRes; float pi2 = 1.57079632675f; // pi/2. // initialize mtrV mtrV.m[0][0] = pVertices[0].x - cx2; mtrV.m[1][0] = pVertices[0].y - cy2; mtrV.m[2][0] = pVertices[0].z; mtrV.m[3][0] = 0.f; mtrV.m[0][1] = pVertices[1].x - cx2; mtrV.m[1][1] = pVertices[1].y - cy2; mtrV.m[2][1] = pVertices[1].z; mtrV.m[3][1] = 0; mtrV.m[0][2] = pVertices[2].x - cx2; mtrV.m[1][2] = pVertices[2].y - cy2; mtrV.m[2][2] = pVertices[2].z; mtrV.m[3][2] = 0; mtrV.m[0][3] = pVertices[3].x - cx2; mtrV.m[1][3] = pVertices[3].y - cy2; mtrV.m[2][3] = pVertices[3].z; mtrV.m[3][3] = 0; D3DXMatrixRotationZ( &mtrRotZ, theta); D3DXMatrixRotationY( &mtrRotY, thetaY); D3DXMatrixPerspectiveFov( &mtrPrs, pi2, 1.1f, 0.f, 1.f); // mtrRotZ * mtrV D3DXMatrixMultiply( &mtrRes, &mtrRotZ, &mtrV); // mtrRotY * mtrRotZ * mtrV D3DXMatrixMultiply( &mtrV, &mtrRotY, &mtrRes); // mtrPrs * mtrRotY * mtrRotZ * mtrV D3DXMatrixMultiply( &mtrRes, &mtrPrs, &mtrV); // here, mtrRes has what we need; copy it back to pVertices pVertices[0].x = mtrRes.m[0][0] + cx2; pVertices[1].x = mtrRes.m[0][1] + cx2; pVertices[2].x = mtrRes.m[0][2] + cx2; pVertices[3].x = mtrRes.m[0][3] + cx2; pVertices[0].y = mtrRes.m[1][0] + cy2; pVertices[1].y = mtrRes.m[1][1] + cy2; pVertices[2].y = mtrRes.m[1][2] + cy2; pVertices[3].y = mtrRes.m[1][3] + cy2; pVertices[0].z = mtrRes.m[2][0]; pVertices[1].z = mtrRes.m[2][1]; pVertices[2].z = mtrRes.m[2][2]; pVertices[3].z = mtrRes.m[2][3]; return; } //---------------------------------------------------------------------------- // IsSurfaceBlendable // // Checks the DD surface description and the given // alpha value to determine if this surface is blendable. // //---------------------------------------------------------------------------- bool IsSurfaceBlendable( DDSURFACEDESC2& ddsd, BYTE fAlpha ) { // Is the surface already a D3D texture ? if (ddsd.ddsCaps.dwCaps & DDSCAPS_TEXTURE) { return true; } // OK we have to mirror the surface return false; } //---------------------------------------------------------------------------- // MirrorSourceSurface // // The mirror surface cab be either 16 or 32 bit RGB depending // upon the format of the source surface. // // Of course it should have the "texture" flag set and should be in VRAM. // If we can't create the surface then the AlphaBlt should fail //---------------------------------------------------------------------------- HRESULT MirrorSourceSurface( LPDIRECTDRAWSURFACE7 lpDDS, DDSURFACEDESC2& ddsd ) { HRESULT hr = DD_OK; DWORD dwMirrorBitDepth = 0; DDSURFACEDESC2 ddsdMirror={0}; // // OK - is it suitable for our needs. // // Apply the following rules: // if ddsd is a FOURCC surface the mirror should be 32 bit // if ddsd is RGB then the mirror's bit depth should match // that of ddsd. // // Also, the mirror must be large enough to actually hold // the surface to be blended // m_lpDDMirror = NULL; if (ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC || ddsd.ddpfPixelFormat.dwRGBBitCount == 32) { if (ddsd.dwWidth > m_ddsdM32.dwWidth || ddsd.dwHeight > m_ddsdM32.dwHeight) { RELEASE(m_lpDDM32); } if (!m_lpDDM32) { dwMirrorBitDepth = 32; } else { m_lpDDMirror = m_lpDDM32; ddsdMirror = m_ddsdM32; } } else if (ddsd.ddpfPixelFormat.dwRGBBitCount == 16) { if (ddsd.dwWidth > m_ddsdM16.dwWidth || ddsd.dwHeight > m_ddsdM16.dwHeight) { RELEASE(m_lpDDM16); } if (!m_lpDDM16) { dwMirrorBitDepth = 16; } else { m_lpDDMirror = m_lpDDM16; ddsdMirror = m_ddsdM16; } } else { // No support for RGB24 or RGB8! return E_INVALIDARG; } if (!m_lpDDMirror) { INITDDSTRUCT(ddsdMirror); ddsdMirror.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); ddsdMirror.ddpfPixelFormat.dwFlags = DDPF_RGB; ddsdMirror.ddpfPixelFormat.dwRGBBitCount = dwMirrorBitDepth; switch (dwMirrorBitDepth) { case 16: ddsdMirror.ddpfPixelFormat.dwRBitMask = 0x0000F800; ddsdMirror.ddpfPixelFormat.dwGBitMask = 0x000007E0; ddsdMirror.ddpfPixelFormat.dwBBitMask = 0x0000001F; break; case 32: ddsdMirror.ddpfPixelFormat.dwRBitMask = 0x00FF0000; ddsdMirror.ddpfPixelFormat.dwGBitMask = 0x0000FF00; ddsdMirror.ddpfPixelFormat.dwBBitMask = 0x000000FF; break; } ddsdMirror.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_TEXTURE; ddsdMirror.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT; if (m_fPowerOf2) { for (ddsdMirror.dwWidth = 1; ddsd.dwWidth > ddsdMirror.dwWidth; ddsdMirror.dwWidth <<= 1); for (ddsdMirror.dwHeight = 1; ddsd.dwHeight > ddsdMirror.dwHeight; ddsdMirror.dwHeight <<= 1); } else { ddsdMirror.dwWidth = ddsd.dwWidth; ddsdMirror.dwHeight = ddsd.dwHeight; } if (m_fSquare) { if (ddsdMirror.dwHeight > ddsdMirror.dwWidth) { ddsdMirror.dwWidth = ddsdMirror.dwHeight; } if (ddsdMirror.dwWidth > ddsdMirror.dwHeight) { ddsdMirror.dwHeight = ddsdMirror.dwWidth; } } __try { // Attempt to create the surface with theses settings CHECK_HR(hr = m_pDD->CreateSurface(&ddsdMirror, &m_lpDDMirror, NULL)); INITDDSTRUCT(ddsdMirror); CHECK_HR(hr = m_lpDDMirror->GetSurfaceDesc(&ddsdMirror)); switch (dwMirrorBitDepth) { case 16: m_ddsdM16 = ddsdMirror; m_lpDDM16 = m_lpDDMirror; break; case 32: m_ddsdM32 = ddsdMirror; m_lpDDM32 = m_lpDDMirror; break; } } __finally {} } if (hr == DD_OK) { __try { RECT rc = {0, 0, ddsd.dwWidth, ddsd.dwHeight}; CHECK_HR(hr = m_lpDDMirror->Blt(&rc, lpDDS, &rc, DDBLT_WAIT, NULL)); ddsd = ddsdMirror; } __finally {} } return hr; } public: //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- CAlphaBlt(LPDIRECTDRAWSURFACE7 lpDDSDst, HRESULT* phr) : m_pDD(NULL), m_pD3D(NULL), m_pD3DDevice(NULL), m_lpDDBackBuffer(NULL), m_lpDDMirror(NULL), m_lpDDM32(NULL), m_lpDDM16(NULL), m_ptxtrMenu( NULL), m_pFont(NULL), m_fPowerOf2(false), m_fSquare(false), m_bNeedToRestoreMenu(false) { ZeroMemory(&m_ddsdM32, sizeof(m_ddsdM32)); ZeroMemory(&m_ddsdM16, sizeof(m_ddsdM16)); HRESULT hr; hr = lpDDSDst->GetDDInterface((LPVOID *)&m_pDD); if (FAILED(hr)) { m_pDD = NULL; *phr = hr; } if (SUCCEEDED(hr)) { hr = m_pDD->QueryInterface(IID_IDirect3D7, (LPVOID *)&m_pD3D); if (FAILED(hr)) { m_pD3D = NULL; *phr = hr; } } if (SUCCEEDED(hr)) { hr = m_pD3D->CreateDevice(IID_IDirect3DHALDevice, lpDDSDst, &m_pD3DDevice); if (FAILED(hr)) { m_pD3DDevice = NULL; *phr = hr; } else { m_lpDDBackBuffer = lpDDSDst; m_lpDDBackBuffer->AddRef(); } } if (SUCCEEDED(hr)) { D3DDEVICEDESC7 ddDesc; if (DD_OK == m_pD3DDevice->GetCaps(&ddDesc)) { if (ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) { m_fPowerOf2 = true; } if (ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY) { m_fSquare = true; } } else { *phr = hr; } } // here, so far we have D3Device, let's Restore texture surface // it actually loads the bitmap from the resource onto a texture surface m_ptxtrMenu = new TextureContainer( "IDB_MENU", 0, 0, IDB_MENU); if( m_ptxtrMenu) { hr = m_ptxtrMenu->LoadImageData(); if( m_ptxtrMenu->m_hbmBitmap ) { BITMAP bm; GetObject( m_ptxtrMenu->m_hbmBitmap, sizeof(BITMAP), &bm ); m_ptxtrMenu->m_dwWidth = (DWORD)bm.bmWidth; m_ptxtrMenu->m_dwHeight = (DWORD)bm.bmHeight; m_ptxtrMenu->m_dwBPP = (DWORD)bm.bmBitsPixel; } hr = m_ptxtrMenu->Restore(m_pD3DDevice); if( FAILED(hr)) { delete m_ptxtrMenu; m_ptxtrMenu = NULL; } } // load the font m_pFont = new CD3DFont( TEXT("Comic Sans MS"),18,0); if( m_pFont ) { m_pFont->InitDeviceObjects( m_pDD, m_pD3DDevice); } // setup menu primitive pVMenu[0].x = 0.f; pVMenu[0].y = 0.f; pVMenu[0].z = 0.0f; pVMenu[0].rhw = 2.0f; pVMenu[0].clr = RGBA_MAKE(0xff, 0xff, 0xff, 0xff); pVMenu[1].x = 60.f; pVMenu[1].y = 0.f; pVMenu[1].z = 0.0f; pVMenu[1].rhw = 2.0f; pVMenu[1].clr = RGBA_MAKE(0xff, 0xff, 0xff, 0xff); pVMenu[2].x = 0.f; pVMenu[2].y = 480.f; pVMenu[2].z = 0.0f; pVMenu[2].rhw = 2.0f; pVMenu[2].clr = RGBA_MAKE(0xff, 0xff, 0xff, 0xff); pVMenu[3].x = 60.f; pVMenu[3].y = 480.f; pVMenu[3].z = 0.0f; pVMenu[3].rhw = 2.0f; pVMenu[3].clr = RGBA_MAKE(0xff, 0xff, 0xff, 0xff); // // Setup the SRC info // pVMenu[0].tu = 0.f; pVMenu[0].tv = 0.f; pVMenu[1].tu = 1.f; pVMenu[1].tv = 0.f; pVMenu[2].tu = 0.f; pVMenu[2].tv = 1.f; pVMenu[3].tu = 1.f; pVMenu[3].tv = 1.f; } //---------------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------------- ~CAlphaBlt() { if( m_ptxtrMenu ) { delete m_ptxtrMenu; m_ptxtrMenu = NULL; } if( m_pFont ) { delete m_pFont; m_pFont = NULL; } RELEASE(m_lpDDBackBuffer); RELEASE(m_lpDDM32); RELEASE(m_lpDDM16); RELEASE(m_pD3DDevice); RELEASE(m_pD3D); RELEASE(m_pDD); } //---------------------------------------------------------------------------- // GetMenuTexture // // returns pointer to texture's DD surface or NULL otherwise //---------------------------------------------------------------------------- LPDIRECTDRAWSURFACE7 GetMenuTexture() { if( m_ptxtrMenu && m_ptxtrMenu->m_pddsSurface ) { return (m_ptxtrMenu->m_pddsSurface); } return NULL; } //---------------------------------------------------------------------------- // SetMenuRestoreFlag // // sets m_bNeedToRestoreMenu = true; (called from CMpegMovie::RestoreDDRawSurfaces() ) //---------------------------------------------------------------------------- void SetMenuRestoreFlag() { m_bNeedToRestoreMenu = true; } //---------------------------------------------------------------------------- // GetFont //---------------------------------------------------------------------------- CD3DFont * GetFont() { return m_pFont; } //---------------------------------------------------------------------------- // PrepareVerticesRotate // // This is the 'main' transformation function for foration effect. // It generates rotation angles from 'time' variable that is just // a static counter of images from CMpegMovie:PresentImage function // // Parameters: // lpDst - destination rectangle // lpSrc - source rectangle // alpha - alpha level for the surface // fWid - width of the surface obtained by CMpegMovie:PresentImage // fHgt - height of the surface obtained by CMpegMovie:PresentImage //---------------------------------------------------------------------------- void PrepareVerticesRotate( RECT* lpDst, RECT* lpSrc, BYTE alpha, float fWid, float fHgt) { float RotRadZ = 0.f; float RotRadY = 0.f; // // Setup the DST info // pVertices[0].x = (float)lpDst->left; pVertices[0].y = (float)lpDst->top; pVertices[0].z = 0.5f; pVertices[0].rhw = 2.0f; pVertices[0].clr = RGBA_MAKE(0xff, 0xff, 0xff, alpha); pVertices[1].x = (float)lpDst->right; pVertices[1].y = (float)lpDst->top; pVertices[1].z = 0.5f; pVertices[1].rhw = 2.0f; pVertices[1].clr = RGBA_MAKE(0xff, 0xff, 0xff, alpha); pVertices[2].x = (float)lpDst->left; pVertices[2].y = (float)lpDst->bottom; pVertices[2].z = 0.5f; pVertices[2].rhw = 2.0f; pVertices[2].clr = RGBA_MAKE(0xff, 0xff, 0xff, alpha); pVertices[3].x = (float)lpDst->right; pVertices[3].y = (float)lpDst->bottom; pVertices[3].z = 0.5f; pVertices[3].rhw = 2.0f; pVertices[3].clr = RGBA_MAKE(0xff, 0xff, 0xff, alpha); // // Setup the SRC info // pVertices[0].tu = ((float)lpSrc->left) / fWid; pVertices[0].tv = ((float)lpSrc->top) / fHgt; pVertices[1].tu = ((float)lpSrc->right) / fWid; pVertices[1].tv = ((float)lpSrc->top) / fHgt; pVertices[2].tu = ((float)lpSrc->left) / fWid; pVertices[2].tv = ((float)lpSrc->bottom) / fHgt; pVertices[3].tu = ((float)lpSrc->right) / fWid; pVertices[3].tv = ((float)lpSrc->bottom) / fHgt; // g_ss.nGradZ is an angle in grades, so calculate radians RotRadZ = (float) (g_ss.nGradZ++) * pi / 180.f; if( !g_ss.bRotateZ) { g_ss.nGradZ--; } RotRadY = (float) (g_ss.nGradY++) * pi / 180.f; if( !g_ss.bRotateY) { g_ss.nGradY--; } // to avoid stack overflow, limit counters withing 360 grades if( g_ss.nGradZ > 360) { g_ss.nGradZ = 0; } if( g_ss.nGradY > 360) { g_ss.nGradY = 0; } // and finally rotate the primitive pVertices // NOTE that rotation center is hardcoded for the case // 640x480 display mode Rotate(RotRadZ, RotRadY, pVertices, 4, 320.f, 240.f); } //---------------------------------------------------------------------------- // PrepareVerticesTwist // // This is the 'main' transformation function for "twist" effect. // It generates transformation parameters 'time' variable that is just // a static counter of images from CMpegMovie:PresentImage function // // Parameters: // lpDst - destination rectangle // lpSrc - source rectangle // alpha - alpha level for the surface // fWid - width of the surface obtained by CMpegMovie:PresentImage // fHgt - height of the surface obtained by CMpegMovie:PresentImage // // Other: put your own effects here // The effect I use is as following: // (a) move picture down to create 'slipping' effect // (b) srink lower part of the picture (parameter c applied to each verticle // so that it would look like a wine glass stem (cosine is what we need) // Shrinking coefficient depends on Y-coordinate of a verticle // (c) twist lower part of the picture around Y axis, angle depends on // Y-coordinate of a verticle //---------------------------------------------------------------------------- void PrepareVerticesTwist( RECT* lpDst, RECT* lpSrc, BYTE alpha, float fW, float fH) { CAlphaBlt::Vertex * V = pVComplex; float W = (float)(lpDst->right - lpDst->left); float H = (float)(lpDst->bottom - lpDst->top); float sW = (float)(lpSrc->right - lpSrc->left)/fW; float sH = (float)(lpSrc->bottom - lpSrc->top); float Ht = 480 - H; float c; float radY = 0.f; float radX = pi/4.f; float x; double costh; double sinth; D3DXMATRIX mtrPrs; D3DXMATRIX mtrOrg; D3DXMATRIX mtrRes; int N = COMPLVERTSIZE/2; g_ss.nDy = g_ss.nDy + 3; if( g_ss.nDy > 480 ) { g_ss.nDy = 0; } for( int i=0; ileft); V[i+1].x = (float)(lpDst->right); V[i ].y = V[i+1].y = (float)(i * H/(N-1)) + g_ss.nDy; V[i ].z = V[i+1].z = 0.5f; V[i ].rhw = V[i+1].rhw = 2.f; V[i ].clr = V[i+1].clr = RGBA_MAKE(0xff, 0xff, 0xff, alpha); V[i ].tu = ((float)lpSrc->left) / fW; V[i+1].tu = ((float)lpSrc->right) / fW; V[i ].tv = V[i+1].tv = (float)(lpSrc->top + sH * (float)i/(N-1.f)/2.f)/fH; if( V[i].y >= H ) { c = (float)( W * (1. + cos(pi * (480. - V[i].y)/Ht)) / 4.); //c *= 0.25f; V[i ].x += c; V[i+1].x -= c; radY = pi * ( V[i].y - H ) / 2.f / Ht; costh = cos(radY); sinth = sin(radY); x = V[i].x - 320.f; V[i].x = (float)(costh * x - sinth * V[i].z) + 320.f; V[i].z = (float)(sinth * x + costh * V[i].z); x = V[i+1].x - 320.f; V[i+1].x = (float)(costh * x - sinth * V[i+1].z) + 320.f; V[i+1].z = (float)(sinth * x + costh * V[i+1].z); } // if }// for i // now let's implement projection D3DXMatrixPerspectiveFov( &mtrPrs, pi/2.f, 1.1f, 0.f, 1.f); for( i=0; iGetSurfaceDesc(&ddsd)); if (!IsSurfaceBlendable(ddsd, bAlpha)) { CHECK_HR(hr = MirrorSourceSurface(lpDDSSrc, ddsd)); lpDDSSrc = m_lpDDMirror; } float fWid = (float)ddsd.dwWidth; float fHgt = (float)ddsd.dwHeight; if( g_ss.bShowTwist ) { nVertSize = COMPLVERTSIZE; PrepareVerticesTwist(lpDst, lpSrc, bAlpha, fWid, fHgt); pV = pVComplex; } else { nVertSize = 4; PrepareVerticesRotate(lpDst, lpSrc, bAlpha, fWid, fHgt); pV = pVertices; } BYTE alpha = bAlpha; m_pD3DDevice->SetTexture(0, lpDDSSrc); // if menu is defined, set it m_pD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, TRUE); m_pD3DDevice->SetRenderState(D3DRENDERSTATE_BLENDENABLE, TRUE); m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA); m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA); m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE); m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); m_pD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_ANISOTROPIC); m_pD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_ANISOTROPIC); m_pD3DDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTFP_LINEAR); m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); m_pD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); // // Do the alpha BLT // CHECK_HR(hr = m_pD3DDevice->BeginScene()); CHECK_HR(hr = m_pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,0.5,0)); CHECK_HR(hr = m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1, pV, nVertSize, D3DDP_WAIT)); // now, draw menu over the video // if user switched modes, menu texture may be lost; then restore if( m_bNeedToRestoreMenu ) { DDSURFACEDESC2 ddsd; ZeroMemory( &ddsd, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_ALL; m_pDD->GetDisplayMode( &ddsd); // if we try to restore surface in a different display mode, we will fail // so make the check first if( ddsd.dwWidth == SCRN_WIDTH && ddsd.dwHeight == SCRN_HEIGHT && ddsd.ddpfPixelFormat.dwRGBBitCount == SCRN_BITDEPTH ) { hr = GetMenuTexture()->Restore(); if( FAILED(hr)) { OutputDebugString("ERROR: Failed to restore menu texture"); } else { // surface restored, but its image lost; reload if( m_ptxtrMenu) { hr = m_ptxtrMenu->LoadImageData(); if( FAILED(hr)) { OutputDebugString("Failed to load the image from resource\n"); } if( m_ptxtrMenu->m_hbmBitmap ) { BITMAP bm; GetObject( m_ptxtrMenu->m_hbmBitmap, sizeof(BITMAP), &bm ); m_ptxtrMenu->m_dwWidth = (DWORD)bm.bmWidth; m_ptxtrMenu->m_dwHeight = (DWORD)bm.bmHeight; m_ptxtrMenu->m_dwBPP = (DWORD)bm.bmBitsPixel; } hr = m_ptxtrMenu->Restore(m_pD3DDevice); if( FAILED(hr)) { delete m_ptxtrMenu; m_ptxtrMenu = NULL; } } m_bNeedToRestoreMenu = false; } } else { OutputDebugString("Failed to restore menu texture"); } } m_pD3DDevice->SetTexture(0, m_ptxtrMenu->m_pddsSurface); m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); m_pD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_ANISOTROPIC); m_pD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_ANISOTROPIC); m_pD3DDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTFP_LINEAR); // m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); m_pD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); CHECK_HR(hr = m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1, pVMenu, 4, D3DDP_WAIT)); m_pD3DDevice->SetTexture(0, NULL); // and if necessary, draw the dext over the menu if( g_ss.bShowHelp ) { HRESULT hr = m_pFont->DrawText((float)g_ss.nXHelp, (float)g_ss.nYHelp, RGBA_MAKE(0xFF, 0xFF, 0x00, 0xFF), g_ss.achHelp ); } if( g_ss.bShowStatistics ) { m_pFont->DrawText( 420, 0, RGBA_MAKE(0x00, 0xFF, 0x00, 0xFF), g_ss.achFPS ); } CHECK_HR(hr = m_pD3DDevice->EndScene()); } __finally { m_pD3DDevice->SetTexture(0, NULL); } return hr; } //---------------------------------------------------------------------------- // TextureSquare // true if texture is square //---------------------------------------------------------------------------- bool TextureSquare() { return m_fSquare; } //---------------------------------------------------------------------------- // TexturePower2 // true if texture size is of a power of 2 //---------------------------------------------------------------------------- bool TexturePower2() { return m_fPowerOf2; } };