blob: a7022a7d9727b1014af79f583472bae9d8a92f21 [file] [log] [blame]
#include "basisthumbprovider.h"
#include <Shlwapi.h>
#include "basisu_transcoder.h"
#include "helpers.h"
#pragma comment(lib, "Shlwapi.lib")
using namespace basist;
static etc1_global_selector_codebook* globalCodebook = NULL;
BasisThumbProvider::BasisThumbProvider() : count(1), stream(NULL) {
dprintf("BasisThumbProvider ctor");
basisu_transcoder_init();
if (!globalCodebook) {
globalCodebook = new etc1_global_selector_codebook(g_global_selector_cb_size, g_global_selector_cb);
}
}
BasisThumbProvider::~BasisThumbProvider() {
dprintf("BasisThumbProvider **dtor**");
if (stream) {
stream->Release();
stream = NULL;
}
}
IFACEMETHODIMP BasisThumbProvider::QueryInterface(REFIID riid, void **ppv) {
static const QITAB qit[] = {
QITABENT(BasisThumbProvider, IThumbnailProvider),
QITABENT(BasisThumbProvider, IInitializeWithStream),
{0},
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) BasisThumbProvider::AddRef() {
return InterlockedIncrement(&count);
}
IFACEMETHODIMP_(ULONG) BasisThumbProvider::Release() {
LONG refs = InterlockedDecrement(&count);
if (refs == 0) {
delete this;
}
return refs;
}
IFACEMETHODIMP BasisThumbProvider::Initialize(IStream *pStream, DWORD grfMode) {
dprintf("BasisThumbProvider::Initialize");
HRESULT hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
if (!stream) {
hr = pStream->QueryInterface(&stream);
}
return hr;
}
// Note: thumbnails get written here: %LocalAppData%\Microsoft\Windows\Explorer
IFACEMETHODIMP BasisThumbProvider::GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha) {
STATSTG stat;
if (stream && SUCCEEDED(stream->Stat(&stat, STATFLAG_NONAME))) {
if (void* data = malloc(static_cast<size_t>(stat.cbSize.LowPart))) {
ULONG size = 0;
if (SUCCEEDED(stream->Read(data, static_cast<ULONG>(stat.cbSize.LowPart), &size))) {
if (size == stat.cbSize.LowPart) {
basisu_transcoder transcoder(globalCodebook);
if (transcoder.validate_header(data, size)) {
dprintf("Requested %d bytes for %dx%d image", size, cx, cx);
basisu_image_info info;
if (transcoder.get_image_info(data, size, info, 0)) {
uint32_t level = 0;
uint32_t descW = 0, descH = 0, blocks;
for (uint32_t n = 0; n < info.m_total_levels; n++) {
if (transcoder.get_image_level_desc(data, size, 0, n, descW, descH, blocks)) {
dprintf("mipmap level w: %d, h: %d (blocks: %d)", descW, descH, blocks);
if (cx >= std::max(descW, descH)) {
level = n;
break;
}
}
}
basisu_file_info fileInfo;
transcoder.get_file_info(data, size, fileInfo);
if (transcoder.start_transcoding(data, size)) {
if (void* dxtBuf = malloc(basis_get_bytes_per_block(cTFBC1) * blocks)) {
if (transcoder.transcode_image_level(data, size, 0, level, dxtBuf, blocks, cTFBC1)) {
dprintf("Decoded!!!!");
*phbmp = dxtToBitmap(static_cast<uint8_t*>(dxtBuf), descW, descH, fileInfo.m_y_flipped);
}
delete dxtBuf;
}
}
}
}
}
}
free(data);
}
}
return (*phbmp) ? S_OK : S_FALSE;
}
//********************************** Factory *********************************/
BasisThumbProviderFactory::BasisThumbProviderFactory() : count(1) {}
BasisThumbProviderFactory::~BasisThumbProviderFactory() {}
IFACEMETHODIMP BasisThumbProviderFactory::QueryInterface(REFIID riid, void **ppv) {
static const QITAB qit[] = {
QITABENT(BasisThumbProviderFactory, IClassFactory),
{0},
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) BasisThumbProviderFactory::AddRef() {
return InterlockedIncrement(&count);
}
IFACEMETHODIMP_(ULONG) BasisThumbProviderFactory::Release() {
LONG refs = InterlockedDecrement(&count);
if (refs == 0) {
delete this;
}
return refs;
}
IFACEMETHODIMP BasisThumbProviderFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv) {
HRESULT hr = CLASS_E_NOAGGREGATION;
if (pUnkOuter == NULL) {
hr = E_OUTOFMEMORY;
if (BasisThumbProvider* provider = new (std::nothrow) BasisThumbProvider()) {
hr = provider->QueryInterface(riid, ppv);
provider->Release();
}
}
return hr;
}
IFACEMETHODIMP BasisThumbProviderFactory::LockServer(BOOL fLock) {
if (fLock) {
InterlockedIncrement(&count);
} else {
InterlockedDecrement(&count);
}
return S_OK;
}