| #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; | 
 | } |