bool GetFormatMSE(const D3DXIMAGE_INFO& info, LPDIRECT3DSURFACE8 pSrcSurf, D3DFORMAT fmt, double& CMSE, double& AMSE) { LPDIRECT3DSURFACE8 pCompSurf = 0, pDstSurf = 0; HRESULT hr; // Compress int Width = PadPow2(info.Width), Height = PadPow2(info.Height); hr = pD3DDevice->CreateImageSurface(Width, Height, fmt, &pCompSurf); CheckHR(hr); hr = D3DXLoadSurfaceFromSurface(pCompSurf, NULL, NULL, pSrcSurf, NULL, NULL, D3DX_FILTER_NONE, 0); CheckHR(hr); // Decompress hr = pD3DDevice->CreateImageSurface(Width, Height, D3DFMT_A8R8G8B8, &pDstSurf); CheckHR(hr); hr = D3DXLoadSurfaceFromSurface(pDstSurf, NULL, NULL, pCompSurf, NULL, NULL, D3DX_FILTER_NONE, 0); CheckHR(hr); pCompSurf->Release(); pCompSurf = 0; // calculate mean square error D3DLOCKED_RECT slr, dlr; hr = pSrcSurf->LockRect(&slr, NULL, D3DLOCK_READONLY); CheckHR(hr); hr = pDstSurf->LockRect(&dlr, NULL, D3DLOCK_READONLY); CheckHR(hr); double CTSE = 0.0; // total colour square error double ATSE = 0.0; // total alpha square error RGBCOLOUR* src = (RGBCOLOUR*)slr.pBits; RGBCOLOUR* dst = (RGBCOLOUR*)dlr.pBits; for (UINT y = 0; y < info.Height; ++y) { for (UINT x = 0; x < info.Width; ++x) { CTSE += (src->b - dst->b) * (src->b - dst->b); CTSE += (src->g - dst->g) * (src->g - dst->g); CTSE += (src->r - dst->r) * (src->r - dst->r); ATSE += (src->a - dst->a) * (src->a - dst->a); ++src; ++dst; } src += (slr.Pitch - info.Width*sizeof(RGBCOLOUR)) / sizeof(RGBCOLOUR); dst += (dlr.Pitch - info.Width*sizeof(RGBCOLOUR)) / sizeof(RGBCOLOUR); } CMSE = CTSE / double(info.Width * info.Height * 3); AMSE = ATSE / double(info.Width * info.Height); pSrcSurf->UnlockRect(); pDstSurf->UnlockRect(); pDstSurf->Release(); pDstSurf = 0; return true; }
int CIFMouseCursor::ChangeCursor( int cursorID, int type ) { HRESULT hr; LPDIRECT3DSURFACE8 pCursorBitmap = NULL; BYTE* pCursorBuffer = NULL; BYTE* pMouseBuffer; DWORD dwSize; switch( type ) { case MOUSE_CURSOR_TYPE : pMouseBuffer = m_mouseCursorBuffer[cursorID].buf; break; case ITEM_CURSOR_TYPE : pMouseBuffer = m_itemCursorBuffer[cursorID].buf; break; case SKILL_CURSOR_TYPE : case ACTION_CURSOR_TYPE : pMouseBuffer = m_skillCursorBuffer[cursorID].buf; break; } dwSize = 32 * 32 * 4; m_pd3dDevice->CreateImageSurface( 32, 32, D3DFMT_A8R8G8B8, &pCursorBitmap ); D3DLOCKED_RECT lr; pCursorBitmap->LockRect( &lr, NULL, 0 ); pCursorBuffer = (BYTE *)lr.pBits; memcpy( pCursorBuffer, pMouseBuffer, dwSize ); pCursorBitmap->UnlockRect(); if( FAILED( hr = m_pd3dDevice->SetCursorProperties( 0, 0, pCursorBitmap ) ) ) { goto CHANGE_CURSOR_END ; } hr = S_OK; CHANGE_CURSOR_END : SAFE_RELEASE( pCursorBitmap ); if( FAILED( hr ) ) return 0; return 1; }
bool CN3Texture::SaveToBitmapFile(const std::string& szFN) { if(szFN.empty()) return false; if(NULL == m_lpTexture) return false; LPDIRECT3DSURFACE8 lpSurfSrc = NULL; m_lpTexture->GetSurfaceLevel(0, &lpSurfSrc); if(NULL == lpSurfSrc) return false; LPDIRECT3DSURFACE8 lpSurfDest = NULL; s_lpD3DDev->CreateImageSurface(m_Header.nWidth, m_Header.nHeight, D3DFMT_A8R8G8B8, &lpSurfDest); if(NULL == lpSurfDest) return false; if(D3D_OK != D3DXLoadSurfaceFromSurface(lpSurfDest, NULL, NULL, lpSurfSrc, NULL, NULL, D3DX_FILTER_TRIANGLE, 0)) // 서피스 복사. { lpSurfDest->Release(); lpSurfDest = NULL; lpSurfSrc->Release(); lpSurfSrc = NULL; } CBitMapFile bmpf; bmpf.Create(m_Header.nWidth, m_Header.nHeight); D3DLOCKED_RECT LR; lpSurfDest->LockRect(&LR, NULL, 0); for(int y = 0; y < m_Header.nHeight; y++) { BYTE* pPixelsSrc = ((BYTE*)LR.pBits) + y * LR.Pitch; BYTE* pPixelsDest = (BYTE*)(bmpf.Pixels(0, y)); for(int x = 0; x < m_Header.nWidth; x++) { pPixelsDest[0] = pPixelsSrc[0]; pPixelsDest[1] = pPixelsSrc[1]; pPixelsDest[2] = pPixelsSrc[2]; pPixelsSrc += 4; pPixelsDest += 3; } } lpSurfDest->UnlockRect(); lpSurfDest->Release(); lpSurfDest = NULL; lpSurfSrc->Release(); lpSurfSrc = NULL; return bmpf.SaveToFile(szFN.c_str()); }
// Converts any fully transparent pixels to black so that the mse calcs work for dxt void FixTransparency(LPDIRECT3DSURFACE8 pSrcSurf) { D3DSURFACE_DESC desc; pSrcSurf->GetDesc(&desc); D3DLOCKED_RECT slr; if (FAILED(pSrcSurf->LockRect(&slr, NULL, 0))) return; DWORD* pix = (DWORD*)slr.pBits; for (UINT y = 0; y < desc.Width; ++y) { for (UINT x = 0; x < desc.Height; ++x) { if (!(*pix & 0xff000000)) *pix = 0; ++pix; } } pSrcSurf->UnlockRect(); }
// only works for gifs or other 256-colour anims void ConvertAnim(const char* Dir, const char* Filename, double MaxMSE) { HRESULT hr; LPDIRECT3DSURFACE8 pSrcSurf = NULL; char OutFilename[52]; if (Dir) _snprintf(OutFilename, 52, "%s\\%s", Dir, Filename); else _snprintf(OutFilename, 52, "%s", Filename); OutFilename[51] = 0; printf("%s: ", OutFilename); TRACE1("%s:\n", OutFilename); int n = strlen(OutFilename); if (n < 40) printf("%*c", 40-n, ' '); // Load up the file CAnimatedGifSet Anim; int nImages = Anim.LoadGIF(Filename); if (!nImages) { puts("ERROR: Unable to load gif (file corrupt?)"); return; } if (nImages > 65535) { printf("ERROR: Too many frames in gif (%d > 65535)\n", nImages); return; } PrintAnimInfo(Anim); UINT Width = PadPow2(Anim.FrameWidth); UINT Height = PadPow2(Anim.FrameHeight); D3DXIMAGE_INFO info; info.Width = Anim.FrameWidth; info.Height = Anim.FrameHeight; info.MipLevels = 1; info.Depth = 0; info.ResourceType = D3DRTYPE_SURFACE; info.Format = D3DFMT_P8; info.ImageFileFormat = D3DXIFF_PNG; PALETTEENTRY pal[256]; memcpy(pal, Anim.m_vecimg[0]->Palette, 256 * sizeof(PALETTEENTRY)); for (int i = 0; i < 256; i++) pal[i].peFlags = 0xff; // alpha if (Anim.m_vecimg[0]->Transparency && Anim.m_vecimg[0]->Transparent >= 0) memset(&pal[Anim.m_vecimg[0]->Transparent], 0, sizeof(PALETTEENTRY)); // setup xpr header WriteXPRHeader((DWORD*)pal, nImages); if (nImages > 1) { XPRFile.AnimInfo->RealSize = (info.Width & 0xffff) | ((info.Height & 0xffff) << 16); XPRFile.AnimInfo->nLoops = Anim.nLoops; } int nActualImages = 0; TotalSrcPixels += info.Width * info.Height * nImages; TotalDstPixels += Width * Height * nImages; float Waste = 100.f * (float)(Width * Height - info.Width * info.Height) / (float)(Width * Height); // alloc hash buffer BYTE (*HashBuf)[20] = new BYTE[nImages][20]; for (int i = 0; i < nImages; ++i) { if (pSrcSurf) pSrcSurf->Release(); pSrcSurf = NULL; printf("%3d%%\b\b\b\b", 100 * i / nImages); UncompressedSize += Width * Height; CAnimatedGif* pGif = Anim.m_vecimg[i]; if (nImages > 1) XPRFile.Texture[i].RealSize = pGif->Delay; // generate sha1 hash SHA1((BYTE*)pGif->Raster, pGif->BytesPerRow * pGif->Height, HashBuf[i]); // duplicate scan int j; for (j = 0; j < i; ++j) { if (!memcmp(HashBuf[j], HashBuf[i], 20)) { // duplicate image! TRACE2(" %03d: Duplicate of %03d\n", i, j); AppendXPRImageLink(j); break; } } if (j < i) continue; ++nActualImages; // DXT1 for P8s if lossless hr = pD3DDevice->CreateImageSurface(Width, Height, D3DFMT_A8R8G8B8, &pSrcSurf); CheckHR(hr); D3DLOCKED_RECT slr; hr = pSrcSurf->LockRect(&slr, NULL, D3DLOCK_READONLY); CheckHR(hr); BYTE* src = (BYTE*)pGif->Raster; DWORD* dst = (DWORD*)slr.pBits; DWORD* dwPal = (DWORD*)pal; for (int y = 0; y < pGif->Height; ++y) { for (UINT x = 0; x < Width; ++x) *dst++ = dwPal[*src++]; } memset(dst, 0, (Height - pGif->Height) * slr.Pitch); pSrcSurf->UnlockRect(); double CMSE, AMSE; TRACE1(" %03d: Checking DXT1: ", i); if (!GetFormatMSE(info, pSrcSurf, D3DFMT_DXT1, CMSE, AMSE)) return; TRACE2("CMSE=%05.2f, AMSE=%07.2f\n", CMSE, AMSE); if (CMSE <= 1e-6 && AMSE <= 1e-6) { TRACE1(" %03d: Selected Format: DXT1\n", i); AppendXPRImage(info, pSrcSurf, XB_D3DFMT_DXT1); } else { pSrcSurf->Release(); hr = pD3DDevice->CreateImageSurface(Width, Height, D3DFMT_P8, &pSrcSurf); CheckHR(hr); hr = pSrcSurf->LockRect(&slr, NULL, D3DLOCK_READONLY); CheckHR(hr); memcpy((BYTE*)slr.pBits, pGif->Raster, pGif->Height * slr.Pitch); memset((BYTE*)slr.pBits + pGif->Height * slr.Pitch, pGif->Transparent, (Height - pGif->Height) * slr.Pitch); pSrcSurf->UnlockRect(); TRACE1(" %03d: Selected Format: P8\n", i); AppendXPRImage(info, pSrcSurf, XB_D3DFMT_P8); } } delete [] HashBuf; printf("(%5df) %4dx%-4d (%5.2f%% waste)\n", nActualImages, Width, Height, Waste); CommitXPR(OutFilename); if (pSrcSurf) pSrcSurf->Release(); }
// Converts to P8 format is colours <= 256 bool ConvertP8(LPDIRECT3DSURFACE8 pSrcSurf, LPDIRECT3DSURFACE8& pDstSurf, DWORD* pal, D3DXIMAGE_INFO &info) { pDstSurf = 0; D3DSURFACE_DESC desc; pSrcSurf->GetDesc(&desc); // convert to p8 UINT Width = PadPow2(desc.Width); UINT Height = PadPow2(desc.Height); HRESULT hr = pD3DDevice->CreateImageSurface(Width, Height, D3DFMT_A8R8G8B8, &pDstSurf); CheckHR(hr); D3DLOCKED_RECT slr, dlr; hr = pDstSurf->LockRect(&dlr, NULL, 0); CheckHR(hr); hr = pSrcSurf->LockRect(&slr, NULL, D3DLOCK_READONLY); CheckHR(hr); DWORD* src = (DWORD*)slr.pBits; BYTE* dst = (BYTE*)dlr.pBits; int n = 0, i; for (UINT y = 0; y < info.Height; ++y) { for (UINT x = 0; x < info.Width; ++x) { for (i = 0; i < n; ++i) { if (pal[i] == *src) break; } if (i == n) { if (n >= 256) { TRACE0(" Too many colours for P8\n"); pSrcSurf->UnlockRect(); pDstSurf->UnlockRect(); pDstSurf->Release(); return false; } pal[n++] = *src; } *dst++ = i; ++src; } for (UINT x = info.Width; x < Width; ++x) { *dst++ = 0; // we don't care about the colour outside of our real image ++src; } } for (UINT y = info.Height; y < Height; ++y) { for (UINT x = 0; x < Width; ++x) { *dst++ = 0; // we don't care about the colour outside of our real image ++src; } } TRACE1(" Colours Used: %d\n", n); pDstSurf->UnlockRect(); pSrcSurf->UnlockRect(); return true; }
void AppendXPRImage(const D3DXIMAGE_INFO& info, LPDIRECT3DSURFACE8 pSrcSurf, XB_D3DFORMAT fmt) { D3DSURFACE_DESC desc; pSrcSurf->GetDesc(&desc); HRESULT hr; UINT Pitch; UINT Size; if (fmt == XB_D3DFMT_DXT1 || fmt == XB_D3DFMT_DXT3 || fmt == XB_D3DFMT_DXT5) { if (fmt == XB_D3DFMT_DXT1) Pitch = desc.Width / 2; else Pitch = desc.Width; Size = ((Pitch * desc.Height) + 127) & ~127; // must be 128-byte aligned for any following images Pitch *= 4; VirtualAlloc(XPRFile.Data, Size, MEM_COMMIT, PAGE_READWRITE); D3DLOCKED_RECT slr; hr = pSrcSurf->LockRect(&slr, NULL, D3DLOCK_READONLY); if (FAILED(hr)) { printf("ERROR: %08x\n", hr); return; } hr = CompressRect(XPRFile.Data, fmt, Pitch, desc.Width, desc.Height, slr.pBits, XB_D3DFMT_LIN_A8R8G8B8, slr.Pitch, 0.5f, 0); if (FAILED(hr)) { printf("ERROR: %08x\n", hr); return; } pSrcSurf->UnlockRect(); } else { UINT bpp = BytesPerPixelFromFormat(fmt); Pitch = desc.Width * bpp; Size = ((Pitch * desc.Height) + 127) & ~127; // must be 128-byte aligned for any following images VirtualAlloc(XPRFile.Data, Size, MEM_COMMIT, PAGE_READWRITE); D3DLOCKED_RECT slr; hr = pSrcSurf->LockRect(&slr, NULL, D3DLOCK_READONLY); if (FAILED(hr)) { printf("ERROR: %08x\n", hr); return; } if (IsSwizzledFormat(fmt)) { // Swizzle for xbox SwizzleRect(slr.pBits, 0, NULL, XPRFile.Data, desc.Width, desc.Height, NULL, bpp); } else { // copy BYTE* src = (BYTE*)slr.pBits; BYTE* dst = (BYTE*)XPRFile.Data; for (UINT y = 0; y < desc.Height; ++y) { memcpy(dst, src, desc.Width * bpp); src += slr.Pitch; dst += Pitch; } } pSrcSurf->UnlockRect(); } SetTextureHeader(desc.Width, desc.Height, 1, 0, fmt, D3DPOOL_DEFAULT, &XPRFile.Texture[XPRFile.nImages].D3DTex, XPRFile.Data - XPRFile.DataStart, Pitch); if (!(*XPRFile.flags & XPRFLAG_ANIM)) XPRFile.Texture[XPRFile.nImages].RealSize = (info.Width & 0xffff) | ((info.Height & 0xffff) << 16); ++XPRFile.nImages; XPRFile.Data += Size; CompressedSize += Size; }
//----------------------------------------------------------------------------- // Name: XBUtil_DumpSurface() // Desc: Writes the contents of a surface (32-bit only) to a .tga file. This // could be a backbuffer, texture, or any other 32-bit surface. //----------------------------------------------------------------------------- HRESULT XBUtil_DumpSurface( LPDIRECT3DSURFACE8 pSurface, const CHAR* strFileName, BOOL bSurfaceIsTiled ) { // Get the surface description. Make sure it's a 32-bit format D3DSURFACE_DESC desc; pSurface->GetDesc( &desc ); if( desc.Size != ( desc.Width * desc.Height * sizeof(DWORD) ) ) return E_NOTIMPL; // Lock the surface D3DLOCKED_RECT lock; if( FAILED( pSurface->LockRect( &lock, 0, bSurfaceIsTiled ? D3DLOCK_TILED : 0 ) ) ) return E_FAIL; // Allocate memory for storing the surface bits VOID* pBits = (VOID*)new DWORD[desc.Width*desc.Height]; // Unswizzle the bits, if necessary if( XGIsSwizzledFormat( desc.Format ) ) XGUnswizzleRect( lock.pBits, desc.Width, desc.Height, NULL, pBits, lock.Pitch, NULL, sizeof(DWORD) ); else memcpy( pBits, lock.pBits, desc.Size ); // Unlock the surface pSurface->UnlockRect(); // Setup the TGA file header struct TargaHeader { BYTE IDLength; BYTE ColormapType; BYTE ImageType; BYTE ColormapSpecification[5]; WORD XOrigin; WORD YOrigin; WORD ImageWidth; WORD ImageHeight; BYTE PixelDepth; BYTE ImageDescriptor; } tgaHeader; ZeroMemory( &tgaHeader, sizeof(tgaHeader) ); tgaHeader.IDLength = 0; tgaHeader.ImageType = 2; tgaHeader.ImageWidth = (WORD)desc.Width; tgaHeader.ImageHeight = (WORD)desc.Height; tgaHeader.PixelDepth = 32; tgaHeader.ImageDescriptor = 0x28; // Create a new file FILE* file = fopen( strFileName, "wb" ); if( NULL == file ) { pSurface->UnlockRect(); return E_FAIL; } // Write the Targa header and the surface pixels to the file fwrite( &tgaHeader, sizeof(TargaHeader), 1, file ); fwrite( pBits, sizeof(BYTE), desc.Size, file ); fclose( file ); // Cleanup and return delete[] pBits; return S_OK; }
//----------------------------------------------------------------------------- // Name: XBUtil_CreateNormalizationCubeMap() // Desc: Creates a cubemap and fills it with normalized RGBA vectors //----------------------------------------------------------------------------- HRESULT XBUtil_CreateNormalizationCubeMap( LPDIRECT3DDEVICE8 pd3dDevice, DWORD dwSize, LPDIRECT3DCUBETEXTURE8* ppCubeMap ) { HRESULT hr; // Create the cube map if( FAILED( hr = pd3dDevice->CreateCubeTexture( dwSize, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, ppCubeMap ) ) ) return E_FAIL; // Allocate temp space for swizzling the cubemap surfaces DWORD* pSourceBits = new DWORD[ dwSize * dwSize ]; // Fill all six sides of the cubemap for( DWORD i=0; i<6; i++ ) { // Lock the i'th cubemap surface LPDIRECT3DSURFACE8 pCubeMapFace; (*ppCubeMap)->GetCubeMapSurface( (D3DCUBEMAP_FACES)i, 0, &pCubeMapFace ); // Write the RGBA-encoded normals to the surface pixels DWORD* pPixel = pSourceBits; D3DXVECTOR3 n; FLOAT w, h; for( DWORD y = 0; y < dwSize; y++ ) { h = (FLOAT)y / (FLOAT)(dwSize-1); // 0 to 1 h = ( h * 2.0f ) - 1.0f; // -1 to 1 for( DWORD x = 0; x < dwSize; x++ ) { w = (FLOAT)x / (FLOAT)(dwSize-1); // 0 to 1 w = ( w * 2.0f ) - 1.0f; // -1 to 1 // Calc the normal for this texel switch( i ) { case D3DCUBEMAP_FACE_POSITIVE_X: // +x n.x = +1.0; n.y = -h; n.z = -w; break; case D3DCUBEMAP_FACE_NEGATIVE_X: // -x n.x = -1.0; n.y = -h; n.z = +w; break; case D3DCUBEMAP_FACE_POSITIVE_Y: // y n.x = +w; n.y = +1.0; n.z = +h; break; case D3DCUBEMAP_FACE_NEGATIVE_Y: // -y n.x = +w; n.y = -1.0; n.z = -h; break; case D3DCUBEMAP_FACE_POSITIVE_Z: // +z n.x = +w; n.y = -h; n.z = +1.0; break; case D3DCUBEMAP_FACE_NEGATIVE_Z: // -z n.x = -w; n.y = -h; n.z = -1.0; break; } // Store the normal as an RGBA color D3DXVec3Normalize( &n, &n ); *pPixel++ = XBUtil_VectorToRGBA( &n ); } } // Swizzle the result into the cubemap face surface D3DLOCKED_RECT lock; pCubeMapFace->LockRect( &lock, 0, 0L ); XGSwizzleRect( pSourceBits, 0, NULL, lock.pBits, dwSize, dwSize, NULL, sizeof(DWORD) ); pCubeMapFace->UnlockRect(); // Release the cubemap face pCubeMapFace->Release(); } // Free temp space SAFE_DELETE_ARRAY( pSourceBits ); return S_OK; }
// read depth buffer and update visibility flag of depth points static void UpdateDepthPointsVisibility( const CDrawPort *pdp, const INDEX iMirrorLevel, DepthInfo *pdi, const INDEX ctCount) { const GfxAPIType eAPI = _pGfx->gl_eCurrentAPI; ASSERT(GfxValidApi(eAPI)); ASSERT( pdp!=NULL && ctCount>0); const CRaster *pra = pdp->dp_Raster; // OpenGL if( eAPI==GAT_OGL) { _sfStats.StartTimer(CStatForm::STI_GFXAPI); FLOAT fPointOoK; // for each stored point for( INDEX idi=0; idi<ctCount; idi++) { DepthInfo &di = pdi[idi]; // skip if not in required mirror level or was already checked in this iteration if( iMirrorLevel!=di.di_iMirrorLevel || _iCheckIteration!=di.di_iSwapLastRequest) continue; const PIX pixJ = pra->ra_Height-1 - di.di_pixJ; // OpenGL has Y-inversed buffer! pglReadPixels( di.di_pixI, pixJ, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &fPointOoK); OGL_CHECKERROR; // it is visible if there is nothing nearer in z-buffer already di.di_bVisible = (di.di_fOoK<fPointOoK); } // done _sfStats.StopTimer(CStatForm::STI_GFXAPI); return; } // Direct3D #ifdef SE1_D3D if( eAPI==GAT_D3D) { _sfStats.StartTimer(CStatForm::STI_GFXAPI); // ok, this will get really complicated ... // We'll have to do it thru back buffer because darn DX8 won't let us have values from z-buffer; // Anyway, we'll lock backbuffer, read color from the lens location and try to write little triangle there // with slightly modified color. Then we'll readout that color and see if triangle passes z-test. Voila! :) // P.S. To avoid lock-modify-lock, we need to batch all the locks in one. Uhhhh ... :( COLOR col; INDEX idi; SLONG slColSize; HRESULT hr; D3DLOCKED_RECT rectLocked; D3DSURFACE_DESC surfDesc; LPDIRECT3DSURFACE8 pBackBuffer; // fetch back buffer (different for full screen and windowed mode) const BOOL bFullScreen = _pGfx->gl_ulFlags & GLF_FULLSCREEN; if( bFullScreen) { hr = _pGfx->gl_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); } else { hr = pra->ra_pvpViewPort->vp_pSwapChain->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); } // what, cannot get a back buffer? if( hr!=D3D_OK) { // to hell with it all _sfStats.StopTimer(CStatForm::STI_GFXAPI); return; } // keep format of back-buffer pBackBuffer->GetDesc(&surfDesc); const D3DFORMAT d3dfBack = surfDesc.Format; // prepare array that'll back-buffer colors from depth point locations _acolDelayed.Push(ctCount); // store all colors for( idi=0; idi<ctCount; idi++) { DepthInfo &di = pdi[idi]; // skip if not in required mirror level or was already checked in this iteration if( iMirrorLevel!=di.di_iMirrorLevel || _iCheckIteration!=di.di_iSwapLastRequest) continue; // fetch pixel _acolDelayed[idi] = 0; const RECT rectToLock = { di.di_pixI, di.di_pixJ, di.di_pixI+1, di.di_pixJ+1 }; hr = pBackBuffer->LockRect( &rectLocked, &rectToLock, D3DLOCK_READONLY); if( hr!=D3D_OK) continue; // skip if lock didn't make it // read, convert and store original color _acolDelayed[idi] = UnpackColor_D3D( (UBYTE*)rectLocked.pBits, d3dfBack, slColSize) | CT_OPAQUE; pBackBuffer->UnlockRect(); } // prepare to draw little triangles there with slightly adjusted colors _sfStats.StopTimer(CStatForm::STI_GFXAPI); gfxEnableDepthTest(); gfxDisableDepthWrite(); gfxDisableBlend(); gfxDisableAlphaTest(); gfxDisableTexture(); _sfStats.StartTimer(CStatForm::STI_GFXAPI); // prepare array and shader _avtxDelayed.Push(ctCount*3); d3dSetVertexShader(D3DFVF_CTVERTEX); // draw one trianle around each depth point INDEX ctVertex = 0; for( idi=0; idi<ctCount; idi++) { DepthInfo &di = pdi[idi]; col = _acolDelayed[idi]; // skip if not in required mirror level or was already checked in this iteration, or wasn't fetched at all if( iMirrorLevel!=di.di_iMirrorLevel || _iCheckIteration!=di.di_iSwapLastRequest || col==0) continue; const ULONG d3dCol = rgba2argb(col^0x20103000); const PIX pixI = di.di_pixI - pdp->dp_MinI; // convert raster loc to drawport loc const PIX pixJ = di.di_pixJ - pdp->dp_MinJ; // batch it and advance to next triangle CTVERTEX &vtx0 = _avtxDelayed[ctVertex++]; CTVERTEX &vtx1 = _avtxDelayed[ctVertex++]; CTVERTEX &vtx2 = _avtxDelayed[ctVertex++]; vtx0.fX=pixI; vtx0.fY=pixJ-2; vtx0.fZ=di.di_fOoK; vtx0.ulColor=d3dCol; vtx0.fU=vtx0.fV=0; vtx1.fX=pixI-2; vtx1.fY=pixJ+2; vtx1.fZ=di.di_fOoK; vtx1.ulColor=d3dCol; vtx1.fU=vtx0.fV=0; vtx2.fX=pixI+2; vtx2.fY=pixJ; vtx2.fZ=di.di_fOoK; vtx2.ulColor=d3dCol; vtx2.fU=vtx0.fV=0; } // draw a bunch hr = _pGfx->gl_pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLELIST, ctVertex/3, &_avtxDelayed[0], sizeof(CTVERTEX)); D3D_CHECKERROR(hr); // readout colors again and compare to old ones for( idi=0; idi<ctCount; idi++) { DepthInfo &di = pdi[idi]; col = _acolDelayed[idi]; // skip if not in required mirror level or was already checked in this iteration, or wasn't fetched at all if( iMirrorLevel!=di.di_iMirrorLevel || _iCheckIteration!=di.di_iSwapLastRequest || col==0) continue; // fetch pixel const RECT rectToLock = { di.di_pixI, di.di_pixJ, di.di_pixI+1, di.di_pixJ+1 }; hr = pBackBuffer->LockRect( &rectLocked, &rectToLock, D3DLOCK_READONLY); if( hr!=D3D_OK) continue; // skip if lock didn't make it // read new color const COLOR colNew = UnpackColor_D3D( (UBYTE*)rectLocked.pBits, d3dfBack, slColSize) | CT_OPAQUE; pBackBuffer->UnlockRect(); // if we managed to write adjusted color, point is visible! di.di_bVisible = (col!=colNew); } // phew, done! :) D3DRELEASE( pBackBuffer, TRUE); _acolDelayed.PopAll(); _avtxDelayed.PopAll(); _sfStats.StopTimer(CStatForm::STI_GFXAPI); return; } #endif // SE1_D3D }
HANDLE CScreenshot::CreateDibFromCurrentSurface() { LPDIRECT3DSURFACE8 pSurface = 0; LPDIRECT3D8 pD3D = 0; BYTE *pbyteDibBuffer = 0; D3DDEVICE_CREATION_PARAMETERS dcp; dcp.AdapterOrdinal = D3DADAPTER_DEFAULT; m_pD3DDevice->GetCreationParameters(&dcp); D3DDISPLAYMODE dm; dm.Width = dm.Height = 0; m_pD3DDevice->GetDirect3D(&pD3D); if(pD3D) { // get the current screen dimensions pD3D->GetAdapterDisplayMode(dcp.AdapterOrdinal, &dm); SAFERELEASE(pD3D); } else { return NULL; } // Grab the ARBG surface. m_pD3DDevice->CreateImageSurface(dm.Width,dm.Height,D3DFMT_A8R8G8B8,&pSurface); m_pD3DDevice->GetFrontBuffer(pSurface); // Setup the dib header. BITMAPINFOHEADER bmih; bmih.biSize = sizeof(bmih); bmih.biWidth = dm.Width; bmih.biHeight = dm.Height; bmih.biPlanes = 1; bmih.biBitCount = 24; bmih.biCompression = BI_RGB; bmih.biSizeImage = dm.Width * dm.Height * 3; bmih.biXPelsPerMeter = 0; bmih.biYPelsPerMeter = 0; bmih.biClrUsed = 0; bmih.biClrImportant = 0; pbyteDibBuffer = (PBYTE)calloc((bmih.biSizeImage+sizeof(BITMAPINFOHEADER)+1),1); if(!pbyteDibBuffer) return NULL; // Lock the surface. D3DLOCKED_RECT LockedRect; pSurface->LockRect(&LockedRect,NULL,D3DLOCK_READONLY); // Copy the bitmap info header into the dib buffer. memcpy(pbyteDibBuffer,&bmih,sizeof(BITMAPINFOHEADER)); PDWORD lpSrc; PBYTE lpDest = pbyteDibBuffer+sizeof(BITMAPINFOHEADER); for(int y = dm.Height - 1; y >= 0; y--) { lpSrc = (PDWORD)(LockedRect.pBits) + y * dm.Width; for(int x = 0; x < (signed)dm.Width; x++) { // Store the pixels *(DWORD *)(lpDest) = *lpSrc; lpSrc++; lpDest += 3; } } // we can unlock and release the surface pSurface->UnlockRect(); SAFERELEASE(pSurface); return pbyteDibBuffer; }