Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

457 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()
{
if (InterlockedDecrement(&m_cRef))
return m_cRef;
delete this;
return 0;
}
HRESULT CTexture::QueryInterface(REFIID riid, void **ppvObj)
{
static const QITAB qit[] =
{
QITABENT(CTexture, IUnknown),
{ 0 },
};
return QISearch(this, qit, riid, ppvObj);
}