VideoCommon: Replace SOIL with libpng for hires textures
This commit is contained in:
parent
0706add584
commit
17e65a7167
|
@ -18,6 +18,7 @@ add_library(common
|
||||||
GekkoDisassembler.cpp
|
GekkoDisassembler.cpp
|
||||||
Hash.cpp
|
Hash.cpp
|
||||||
HttpRequest.cpp
|
HttpRequest.cpp
|
||||||
|
Image.cpp
|
||||||
IniFile.cpp
|
IniFile.cpp
|
||||||
JitRegister.cpp
|
JitRegister.cpp
|
||||||
Logging/LogManager.cpp
|
Logging/LogManager.cpp
|
||||||
|
@ -54,6 +55,7 @@ PUBLIC
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${CURL_LIBRARIES}
|
${CURL_LIBRARIES}
|
||||||
${ICONV_LIBRARIES}
|
${ICONV_LIBRARIES}
|
||||||
|
png
|
||||||
${VTUNE_LIBRARIES}
|
${VTUNE_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,7 @@
|
||||||
<ClInclude Include="FloatUtils.h" />
|
<ClInclude Include="FloatUtils.h" />
|
||||||
<ClInclude Include="Hash.h" />
|
<ClInclude Include="Hash.h" />
|
||||||
<ClInclude Include="HttpRequest.h" />
|
<ClInclude Include="HttpRequest.h" />
|
||||||
|
<ClInclude Include="Image.h" />
|
||||||
<ClInclude Include="IniFile.h" />
|
<ClInclude Include="IniFile.h" />
|
||||||
<ClInclude Include="JitRegister.h" />
|
<ClInclude Include="JitRegister.h" />
|
||||||
<ClInclude Include="Lazy.h" />
|
<ClInclude Include="Lazy.h" />
|
||||||
|
@ -188,6 +189,7 @@
|
||||||
<ClCompile Include="GL\GLUtil.cpp" />
|
<ClCompile Include="GL\GLUtil.cpp" />
|
||||||
<ClCompile Include="Hash.cpp" />
|
<ClCompile Include="Hash.cpp" />
|
||||||
<ClCompile Include="HttpRequest.cpp" />
|
<ClCompile Include="HttpRequest.cpp" />
|
||||||
|
<ClCompile Include="Image.cpp" />
|
||||||
<ClCompile Include="IniFile.cpp" />
|
<ClCompile Include="IniFile.cpp" />
|
||||||
<ClCompile Include="JitRegister.cpp" />
|
<ClCompile Include="JitRegister.cpp" />
|
||||||
<ClCompile Include="LdrWatcher.cpp" />
|
<ClCompile Include="LdrWatcher.cpp" />
|
||||||
|
@ -230,6 +232,9 @@
|
||||||
<ProjectReference Include="$(ExternalsDir)mbedtls\mbedTLS.vcxproj">
|
<ProjectReference Include="$(ExternalsDir)mbedtls\mbedTLS.vcxproj">
|
||||||
<Project>{bdb6578b-0691-4e80-a46c-df21639fd3b8}</Project>
|
<Project>{bdb6578b-0691-4e80-a46c-df21639fd3b8}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="$(ExternalsDir)libpng\png\png.vcxproj">
|
||||||
|
<Project>{4c9f135b-a85e-430c-bad4-4c67ef5fc12c}</Project>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\..\..\Externals\curl\curl.vcxproj">
|
<ProjectReference Include="..\..\..\Externals\curl\curl.vcxproj">
|
||||||
<Project>{bb00605c-125f-4a21-b33b-7bf418322dcb}</Project>
|
<Project>{bb00605c-125f-4a21-b33b-7bf418322dcb}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
<ClInclude Include="FPURoundMode.h" />
|
<ClInclude Include="FPURoundMode.h" />
|
||||||
<ClInclude Include="Hash.h" />
|
<ClInclude Include="Hash.h" />
|
||||||
<ClInclude Include="HttpRequest.h" />
|
<ClInclude Include="HttpRequest.h" />
|
||||||
|
<ClInclude Include="Image.h" />
|
||||||
<ClInclude Include="IniFile.h" />
|
<ClInclude Include="IniFile.h" />
|
||||||
<ClInclude Include="LinearDiskCache.h" />
|
<ClInclude Include="LinearDiskCache.h" />
|
||||||
<ClInclude Include="MathUtil.h" />
|
<ClInclude Include="MathUtil.h" />
|
||||||
|
@ -281,6 +282,7 @@
|
||||||
<ClCompile Include="FloatUtils.cpp" />
|
<ClCompile Include="FloatUtils.cpp" />
|
||||||
<ClCompile Include="Hash.cpp" />
|
<ClCompile Include="Hash.cpp" />
|
||||||
<ClCompile Include="HttpRequest.cpp" />
|
<ClCompile Include="HttpRequest.cpp" />
|
||||||
|
<ClCompile Include="Image.cpp" />
|
||||||
<ClCompile Include="IniFile.cpp" />
|
<ClCompile Include="IniFile.cpp" />
|
||||||
<ClCompile Include="MathUtil.cpp" />
|
<ClCompile Include="MathUtil.cpp" />
|
||||||
<ClCompile Include="MemArena.cpp" />
|
<ClCompile Include="MemArena.cpp" />
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
// Copyright 2016 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "Common/Image.h"
|
||||||
|
|
||||||
|
#include <csetjmp>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include <png.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
|
static int MultiplyAlpha(int alpha, int color)
|
||||||
|
{
|
||||||
|
const int temp = (alpha * color) + 0x80;
|
||||||
|
return ((temp + (temp >> 8)) >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PremultiplyData(png_structp png, png_row_infop row_info, png_bytep data)
|
||||||
|
{
|
||||||
|
for (png_size_t i = 0; i < row_info->rowbytes; i += 4, data += 4)
|
||||||
|
{
|
||||||
|
const png_byte alpha = data[3];
|
||||||
|
u32 w;
|
||||||
|
|
||||||
|
if (alpha == 0)
|
||||||
|
{
|
||||||
|
w = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
png_byte red = data[0];
|
||||||
|
png_byte green = data[1];
|
||||||
|
png_byte blue = data[2];
|
||||||
|
|
||||||
|
if (alpha != 0xff)
|
||||||
|
{
|
||||||
|
red = MultiplyAlpha(alpha, red);
|
||||||
|
green = MultiplyAlpha(alpha, green);
|
||||||
|
blue = MultiplyAlpha(alpha, blue);
|
||||||
|
}
|
||||||
|
w = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(data, &w, sizeof(w));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ReadProgress
|
||||||
|
{
|
||||||
|
const u8* current;
|
||||||
|
const u8* end;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ReadCallback(png_structp png, png_bytep data, png_size_t size)
|
||||||
|
{
|
||||||
|
ReadProgress* progress = static_cast<ReadProgress*>(png_get_io_ptr(png));
|
||||||
|
for (size_t i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
if (progress->current >= progress->end)
|
||||||
|
png_error(png, "Read beyond end of file"); // This makes us longjmp back to LoadPNG
|
||||||
|
|
||||||
|
data[i] = *(progress->current);
|
||||||
|
++(progress->current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PNGErrorCallback(png_structp png, png_const_charp error_msg)
|
||||||
|
{
|
||||||
|
ERROR_LOG(COMMON, "PNG loading error: %s", error_msg);
|
||||||
|
longjmp(png_jmpbuf(png), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4611)
|
||||||
|
// VS shows the following warning even though no C++ objects are destroyed in LoadPNG:
|
||||||
|
// "warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool LoadPNG(const std::vector<u8>& input, std::vector<u8>* data_out, u32* width_out,
|
||||||
|
u32* height_out)
|
||||||
|
{
|
||||||
|
const bool is_png = !png_sig_cmp(input.data(), 0, input.size());
|
||||||
|
if (!is_png)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
png_struct* png =
|
||||||
|
png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, PNGErrorCallback, nullptr);
|
||||||
|
if (!png)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
png_info* info = png_create_info_struct(png);
|
||||||
|
if (!info)
|
||||||
|
{
|
||||||
|
png_destroy_read_struct(&png, &info, nullptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// It would've been nice to use std::vector for this, but using setjmp safely
|
||||||
|
// means that we have to use this manually managed volatile pointer garbage instead.
|
||||||
|
png_byte** volatile row_pointers_volatile = nullptr;
|
||||||
|
|
||||||
|
if (setjmp(png_jmpbuf(png)))
|
||||||
|
{
|
||||||
|
free(row_pointers_volatile);
|
||||||
|
png_destroy_read_struct(&png, &info, nullptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadProgress read_progress{input.data(), input.data() + input.size()};
|
||||||
|
png_set_read_fn(png, &read_progress, ReadCallback);
|
||||||
|
png_read_info(png, info);
|
||||||
|
|
||||||
|
png_uint_32 width, height;
|
||||||
|
int depth, color_type, interlace;
|
||||||
|
png_get_IHDR(png, info, &width, &height, &depth, &color_type, &interlace, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||||
|
png_set_palette_to_rgb(png);
|
||||||
|
else if (color_type == PNG_COLOR_TYPE_GRAY)
|
||||||
|
png_set_expand_gray_1_2_4_to_8(png);
|
||||||
|
|
||||||
|
if (png_get_valid(png, info, PNG_INFO_tRNS))
|
||||||
|
png_set_tRNS_to_alpha(png);
|
||||||
|
|
||||||
|
if (depth == 16)
|
||||||
|
png_set_strip_16(png);
|
||||||
|
else if (depth < 8)
|
||||||
|
png_set_packing(png);
|
||||||
|
|
||||||
|
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||||
|
png_set_gray_to_rgb(png);
|
||||||
|
|
||||||
|
if (interlace != PNG_INTERLACE_NONE)
|
||||||
|
png_set_interlace_handling(png);
|
||||||
|
|
||||||
|
png_set_bgr(png);
|
||||||
|
png_set_filler(png, 0xff, PNG_FILLER_AFTER);
|
||||||
|
png_set_read_user_transform_fn(png, PremultiplyData);
|
||||||
|
png_read_update_info(png, info);
|
||||||
|
png_get_IHDR(png, info, &width, &height, &depth, &color_type, &interlace, nullptr, nullptr);
|
||||||
|
|
||||||
|
const size_t stride = width * 4;
|
||||||
|
data_out->resize(stride * height);
|
||||||
|
|
||||||
|
png_byte** row_pointers = static_cast<png_byte**>(malloc(height * sizeof(png_byte*)));
|
||||||
|
if (!row_pointers)
|
||||||
|
{
|
||||||
|
png_destroy_read_struct(&png, &info, nullptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (png_uint_32 i = 0; i < height; i++)
|
||||||
|
row_pointers[i] = &(*data_out)[i * stride];
|
||||||
|
|
||||||
|
row_pointers_volatile = row_pointers;
|
||||||
|
|
||||||
|
png_read_image(png, row_pointers);
|
||||||
|
png_read_end(png, info);
|
||||||
|
|
||||||
|
free(row_pointers);
|
||||||
|
png_destroy_read_struct(&png, &info, nullptr);
|
||||||
|
|
||||||
|
*width_out = width;
|
||||||
|
*height_out = height;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace Common
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2016 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
|
bool LoadPNG(const std::vector<u8>& input, std::vector<u8>* data_out, u32* width_out,
|
||||||
|
u32* height_out);
|
||||||
|
}
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#include "VideoCommon/HiresTextures.h"
|
#include "VideoCommon/HiresTextures.h"
|
||||||
|
|
||||||
#include <SOIL/SOIL.h>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -22,6 +21,7 @@
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/Flag.h"
|
#include "Common/Flag.h"
|
||||||
#include "Common/Hash.h"
|
#include "Common/Hash.h"
|
||||||
|
#include "Common/Image.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/MemoryUtil.h"
|
#include "Common/MemoryUtil.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
@ -49,10 +49,6 @@ static std::thread s_prefetcher;
|
||||||
|
|
||||||
static const std::string s_format_prefix = "tex1_";
|
static const std::string s_format_prefix = "tex1_";
|
||||||
|
|
||||||
HiresTexture::Level::Level() : data(nullptr, SOIL_free_image_data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void HiresTexture::Init()
|
void HiresTexture::Init()
|
||||||
{
|
{
|
||||||
Update();
|
Update();
|
||||||
|
@ -92,10 +88,7 @@ void HiresTexture::Update()
|
||||||
|
|
||||||
const std::string& game_id = SConfig::GetInstance().GetGameID();
|
const std::string& game_id = SConfig::GetInstance().GetGameID();
|
||||||
const std::string texture_directory = GetTextureDirectory(game_id);
|
const std::string texture_directory = GetTextureDirectory(game_id);
|
||||||
std::vector<std::string> extensions{
|
const std::vector<std::string> extensions{".png", ".dds"};
|
||||||
".png", ".bmp", ".tga", ".dds",
|
|
||||||
".jpg" // Why not? Could be useful for large photo-like textures
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<std::string> texture_paths =
|
const std::vector<std::string> texture_paths =
|
||||||
Common::DoFileSearch({texture_directory}, extensions, /*recursive*/ true);
|
Common::DoFileSearch({texture_directory}, extensions, /*recursive*/ true);
|
||||||
|
@ -183,9 +176,7 @@ void HiresTexture::Prefetch()
|
||||||
if (iter != s_textureCache.end())
|
if (iter != s_textureCache.end())
|
||||||
{
|
{
|
||||||
for (const Level& l : iter->second->m_levels)
|
for (const Level& l : iter->second->m_levels)
|
||||||
{
|
size_sum += l.data.size();
|
||||||
size_sum += l.data_size;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,6 +352,7 @@ std::unique_ptr<HiresTexture> HiresTexture::Load(const std::string& base_filenam
|
||||||
file.Open(filename_iter->second.path, "rb");
|
file.Open(filename_iter->second.path, "rb");
|
||||||
std::vector<u8> buffer(file.GetSize());
|
std::vector<u8> buffer(file.GetSize());
|
||||||
file.ReadBytes(buffer.data(), file.GetSize());
|
file.ReadBytes(buffer.data(), file.GetSize());
|
||||||
|
|
||||||
if (!LoadTexture(level, buffer))
|
if (!LoadTexture(level, buffer))
|
||||||
{
|
{
|
||||||
ERROR_LOG(VIDEO, "Custom texture %s failed to load", filename.c_str());
|
ERROR_LOG(VIDEO, "Custom texture %s failed to load", filename.c_str());
|
||||||
|
@ -440,22 +432,15 @@ std::unique_ptr<HiresTexture> HiresTexture::Load(const std::string& base_filenam
|
||||||
|
|
||||||
bool HiresTexture::LoadTexture(Level& level, const std::vector<u8>& buffer)
|
bool HiresTexture::LoadTexture(Level& level, const std::vector<u8>& buffer)
|
||||||
{
|
{
|
||||||
int channels;
|
if (!Common::LoadPNG(buffer, &level.data, &level.width, &level.height))
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
|
|
||||||
u8* data = SOIL_load_image_from_memory(buffer.data(), static_cast<int>(buffer.size()), &width,
|
|
||||||
&height, &channels, SOIL_LOAD_RGBA);
|
|
||||||
if (!data)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Images loaded by SOIL are converted to RGBA.
|
if (level.data.empty())
|
||||||
level.width = static_cast<u32>(width);
|
return false;
|
||||||
level.height = static_cast<u32>(height);
|
|
||||||
|
// Loaded PNG images are converted to RGBA.
|
||||||
level.format = AbstractTextureFormat::RGBA8;
|
level.format = AbstractTextureFormat::RGBA8;
|
||||||
level.data = ImageDataPointer(data, SOIL_free_image_data);
|
|
||||||
level.row_length = level.width;
|
level.row_length = level.width;
|
||||||
level.data_size = static_cast<size_t>(level.row_length) * 4 * level.height;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,6 @@ enum class TextureFormat;
|
||||||
class HiresTexture
|
class HiresTexture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using ImageDataPointer = std::unique_ptr<u8, void (*)(unsigned char*)>;
|
|
||||||
|
|
||||||
static void Init();
|
static void Init();
|
||||||
static void Update();
|
static void Update();
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
|
@ -39,14 +37,11 @@ public:
|
||||||
|
|
||||||
struct Level
|
struct Level
|
||||||
{
|
{
|
||||||
Level();
|
std::vector<u8> data;
|
||||||
|
|
||||||
ImageDataPointer data;
|
|
||||||
AbstractTextureFormat format = AbstractTextureFormat::RGBA8;
|
AbstractTextureFormat format = AbstractTextureFormat::RGBA8;
|
||||||
u32 width = 0;
|
u32 width = 0;
|
||||||
u32 height = 0;
|
u32 height = 0;
|
||||||
u32 row_length = 0;
|
u32 row_length = 0;
|
||||||
size_t data_size = 0;
|
|
||||||
};
|
};
|
||||||
std::vector<Level> m_levels;
|
std::vector<Level> m_levels;
|
||||||
|
|
||||||
|
|
|
@ -155,14 +155,9 @@ u32 GetBlockCount(u32 extent, u32 block_size)
|
||||||
return std::max(Common::AlignUp(extent, block_size) / block_size, 1u);
|
return std::max(Common::AlignUp(extent, block_size) / block_size, 1u);
|
||||||
}
|
}
|
||||||
|
|
||||||
HiresTexture::ImageDataPointer AllocateLevelData(size_t size)
|
|
||||||
{
|
|
||||||
return HiresTexture::ImageDataPointer(new u8[size], [](u8* data) { delete[] data; });
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConvertTexture_X8B8G8R8(HiresTexture::Level* level)
|
void ConvertTexture_X8B8G8R8(HiresTexture::Level* level)
|
||||||
{
|
{
|
||||||
u8* data_ptr = level->data.get();
|
u8* data_ptr = level->data.data();
|
||||||
for (u32 row = 0; row < level->height; row++)
|
for (u32 row = 0; row < level->height; row++)
|
||||||
{
|
{
|
||||||
for (u32 x = 0; x < level->row_length; x++)
|
for (u32 x = 0; x < level->row_length; x++)
|
||||||
|
@ -176,7 +171,7 @@ void ConvertTexture_X8B8G8R8(HiresTexture::Level* level)
|
||||||
|
|
||||||
void ConvertTexture_A8R8G8B8(HiresTexture::Level* level)
|
void ConvertTexture_A8R8G8B8(HiresTexture::Level* level)
|
||||||
{
|
{
|
||||||
u8* data_ptr = level->data.get();
|
u8* data_ptr = level->data.data();
|
||||||
for (u32 row = 0; row < level->height; row++)
|
for (u32 row = 0; row < level->height; row++)
|
||||||
{
|
{
|
||||||
for (u32 x = 0; x < level->row_length; x++)
|
for (u32 x = 0; x < level->row_length; x++)
|
||||||
|
@ -193,7 +188,7 @@ void ConvertTexture_A8R8G8B8(HiresTexture::Level* level)
|
||||||
|
|
||||||
void ConvertTexture_X8R8G8B8(HiresTexture::Level* level)
|
void ConvertTexture_X8R8G8B8(HiresTexture::Level* level)
|
||||||
{
|
{
|
||||||
u8* data_ptr = level->data.get();
|
u8* data_ptr = level->data.data();
|
||||||
for (u32 row = 0; row < level->height; row++)
|
for (u32 row = 0; row < level->height; row++)
|
||||||
{
|
{
|
||||||
for (u32 x = 0; x < level->row_length; x++)
|
for (u32 x = 0; x < level->row_length; x++)
|
||||||
|
@ -210,14 +205,10 @@ void ConvertTexture_X8R8G8B8(HiresTexture::Level* level)
|
||||||
|
|
||||||
void ConvertTexture_R8G8B8(HiresTexture::Level* level)
|
void ConvertTexture_R8G8B8(HiresTexture::Level* level)
|
||||||
{
|
{
|
||||||
// Have to reallocate the buffer for this one, since the data in the file
|
std::vector<u8> new_data(level->row_length * level->height * sizeof(u32));
|
||||||
// does not have an alpha byte.
|
|
||||||
level->data_size = level->row_length * level->height * sizeof(u32);
|
|
||||||
HiresTexture::ImageDataPointer rgb_data = AllocateLevelData(level->data_size);
|
|
||||||
std::swap(level->data, rgb_data);
|
|
||||||
|
|
||||||
const u8* rgb_data_ptr = rgb_data.get();
|
const u8* rgb_data_ptr = level->data.data();
|
||||||
u8* data_ptr = level->data.get();
|
u8* data_ptr = new_data.data();
|
||||||
|
|
||||||
for (u32 row = 0; row < level->height; row++)
|
for (u32 row = 0; row < level->height; row++)
|
||||||
{
|
{
|
||||||
|
@ -232,6 +223,8 @@ void ConvertTexture_R8G8B8(HiresTexture::Level* level)
|
||||||
rgb_data_ptr += 3;
|
rgb_data_ptr += 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
level->data = std::move(new_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
|
bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
|
||||||
|
@ -410,19 +403,14 @@ bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
|
||||||
bool ReadMipLevel(HiresTexture::Level* level, File::IOFile& file, const DDSLoadInfo& info,
|
bool ReadMipLevel(HiresTexture::Level* level, File::IOFile& file, const DDSLoadInfo& info,
|
||||||
u32 width, u32 height, u32 row_length, size_t size)
|
u32 width, u32 height, u32 row_length, size_t size)
|
||||||
{
|
{
|
||||||
// Copy to the final storage location. The deallocator here is simple, nothing extra is
|
// Copy to the final storage location.
|
||||||
// needed, compared to the SOIL-based loader.
|
|
||||||
level->width = width;
|
level->width = width;
|
||||||
level->height = height;
|
level->height = height;
|
||||||
level->format = info.format;
|
level->format = info.format;
|
||||||
level->row_length = row_length;
|
level->row_length = row_length;
|
||||||
level->data_size = size;
|
level->data.resize(size);
|
||||||
level->data = AllocateLevelData(level->data_size);
|
if (!file.ReadBytes(level->data.data(), level->data.size()))
|
||||||
if (!file.ReadBytes(level->data.get(), level->data_size))
|
|
||||||
{
|
|
||||||
level->data.reset();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// Apply conversion function for uncompressed textures.
|
// Apply conversion function for uncompressed textures.
|
||||||
if (info.conversion_function)
|
if (info.conversion_function)
|
||||||
|
|
|
@ -957,8 +957,8 @@ TextureCacheBase::GetTexture(u32 address, u32 width, u32 height, const TextureFo
|
||||||
if (hires_tex)
|
if (hires_tex)
|
||||||
{
|
{
|
||||||
const auto& level = hires_tex->m_levels[0];
|
const auto& level = hires_tex->m_levels[0];
|
||||||
entry->texture->Load(0, level.width, level.height, level.row_length, level.data.get(),
|
entry->texture->Load(0, level.width, level.height, level.row_length, level.data.data(),
|
||||||
level.data_size);
|
level.data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialized to null because only software loading uses this buffer
|
// Initialized to null because only software loading uses this buffer
|
||||||
|
@ -1042,7 +1042,7 @@ TextureCacheBase::GetTexture(u32 address, u32 width, u32 height, const TextureFo
|
||||||
{
|
{
|
||||||
const auto& level = hires_tex->m_levels[level_index];
|
const auto& level = hires_tex->m_levels[level_index];
|
||||||
entry->texture->Load(level_index, level.width, level.height, level.row_length,
|
entry->texture->Load(level_index, level.width, level.height, level.row_length,
|
||||||
level.data.get(), level.data_size);
|
level.data.data(), level.data.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue