You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
459 lines
16 KiB
459 lines
16 KiB
/*****************************************************************************\
|
|
FILE: texture.cpp
|
|
|
|
DESCRIPTION:
|
|
Manage a texture for several instance for each monitor. Also manage keeping the
|
|
ratio correct when it's not square when loaded.
|
|
|
|
BryanSt 2/9/2000
|
|
Copyright (C) Microsoft Corp 2000-2001. All rights reserved.
|
|
\*****************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "texture.h"
|
|
#include "util.h"
|
|
|
|
|
|
int g_nTotalTexturesLoaded = 0;
|
|
int g_nTexturesRenderedInThisFrame = 0;
|
|
|
|
|
|
CTexture::CTexture(CMSLogoDXScreenSaver * pMain, LPCTSTR pszPath, LPVOID pvBits, DWORD cbSize)
|
|
{
|
|
_Init(pMain);
|
|
|
|
Str_SetPtr(&m_pszPath, pszPath);
|
|
m_pvBits = pvBits;
|
|
m_cbSize = cbSize;
|
|
}
|
|
|
|
|
|
CTexture::CTexture(CMSLogoDXScreenSaver * pMain, LPCTSTR pszPath, LPCTSTR pszResource, float fScale)
|
|
{
|
|
_Init(pMain);
|
|
Str_SetPtr(&m_pszPath, pszPath);
|
|
Str_SetPtr(&m_pszResource, pszResource);
|
|
m_fScale = fScale;
|
|
}
|
|
|
|
|
|
CTexture::~CTexture()
|
|
{
|
|
Str_SetPtr(&m_pszResource, NULL);
|
|
Str_SetPtr(&m_pszPath, NULL);
|
|
if (m_pvBits)
|
|
{
|
|
LocalFree(m_pvBits);
|
|
m_pvBits = NULL;
|
|
m_cbSize = 0;
|
|
}
|
|
|
|
for (int nIndex = 0; nIndex < ARRAYSIZE(m_pTexture); nIndex++)
|
|
{
|
|
if (m_pTexture[nIndex])
|
|
{
|
|
SAFE_RELEASE(m_pTexture[nIndex]);
|
|
g_nTotalTexturesLoaded--;
|
|
}
|
|
}
|
|
|
|
m_pMain = NULL;
|
|
}
|
|
|
|
|
|
void CTexture::_Init(CMSLogoDXScreenSaver * pMain)
|
|
{
|
|
m_pszResource = NULL;
|
|
m_fScale = 1.0f;
|
|
m_pszPath = NULL;
|
|
m_pvBits = NULL;
|
|
m_cbSize = 0;
|
|
|
|
m_dxImageInfo.Width = 0;
|
|
m_dxImageInfo.Height = 0;
|
|
m_dxImageInfo.Depth = 0;
|
|
m_dxImageInfo.MipLevels = 0;
|
|
m_dxImageInfo.Format = D3DFMT_UNKNOWN;
|
|
|
|
for (int nIndex = 0; nIndex < ARRAYSIZE(m_pTexture); nIndex++)
|
|
{
|
|
m_pTexture[nIndex] = NULL;
|
|
}
|
|
|
|
m_cRef = 1;
|
|
m_pMain = pMain;
|
|
}
|
|
|
|
|
|
BOOL CTexture::IsLoadedInAnyDevice(void)
|
|
{
|
|
BOOL fIsLoaded = FALSE;
|
|
|
|
for (int nIndex = 0; nIndex < ARRAYSIZE(m_pTexture); nIndex++)
|
|
{
|
|
if (m_pTexture[nIndex])
|
|
{
|
|
fIsLoaded = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return fIsLoaded;
|
|
}
|
|
|
|
|
|
BOOL CTexture::IsLoadedForThisDevice(void)
|
|
{
|
|
BOOL fIsLoaded = FALSE;
|
|
|
|
if (m_pMain)
|
|
{
|
|
int nCurrMonitor = m_pMain->GetCurrMonitorIndex();
|
|
|
|
if (m_pTexture[nCurrMonitor])
|
|
{
|
|
fIsLoaded = TRUE;
|
|
}
|
|
}
|
|
|
|
return fIsLoaded;
|
|
}
|
|
|
|
|
|
HRESULT CTexture::_GetPictureInfo(HRESULT hr, LPTSTR pszString, DWORD cchSize)
|
|
{
|
|
int nCurrMonitor = m_pMain->GetCurrMonitorIndex();
|
|
|
|
StrCpyN(pszString, TEXT("<NoInfo>"), cchSize);
|
|
if (SUCCEEDED(hr) && m_pTexture[nCurrMonitor] && m_pMain)
|
|
{
|
|
D3DSURFACE_DESC d3dSurfaceDesc;
|
|
|
|
if (SUCCEEDED(m_pTexture[nCurrMonitor]->GetLevelDesc(0, &d3dSurfaceDesc)))
|
|
{
|
|
wnsprintf(pszString, cchSize, TEXT("Size Orig=<%d,%d> Now=<%d,%d>"),
|
|
m_dxImageInfo.Width, m_dxImageInfo.Height, d3dSurfaceDesc.Width, d3dSurfaceDesc.Height);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
BOOL CTexture::_DoesImageNeedClipping(int * pnNewWidth, int * pnNewHeight)
|
|
{
|
|
BOOL fClip = FALSE;
|
|
|
|
*pnNewWidth = 512;
|
|
*pnNewHeight = 512;
|
|
if (m_pMain)
|
|
{
|
|
int nScreenWidth;
|
|
int nScreenHeight;
|
|
int nCurrMonitor = m_pMain->GetCurrMonitorIndex();
|
|
D3DSURFACE_DESC d3dSurfaceDesc;
|
|
|
|
if (FAILED(m_pMain->GetCurrentScreenSize(&nScreenWidth, &nScreenHeight)))
|
|
{
|
|
nScreenWidth = 800; // Fall back values
|
|
nScreenHeight = 600;
|
|
}
|
|
|
|
if (!m_pTexture[nCurrMonitor] ||
|
|
FAILED(m_pTexture[nCurrMonitor]->GetLevelDesc(0, &d3dSurfaceDesc)))
|
|
{
|
|
d3dSurfaceDesc.Width = 800; // default values
|
|
d3dSurfaceDesc.Height = 800; // default values
|
|
}
|
|
|
|
int nCapWidth = 256;
|
|
int nCapHeight = 256;
|
|
|
|
if (d3dSurfaceDesc.Width > 256)
|
|
{
|
|
if (d3dSurfaceDesc.Width > 300)
|
|
{
|
|
nCapWidth = 512;
|
|
|
|
if (d3dSurfaceDesc.Width > 512)
|
|
{
|
|
if (d3dSurfaceDesc.Width > 640) // 615 is 20% larger than 512
|
|
{
|
|
nCapWidth = 1024;
|
|
if (d3dSurfaceDesc.Width > 1024) // 615 is 20% larger than 512
|
|
{
|
|
fClip = TRUE; // We don't want it any larger than this
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fClip = TRUE; // We are forcing it down to 512
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fClip = TRUE; // We are forcing it down to 256
|
|
}
|
|
}
|
|
|
|
if (d3dSurfaceDesc.Height > 256)
|
|
{
|
|
if (d3dSurfaceDesc.Height > 300)
|
|
{
|
|
nCapHeight = 512;
|
|
|
|
if (d3dSurfaceDesc.Height > 512)
|
|
{
|
|
if (d3dSurfaceDesc.Height > 640) // 615 is 20% larger than 512
|
|
{
|
|
nCapHeight = 1024;
|
|
if (d3dSurfaceDesc.Height > 1024) // 615 is 20% larger than 512
|
|
{
|
|
fClip = TRUE; // We don't want it any larger than this
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fClip = TRUE; // We are forcing it down to 512
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fClip = TRUE; // We are forcing it down to 256
|
|
}
|
|
}
|
|
|
|
if ((FALSE == fClip) && m_pMain->UseSmallImages())
|
|
{
|
|
// The caller wants to make sure we don't use anything larger than 512.
|
|
if (512 < nCapHeight)
|
|
{
|
|
nCapHeight = 512;
|
|
fClip = TRUE;
|
|
}
|
|
|
|
if (512 < nCapWidth)
|
|
{
|
|
nCapWidth = 512;
|
|
fClip = TRUE;
|
|
}
|
|
}
|
|
|
|
*pnNewWidth = nCapWidth;
|
|
*pnNewHeight = nCapHeight;
|
|
}
|
|
|
|
return fClip;
|
|
}
|
|
|
|
IDirect3DTexture8 * CTexture::GetTexture(float * pfScale)
|
|
{
|
|
IDirect3DTexture8 * pTexture = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
TCHAR szPictureInfo[MAX_PATH];
|
|
|
|
if (pfScale)
|
|
{
|
|
*pfScale = m_fScale;
|
|
}
|
|
|
|
// PERF NOTES: Often the background thread will only spend 107ms to load the file (ReadFile)
|
|
// but it will take the forground thread 694ms in D3DXCreateTextureFromFileInMemoryEx to
|
|
// load and decode the file. This is because more memory is needed after the file is finished
|
|
// being compressed and it takes a while to decompress. After this, if the image is too large,
|
|
// it will need to call D3DXCreateTextureFromFileInMemoryEx in order to load it into a smaller
|
|
// size, which will take 902ms.
|
|
// TODO: How should we solve this?
|
|
if (m_pMain)
|
|
{
|
|
int nCurrMonitor = m_pMain->GetCurrMonitorIndex();
|
|
|
|
pTexture = m_pTexture[nCurrMonitor];
|
|
if (!pTexture) // Cache is empty, so populate it.
|
|
{
|
|
if (m_pvBits)
|
|
{
|
|
DebugStartWatch();
|
|
hr = D3DXCreateTextureFromFileInMemoryEx(m_pMain->GetD3DDevice(), m_pvBits, m_cbSize,
|
|
D3DX_DEFAULT /* Size X*/, D3DX_DEFAULT /* Size Y*/, 5/*MIP Levels*/, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR,
|
|
D3DX_FILTER_BOX, 0, &m_dxImageInfo, NULL,
|
|
&(m_pTexture[nCurrMonitor]));
|
|
_GetPictureInfo(hr, szPictureInfo, ARRAYSIZE(szPictureInfo));
|
|
DXUtil_Trace(TEXT("PICTURE: It took %d ms for D3DXCreateTextureFromFileInMemoryEx(\"%ls\"). %s hr=%#08lx\n"), DebugStopWatch(), m_pszPath, szPictureInfo, hr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
int nNewWidth;
|
|
int nNewHeight;
|
|
|
|
g_nTotalTexturesLoaded++;
|
|
|
|
// In order to save memory, we never want to load images over 800x600. If the render surface is small, we want to use
|
|
// even smaller max sizes.
|
|
if (_DoesImageNeedClipping(&nNewWidth, &nNewHeight))
|
|
{
|
|
SAFE_RELEASE(m_pTexture[nCurrMonitor]);
|
|
g_nTotalTexturesLoaded--;
|
|
|
|
DebugStartWatch();
|
|
// Now we found that we want to re-render the image, but this time shrink it, then we do that now.
|
|
hr = D3DXCreateTextureFromFileInMemoryEx(m_pMain->GetD3DDevice(), m_pvBits, m_cbSize,
|
|
nNewWidth /* Size X*/, nNewHeight /* Size Y*/, 5/*MIP Levels*/, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR,
|
|
D3DX_FILTER_BOX, 0, &m_dxImageInfo, NULL,
|
|
&(m_pTexture[nCurrMonitor]));
|
|
_GetPictureInfo(hr, szPictureInfo, ARRAYSIZE(szPictureInfo));
|
|
DXUtil_Trace(TEXT("PICTURE: It took %d ms for D3DXCreateTextureFromFileInMemoryEx(\"%ls\") 2nd time. %s hr=%#08lx\n"), DebugStopWatch(), m_pszPath, szPictureInfo, hr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
g_nTotalTexturesLoaded++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// This will give people a chance to customize the images.
|
|
if (m_pszPath && PathFileExists(m_pszPath))
|
|
{
|
|
int nOrigX;
|
|
int nOrigY;
|
|
|
|
DebugStartWatch();
|
|
hr = D3DXCreateTextureFromFileEx(m_pMain->GetD3DDevice(), m_pszPath,
|
|
D3DX_DEFAULT /* Size X*/, D3DX_DEFAULT /* Size Y*/, 5/*MIP Levels*/, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR,
|
|
D3DX_FILTER_BOX, 0, &m_dxImageInfo, NULL,
|
|
&(m_pTexture[nCurrMonitor]));
|
|
_GetPictureInfo(hr, szPictureInfo, ARRAYSIZE(szPictureInfo));
|
|
DXUtil_Trace(TEXT("PICTURE: It took %d ms for FromFileEx(\"%ls\"). %s hr=%#08lx\n"),
|
|
DebugStopWatch(), (PathFindFileName(m_pszPath) ? PathFindFileName(m_pszPath) : m_pszPath), szPictureInfo, hr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
int nNewWidth;
|
|
int nNewHeight;
|
|
|
|
g_nTotalTexturesLoaded++;
|
|
|
|
// In order to save memory, we never want to load images over 800x600. If the render surface is small, we want to use
|
|
// even smaller max sizes.
|
|
if (_DoesImageNeedClipping(&nNewWidth, &nNewHeight))
|
|
{
|
|
SAFE_RELEASE(m_pTexture[nCurrMonitor]);
|
|
g_nTotalTexturesLoaded--;
|
|
|
|
DebugStartWatch();
|
|
// Now we found that we want to re-render the image, but this time shrink it, then we do that now.
|
|
hr = D3DXCreateTextureFromFileEx(m_pMain->GetD3DDevice(), m_pszPath,
|
|
nNewWidth /* Size X*/, nNewHeight /* Size Y*/, 5/*MIP Levels*/, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR,
|
|
D3DX_FILTER_BOX, 0, &m_dxImageInfo, NULL,
|
|
&(m_pTexture[nCurrMonitor]));
|
|
_GetPictureInfo(hr, szPictureInfo, ARRAYSIZE(szPictureInfo));
|
|
DXUtil_Trace(TEXT("PICTURE: It took %d ms for FromFileEx(\"%ls\") 2nd time. %s hr=%#08lx\n"),
|
|
DebugStopWatch(), (PathFindFileName(m_pszPath) ? PathFindFileName(m_pszPath) : m_pszPath), szPictureInfo, hr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
g_nTotalTexturesLoaded++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We failed to load the picture, so it may be a type we don't support,
|
|
// like .gif. So stop trying to load it.
|
|
Str_SetPtr(&m_pszPath, NULL);
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr) && m_pszResource)
|
|
{
|
|
// Now, let's grab our standard value.
|
|
int nMipLevels = 5;
|
|
|
|
DebugStartWatch();
|
|
hr = D3DXCreateTextureFromResourceEx(m_pMain->GetD3DDevice(), HINST_THISDLL, m_pszResource,
|
|
D3DX_DEFAULT /* Size X*/, D3DX_DEFAULT /* Size Y*/, nMipLevels/*MIP Levels*/, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR,
|
|
D3DX_FILTER_BOX, 0, &m_dxImageInfo, NULL,
|
|
&(m_pTexture[nCurrMonitor]));
|
|
_GetPictureInfo(hr, szPictureInfo, ARRAYSIZE(szPictureInfo));
|
|
DXUtil_Trace(TEXT("PICTURE: It took %d ms for D3DXCreateTextureFromResourceEx(\"%ls\"). %s hr=%#08lx\n"), DebugStopWatch(), m_pszResource, szPictureInfo, hr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
int nNewWidth;
|
|
int nNewHeight;
|
|
|
|
g_nTotalTexturesLoaded++;
|
|
|
|
// In order to save memory, we never want to load images over 800x600. If the render surface is small, we want to use
|
|
// even smaller max sizes.
|
|
if (_DoesImageNeedClipping(&nNewWidth, &nNewHeight))
|
|
{
|
|
SAFE_RELEASE(m_pTexture[nCurrMonitor]);
|
|
g_nTotalTexturesLoaded--;
|
|
|
|
DebugStartWatch();
|
|
// Now we found that we want to re-render the image, but this time shrink it, then we do that now.
|
|
hr = D3DXCreateTextureFromResourceEx(m_pMain->GetD3DDevice(), HINST_THISDLL, m_pszResource,
|
|
nNewWidth /* Size X*/, nNewHeight /* Size Y*/, 5/*MIP Levels*/, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR,
|
|
D3DX_FILTER_BOX, 0, &m_dxImageInfo, NULL,
|
|
&(m_pTexture[nCurrMonitor]));
|
|
_GetPictureInfo(hr, szPictureInfo, ARRAYSIZE(szPictureInfo));
|
|
DXUtil_Trace(TEXT("PICTURE: It took %d ms for D3DXCreateTextureFromResourceEx(\"%ls\") 2nd time. %s hr=%#08lx\n"), DebugStopWatch(), m_pszResource, szPictureInfo, hr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
g_nTotalTexturesLoaded++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We failed to load the picture, so it may be a type we don't support,
|
|
// like .gif. So stop trying to load it.
|
|
Str_SetPtr(&m_pszPath, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
pTexture = m_pTexture[nCurrMonitor];
|
|
}
|
|
}
|
|
|
|
return pTexture;
|
|
}
|
|
|
|
|
|
|
|
//===========================
|
|
// *** IUnknown Interface ***
|
|
//===========================
|
|
ULONG CTexture::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
|
|
ULONG CTexture::Release()
|
|
{
|
|
ASSERT( 0 != m_cRef );
|
|
ULONG cRef = InterlockedDecrement(&m_cRef);
|
|
if ( 0 == cRef )
|
|
{
|
|
delete this;
|
|
}
|
|
return cRef;
|
|
}
|
|
|
|
|
|
HRESULT CTexture::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
static const QITAB qit[] =
|
|
{
|
|
QITABENT(CTexture, IUnknown),
|
|
{ 0 },
|
|
};
|
|
|
|
return QISearch(this, qit, riid, ppvObj);
|
|
}
|