SleakEngine 1.0.0
C++23 multi-backend game engine
Loading...
Searching...
No Matches
DirectX11Texture.cpp
Go to the documentation of this file.
2#include <stdexcept>
3#include <Core/Logger.hpp>
4#include <wincodec.h>
5
6namespace Sleak {
7namespace RenderEngine {
8
10 : m_device(device), m_width(0), m_height(0),
11 m_format(TextureFormat::RGBA8), m_type(TextureType::Texture2D),
12 m_filter(TextureFilter::Linear), m_wrapMode(TextureWrapMode::Repeat) {
13 device->GetImmediateContext(m_deviceContext.GetAddressOf());
14
15}
16
18 // Release resources
19 m_shaderResourceView.Reset();
20 m_texture.Reset();
21 m_samplerState.Reset();
22}
23
24bool DirectX11Texture::LoadFromMemory(const void* data, uint32_t width, uint32_t height, TextureFormat format) {
25 // Store texture properties
26 m_width = width;
27 m_height = height;
28 m_format = format;
29
30 // Create texture description with mipmap generation support
31 D3D11_TEXTURE2D_DESC textureDesc = {};
32 textureDesc.Width = width;
33 textureDesc.Height = height;
34 textureDesc.MipLevels = 0; // 0 = auto-calculate full mip chain
35 textureDesc.ArraySize = 1;
36 textureDesc.Format = GetDXGIFormat(format);
37 textureDesc.SampleDesc.Count = 1;
38 textureDesc.SampleDesc.Quality = 0;
39 textureDesc.Usage = D3D11_USAGE_DEFAULT;
40 textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
41 textureDesc.CPUAccessFlags = 0;
42 textureDesc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;
43
44 // Create the texture (no initial data — we'll upload via UpdateSubresource)
45 HRESULT hr = m_device->CreateTexture2D(&textureDesc, nullptr, &m_texture);
46 if (FAILED(hr)) {
47 SLEAK_ERROR("Failed to create texture! HRESULT: 0x{:08X}", static_cast<unsigned int>(hr));
48 return false;
49 }
50
51 // Create the shader resource view (all mip levels)
52 D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
53 srvDesc.Format = textureDesc.Format;
54 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
55 srvDesc.Texture2D.MipLevels = static_cast<UINT>(-1); // all mip levels
56 srvDesc.Texture2D.MostDetailedMip = 0;
57
58 hr = m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, &m_shaderResourceView);
59 if (FAILED(hr)) {
60 SLEAK_ERROR("Failed to create shader resource view! HRESULT: 0x{:08X}", static_cast<unsigned int>(hr));
61 return false;
62 }
63
64 // Upload base level and generate mipmaps
65 m_deviceContext->UpdateSubresource(m_texture.Get(), 0, nullptr, data, width * 4, 0);
66 m_deviceContext->GenerateMips(m_shaderResourceView.Get());
67
68 // Create the sampler state
69 CreateSamplerState();
70
71 SLEAK_INFO("Successfully created texture from memory: {}x{}", width, height);
72 return true;
73}
74
75void DirectX11Texture::Bind(uint32_t slot) const {
76 if (m_shaderResourceView && m_samplerState) {
77 m_deviceContext->PSSetShaderResources(slot, 1, m_shaderResourceView.GetAddressOf());
78 m_deviceContext->PSSetSamplers(slot, 1, m_samplerState.GetAddressOf());
79 }
80}
81
82bool DirectX11Texture::LoadFromFile(const std::string& filePath) {
83 // Initialize WIC
84 Microsoft::WRL::ComPtr<IWICImagingFactory> wicFactory;
85 HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&wicFactory));
86 if (FAILED(hr)) {
87 SLEAK_ERROR("Failed to create WIC imaging factory! HRESULT: 0x{:08X}", static_cast<unsigned int>(hr));
88 return false;
89 }
90
91 // Load the image file
92 Microsoft::WRL::ComPtr<IWICBitmapDecoder> decoder;
93 hr = wicFactory->CreateDecoderFromFilename(
94 std::wstring(filePath.begin(), filePath.end()).c_str(), // File path
95 nullptr, // No preferred vendor
96 GENERIC_READ, // Desired access
97 WICDecodeMetadataCacheOnLoad, // Cache metadata
98 &decoder);
99 if (FAILED(hr)) {
100 SLEAK_ERROR("Failed to load texture file: {}", filePath);
101 return false;
102 }
103
104 // Get the first frame (for multi-frame images like GIFs)
105 Microsoft::WRL::ComPtr<IWICBitmapFrameDecode> frame;
106 hr = decoder->GetFrame(0, &frame);
107 if (FAILED(hr)) {
108 SLEAK_ERROR("Failed to get frame from texture file: {}", filePath);
109 return false;
110 }
111
112 // Convert the image format to 32-bit RGBA
113 Microsoft::WRL::ComPtr<IWICFormatConverter> converter;
114 hr = wicFactory->CreateFormatConverter(&converter);
115 if (FAILED(hr)) {
116 SLEAK_ERROR("Failed to create WIC format converter! HRESULT: 0x{:08X}", static_cast<unsigned int>(hr));
117 return false;
118 }
119
120 hr = converter->Initialize(
121 frame.Get(), // Input frame
122 GUID_WICPixelFormat32bppRGBA, // Desired pixel format
123 WICBitmapDitherTypeNone, // No dithering
124 nullptr, // No palette
125 0.0f, // Alpha threshold
126 WICBitmapPaletteTypeCustom); // No palette
127 if (FAILED(hr)) {
128 SLEAK_ERROR("Failed to initialize WIC format converter! HRESULT: 0x{:08X}", static_cast<unsigned int>(hr));
129 return false;
130 }
131
132 // Get the image dimensions
133 UINT width, height;
134 hr = converter->GetSize(&width, &height);
135 if (FAILED(hr)) {
136 SLEAK_ERROR("Failed to get texture dimensions! HRESULT: 0x{:08X}", static_cast<unsigned int>(hr));
137 return false;
138 }
139
140 // Allocate memory for the image data
141 std::vector<uint8_t> imageData(width * height * 4); // 4 bytes per pixel (RGBA)
142
143 // Copy the image data into the buffer
144 hr = converter->CopyPixels(
145 nullptr, // No rectangle (entire image)
146 width * 4, // Stride (bytes per row)
147 static_cast<UINT>(imageData.size()), // Buffer size
148 imageData.data()); // Destination buffer
149 if (FAILED(hr)) {
150 SLEAK_ERROR("Failed to copy texture pixels! HRESULT: 0x{:08X}", static_cast<unsigned int>(hr));
151 return false;
152 }
153
154 // Load the texture from memory
155 return LoadFromMemory(imageData.data(), width, height, TextureFormat::RGBA8);
156}
157
159 ID3D11ShaderResourceView* nullSRV = nullptr;
160 ID3D11SamplerState* nullSampler = nullptr;
161 m_deviceContext->PSSetShaderResources(0, 1, &nullSRV);
162 m_deviceContext->PSSetSamplers(0, 1, &nullSampler);
163}
164
166 m_filter = filter;
167 CreateSamplerState();
168}
169
171 m_wrapMode = wrapMode;
172 CreateSamplerState();
173}
174
176 m_lodBias = bias;
177 CreateSamplerState();
178}
179
181 return m_width;
182}
183
185 return m_height;
186}
187
189 return m_format;
190}
191
193 return m_type;
194}
195
196void DirectX11Texture::CreateSamplerState() {
197 UINT maxAniso = 1;
198 switch (m_filter) {
199 case TextureFilter::Anisotropic2x: maxAniso = 2; break;
200 case TextureFilter::Anisotropic4x: maxAniso = 4; break;
201 case TextureFilter::Anisotropic8x: maxAniso = 8; break;
202 case TextureFilter::Anisotropic16x: maxAniso = 16; break;
203 default: break;
204 }
205
206 D3D11_SAMPLER_DESC samplerDesc = {};
207 samplerDesc.Filter = GetD3D11Filter(m_filter);
208 samplerDesc.AddressU = GetD3D11WrapMode(m_wrapMode);
209 samplerDesc.AddressV = GetD3D11WrapMode(m_wrapMode);
210 samplerDesc.AddressW = GetD3D11WrapMode(m_wrapMode);
211 samplerDesc.MipLODBias = m_lodBias;
212 samplerDesc.MaxAnisotropy = maxAniso;
213 samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
214 samplerDesc.MinLOD = 0;
215 samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
216
217 HRESULT hr = m_device->CreateSamplerState(&samplerDesc, &m_samplerState);
218 if (FAILED(hr)) {
219 SLEAK_ERROR("Failed to create sampler state! HRESULT: 0x{:08X}", static_cast<unsigned int>(hr));
220 }
221}
222
223DXGI_FORMAT DirectX11Texture::GetDXGIFormat(TextureFormat format) const {
224 switch (format) {
225 case TextureFormat::RGBA8: return DXGI_FORMAT_R8G8B8A8_UNORM;
226 case TextureFormat::RGB8: return DXGI_FORMAT_B8G8R8X8_UNORM;
227 case TextureFormat::BGRA8: return DXGI_FORMAT_B8G8R8A8_UNORM;
228 case TextureFormat::DXT1: return DXGI_FORMAT_BC1_UNORM;
229 case TextureFormat::DXT5: return DXGI_FORMAT_BC3_UNORM;
230 default: return DXGI_FORMAT_UNKNOWN;
231 }
232}
233
234D3D11_FILTER DirectX11Texture::GetD3D11Filter(TextureFilter filter) const {
235 switch (filter) {
236 case TextureFilter::Nearest: return D3D11_FILTER_MIN_MAG_MIP_POINT;
237 case TextureFilter::Bilinear: return D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
238 case TextureFilter::Trilinear: return D3D11_FILTER_MIN_MAG_MIP_LINEAR;
242 case TextureFilter::Anisotropic16x: return D3D11_FILTER_ANISOTROPIC;
243 default: return D3D11_FILTER_MIN_MAG_MIP_LINEAR;
244 }
245}
246
247D3D11_TEXTURE_ADDRESS_MODE DirectX11Texture::GetD3D11WrapMode(TextureWrapMode wrapMode) const {
248 switch (wrapMode) {
249 case TextureWrapMode::Repeat: return D3D11_TEXTURE_ADDRESS_WRAP;
250 case TextureWrapMode::ClampToEdge: return D3D11_TEXTURE_ADDRESS_CLAMP;
251 case TextureWrapMode::ClampToBorder: return D3D11_TEXTURE_ADDRESS_BORDER;
252 case TextureWrapMode::Mirror: return D3D11_TEXTURE_ADDRESS_MIRROR;
253 case TextureWrapMode::MirrorClampToEdge: return D3D11_TEXTURE_ADDRESS_MIRROR_ONCE;
254 default: return D3D11_TEXTURE_ADDRESS_WRAP;
255 }
256}
257
258} // namespace RenderEngine
259} // namespace Sleak
int width
int height
#define SLEAK_ERROR(...)
Definition Logger.hpp:22
#define SLEAK_INFO(...)
Definition Logger.hpp:20
void SetWrapMode(TextureWrapMode wrapMode) override
TextureType GetType() const override
bool LoadFromMemory(const void *data, uint32_t width, uint32_t height, TextureFormat format) override
Uploads raw pixel data as the texture's contents, replacing any existing image.
void Bind(uint32_t slot=0) const override
void SetFilter(TextureFilter filter) override
bool LoadFromFile(const std::string &filePath) override
Loads and uploads an image file from disk.
TextureFormat GetFormat() const override
TextureFormat
Definition Texture.hpp:10
TextureFilter
Definition Texture.hpp:28
TextureType
Definition Texture.hpp:20
TextureWrapMode
Definition Texture.hpp:43
Backend-facing rendering layer shared by the four graphics backends.
Root namespace for everything the engine exposes.
Definition Camera.hpp:10