115 lines
3.9 KiB
C++
115 lines
3.9 KiB
C++
#include "TextureAssetLoader.h"
|
|
|
|
#include <windows.h>
|
|
#include <wincodec.h>
|
|
|
|
#include <atlbase.h>
|
|
#include <cstring>
|
|
#include <vector>
|
|
|
|
bool LoadTextureAsset(const ShaderTextureAsset& textureAsset, GLuint& textureId, std::string& error)
|
|
{
|
|
textureId = 0;
|
|
|
|
HRESULT comInitResult = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
const bool shouldUninitializeCom = (comInitResult == S_OK || comInitResult == S_FALSE);
|
|
if (FAILED(comInitResult) && comInitResult != RPC_E_CHANGED_MODE)
|
|
{
|
|
error = "Could not initialize COM to load shader texture assets.";
|
|
return false;
|
|
}
|
|
|
|
CComPtr<IWICImagingFactory> imagingFactory;
|
|
HRESULT result = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&imagingFactory));
|
|
if (FAILED(result) || !imagingFactory)
|
|
{
|
|
if (shouldUninitializeCom)
|
|
CoUninitialize();
|
|
error = "Could not create a WIC imaging factory to load shader texture assets.";
|
|
return false;
|
|
}
|
|
|
|
CComPtr<IWICBitmapDecoder> bitmapDecoder;
|
|
result = imagingFactory->CreateDecoderFromFilename(textureAsset.path.wstring().c_str(), NULL, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &bitmapDecoder);
|
|
if (FAILED(result) || !bitmapDecoder)
|
|
{
|
|
if (shouldUninitializeCom)
|
|
CoUninitialize();
|
|
error = "Could not open shader texture asset: " + textureAsset.path.string();
|
|
return false;
|
|
}
|
|
|
|
CComPtr<IWICBitmapFrameDecode> bitmapFrame;
|
|
result = bitmapDecoder->GetFrame(0, &bitmapFrame);
|
|
if (FAILED(result) || !bitmapFrame)
|
|
{
|
|
if (shouldUninitializeCom)
|
|
CoUninitialize();
|
|
error = "Could not decode the first frame of shader texture asset: " + textureAsset.path.string();
|
|
return false;
|
|
}
|
|
|
|
CComPtr<IWICFormatConverter> formatConverter;
|
|
result = imagingFactory->CreateFormatConverter(&formatConverter);
|
|
if (FAILED(result) || !formatConverter)
|
|
{
|
|
if (shouldUninitializeCom)
|
|
CoUninitialize();
|
|
error = "Could not create a WIC format converter for shader texture asset: " + textureAsset.path.string();
|
|
return false;
|
|
}
|
|
|
|
result = formatConverter->Initialize(bitmapFrame, GUID_WICPixelFormat32bppBGRA, WICBitmapDitherTypeNone, NULL, 0.0, WICBitmapPaletteTypeCustom);
|
|
if (FAILED(result))
|
|
{
|
|
if (shouldUninitializeCom)
|
|
CoUninitialize();
|
|
error = "Could not convert shader texture asset to BGRA: " + textureAsset.path.string();
|
|
return false;
|
|
}
|
|
|
|
UINT width = 0;
|
|
UINT height = 0;
|
|
result = formatConverter->GetSize(&width, &height);
|
|
if (FAILED(result) || width == 0 || height == 0)
|
|
{
|
|
if (shouldUninitializeCom)
|
|
CoUninitialize();
|
|
error = "Shader texture asset has an invalid size: " + textureAsset.path.string();
|
|
return false;
|
|
}
|
|
|
|
const UINT stride = width * 4;
|
|
std::vector<unsigned char> pixels(static_cast<std::size_t>(stride) * static_cast<std::size_t>(height));
|
|
result = formatConverter->CopyPixels(NULL, stride, static_cast<UINT>(pixels.size()), pixels.data());
|
|
if (FAILED(result))
|
|
{
|
|
if (shouldUninitializeCom)
|
|
CoUninitialize();
|
|
error = "Could not read shader texture pixels: " + textureAsset.path.string();
|
|
return false;
|
|
}
|
|
|
|
std::vector<unsigned char> flippedPixels(pixels.size());
|
|
for (UINT row = 0; row < height; ++row)
|
|
{
|
|
const std::size_t srcOffset = static_cast<std::size_t>(row) * stride;
|
|
const std::size_t dstOffset = static_cast<std::size_t>(height - 1 - row) * stride;
|
|
std::memcpy(flippedPixels.data() + dstOffset, pixels.data() + srcOffset, stride);
|
|
}
|
|
|
|
glGenTextures(1, &textureId);
|
|
glBindTexture(GL_TEXTURE_2D, textureId);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, static_cast<GLsizei>(width), static_cast<GLsizei>(height), 0, GL_BGRA, GL_UNSIGNED_BYTE, flippedPixels.data());
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
if (shouldUninitializeCom)
|
|
CoUninitialize();
|
|
|
|
return true;
|
|
}
|