|
|
/*****************************************************************************\
FILE: pictures.cpp
DESCRIPTION: Manage the pictures in the user's directories. Convert them when needed. Handle caching and making sure we don't use too much diskspace. Also add picture frame when needed.
BryanSt 12/24/2000 Copyright (C) Microsoft Corp 2000-2001. All rights reserved. \*****************************************************************************/
#include "stdafx.h"
#include <shlobj.h>
#include "pictures.h"
#include "util.h"
#undef __IShellFolder2_FWD_DEFINED__
#include <ccstock.h>
CPictureManager * g_pPictureMgr = NULL;
int CALLBACK DSACallback_FreePainting(LPVOID p, LPVOID pData) { SSPICTURE_INFO * pPInfo = (SSPICTURE_INFO *) p;
if (pPInfo) { Str_SetPtr(&pPInfo->pszPath, NULL); }
return 1; }
CPictureManager::CPictureManager(CMSLogoDXScreenSaver * pMain) { m_nCurrent = 0; m_hdsaPictures = NULL;
m_pMain = pMain;
m_hdsaBatches = 0; m_nCurrentBatch = 0;
_EnumPaintings(); }
CPictureManager::~CPictureManager() { if (m_hdsaBatches) { DSA_Destroy(m_hdsaBatches); m_hdsaBatches = NULL; }
if (m_hdsaPictures) { DSA_DestroyCallback(m_hdsaPictures, DSACallback_FreePainting, NULL); m_hdsaPictures = NULL; }
m_pMain = NULL; }
HRESULT CPictureManager::_PInfoCreate(int nIndex, LPCTSTR pszPath) { HRESULT hr = S_OK; SSPICTURE_INFO pInfo = {0};
pInfo.fInABatch = FALSE; pInfo.pszPath = NULL; Str_SetPtr(&pInfo.pszPath, pszPath);
// We add them in a random order so the pattern doesn't get boring.
if (-1 == DSA_InsertItem(m_hdsaPictures, nIndex, &pInfo)) { // We failed so free the memory
Str_SetPtr(&pInfo.pszPath, NULL); hr = E_OUTOFMEMORY; }
return S_OK; }
HRESULT CPictureManager::_AddPaintingsFromDir(LPCTSTR pszPath) { HRESULT hr = E_OUTOFMEMORY;
if (!m_hdsaPictures) { m_hdsaPictures = DSA_Create(sizeof(SSPICTURE_INFO), 20); }
if (m_hdsaPictures) { TCHAR szSearch[MAX_PATH]; WIN32_FIND_DATA findFileData;
hr = S_OK; StrCpyN(szSearch, pszPath, ARRAYSIZE(szSearch)); PathAppend(szSearch, TEXT("*.*")); HANDLE hFindFiles = FindFirstFile(szSearch, &findFileData); if (INVALID_HANDLE_VALUE != hFindFiles) { while ((INVALID_HANDLE_VALUE != hFindFiles)) { if (!PathIsDotOrDotDot(findFileData.cFileName)) { if (!(FILE_ATTRIBUTE_DIRECTORY & findFileData.dwFileAttributes)) { LPCTSTR pszExt = PathFindExtension(findFileData.cFileName);
if (pszExt && pszExt[0] && (!StrCmpI(pszExt, TEXT(".bmp")) || !StrCmpI(pszExt, TEXT(".jpg")) || !StrCmpI(pszExt, TEXT(".jpeg")) || !StrCmpI(pszExt, TEXT(".png")) // || !StrCmpI(pszExt, TEXT(".gif"))
|| !StrCmpI(pszExt, TEXT(".tiff")) )) { int nInsertLoc = GetRandomInt(0, max(0, DSA_GetItemCount(m_hdsaPictures) - 1));
StrCpyN(szSearch, pszPath, ARRAYSIZE(szSearch)); PathAppend(szSearch, findFileData.cFileName);
hr = _PInfoCreate(nInsertLoc, szSearch); } } else { StrCpyN(szSearch, pszPath, ARRAYSIZE(szSearch)); PathAppend(szSearch, findFileData.cFileName); hr = _AddPaintingsFromDir(szSearch); } }
if (!FindNextFile(hFindFiles, &findFileData)) { break; } }
FindClose(hFindFiles); } }
return hr; }
HRESULT CPictureManager::_EnumPaintings(void) { HRESULT hr = E_FAIL; TCHAR szDir[MAX_PATH];
if (g_pConfig) { hr = S_OK; if (g_pConfig->GetFolderOn(CONFIG_FOLDER_MYPICTS) && SHGetSpecialFolderPath(NULL, szDir, CSIDL_MYPICTURES, TRUE)) { hr = _AddPaintingsFromDir(szDir); }
if (g_pConfig->GetFolderOn(CONFIG_FOLDER_COMMONPICTS)) { // TODO: When Common Pictures are added.
}
if (g_pConfig->GetFolderOn(CONFIG_FOLDER_OTHER) && SUCCEEDED(g_pConfig->GetOtherDir(szDir, ARRAYSIZE(szDir)))) { hr = _AddPaintingsFromDir(szDir); }
// If we have less than 10 paintings, then we force add the
// Windows wallpapers.
if ((g_pConfig->GetFolderOn(CONFIG_FOLDER_WINPICTS) || (10 > DSA_GetItemCount(m_hdsaPictures))) && SHGetSpecialFolderPath(NULL, szDir, CSIDL_WINDOWS, TRUE)) { PathAppend(szDir, TEXT("Web\\Wallpaper")); hr = _AddPaintingsFromDir(szDir); }
if (m_hdsaPictures) { m_nCurrent = GetRandomInt(0, max(0, DSA_GetItemCount(m_hdsaPictures) - 1)); } }
return hr; }
HRESULT CPictureManager::_LoadTexture(SSPICTURE_INFO * pInfo, BOOL fFaultInTexture) { // We keep trying until we hit the end. We give up after that.
HRESULT hr = E_INVALIDARG;
if (pInfo) { if (!pInfo->pTexture) { pInfo->pTexture = new CTexture(m_pMain, pInfo->pszPath, NULL, 1.0f); }
hr = (pInfo->pTexture ? S_OK : E_OUTOFMEMORY);
if (pInfo->pTexture && fFaultInTexture) { pInfo->pTexture->GetTexture(NULL); // Force the image to be paged in.
} }
return hr; }
#define GNPF_NONE 0x00000000
#define GNPF_ALREADYLOADED 0x00000001
#define GNPF_FAULTINTEXTURE 0x00000002
#define GNPF_ALLOWALREADYINBATCH 0x00000004
HRESULT CPictureManager::_TryGetNextPainting(SSPICTURE_INFO ** ppInfo, DWORD dwFlags) { // We keep trying until we hit the end. We give up after that.
HRESULT hr = E_FAIL;
while (m_hdsaPictures && FAILED(hr) && (m_nCurrent < DSA_GetItemCount(m_hdsaPictures))) { SSPICTURE_INFO * pPInfo = (SSPICTURE_INFO *) DSA_GetItemPtr(m_hdsaPictures, m_nCurrent);
if (pPInfo && pPInfo->pszPath) { if (!pPInfo->fInABatch || (dwFlags & GNPF_ALLOWALREADYINBATCH)) { if (dwFlags & GNPF_ALREADYLOADED) { if (pPInfo->pTexture && pPInfo->pTexture->IsLoadedInAnyDevice()) { // The caller only wants an object that's already pre-fetched, and we just found one.
*ppInfo = pPInfo; pPInfo->fInABatch = TRUE; hr = S_OK; } } else { // The caller is happen to this now. We only get this far if we failed to load it.
hr = _LoadTexture(pPInfo, (dwFlags & GNPF_FAULTINTEXTURE)); if (SUCCEEDED(hr)) { *ppInfo = pPInfo; pPInfo->fInABatch = TRUE; } } } }
m_nCurrent++; }
return hr; }
HRESULT CPictureManager::_GetNextWithWrap(SSPICTURE_INFO ** ppInfo, BOOL fAlreadyLoaded, BOOL fFaultInTexture) { DWORD dwFlags = ((fAlreadyLoaded ? GNPF_ALREADYLOADED : GNPF_NONE) | (fFaultInTexture ? GNPF_FAULTINTEXTURE : GNPF_NONE));
*ppInfo = NULL; HRESULT hr = _TryGetNextPainting(ppInfo, dwFlags);
if (m_nCurrent >= DSA_GetItemCount(m_hdsaPictures)) { m_nCurrent = 0; if (FAILED(hr)) { // Maybe it was necessary to wrap. We don't loop to prevent infinite recursion in corner cases.
hr = _TryGetNextPainting(ppInfo, dwFlags); if (FAILED(hr)) { // Maybe we have so few paintings available that we need to reuse.
m_nCurrent = 0; hr = _TryGetNextPainting(ppInfo, (dwFlags | GNPF_ALLOWALREADYINBATCH)); } } }
if (SUCCEEDED(hr) && (10 < DSA_GetItemCount(m_hdsaPictures)) && (1 == GetRandomInt(0, 4))) { // There is a one in for chance we want to skip pictures. This will keep the order somewhat random
// while still not always going in the same order. We only do this if the user has more than 10
// pictures or it may lap and the user will have the same picture twice in the same room.
m_nCurrent += GetRandomInt(1, 5); if (m_nCurrent >= DSA_GetItemCount(m_hdsaPictures)) { m_nCurrent = 0; } }
return hr; }
HRESULT CPictureManager::_CreateNewBatch(int nBatch, BOOL fFaultInTexture) { HRESULT hr = S_OK; SSPICTURES_BATCH batch = {0}; int nIndex;
for (nIndex = 0; (nIndex < ARRAYSIZE(batch.pInfo)) && SUCCEEDED(hr); nIndex++) { // First try and not get any dups
hr = _GetNextWithWrap(&(batch.pInfo[nIndex]), FALSE, fFaultInTexture); }
if (SUCCEEDED(hr)) { if (-1 == DSA_AppendItem(m_hdsaBatches, &batch)) { // We failed so free the memory
hr = E_OUTOFMEMORY; } }
return hr; }
///////////////////////////////////////////////////////////////////////
// FUNCTION: GetPainting
///////////////////////////////////////////////////////////////////////
HRESULT CPictureManager::GetPainting(int nBatch, int nIndex, DWORD dwFlags, CTexture ** ppTexture) { HRESULT hr = E_FAIL;
if (!m_hdsaBatches) { m_hdsaBatches = DSA_Create(sizeof(SSPICTURES_BATCH), 20); }
m_nCurrentBatch = max(m_nCurrentBatch, nBatch);
*ppTexture = NULL; if (m_hdsaPictures && m_hdsaBatches) { hr = S_OK;
while ((nBatch >= DSA_GetItemCount(m_hdsaBatches)) && SUCCEEDED(hr)) { hr = _CreateNewBatch(nBatch, TRUE); }
if (SUCCEEDED(hr)) { SSPICTURES_BATCH * pBatch = (SSPICTURES_BATCH *) DSA_GetItemPtr(m_hdsaBatches, nBatch);
if (pBatch && ((void *)-1 != pBatch) && pBatch->pInfo[nIndex] && pBatch->pInfo[nIndex]->pTexture) { IUnknown_Set((IUnknown **) ppTexture, (IUnknown *) pBatch->pInfo[nIndex]->pTexture); } else { hr = E_FAIL; } } }
return hr; }
///////////////////////////////////////////////////////////////////////
// FUNCTION: PreFetch
///////////////////////////////////////////////////////////////////////
HRESULT CPictureManager::PreFetch(int nBatch, int nToFetch) { HRESULT hr = S_OK;
while ((nBatch >= DSA_GetItemCount(m_hdsaBatches)) && SUCCEEDED(hr)) { hr = _CreateNewBatch(nBatch, FALSE); if (FAILED(hr)) { DXUtil_Trace(TEXT("ERROR: PreFetch() _CreateNewBatch failed. nBatch=%d\n"), nBatch); } }
SSPICTURES_BATCH * pBatch = (SSPICTURES_BATCH *) DSA_GetItemPtr(m_hdsaBatches, nBatch);
if (pBatch && (nToFetch < ARRAYSIZE(pBatch->pInfo))) { int nIndex;
for (nIndex = 0; (nIndex < ARRAYSIZE(pBatch->pInfo)) && nToFetch; nIndex++) { if (pBatch->pInfo[nIndex] && (!pBatch->pInfo[nIndex]->pTexture || !pBatch->pInfo[nIndex]->pTexture->IsLoadedForThisDevice())) { hr = _LoadTexture(pBatch->pInfo[nIndex], TRUE);
nToFetch--; } } } else { hr = E_FAIL; }
return hr; }
///////////////////////////////////////////////////////////////////////
// FUNCTION: ReleaseBatch
///////////////////////////////////////////////////////////////////////
HRESULT CPictureManager::ReleaseBatch(int nBatch) { HRESULT hr = E_INVALIDARG;
for (int nIndex = 0; nIndex < nBatch; nIndex++) { SSPICTURES_BATCH * pBatch = (SSPICTURES_BATCH *) DSA_GetItemPtr(m_hdsaBatches, nIndex);
for (int nIndex2 = 0; nIndex2 < ARRAYSIZE(pBatch->pInfo); nIndex2++) { if (pBatch && pBatch->pInfo[nIndex2] && (pBatch->pInfo[nIndex2]->fInABatch || pBatch->pInfo[nIndex2]->pTexture)) { ReleaseBatch(nIndex); DXUtil_Trace(TEXT("ERROR: ReleaseBatch() and previous batch aren't released. nBatch=%d, nIndex=%d\n"), nBatch, nIndex); break; } } }
if (nBatch < m_nCurrentBatch) { SSPICTURES_BATCH * pBatch = (SSPICTURES_BATCH *) DSA_GetItemPtr(m_hdsaBatches, nBatch);
if (pBatch && ((void *)-1 != pBatch)) { hr = S_OK; for (int nIndex = 0; (nIndex < ARRAYSIZE(pBatch->pInfo)); nIndex++) { if (pBatch->pInfo[nIndex]) { SAFE_RELEASE(pBatch->pInfo[nIndex]->pTexture); pBatch->pInfo[nIndex]->fInABatch = FALSE; pBatch->pInfo[nIndex] = NULL; } } } } else { DXUtil_Trace(TEXT("ERROR: ReleaseBatch() and batch is bad. nBatch=%d, m_nCurrentBatch=%d\n"), nBatch, m_nCurrentBatch); hr = E_UNEXPECTED; }
return hr; }
|