#include "texture.h" #include #include #include #pragma comment(lib, "windowscodecs.lib") // 为 MinGW 提供 COM 助手宏(MSVC 已内联提供) #ifndef _MSC_VER #define ID3D11ShaderResourceView_Release(p) (p)->lpVtbl->Release(p) #define ID3D11Texture2D_Release(p) (p)->lpVtbl->Release(p) #define ID3D11Device_CreateTexture2D(p,a,b,c) (p)->lpVtbl->CreateTexture2D(p,a,b,c) #define ID3D11Device_CreateShaderResourceView(p,a,b,c) (p)->lpVtbl->CreateShaderResourceView(p,a,b,c) #define ID3D11DeviceContext_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a) #define ID3D11DeviceContext_PSSetShaderResources(p,a,b,c) (p)->lpVtbl->PSSetShaderResources(p,a,b,c) #define ID3D11DeviceContext_PSSetSamplers(p,a,b,c) (p)->lpVtbl->PSSetSamplers(p,a,b,c) #define ID3D11Device_CreateSamplerState(p,a,b) (p)->lpVtbl->CreateSamplerState(p,a,b) #define IWICBitmapDecoder_GetFrame(p,a,b) (p)->lpVtbl->GetFrame(p,a,b) #define IWICBitmapFrameDecode_GetSize(p,a,b) (p)->lpVtbl->GetSize(p,a,b) #define IWICImagingFactory_CreateFormatConverter(p,a) (p)->lpVtbl->CreateFormatConverter(p,a) #define IWICFormatConverter_Initialize(p,a,b,c,d,e,f) (p)->lpVtbl->Initialize(p,a,b,c,d,e,f) #define IWICFormatConverter_CopyPixels(p,a,b,c,d) (p)->lpVtbl->CopyPixels(p,a,b,c,d) #define IWICFormatConverter_Release(p) (p)->lpVtbl->Release(p) #define IWICBitmapFrameDecode_Release(p) (p)->lpVtbl->Release(p) #define IWICImagingFactory_CreateDecoderFromFilename(p,a,b,c,d,e) (p)->lpVtbl->CreateDecoderFromFilename(p,a,b,c,d,e) #define IWICBitmapDecoder_Release(p) (p)->lpVtbl->Release(p) #define IWICImagingFactory_CreateStream(p,a) (p)->lpVtbl->CreateStream(p,a) #define IWICStream_InitializeFromMemory(p,a,b) (p)->lpVtbl->InitializeFromMemory(p,a,b) #define IWICImagingFactory_CreateDecoderFromStream(p,a,b,c,d) (p)->lpVtbl->CreateDecoderFromStream(p,a,b,c,d) #define IWICStream_Release(p) (p)->lpVtbl->Release(p) #endif 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; static ID3D11SamplerState* default_sampler = NULL; if (!default_sampler) { ID3D11Device* device = NULL; ctx->lpVtbl->GetDevice(ctx, &device); if (device) { D3D11_SAMPLER_DESC sd = {0}; sd.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; sd.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; sd.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; sd.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; sd.ComparisonFunc = D3D11_COMPARISON_NEVER; sd.MinLOD = 0; sd.MaxLOD = D3D11_FLOAT32_MAX; device->lpVtbl->CreateSamplerState(device, &sd, &default_sampler); device->lpVtbl->Release(device); } } ctx->lpVtbl->PSSetShaderResources(ctx, slot, 1, &texture->srv); ctx->lpVtbl->PSSetSamplers(ctx, slot, 1, &default_sampler); }