void CALL HGE_Impl::System_Snapshot(const char *filename) { LPDIRECT3DSURFACE8 pSurf; char *shotname, tempname[_MAX_PATH]; int i; if(!filename) { i=0; shotname=Resource_EnumFiles("shot???.bmp"); while(shotname) { i++; shotname=Resource_EnumFiles(); } sprintf(tempname, "shot%03d.bmp", i); filename=Resource_MakePath(tempname); } if(pD3DDevice) { pD3DDevice->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pSurf); D3DXSaveSurfaceToFile(filename, D3DXIFF_BMP, pSurf, NULL, NULL); pSurf->Release(); } }
void CComboRenderer::Render(DWORD flags) { if ( m_RGBSurface[m_iYUY2RenderBuffer] == NULL ) { RenderLowMem(flags); } else { YV12toYUY2(); CheckScreenSaver(); /* clear target area, otherwise we won't get any picture */ D3DRECT target; target.x1 = rd.left; target.x2 = rd.right; target.y1 = rd.top; target.y2 = rd.bottom; m_pD3DDevice->Clear( 1L, &target, D3DCLEAR_TARGET, m_clearColour, 1.0f, 0L ); // Don't render if we are waiting an overlay event while (!m_pD3DDevice->GetOverlayUpdateStatus()) Sleep(1); LPDIRECT3DSURFACE8 pSurface; m_YUY2Texture[m_iYUY2RenderBuffer]->GetSurfaceLevel(0, &pSurface); m_pD3DDevice->UpdateOverlay( pSurface, &rs, &rd, TRUE, m_clearColour ); pSurface->Release(); } CXBoxRenderer::Render(flags | RENDER_FLAG_NOOSDALPHA); }
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()); }
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; }
bool CN3Texture::Convert(D3DFORMAT Format, int nWidth, int nHeight, BOOL bGenerateMipMap) { if(m_lpTexture == NULL) return false; D3DSURFACE_DESC dsd; m_lpTexture->GetLevelDesc(0, &dsd); if(0 >= nWidth || 0 >= nHeight) { nWidth = dsd.Width; nHeight = dsd.Height; } LPDIRECT3DTEXTURE8 lpTexOld = m_lpTexture; m_lpTexture = NULL; if(this->Create(nWidth, nHeight, Format, bGenerateMipMap) == false) return false; if(bGenerateMipMap) { LPDIRECT3DSURFACE8 lpTSOld; lpTexOld->GetSurfaceLevel(0, &lpTSOld); this->GenerateMipMap(lpTSOld); // MipMap 생성 lpTSOld->Release(); } else { LPDIRECT3DSURFACE8 lpTSNew; LPDIRECT3DSURFACE8 lpTSOld; m_lpTexture->GetSurfaceLevel(0, &lpTSNew); lpTexOld->GetSurfaceLevel(0, &lpTSOld); D3DXLoadSurfaceFromSurface(lpTSNew, NULL, NULL, lpTSOld, NULL, NULL, D3DX_FILTER_NONE, 0); // 첫번재 레벨 서피스 복사. lpTSOld->Release(); lpTSNew->Release(); } lpTexOld->Release(); lpTexOld = NULL; return true; }
int Render(){ HRESULT r; // D3DLOCKED_RECT LockedRect;//locked area of display memory(buffer really) we are drawing to LPDIRECT3DSURFACE8 pBackSurf = 0; if(!g_pDevice){ SetError("Cannot render because there is no device"); return E_FAIL; } //clear the display arera with colour black, ignore stencil buffer g_pDevice->Clear(0,0,D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,25), 1.0f, 0); //get pointer to backbuffer r=g_pDevice->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO, &pBackSurf); if(FAILED(r)){ SetError("Couldn't get backbuffer"); } /* //get a lock on the surface r=pBackSurf->LockRect(&LockedRect, NULL, 0); if(FAILED(r)){ SetError("Could not lock the back buffer"); } DWORD* pData = (DWORD*)(LockedRect.pBits); //DRAW CODE GOES HERE - use pData Draw(LockedRect.Pitch, pData); */ LPDIRECT3DSURFACE8 pSurface = 0; r=LoadBitmapToSurface("baboon.bmp", &pSurface, g_pDevice); if(FAILED(r)){ SetError("could not load bitmap surface"); } D3DSURFACE_DESC d3dsd; pSurface->GetDesc(&d3dsd);//get info about surface POINT DestPoint = {0, 0}; RECT rect = {0,0, d3dsd.Width, d3dsd.Height};//source dimensions // SetError("size x=%d size y=%d format=%d",d3dsd.Width, d3dsd.Height, d3dsd.Format); // r=g_pDevice->CopyRects(pSurface, &rect, 1, pBackSurf, &DestPoint);//copy surface to buffer (like a bitblt) r=D3DXLoadSurfaceFromSurface(pBackSurf, NULL, NULL, pSurface, NULL, &rect, D3DX_FILTER_TRIANGLE,0); // r=D3DXLoadSurfaceFromSurface(pBackSurf, NULL, NULL, pSurface, NULL, &rect, D3DX_FILTER_POINT, 0); if(ERROR(r)) SetError("did not copy surface"); // SimpleBitmapDraw("baboon.bmp", pBackSurf, 10,10); pSurface->Release(); pSurface = 0; // pBackSurf->UnlockRect(); // pData = 0; // pBackSurf->Release();//release lock // pBackSurf = 0; g_pDevice->Present(NULL, NULL, NULL, NULL);//swap over buffer to primary surface return S_OK; }
void CComboRenderer::YV12toYUY2() { int index = m_iYV12RenderBuffer; if (!m_RGBSurface[m_iYUY2RenderBuffer]) return; /* if we have dimmed our texture, don't overwrite it */ if( g_application.IsInScreenSaver() && m_bHasDimView ) return; if( WaitForSingleObject(m_eventTexturesDone[index], 500) == WAIT_TIMEOUT ) CLog::Log(LOGWARNING, __FUNCTION__" - Timeout waiting for texture %d", index); // Do the YV12 -> YUY2 conversion. // ALWAYS use buffer 0 in this case (saves 12 bits/pixel) m_pD3DDevice->SetTexture( 0, m_YUVTexture[index][FIELD_FULL][PLANE_Y] ); m_pD3DDevice->SetTexture( 1, m_YUVTexture[index][FIELD_FULL][PLANE_U] ); m_pD3DDevice->SetTexture( 2, m_YUVTexture[index][FIELD_FULL][PLANE_Y] ); m_pD3DDevice->SetTexture( 3, m_YUVTexture[index][FIELD_FULL][PLANE_V] ); for (int i = 0; i < 4; ++i) { m_pD3DDevice->SetTextureStageState( i, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP ); m_pD3DDevice->SetTextureStageState( i, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP ); m_pD3DDevice->SetTextureStageState( i, D3DTSS_MAGFILTER, D3DTEXF_POINT ); m_pD3DDevice->SetTextureStageState( i, D3DTSS_MINFILTER, D3DTEXF_POINT ); } // U and V need to use linear filtering, as they're being doubled vertically m_pD3DDevice->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); m_pD3DDevice->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); m_pD3DDevice->SetTextureStageState( 3, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); m_pD3DDevice->SetTextureStageState( 3, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); m_pD3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); m_pD3DDevice->SetRenderState( D3DRS_FOGENABLE, FALSE ); m_pD3DDevice->SetRenderState( D3DRS_FOGTABLEMODE, D3DFOG_NONE ); m_pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); m_pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW ); m_pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); m_pD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE ); m_pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO ); m_pD3DDevice->SetRenderState( D3DRS_YUVENABLE, FALSE ); m_pD3DDevice->SetVertexShader( FVF_YUYVVERTEX ); m_pD3DDevice->SetPixelShader( m_hPixelShader ); // Render the image LPDIRECT3DSURFACE8 pOldRT; m_pD3DDevice->GetRenderTarget(&pOldRT); m_pD3DDevice->SetRenderTarget(m_RGBSurface[m_iYUY2RenderBuffer], NULL); m_pD3DDevice->Begin(D3DPT_QUADLIST); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, (float)1.5f, (float)0.5f ); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD1, (float)0.5f, (float)0.5f ); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD2, (float)0.5f, (float)0.5f ); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD3, (float)0.5f, (float)0.5f); m_pD3DDevice->SetVertexData4f( D3DVSDE_VERTEX, (float)0.0f, (float)0.0f, 0, 1.0f ); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, (float)m_iSourceWidth + 1.5f, (float)0.5f ); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD1, (float)m_iSourceWidth / 2.0f + 0.5f, (float)0.5f ); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD2, (float)m_iSourceWidth + 0.5f, (float)0.5f ); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD3, (float)m_iSourceWidth / 2.0f + 0.5f, (float)0.5f ); m_pD3DDevice->SetVertexData4f( D3DVSDE_VERTEX, (float)m_iSourceWidth / 2.0f, (float)0.0f, 0, 1.0f ); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, (float)m_iSourceWidth + 1.5f, (float)m_iSourceHeight + 0.5f ); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD1, (float)m_iSourceWidth / 2.0f + 0.5f, (float)m_iSourceHeight / 2.0f + 0.5f ); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD2, (float)m_iSourceWidth + 0.5f, (float)m_iSourceHeight + 0.5f); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD3, (float)m_iSourceWidth / 2.0f + 0.5f, (float)m_iSourceHeight / 2.0f + 0.5f ); m_pD3DDevice->SetVertexData4f( D3DVSDE_VERTEX, (float)m_iSourceWidth / 2.0f, (float)m_iSourceHeight, 0, 1.0f ); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, (float)1.5f, (float)m_iSourceHeight + 0.5f ); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD1, (float)0.5f, (float)m_iSourceHeight / 2.0f + 0.5f ); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD2, (float)0.5f, (float)m_iSourceHeight + 0.5f ); m_pD3DDevice->SetVertexData2f( D3DVSDE_TEXCOORD3, (float)0.5f, (float)m_iSourceHeight / 2.0f + 0.5f ); m_pD3DDevice->SetVertexData4f( D3DVSDE_VERTEX, (float)0.0f, (float)m_iSourceHeight, 0, 1.0f ); m_pD3DDevice->End(); m_pD3DDevice->SetTexture(0, NULL); m_pD3DDevice->SetTexture(1, NULL); m_pD3DDevice->SetTexture(2, NULL); m_pD3DDevice->SetTexture(3, NULL); m_pD3DDevice->SetRenderState( D3DRS_YUVENABLE, FALSE ); m_pD3DDevice->SetPixelShader( NULL ); m_pD3DDevice->SetRenderTarget(pOldRT, NULL); m_pD3DDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); m_pD3DDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); m_pD3DDevice->SetTextureStageState( 2, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); m_pD3DDevice->SetTextureStageState( 2, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); pOldRT->Release(); //Okey, when the gpu is done with the textures here, they are free to be modified again m_pD3DDevice->InsertCallback(D3DCALLBACK_WRITE,&TextureCallback, (DWORD)m_eventTexturesDone[index]); m_pD3DDevice->KickPushBuffer(); m_bHasDimView = false; }
bool CN3Texture::GenerateMipMap(LPDIRECT3DSURFACE8 lpSurfSrc) { if(m_lpTexture == NULL) return false; // MipMap 이 몇개 필요한지 계산.. int nMMC = m_lpTexture->GetLevelCount(); int nMMC2 = 0; for(int nW = m_Header.nWidth, nH = m_Header.nHeight; nW >=4 && nH >= 4; nW /=2, nH /= 2) nMMC2++; bool bNeedReleaseSurf = false; if(NULL == lpSurfSrc) { bNeedReleaseSurf = true; if(D3D_OK != m_lpTexture->GetSurfaceLevel(0, &lpSurfSrc)) return false; } HRESULT rval = D3D_OK; if(nMMC < nMMC2) // 적으면 새로 생성.. { LPDIRECT3DTEXTURE8 lpTexOld = m_lpTexture; m_lpTexture = NULL; rval = this->CreateFromSurface(lpSurfSrc, m_Header.Format, TRUE); if(bNeedReleaseSurf) { lpSurfSrc->Release(); lpSurfSrc = NULL; } lpTexOld->Release(); lpTexOld = NULL; if(D3D_OK == rval) { m_Header.bMipMap = TRUE; return true; } else { m_Header.bMipMap = FALSE; return FALSE; } } else // MipMap 이 있으면 그냥 표면만 복사 { if(false == bNeedReleaseSurf) // 다른 서피스에서 복사해야 되는 거면 0 레벨도 복사.. { LPDIRECT3DSURFACE8 lpSurfDest; m_lpTexture->GetSurfaceLevel(0, &lpSurfDest); DWORD dwFilter = D3DX_FILTER_TRIANGLE; // 기본 필터는 없다.. HRESULT rval = D3DXLoadSurfaceFromSurface(lpSurfDest, NULL, NULL, lpSurfSrc, NULL, NULL, dwFilter, 0); // 작은 맵 체인에 서피스 이미지 축소 복사 lpSurfDest->Release(); lpSurfDest = NULL; } for(int i = 1; i < nMMC2; i++) { LPDIRECT3DSURFACE8 lpSurfDest, lpSurfUp; m_lpTexture->GetSurfaceLevel(i-1, &lpSurfUp); m_lpTexture->GetSurfaceLevel(i, &lpSurfDest); DWORD dwFilter = D3DX_FILTER_TRIANGLE; // 기본 필터는 없다.. HRESULT rval = D3DXLoadSurfaceFromSurface(lpSurfDest, NULL, NULL, lpSurfUp, NULL, NULL, dwFilter, 0); // 작은 맵 체인에 서피스 이미지 축소 복사 lpSurfDest->Release(); lpSurfUp->Release(); } if(bNeedReleaseSurf) { lpSurfSrc->Release(); lpSurfSrc = NULL; } if(D3D_OK == rval) { m_Header.bMipMap = TRUE; return true; } else { m_Header.bMipMap = FALSE; return FALSE; } } }
bool CN3Texture::Save(HANDLE hFile) { if(NULL == m_lpTexture) return false; CN3BaseFileAccess::Save(hFile); DWORD dwRWC = 0; D3DSURFACE_DESC sd; m_lpTexture->GetLevelDesc(0, &sd); int nMMC = m_lpTexture->GetLevelCount(); (nMMC > 1) ? m_Header.bMipMap = TRUE : m_Header.bMipMap = FALSE; if(TRUE == m_Header.bMipMap) // MipMap 갯수가 맞는지 확인.. { int nMMC2 = 0; for(int nW = sd.Width, nH = sd.Height; nW >=4 && nH >= 4; nW /=2, nH /= 2) nMMC2++; if(nMMC < nMMC2) { #ifdef _N3GAME CLogWriter::Write("N3Texture save warning - Invalid MipMap Count (%s)", m_szFileName.c_str()); #endif m_Header.bMipMap = FALSE; nMMC = 1; } else { nMMC = nMMC2; } } m_Header.szID[0] = 'N'; m_Header.szID[1] = 'T'; m_Header.szID[2] = 'F'; m_Header.szID[3] = 3; // Noah Texture File Ver '3' m_Header.nWidth = sd.Width; m_Header.nHeight = sd.Height; m_Header.bMipMap = (nMMC > 1) ? TRUE : FALSE; WriteFile(hFile, &m_Header, sizeof(m_Header), &dwRWC, NULL); // 헤더를 쓰고 if(m_lpTexture == NULL) return false; if( D3DFMT_DXT1 == sd.Format || D3DFMT_DXT2 == sd.Format || D3DFMT_DXT3 == sd.Format || D3DFMT_DXT4 == sd.Format || D3DFMT_DXT5 == sd.Format ) { D3DLOCKED_RECT LR; for(int i = 0; i < nMMC; i++) { m_lpTexture->GetLevelDesc(i, &sd); m_lpTexture->LockRect(i, &LR, NULL, NULL); WriteFile(hFile, (BYTE*)LR.pBits, sd.Size, &dwRWC, NULL); // 일렬로 된 데이터를 쓰고.. m_lpTexture->UnlockRect(i); } // 추가로 압축되지 않은 형식을 써준다.. 절반 크기이다. // 압축되지 않은 형식을 해상도를 한단계 낮추어서 저장. LPDIRECT3DSURFACE8 lpSurfSrc = NULL, lpSurfDest = NULL; D3DFORMAT fmtExtra = D3DFMT_UNKNOWN; if(D3DFMT_DXT1 == sd.Format) fmtExtra = D3DFMT_A1R5G5B5; else fmtExtra = D3DFMT_A4R4G4B4; int nMMC2 = nMMC - 1; if(nMMC == 1) nMMC2 = nMMC; for(i = 0; i < nMMC2; i++) { m_lpTexture->GetLevelDesc(i, &sd); m_lpTexture->GetSurfaceLevel(i, &lpSurfSrc); int nW = sd.Width / 2, nH = sd.Height / 2; s_lpD3DDev->CreateImageSurface(nW, nH, fmtExtra, &lpSurfDest); D3DXLoadSurfaceFromSurface(lpSurfDest, NULL, NULL, lpSurfSrc, NULL, NULL, D3DX_FILTER_TRIANGLE, 0); // 서피스 복사. int nPixelSize = 2; lpSurfDest->LockRect(&LR, NULL, NULL); for(int y = 0; y < nH; y++) { WriteFile(hFile, (BYTE*)LR.pBits + y * LR.Pitch, nW * 2, &dwRWC, NULL); } lpSurfDest->UnlockRect(); lpSurfDest->Release(); lpSurfDest = NULL; lpSurfSrc->Release(); lpSurfSrc = NULL; } if(nMMC == 1 && m_Header.nWidth >= 1024) // 부두를 위해 256 * 256 짜리 하나 더 저장해준다.. { m_lpTexture->GetLevelDesc(0, &sd); m_lpTexture->GetSurfaceLevel(0, &lpSurfSrc); int nW = 256, nH = 256; s_lpD3DDev->CreateImageSurface(nW, nH, fmtExtra, &lpSurfDest); D3DXLoadSurfaceFromSurface(lpSurfDest, NULL, NULL, lpSurfSrc, NULL, NULL, D3DX_FILTER_TRIANGLE, 0); // 서피스 복사. int nPixelSize = 2; lpSurfDest->LockRect(&LR, NULL, NULL); for(int y = 0; y < nH; y++) { WriteFile(hFile, (BYTE*)LR.pBits + y * LR.Pitch, nW * 2, &dwRWC, NULL); } lpSurfDest->UnlockRect(); lpSurfDest->Release(); lpSurfDest = NULL; lpSurfSrc->Release(); lpSurfSrc = NULL; } } else // 일반적인 포맷이면. { int nPixelSize = 0; if( D3DFMT_A1R5G5B5 == sd.Format || D3DFMT_A4R4G4B4 == sd.Format) nPixelSize = 2; else if(D3DFMT_R8G8B8 == sd.Format) nPixelSize = 3; else if(D3DFMT_A8R8G8B8 == sd.Format || D3DFMT_X8R8G8B8 == sd.Format) nPixelSize = 4; else { __ASSERT(0, "this Texture Format Not Supported"); } D3DLOCKED_RECT LR; for(int i = 0; i < nMMC; i++) { m_lpTexture->GetLevelDesc(i, &sd); m_lpTexture->LockRect(i, &LR, NULL, 0); // 각 레벨 Lock int nH = sd.Height; for(int y = 0; y < nH; y++) // 그냥 픽셀 저장.. WriteFile(hFile, (BYTE*)LR.pBits + y * LR.Pitch, sd.Width * nPixelSize, &dwRWC, NULL); m_lpTexture->UnlockRect(i); } if(nMMC == 1 && m_Header.nWidth >= 512) // 부두를 위해 256 * 256 짜리 하나 더 저장해준다.. { LPDIRECT3DSURFACE8 lpSurfSrc = NULL, lpSurfDest = NULL; m_lpTexture->GetLevelDesc(0, &sd); m_lpTexture->GetSurfaceLevel(0, &lpSurfSrc); int nW = 256, nH = 256; s_lpD3DDev->CreateImageSurface(nW, nH, sd.Format, &lpSurfDest); HRESULT rval = D3DXLoadSurfaceFromSurface(lpSurfDest, NULL, NULL, lpSurfSrc, NULL, NULL, D3DX_FILTER_TRIANGLE, 0); // 서피스 복사. lpSurfDest->LockRect(&LR, NULL, NULL); for(int y = 0; y < nH; y++) { WriteFile(hFile, (BYTE*)LR.pBits + y * LR.Pitch, nW * 2, &dwRWC, NULL); } lpSurfDest->UnlockRect(); lpSurfDest->Release(); lpSurfDest = NULL; lpSurfSrc->Release(); lpSurfSrc = NULL; } } return true; }
// 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(); }
void ConvertFile(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, ' '); if (pSrcSurf) pSrcSurf->Release(); pSrcSurf = NULL; // Load up the file D3DXIMAGE_INFO info; hr = D3DXGetImageInfoFromFile(Filename, &info); CheckHR(hr); PrintImageInfo(info); UINT Width = PadPow2(info.Width); UINT Height = PadPow2(info.Height); float Waste = 100.f * (float)(Width * Height - info.Width * info.Height) / (float)(Width * Height); UncompressedSize += Width * Height * 4; TotalSrcPixels += info.Width * info.Height; TotalDstPixels += Width * Height; // Special case for 256-colour files - just directly drop into a P8 xpr if (info.Format == D3DFMT_P8) { hr = pD3DDevice->CreateImageSurface(Width, Height, D3DFMT_A8R8G8B8, &pSrcSurf); CheckHR(hr); hr = D3DXLoadSurfaceFromFile(pSrcSurf, NULL, NULL, Filename, NULL, D3DX_FILTER_NONE, 0, NULL); CheckHR(hr); FixTransparency(pSrcSurf); if (Width * Height > 4096) { // DXT1 for P8s if lossless and more than 4k image LPDIRECT3DSURFACE8 pTempSurf; hr = pD3DDevice->CreateImageSurface(Width, Height, D3DFMT_A8R8G8B8, &pTempSurf); CheckHR(hr); hr = D3DXLoadSurfaceFromSurface(pTempSurf, NULL, NULL, pSrcSurf, NULL, NULL, D3DX_FILTER_NONE, 0); CheckHR(hr); double CMSE, AMSE; TRACE0(" Checking DXT1: "); if (!GetFormatMSE(info, pTempSurf, D3DFMT_DXT1, CMSE, AMSE)) { pTempSurf->Release(); return; } TRACE2("CMSE=%05.2f, AMSE=%07.2f\n", CMSE, AMSE); if (CMSE <= 1e-6 && AMSE <= 1e-6) { printf("DXT1 %4dx%-4d (%5.2f%% waste)\n", Width, Height, Waste); TRACE0(" Selected Format: DXT1\n"); WriteXPR(OutFilename, info, pTempSurf, XB_D3DFMT_DXT1, NULL); pTempSurf->Release(); return; } pTempSurf->Release(); } printf("P8 %4dx%-4d (%5.2f%% waste)\n", Width, Height, Waste); TRACE0(" Selected Format: P8\n"); LPDIRECT3DSURFACE8 pTempSurf; DWORD pal[256]; ConvertP8(pSrcSurf, pTempSurf, pal, info); WriteXPR(OutFilename, info, pTempSurf, XB_D3DFMT_P8, pal); pTempSurf->Release(); return; } // test linear format versus non-linear format // Linear format requires 64 pixel aligned width, whereas // Non-linear format requires power of 2 width and height bool useLinearFormat(false); UINT linearWidth = (info.Width + 0x3f) & ~0x3f; if (AllowLinear && linearWidth * info.Height < Width * Height) useLinearFormat = true; hr = pD3DDevice->CreateImageSurface(Width, Height, D3DFMT_A8R8G8B8, &pSrcSurf); CheckHR(hr); hr = D3DXLoadSurfaceFromFile(pSrcSurf, NULL, NULL, Filename, NULL, D3DX_FILTER_NONE, 0, NULL); CheckHR(hr); // create the linear version as well LPDIRECT3DSURFACE8 pLinearSrcSurf = NULL; if (useLinearFormat) { hr = pD3DDevice->CreateImageSurface(linearWidth, info.Height, D3DFMT_A8R8G8B8, &pLinearSrcSurf); CheckHR(hr); hr = D3DXLoadSurfaceFromFile(pLinearSrcSurf, NULL, NULL, Filename, NULL, D3DX_FILTER_NONE, 0, NULL); CheckHR(hr); } // special case for small files - all textures are alloced on page granularity so just output uncompressed // dxt is crap on small files anyway if (Width * Height <= 1024) { if (useLinearFormat) { // correct sizing amounts UncompressedSize -= Width * Height * 4; UncompressedSize += linearWidth * info.Height * 4; TotalDstPixels -= Width * Height; TotalDstPixels += linearWidth * info.Height; Waste = 100.f * (float)(linearWidth * info.Height - info.Width * info.Height) / (float)(linearWidth * info.Height); printf("LIN_A8R8G8B8 %4dx%-4d (%5.2f%% waste)\n", linearWidth, info.Height, Waste); TRACE0(" Selected Format: LIN_A8R8G8B8\n"); WriteXPR(OutFilename, info, pLinearSrcSurf, XB_D3DFMT_LIN_A8R8G8B8, NULL); } else { printf("A8R8G8B8 %4dx%-4d (%5.2f%% waste)\n", Width, Height, Waste); TRACE0(" Selected Format: A8R8G8B8\n"); WriteXPR(OutFilename, info, pSrcSurf, XB_D3DFMT_A8R8G8B8, NULL); } return; } FixTransparency(pSrcSurf); // Find the best format within specified tolerance double CMSE, AMSE[2]; // DXT1 is the preferred format as it's smallest TRACE0(" Checking DXT1: "); if (!GetFormatMSE(info, pSrcSurf, D3DFMT_DXT1, CMSE, AMSE[0])) return; TRACE2("CMSE=%05.2f, AMSE=%07.2f\n", CMSE, AMSE[0]); if (CMSE <= MaxMSE && AMSE[0] <= MaxMSE) { printf("DXT1 %4dx%-4d (%5.2f%% waste)\n", Width, Height, Waste); TRACE0(" Selected Format: DXT1\n"); WriteXPR(OutFilename, info, pSrcSurf, XB_D3DFMT_DXT1, NULL); return; } // Use P8 is possible as it's lossless LPDIRECT3DSURFACE8 pTempSurf; DWORD pal[256]; if (ConvertP8(pSrcSurf, pTempSurf, pal, info)) { printf("P8 %4dx%-4d (%5.2f%% waste)\n", Width, Height, Waste); TRACE0(" Selected Format: P8\n"); WriteXPR(OutFilename, info, pTempSurf, XB_D3DFMT_P8, pal); pTempSurf->Release(); return; } // DXT3/5 are the same size so use whichever is better if good enough // CMSE will be equal for both TRACE0(" Checking DXT3: "); if (!GetFormatMSE(info, pSrcSurf, D3DFMT_DXT3, CMSE, AMSE[0])) return; TRACE2("CMSE=%05.2f, AMSE=%07.2f\n", CMSE, AMSE[0]); TRACE0(" Checking DXT5: "); if (!GetFormatMSE(info, pSrcSurf, D3DFMT_DXT5, CMSE, AMSE[1])) return; TRACE2("CMSE=%05.2f, AMSE=%07.2f\n", CMSE, AMSE[1]); if (AMSE[0] <= AMSE[1]) { if (CMSE <= MaxMSE && AMSE[0] <= MaxMSE) { printf("DXT3 %4dx%-4d (%5.2f%% waste)\n", Width, Height, Waste); TRACE0(" Selected Format: DXT3\n"); WriteXPR(OutFilename, info, pSrcSurf, XB_D3DFMT_DXT3, NULL); return; } } else { if (CMSE <= MaxMSE && AMSE[1] <= MaxMSE) { printf("DXT5 %4dx%-4d (%5.2f%% waste)\n", Width, Height, Waste); TRACE0(" Selected Format: DXT5\n"); WriteXPR(OutFilename, info, pSrcSurf, XB_D3DFMT_DXT5, NULL); return; } } // No good compressed format so use uncompressed // A1R5G5B5 is worth a try I guess... TRACE0(" Checking A1R5G5B5: "); if (!GetFormatMSE(info, pSrcSurf, D3DFMT_A1R5G5B5, CMSE, AMSE[0])) return; TRACE2("CMSE=%05.2f, AMSE=%07.2f\n", CMSE, AMSE[0]); if (CMSE <= MaxMSE && AMSE[0] <= MaxMSE) { printf("A1R5G5B5 %4dx%-4d (%5.2f%% waste)\n", Width, Height, Waste); TRACE0(" Selected Format: A1R5G5B5\n"); LPDIRECT3DSURFACE8 pTempSurf; hr = pD3DDevice->CreateImageSurface(Width, Height, D3DFMT_A1R5G5B5, &pTempSurf); CheckHR(hr); hr = D3DXLoadSurfaceFromSurface(pTempSurf, NULL, NULL, pSrcSurf, NULL, NULL, D3DX_FILTER_NONE, 0); CheckHR(hr); WriteXPR(OutFilename, info, pTempSurf, XB_D3DFMT_A1R5G5B5, NULL); pTempSurf->Release(); return; } // Use A8R8G8B8 if (useLinearFormat) { // correct sizing information UncompressedSize -= Width * Height * 4; UncompressedSize += linearWidth * info.Height * 4; TotalDstPixels -= Width * Height; TotalDstPixels += linearWidth * info.Height; Waste = 100.f * (float)(linearWidth * info.Height - info.Width * info.Height) / (float)(linearWidth * info.Height); printf("LIN_A8R8G8B8 %4dx%-4d (%5.2f%% waste)\n", linearWidth, info.Height, Waste); TRACE0(" Selected Format: LIN_A8R8G8B8\n"); WriteXPR(OutFilename, info, pLinearSrcSurf, XB_D3DFMT_LIN_A8R8G8B8, NULL); } else { printf("A8R8G8B8 %4dx%-4d (%5.2f%% waste)\n", Width, Height, Waste); TRACE0(" Selected Format: A8R8G8B8\n"); WriteXPR(OutFilename, info, pSrcSurf, XB_D3DFMT_A8R8G8B8, NULL); } 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; }
//----------------------------------------------------------------------------- // 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; }