summaryrefslogtreecommitdiff
path: root/Source/Core/Common
diff options
context:
space:
mode:
authorEmmanuel Gil Peyrot <linkmauve@linkmauve.fr>2016-12-27 16:32:32 +0100
committerJosJuice <josjuice@gmail.com>2018-05-20 13:44:38 +0200
commit17e65a7167caaf9d55ae7ea0141c298d02689ea2 (patch)
treea85016919258539bddc6d3847fe8932c6d882361 /Source/Core/Common
parent0706add5840edcc7faeca538dafcd4f56cee7940 (diff)
VideoCommon: Replace SOIL with libpng for hires textures
Diffstat (limited to 'Source/Core/Common')
-rw-r--r--Source/Core/Common/CMakeLists.txt2
-rw-r--r--Source/Core/Common/Common.vcxproj5
-rw-r--r--Source/Core/Common/Common.vcxproj.filters2
-rw-r--r--Source/Core/Common/Image.cpp180
-rw-r--r--Source/Core/Common/Image.h15
5 files changed, 204 insertions, 0 deletions
diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt
index cf87fd6e38..c0e3e94462 100644
--- a/Source/Core/Common/CMakeLists.txt
+++ b/Source/Core/Common/CMakeLists.txt
@@ -18,6 +18,7 @@ add_library(common
GekkoDisassembler.cpp
Hash.cpp
HttpRequest.cpp
+ Image.cpp
IniFile.cpp
JitRegister.cpp
Logging/LogManager.cpp
@@ -54,6 +55,7 @@ PUBLIC
PRIVATE
${CURL_LIBRARIES}
${ICONV_LIBRARIES}
+ png
${VTUNE_LIBRARIES}
)
diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj
index db4031ed0a..c03dd0b6ac 100644
--- a/Source/Core/Common/Common.vcxproj
+++ b/Source/Core/Common/Common.vcxproj
@@ -125,6 +125,7 @@
<ClInclude Include="FloatUtils.h" />
<ClInclude Include="Hash.h" />
<ClInclude Include="HttpRequest.h" />
+ <ClInclude Include="Image.h" />
<ClInclude Include="IniFile.h" />
<ClInclude Include="JitRegister.h" />
<ClInclude Include="Lazy.h" />
@@ -188,6 +189,7 @@
<ClCompile Include="GL\GLUtil.cpp" />
<ClCompile Include="Hash.cpp" />
<ClCompile Include="HttpRequest.cpp" />
+ <ClCompile Include="Image.cpp" />
<ClCompile Include="IniFile.cpp" />
<ClCompile Include="JitRegister.cpp" />
<ClCompile Include="LdrWatcher.cpp" />
@@ -230,6 +232,9 @@
<ProjectReference Include="$(ExternalsDir)mbedtls\mbedTLS.vcxproj">
<Project>{bdb6578b-0691-4e80-a46c-df21639fd3b8}</Project>
</ProjectReference>
+ <ProjectReference Include="$(ExternalsDir)libpng\png\png.vcxproj">
+ <Project>{4c9f135b-a85e-430c-bad4-4c67ef5fc12c}</Project>
+ </ProjectReference>
<ProjectReference Include="..\..\..\Externals\curl\curl.vcxproj">
<Project>{bb00605c-125f-4a21-b33b-7bf418322dcb}</Project>
</ProjectReference>
diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters
index 8e0817faf1..b26498b90b 100644
--- a/Source/Core/Common/Common.vcxproj.filters
+++ b/Source/Core/Common/Common.vcxproj.filters
@@ -51,6 +51,7 @@
<ClInclude Include="FPURoundMode.h" />
<ClInclude Include="Hash.h" />
<ClInclude Include="HttpRequest.h" />
+ <ClInclude Include="Image.h" />
<ClInclude Include="IniFile.h" />
<ClInclude Include="LinearDiskCache.h" />
<ClInclude Include="MathUtil.h" />
@@ -281,6 +282,7 @@
<ClCompile Include="FloatUtils.cpp" />
<ClCompile Include="Hash.cpp" />
<ClCompile Include="HttpRequest.cpp" />
+ <ClCompile Include="Image.cpp" />
<ClCompile Include="IniFile.cpp" />
<ClCompile Include="MathUtil.cpp" />
<ClCompile Include="MemArena.cpp" />
diff --git a/Source/Core/Common/Image.cpp b/Source/Core/Common/Image.cpp
new file mode 100644
index 0000000000..2ce3fbfabf
--- /dev/null
+++ b/Source/Core/Common/Image.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
diff --git a/Source/Core/Common/Image.h b/Source/Core/Common/Image.h
new file mode 100644
index 0000000000..d1354b8e0b
--- /dev/null
+++ b/Source/Core/Common/Image.h
@@ -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);
+}