Add ktx
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
#include "basisthumbprovider.h"
|
||||
|
||||
#include <Shlwapi.h>
|
||||
|
||||
#include "basisu_transcoder.cpp"
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
|
||||
using namespace basist;
|
||||
|
||||
BasisThumbProvider::BasisThumbProvider() : count(1), stream(NULL) {
|
||||
dprintf("BasisThumbProvider ctor");
|
||||
basisu_transcoder_init();
|
||||
}
|
||||
|
||||
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;
|
||||
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)) {
|
||||
uint32_t bytes = basis_get_uncompressed_bytes_per_pixel(transcoder_texture_format::cTFRGBA32) * descW * descH;
|
||||
dprintf("Started transcode (%dx%d @ %d bytes)", descW, descH, bytes);
|
||||
if (void* rgbBuf = malloc(bytes)) {
|
||||
// Note: the API expects total pixels here instead of blocks for cTFRGBA32
|
||||
if (transcoder.transcode_image_level(data, size, 0, level, rgbBuf, descW * descH, transcoder_texture_format::cTFRGBA32)) {
|
||||
dprintf("Decoded!!!!");
|
||||
*phbmp = rgbToBitmap(static_cast<uint32_t*>(rgbBuf), descW, descH, fileInfo.m_y_flipped);
|
||||
}
|
||||
delete rgbBuf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user