#include "texture.h" #include #include #include #pragma comment(lib, "windowscodecs.lib") static IWICImagingFactory* wic_factory = NULL; static HRESULT ensure_wic(void) { if (wic_factory) return S_OK; return CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (void**)&wic_factory); } Texture* texture_create(void) { return (Texture*)calloc(1, sizeof(Texture)); } void texture_destroy(Texture* texture) { if (!texture) return; if (texture->srv) ID3D11ShaderResourceView_Release(texture->srv); if (texture->texture) ID3D11Texture2D_Release(texture->texture); free(texture); } static Texture* create_from_wic(ID3D11Device* device, IWICBitmapDecoder* decoder) { IWICBitmapFrameDecode* frame = NULL; IWICBitmapDecoder_GetFrame(decoder, 0, &frame); uint32_t w, h; IWICBitmapFrameDecode_GetSize(frame, &w, &h); IWICFormatConverter* converter = NULL; IWICImagingFactory_CreateFormatConverter(wic_factory, &converter); IWICFormatConverter_Initialize(converter, (IWICBitmapSource*)frame, &GUID_WICPixelFormat32bppRGBA, WICBitmapDitherTypeNone, NULL, 0.0, WICBitmapPaletteTypeCustom); uint8_t* pixels = (uint8_t*)malloc(w * h * 4); IWICFormatConverter_CopyPixels(converter, NULL, w * 4, w * h * 4, pixels); IWICFormatConverter_Release(converter); IWICBitmapFrameDecode_Release(frame); D3D11_TEXTURE2D_DESC desc = {0}; desc.Width = w; desc.Height = h; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.SampleDesc.Count = 1; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; D3D11_SUBRESOURCE_DATA init = {pixels, w * 4, 0}; Texture* tex = texture_create(); ID3D11Device_CreateTexture2D(device, &desc, &init, &tex->texture); D3D11_SHADER_RESOURCE_VIEW_DESC srvd = {0}; srvd.Format = desc.Format; srvd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvd.Texture2D.MipLevels = 1; ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource*)tex->texture, &srvd, &tex->srv); tex->width = w; tex->height = h; tex->mip_levels = 1; free(pixels); return tex; } Texture* texture_load_from_file(ID3D11Device* device, const char* path) { if (FAILED(ensure_wic())) return NULL; IWICBitmapDecoder* decoder = NULL; wchar_t wpath[512]; MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, 512); HRESULT hr = IWICImagingFactory_CreateDecoderFromFilename(wic_factory, wpath, NULL, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &decoder); if (FAILED(hr)) return NULL; Texture* tex = create_from_wic(device, decoder); IWICBitmapDecoder_Release(decoder); return tex; } Texture* texture_load_from_memory(ID3D11Device* device, const uint8_t* data, uint32_t size) { if (FAILED(ensure_wic())) return NULL; IWICStream* stream = NULL; IWICImagingFactory_CreateStream(wic_factory, &stream); IWICStream_InitializeFromMemory(stream, (BYTE*)data, size); IWICBitmapDecoder* decoder = NULL; IWICImagingFactory_CreateDecoderFromStream(wic_factory, (IStream*)stream, NULL, WICDecodeMetadataCacheOnLoad, &decoder); IWICStream_Release(stream); if (!decoder) return NULL; Texture* tex = create_from_wic(device, decoder); IWICBitmapDecoder_Release(decoder); return tex; } Texture* texture_create_solid(ID3D11Device* device, uint32_t w, uint32_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { uint8_t* pixels = (uint8_t*)malloc(w * h * 4); for (uint32_t i = 0; i < w * h; i++) { pixels[i * 4 + 0] = r; pixels[i * 4 + 1] = g; pixels[i * 4 + 2] = b; pixels[i * 4 + 3] = a; } D3D11_TEXTURE2D_DESC desc = {0}; desc.Width = w; desc.Height = h; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.SampleDesc.Count = 1; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; D3D11_SUBRESOURCE_DATA init = {pixels, w * 4, 0}; Texture* tex = texture_create(); ID3D11Device_CreateTexture2D(device, &desc, &init, &tex->texture); D3D11_SHADER_RESOURCE_VIEW_DESC srvd = {0}; srvd.Format = desc.Format; srvd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvd.Texture2D.MipLevels = 1; ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource*)tex->texture, &srvd, &tex->srv); tex->width = w; tex->height = h; free(pixels); return tex; } Texture* texture_create_checkerboard(ID3D11Device* device, uint32_t size, uint32_t checks) { uint8_t* pixels = (uint8_t*)malloc(size * size * 4); uint32_t cell = size / checks; for (uint32_t y = 0; y < size; y++) { for (uint32_t x = 0; x < size; x++) { uint8_t c = ((x / cell) + (y / cell)) % 2 ? 200 : 55; uint32_t i = (y * size + x) * 4; pixels[i] = pixels[i + 1] = pixels[i + 2] = c; pixels[i + 3] = 255; } } D3D11_TEXTURE2D_DESC desc = {0}; desc.Width = size; desc.Height = size; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.SampleDesc.Count = 1; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; D3D11_SUBRESOURCE_DATA init = {pixels, size * 4, 0}; Texture* tex = texture_create(); ID3D11Device_CreateTexture2D(device, &desc, &init, &tex->texture); D3D11_SHADER_RESOURCE_VIEW_DESC srvd = {0}; srvd.Format = desc.Format; srvd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvd.Texture2D.MipLevels = 1; ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource*)tex->texture, &srvd, &tex->srv); tex->width = size; tex->height = size; free(pixels); return tex; } void texture_bind(Texture* texture, ID3D11DeviceContext* ctx, uint32_t slot) { if (!texture || !texture->srv) return; ID3D11DeviceContext_PSSetShaderResources(ctx, slot, 1, &texture->srv); ID3D11DeviceContext_PSSetSamplers(ctx, slot, 1, &(ID3D11SamplerState*){NULL}); }