6#define STB_IMAGE_IMPLEMENTATION
21 std::vector<unsigned char>
rgba;
25 WIN32_FILE_ATTRIBUTE_DATA attributes{};
26 if (!GetFileAttributesExA(path.c_str(), GetFileExInfoStandard, &attributes)) {
30 ULARGE_INTEGER fileTime{};
31 fileTime.LowPart = attributes.ftLastWriteTime.dwLowDateTime;
32 fileTime.HighPart = attributes.ftLastWriteTime.dwHighDateTime;
33 outWriteTime = fileTime.QuadPart;
38 return sourcePath +
".wvtx";
42 ULONGLONG sourceWriteTime = 0;
43 ULONGLONG cacheWriteTime = 0;
50 return cacheWriteTime >= sourceWriteTime;
53bool SaveTextureCache(
const std::string& cachePath,
int width,
int height,
const unsigned char* data) {
54 std::ofstream stream(cachePath, std::ios::binary | std::ios::trunc);
55 if (!stream.is_open()) {
59 const uint32_t dataSize =
static_cast<uint32_t
>(width * height * 4);
62 stream.write(
reinterpret_cast<const char*
>(&width),
sizeof(width));
63 stream.write(
reinterpret_cast<const char*
>(&height),
sizeof(height));
64 stream.write(
reinterpret_cast<const char*
>(&dataSize),
sizeof(dataSize));
65 stream.write(
reinterpret_cast<const char*
>(data), dataSize);
70 std::ifstream stream(cachePath, std::ios::binary);
71 if (!stream.is_open()) {
77 uint32_t dataSize = 0;
78 stream.read(
reinterpret_cast<char*
>(&magic),
sizeof(magic));
79 stream.read(
reinterpret_cast<char*
>(&version),
sizeof(version));
80 stream.read(
reinterpret_cast<char*
>(&outTexture.
width),
sizeof(outTexture.
width));
81 stream.read(
reinterpret_cast<char*
>(&outTexture.
height),
sizeof(outTexture.
height));
82 stream.read(
reinterpret_cast<char*
>(&dataSize),
sizeof(dataSize));
87 outTexture.
width <= 0 ||
89 dataSize !=
static_cast<uint32_t
>(outTexture.
width * outTexture.
height * 4)) {
93 outTexture.
rgba.resize(dataSize);
94 stream.read(
reinterpret_cast<char*
>(outTexture.
rgba.data()), dataSize);
101 const unsigned char* data,
102 ID3D11Texture2D** outTexture,
103 ID3D11ShaderResourceView** outSRV) {
104 D3D11_TEXTURE2D_DESC textureDesc = {};
105 textureDesc.Width = width;
106 textureDesc.Height = height;
107 textureDesc.MipLevels = 1;
108 textureDesc.ArraySize = 1;
109 textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
110 textureDesc.SampleDesc.Count = 1;
111 textureDesc.Usage = D3D11_USAGE_DEFAULT;
112 textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
114 D3D11_SUBRESOURCE_DATA initData = {};
115 initData.pSysMem = data;
116 initData.SysMemPitch = width * 4;
118 HRESULT hr = device.
CreateTexture2D(&textureDesc, &initData, outTexture);
123 D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
124 srvDesc.Format = textureDesc.Format;
125 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
126 srvDesc.Texture2D.MipLevels = 1;
128 hr = device.
m_device->CreateShaderResourceView(*outTexture, &srvDesc, outSRV);
130 if (*outTexture !=
nullptr) {
131 (*outTexture)->Release();
132 *outTexture =
nullptr;
145 unsigned char* decodedData =
nullptr;
146 const unsigned char* uploadData =
nullptr;
149 width = cachedTexture.
width;
150 height = cachedTexture.
height;
151 uploadData = cachedTexture.
rgba.data();
154 decodedData = stbi_load(fullPath.c_str(), &width, &height, &channels, 4);
156 ERROR(
"Texture",
"init",
157 (
"Failed to load texture: " + std::string(stbi_failure_reason())).c_str());
160 uploadData = decodedData;
166 stbi_image_free(decodedData);
172 ERROR(
"Texture",
"init",
"Failed to create shader resource view for cached image texture");
183 const std::string& textureName,
186 ERROR(
"Texture",
"init",
"Device is null.");
189 if (textureName.empty()) {
190 ERROR(
"Texture",
"init",
"Texture name cannot be empty.");
196 switch (extensionType) {
200 hr = D3DX11CreateShaderResourceViewFromFile(
210 ERROR(
"Texture",
"init",
211 (
"Failed to load DDS texture. Verify filepath: " +
m_textureName).c_str());
228 ERROR(
"Texture",
"init",
"Unsupported extension type");
240 unsigned int BindFlags,
241 unsigned int sampleCount,
242 unsigned int qualityLevels) {
244 ERROR(
"Texture",
"init",
"Device is null.");
247 if (width == 0 || height == 0) {
248 ERROR(
"Texture",
"init",
"Width and height must be greater than 0");
252 D3D11_TEXTURE2D_DESC desc;
253 memset(&desc, 0,
sizeof(desc));
255 desc.Height = height;
258 desc.Format = Format;
259 desc.SampleDesc.Count = sampleCount;
260 desc.SampleDesc.Quality = qualityLevels;
261 desc.Usage = D3D11_USAGE_DEFAULT;
262 desc.BindFlags = BindFlags;
263 desc.CPUAccessFlags = 0;
269 ERROR(
"Texture",
"init",
270 (
"Failed to create texture with specified params. HRESULT: " + std::to_string(hr)).c_str());
280 ERROR(
"Texture",
"init",
"Device is null.");
284 ERROR(
"Texture",
"init",
"Texture is null.");
288 D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
289 srvDesc.Format = format;
290 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
291 srvDesc.Texture2D.MipLevels = 1;
292 srvDesc.Texture2D.MostDetailedMip = 0;
299 ERROR(
"Texture",
"init",
300 (
"Failed to create shader resource view for PNG textures. HRESULT: " + std::to_string(hr)).c_str());
314 unsigned int StartSlot,
315 unsigned int NumViews) {
317 ERROR(
"Texture",
"render",
"Device Context is null.");
339 const std::array<std::string, 6>& facePaths,
343 stbi_set_flip_vertically_on_load(
false);
345 int width = 0, height = 0, channels = 0;
346 std::array<unsigned char*, 6> facePixels{};
347 facePixels.fill(
nullptr);
349 for (
int i = 0; i < 6; ++i) {
350 int w = 0, h = 0, c = 0;
351 facePixels[i] = stbi_load(facePaths[i].c_str(), &w, &h, &c, 4);
352 if (!facePixels[i]) {
353 for (
int k = 0; k < i; ++k) {
355 stbi_image_free(facePixels[k]);
365 else if (w != width || h != height) {
366 ERROR(
"Texture",
"CreateCubemap",
"All cubemap faces must have the same dimensions.");
367 for (
int k = 0; k <= i; ++k) {
369 stbi_image_free(facePixels[k]);
376 D3D11_TEXTURE2D_DESC texDesc{};
377 texDesc.Width =
static_cast<unsigned int>(width);
378 texDesc.Height =
static_cast<unsigned int>(height);
379 texDesc.MipLevels = generateMips ? 0 : 1;
380 texDesc.ArraySize = 6;
381 texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
382 texDesc.SampleDesc.Count = 1;
383 texDesc.SampleDesc.Quality = 0;
384 texDesc.Usage = D3D11_USAGE_DEFAULT;
385 texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | (generateMips ? D3D11_BIND_RENDER_TARGET : 0);
386 texDesc.CPUAccessFlags = 0;
387 texDesc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE | (generateMips ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0);
392 std::array<D3D11_SUBRESOURCE_DATA, 6> initData{};
393 for (
int face = 0; face < 6; ++face)
395 initData[face].pSysMem = facePixels[face];
396 initData[face].SysMemPitch =
static_cast<unsigned int>(width * 4);
397 initData[face].SysMemSlicePitch = 0;
402 for (
auto* p : facePixels) {
413 for (
auto* p : facePixels) {
421 UINT mipCount = 1 + (UINT)floor(log2(max(width, height)));
423 for (UINT face = 0; face < 6; ++face)
425 UINT sub = D3D11CalcSubresource(0, face, mipCount);
438 D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc{};
439 srvDesc.Format = texDesc.Format;
440 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
441 srvDesc.TextureCube.MostDetailedMip = 0;
442 srvDesc.TextureCube.MipLevels = generateMips ? (
unsigned int)-1 : 1;
447 for (
auto* p : facePixels) {
461 for (
auto* p : facePixels) {
Declara la API de DeviceContext dentro del subsistema Core.
Declara la API de Device dentro del subsistema Core.
#define ERROR(classObj, method, errorMSG)
Declara la API de Texture dentro del subsistema Core.
void PSSetShaderResources(unsigned int StartSlot, unsigned int NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews)
Asigna Shader Resource Views a la etapa de Pixel Shader.
ID3D11DeviceContext * m_deviceContext
Puntero al contexto inmediato de Direct3D 11.
void UpdateSubresource(ID3D11Resource *pDstResource, unsigned int DstSubresource, const D3D11_BOX *pDstBox, const void *pSrcData, unsigned int SrcRowPitch, unsigned int SrcDepthPitch)
Copia datos desde CPU hacia un recurso en GPU.
Encapsula un ID3D11Device y facilita la creación de recursos gráficos en Direct3D 11.
HRESULT CreateTexture2D(const D3D11_TEXTURE2D_DESC *pDesc, const D3D11_SUBRESOURCE_DATA *pInitialData, ID3D11Texture2D **ppTexture2D)
Crea una textura 2D.
ID3D11Device * m_device
Puntero al dispositivo Direct3D 11.
Encapsula una textura 2D en Direct3D 11, incluyendo su recurso y vista como Shader Resource.
void render(DeviceContext &deviceContext, unsigned int StartSlot, unsigned int NumViews)
Asigna la textura al pipeline de render.
void update()
Actualiza el contenido de la textura.
HRESULT init(Device &device, const std::string &textureName, ExtensionType extensionType)
Inicializa una textura cargada desde archivo.
void destroy()
Libera los recursos de la textura.
HRESULT CreateCubemap(Device &device, DeviceContext &deviceContext, const std::array< std::string, 6 > &facePaths, bool generateMips)
ID3D11Texture2D * m_texture
Recurso base de la textura en GPU.
std::string m_textureName
Nombre o ruta de la textura (si proviene de archivo).
ID3D11ShaderResourceView * m_textureFromImg
Vista de la textura como recurso de shader.
constexpr uint32_t kTextureCacheVersion
bool GetFileWriteTime(const std::string &path, ULONGLONG &outWriteTime)
bool SaveTextureCache(const std::string &cachePath, int width, int height, const unsigned char *data)
std::string GetTextureCachePath(const std::string &sourcePath)
HRESULT CreateTextureFromRGBA(Device &device, int width, int height, const unsigned char *data, ID3D11Texture2D **outTexture, ID3D11ShaderResourceView **outSRV)
HRESULT InitTextureFromImage(Device &device, const std::string &fullPath, Texture &texture)
constexpr uint32_t kTextureCacheMagic
bool IsTextureCacheUpToDate(const std::string &sourcePath, const std::string &cachePath)
bool LoadTextureCache(const std::string &cachePath, CachedTextureData &outTexture)
std::vector< unsigned char > rgba