Files
lity3d/Engine/Rendering/texture.c
T
shuiyu1123 0669d102ce feat: major engine overhaul - scene demo with lighting, sphere, ground
- Scene Demo: cube + sphere + ground plane with proper lighting
- Audio: XAudio2 dynamic loading + WAV playback
- Physics: expanded collision system
- Renderer: improved pipeline with materials
- UI: extended widget system
- VisualScript: enhanced serializer + block interactions
- ASM: optimized math/memory/profiling routines
- Window: mouse input + scroll support
2026-07-12 08:21:07 +08:00

232 lines
8.7 KiB
C

#include "texture.h"
#include <wincodec.h>
#include <stdlib.h>
#include <stdio.h>
#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);
}