summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/Assets/CustomTextureData.cpp
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2023-09-03 18:29:00 -0400
committerGitHub <noreply@github.com>2023-09-03 18:29:00 -0400
commit900439ea0d3cfdfae259890a94dfc383103f1bad (patch)
tree3bba0bfc72346aee1301dcc3f118098c48ae7881 /Source/Core/VideoCommon/Assets/CustomTextureData.cpp
parent6f6eb73667d461073b44f993c00095c30ac35414 (diff)
parent62fee2f3b60c84b27efbb0792e3695bbe812ac1a (diff)
Merge pull request #12102 from iwubcode/cubemap_custom_texture
VideoCommon: add ability to load cube maps into custom texture data
Diffstat (limited to 'Source/Core/VideoCommon/Assets/CustomTextureData.cpp')
-rw-r--r--Source/Core/VideoCommon/Assets/CustomTextureData.cpp131
1 files changed, 90 insertions, 41 deletions
diff --git a/Source/Core/VideoCommon/Assets/CustomTextureData.cpp b/Source/Core/VideoCommon/Assets/CustomTextureData.cpp
index 04183da3f0..23af429d11 100644
--- a/Source/Core/VideoCommon/Assets/CustomTextureData.cpp
+++ b/Source/Core/VideoCommon/Assets/CustomTextureData.cpp
@@ -62,6 +62,19 @@ struct DDS_PIXELFORMAT
#define DDS_PAL8A 0x00000021 // DDPF_PALETTEINDEXED8 | DDPF_ALPHAPIXELS
#define DDS_BUMPDUDV 0x00080000 // DDPF_BUMPDUDV
+#define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX
+#define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX
+#define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY
+#define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY
+#define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ
+#define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ
+
+#define DDS_CUBEMAP_ALLFACES \
+ (DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX | DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY | \
+ DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ)
+
+#define DDS_CUBEMAP 0x00000200 // DDSCAPS2_CUBEMAP
+
#ifndef MAKEFOURCC
#define MAKEFOURCC(ch0, ch1, ch2, ch3) \
((uint32_t)(uint8_t)(ch0) | ((uint32_t)(uint8_t)(ch1) << 8) | ((uint32_t)(uint8_t)(ch2) << 16) | \
@@ -143,12 +156,13 @@ struct DDSLoadInfo
u32 width = 0;
u32 height = 0;
u32 mip_count = 0;
+ u32 array_size = 0;
AbstractTextureFormat format = AbstractTextureFormat::RGBA8;
size_t first_mip_offset = 0;
size_t first_mip_size = 0;
u32 first_mip_row_length = 0;
- std::function<void(VideoCommon::CustomTextureData::Level*)> conversion_function;
+ std::function<void(VideoCommon::CustomTextureData::ArraySlice::Level*)> conversion_function;
};
static constexpr u32 GetBlockCount(u32 extent, u32 block_size)
@@ -171,7 +185,7 @@ static u32 CalculateMipCount(u32 width, u32 height)
return mip_count;
}
-static void ConvertTexture_X8B8G8R8(VideoCommon::CustomTextureData::Level* level)
+static void ConvertTexture_X8B8G8R8(VideoCommon::CustomTextureData::ArraySlice::Level* level)
{
u8* data_ptr = level->data.data();
for (u32 row = 0; row < level->height; row++)
@@ -185,7 +199,7 @@ static void ConvertTexture_X8B8G8R8(VideoCommon::CustomTextureData::Level* level
}
}
-static void ConvertTexture_A8R8G8B8(VideoCommon::CustomTextureData::Level* level)
+static void ConvertTexture_A8R8G8B8(VideoCommon::CustomTextureData::ArraySlice::Level* level)
{
u8* data_ptr = level->data.data();
for (u32 row = 0; row < level->height; row++)
@@ -202,7 +216,7 @@ static void ConvertTexture_A8R8G8B8(VideoCommon::CustomTextureData::Level* level
}
}
-static void ConvertTexture_X8R8G8B8(VideoCommon::CustomTextureData::Level* level)
+static void ConvertTexture_X8R8G8B8(VideoCommon::CustomTextureData::ArraySlice::Level* level)
{
u8* data_ptr = level->data.data();
for (u32 row = 0; row < level->height; row++)
@@ -219,7 +233,7 @@ static void ConvertTexture_X8R8G8B8(VideoCommon::CustomTextureData::Level* level
}
}
-static void ConvertTexture_R8G8B8(VideoCommon::CustomTextureData::Level* level)
+static void ConvertTexture_R8G8B8(VideoCommon::CustomTextureData::ArraySlice::Level* level)
{
std::vector<u8> new_data(level->row_length * level->height * sizeof(u32));
@@ -297,13 +311,26 @@ static bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
if (!file.ReadBytes(&dxt10_header, sizeof(dxt10_header)))
return false;
- // Can't handle array textures here. Doesn't make sense to use them, anyway.
- if (dxt10_header.resourceDimension != DDS_DIMENSION_TEXTURE2D || dxt10_header.arraySize != 1)
- return false;
-
+ info->array_size = dxt10_header.arraySize;
header_size += sizeof(dxt10_header);
dxt10_format = dxt10_header.dxgiFormat;
}
+ else
+ {
+ if (header.dwCaps2 & DDS_CUBEMAP)
+ {
+ if ((header.dwCaps2 & DDS_CUBEMAP_ALLFACES) != DDS_CUBEMAP_ALLFACES)
+ {
+ return false;
+ }
+
+ info->array_size = 6;
+ }
+ else
+ {
+ info->array_size = 1;
+ }
+ }
// Currently, we only handle compressed textures here, and leave the rest to the SOIL loader.
// In the future, this could be extended, but these isn't much benefit in doing so currently.
@@ -369,6 +396,20 @@ static bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
return false;
}
+ if (header.dwCaps2 & DDS_CUBEMAP)
+ {
+ if ((header.dwCaps2 & DDS_CUBEMAP_ALLFACES) != DDS_CUBEMAP_ALLFACES)
+ {
+ return false;
+ }
+
+ info->array_size = 6;
+ }
+ else
+ {
+ info->array_size = 1;
+ }
+
// All these formats are RGBA, just with byte swapping.
info->format = AbstractTextureFormat::RGBA8;
info->block_size = 1;
@@ -416,9 +457,10 @@ static bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
return true;
}
-static bool ReadMipLevel(VideoCommon::CustomTextureData::Level* level, File::IOFile& file,
- const std::string& filename, u32 mip_level, const DDSLoadInfo& info,
- u32 width, u32 height, u32 row_length, size_t size)
+static bool ReadMipLevel(VideoCommon::CustomTextureData::ArraySlice::Level* level,
+ File::IOFile& file, const std::string& filename, u32 mip_level,
+ const DDSLoadInfo& info, u32 width, u32 height, u32 row_length,
+ size_t size)
{
// D3D11 cannot handle block compressed textures where the first mip level is
// not a multiple of the block size.
@@ -463,43 +505,50 @@ bool LoadDDSTexture(CustomTextureData* texture, const std::string& filename)
if (!ParseDDSHeader(file, &info))
return false;
- // Read first mip level, as it may have a custom pitch.
- CustomTextureData::Level first_level;
- if (!file.Seek(info.first_mip_offset, File::SeekOrigin::Begin) ||
- !ReadMipLevel(&first_level, file, filename, 0, info, info.width, info.height,
- info.first_mip_row_length, info.first_mip_size))
- {
+ if (!file.Seek(info.first_mip_offset, File::SeekOrigin::Begin))
return false;
- }
- texture->m_levels.push_back(std::move(first_level));
-
- // Read in any remaining mip levels in the file.
- // If the .dds file does not contain a full mip chain, we'll fall back to the old path.
- u32 mip_width = info.width;
- u32 mip_height = info.height;
- for (u32 i = 1; i < info.mip_count; i++)
+ for (u32 arr_i = 0; arr_i < info.array_size; arr_i++)
{
- mip_width = std::max(mip_width / 2, 1u);
- mip_height = std::max(mip_height / 2, 1u);
+ auto& slice = texture->m_slices.emplace_back();
+ // Read first mip level, as it may have a custom pitch.
+ CustomTextureData::ArraySlice::Level first_level;
+ if (!ReadMipLevel(&first_level, file, filename, 0, info, info.width, info.height,
+ info.first_mip_row_length, info.first_mip_size))
+ {
+ return false;
+ }
- // Pitch can't be specified with each mip level, so we have to calculate it ourselves.
- u32 blocks_wide = GetBlockCount(mip_width, info.block_size);
- u32 blocks_high = GetBlockCount(mip_height, info.block_size);
- u32 mip_row_length = blocks_wide * info.block_size;
- size_t mip_size = blocks_wide * static_cast<size_t>(info.bytes_per_block) * blocks_high;
- CustomTextureData::Level level;
- if (!ReadMipLevel(&level, file, filename, i, info, mip_width, mip_height, mip_row_length,
- mip_size))
- break;
-
- texture->m_levels.push_back(std::move(level));
+ slice.m_levels.push_back(std::move(first_level));
+
+ // Read in any remaining mip levels in the file.
+ // If the .dds file does not contain a full mip chain, we'll fall back to the old path.
+ u32 mip_width = info.width;
+ u32 mip_height = info.height;
+ for (u32 i = 1; i < info.mip_count; i++)
+ {
+ mip_width = std::max(mip_width / 2, 1u);
+ mip_height = std::max(mip_height / 2, 1u);
+
+ // Pitch can't be specified with each mip level, so we have to calculate it ourselves.
+ u32 blocks_wide = GetBlockCount(mip_width, info.block_size);
+ u32 blocks_high = GetBlockCount(mip_height, info.block_size);
+ u32 mip_row_length = blocks_wide * info.block_size;
+ size_t mip_size = blocks_wide * static_cast<size_t>(info.bytes_per_block) * blocks_high;
+ CustomTextureData::ArraySlice::Level level;
+ if (!ReadMipLevel(&level, file, filename, i, info, mip_width, mip_height, mip_row_length,
+ mip_size))
+ break;
+
+ slice.m_levels.push_back(std::move(level));
+ }
}
return true;
}
-bool LoadDDSTexture(CustomTextureData::Level* level, const std::string& filename, u32 mip_level)
+bool LoadDDSTexture(CustomTextureData::ArraySlice::Level* level, const std::string& filename,
+ u32 mip_level)
{
// Only loading a single mip level.
File::IOFile file;
@@ -515,7 +564,7 @@ bool LoadDDSTexture(CustomTextureData::Level* level, const std::string& filename
info.first_mip_row_length, info.first_mip_size);
}
-bool LoadPNGTexture(CustomTextureData::Level* level, const std::string& filename)
+bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::string& filename)
{
if (!level) [[unlikely]]
return false;