From 145450a0448a17a5d98b3888c4e4218632c13f86 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 22 Aug 2023 00:54:16 +0600 Subject: [PATCH] WebP image support --- .github/workflows/appimage.yml | 2 +- .github/workflows/continuous_integration.yml | 10 +- CMakeLists.txt | 14 ++ src/CMakeLists.txt | 8 ++ src/common/textures/formats/webptexture.cpp | 143 +++++++++++++++++++ src/common/textures/image.cpp | 2 + vcpkg.json | 4 + 7 files changed, 177 insertions(+), 6 deletions(-) create mode 100644 src/common/textures/formats/webptexture.cpp diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index e02a61097..885c32921 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -12,7 +12,7 @@ jobs: - name: Install GZDoom dependencies run: | sudo apt-get update - sudo apt-get install clang-12 libsdl2-dev libvpx-dev cmake -y + sudo apt-get install clang-12 libsdl2-dev libvpx-dev libwebp-dev cmake -y - name: Install appimage-builder dependencies run: | sudo apt-get install binutils coreutils desktop-file-utils fakeroot fuse libgdk-pixbuf2.0-dev patchelf -y diff --git a/.github/workflows/continuous_integration.yml b/.github/workflows/continuous_integration.yml index d18de22ea..4a7dcbee4 100644 --- a/.github/workflows/continuous_integration.yml +++ b/.github/workflows/continuous_integration.yml @@ -31,28 +31,28 @@ jobs: - { name: "macOS", os: macos-12, - deps_cmdline: "brew install libvpx", + deps_cmdline: "brew install libvpx webp", build_type: "Release" } - { name: "macOS", os: macos-12, extra_options: "-G Xcode -DDYN_OPENAL=OFF", - deps_cmdline: "brew install libvpx fluidsynth mpg123 libsndfile", + deps_cmdline: "brew install libvpx fluidsynth mpg123 libsndfile webp", build_type: "Debug" } - { name: "Linux GCC 7", os: ubuntu-20.04, extra_options: "-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7", - deps_cmdline: "sudo apt update && sudo apt install g++-7 libsdl2-dev libvpx-dev libgtk2.0-dev", + deps_cmdline: "sudo apt update && sudo apt install g++-7 libsdl2-dev libvpx-dev libgtk2.0-dev libwebp-dev", build_type: "RelWithDebInfo" } - { name: "Linux GCC 11", os: ubuntu-20.04, extra_options: "-DCMAKE_C_COMPILER=gcc-11 -DCMAKE_CXX_COMPILER=g++-11", - deps_cmdline: "sudo apt update && sudo apt install g++-11 libsdl2-dev libvpx-dev libgtk-3-dev", + deps_cmdline: "sudo apt update && sudo apt install g++-11 libsdl2-dev libvpx-dev libgtk-3-dev libwebp-dev", build_type: "MinSizeRel" } # - { @@ -66,7 +66,7 @@ jobs: name: "Linux Clang 12", os: ubuntu-20.04, extra_options: "-DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12", - deps_cmdline: "sudo apt update && sudo apt install clang-12 libsdl2-dev libvpx-dev", + deps_cmdline: "sudo apt update && sudo apt install clang-12 libsdl2-dev libvpx-dev libwebp-dev", build_type: "Release" } diff --git a/CMakeLists.txt b/CMakeLists.txt index 46205f0f8..d59560964 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,6 +217,20 @@ find_package( BZip2 ) find_package( JPEG ) find_package( VPX ) find_package( ZLIB ) +find_package( WebP ) +if (NOT WebP_FOUND) + include(FindPkgConfig) + pkg_check_modules(libwebp IMPORTED_TARGET libwebp) + if (NOT TARGET PkgConfig::libwebp) + message(SEND_ERROR "libwebp not found") + endif() + pkg_check_modules(libwebpmux REQUIRED IMPORTED_TARGET libwebpmux) + pkg_check_modules(libwebpdemux REQUIRED IMPORTED_TARGET libwebpdemux) + + add_library(WebP::webp ALIAS PkgConfig::libwebp) + add_library(WebP::webpdemux ALIAS PkgConfig::libwebpdemux) + add_library(WebP::libwebpmux ALIAS PkgConfig::libwebpmux) +endif() include( TargetArch ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3ee43be60..04f19ef68 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -380,6 +380,13 @@ else() message( SEND_ERROR "Could not find libvpx" ) endif() +if (TARGET WebP::webp) + list( APPEND PROJECT_LIBRARIES WebP::webp WebP::webpdemux WebP::libwebpmux ) + if (TARGET WebP::webpdecoder) + list( APPEND PROJECT_LIBRARIES WebP::webpdecoder) + endif() +endif() + include_directories( SYSTEM "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${ZMUSIC_INCLUDE_DIR}" "${DRPC_INCLUDE_DIR}") if( ${HAVE_VM_JIT} ) @@ -1028,6 +1035,7 @@ set (PCH_SOURCES common/textures/formats/anmtexture.cpp common/textures/formats/startscreentexture.cpp common/textures/formats/qoitexture.cpp + common/textures/formats/webptexture.cpp common/textures/hires/hqresize.cpp common/models/models_md3.cpp common/models/models_md2.cpp diff --git a/src/common/textures/formats/webptexture.cpp b/src/common/textures/formats/webptexture.cpp new file mode 100644 index 000000000..60a9ccbc3 --- /dev/null +++ b/src/common/textures/formats/webptexture.cpp @@ -0,0 +1,143 @@ +/* +** webptexture.cpp +** Texture class for WebP images. +** +**--------------------------------------------------------------------------- +** Copyright 2023 Cacodemon345 +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ +#include "webp/decode.h" +#include "webp/mux.h" + +#include "files.h" +#include "filesystem.h" +#include "bitmap.h" +#include "imagehelpers.h" +#include "image.h" +#include "printf.h" + +class FWebPTexture : public FImageSource +{ + +public: + FWebPTexture(int lumpnum, int w, int h, int xoff, int yoff); + PalettedPixels CreatePalettedPixels(int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion) override; +}; + + +FImageSource *WebPImage_TryCreate(FileReader &file, int lumpnum) +{ + int width = 0, height = 0; + int xoff = 0, yoff = 0; + file.Seek(0, FileReader::SeekSet); + auto bytes = file.Read(); + + if (WebPGetInfo(bytes.Data(), bytes.Size(), &width, &height)) + { + WebPData data{ bytes.Data(), bytes.Size() }; + WebPData chunk_data; + auto mux = WebPMuxCreate(&data, 0); + if (mux) + { + const char fourcc[4] = { 'g', 'r', 'A', 'b' }; + if (WebPMuxGetChunk(mux, fourcc, &chunk_data) == WEBP_MUX_OK && chunk_data.size >= 4) + { + xoff = chunk_data.bytes[0] | (chunk_data.bytes[1] << 8); + yoff = chunk_data.bytes[2] | (chunk_data.bytes[3] << 8); + } + WebPMuxDelete(mux); + } + return new FWebPTexture(lumpnum, width, height, xoff, yoff); + } + return NULL; +} + +FWebPTexture::FWebPTexture(int lumpnum, int w, int h, int xoff, int yoff) + : FImageSource(lumpnum) +{ + Width = w; + Height = h; + LeftOffset = xoff; + TopOffset = yoff; +} + +PalettedPixels FWebPTexture::CreatePalettedPixels(int conversion) +{ + FBitmap bitmap; + bitmap.Create(Width, Height); + CopyPixels(&bitmap, conversion); + const uint8_t *data = bitmap.GetPixels(); + + uint8_t *dest_p; + int dest_adv = Height; + int dest_rew = Width * Height - 1; + + PalettedPixels Pixels(Width*Height); + dest_p = Pixels.Data(); + + bool doalpha = conversion == luminance; + // Convert the source image from row-major to column-major format and remap it + for (int y = Height; y != 0; --y) + { + for (int x = Width; x != 0; --x) + { + int b = *data++; + int g = *data++; + int r = *data++; + int a = *data++; + if (a < 128) *dest_p = 0; + else *dest_p = ImageHelpers::RGBToPalette(doalpha, r, g, b); + dest_p += dest_adv; + } + dest_p -= dest_rew; + } + return Pixels; +} + +int FWebPTexture::CopyPixels(FBitmap *bmp, int conversion) +{ + WebPDecoderConfig config; + auto lump = fileSystem.OpenFileReader(SourceLump); + auto bytes = lump.Read(); + + if (WebPInitDecoderConfig(&config) == false) + return 0; + + config.options.no_fancy_upsampling = 0; + config.output.colorspace = MODE_BGRA; + config.output.u.RGBA.rgba = (uint8_t*)bmp->GetPixels(); + config.output.u.RGBA.size = bmp->GetBufferSize(); + config.output.u.RGBA.stride = bmp->GetPitch(); + config.output.is_external_memory = 1; + + (void)WebPDecode(bytes.Data(), bytes.Size(), &config); + + return 0; +} diff --git a/src/common/textures/image.cpp b/src/common/textures/image.cpp index e1939dfe1..dcd1f28d3 100644 --- a/src/common/textures/image.cpp +++ b/src/common/textures/image.cpp @@ -323,6 +323,7 @@ FImageSource *PCXImage_TryCreate(FileReader &, int lumpnum); FImageSource *TGAImage_TryCreate(FileReader &, int lumpnum); FImageSource *StbImage_TryCreate(FileReader &, int lumpnum); FImageSource *QOIImage_TryCreate(FileReader &, int lumpnum); +FImageSource *WebPImage_TryCreate(FileReader &, int lumpnum); FImageSource *AnmImage_TryCreate(FileReader &, int lumpnum); FImageSource *RawPageImage_TryCreate(FileReader &, int lumpnum); FImageSource *FlatImage_TryCreate(FileReader &, int lumpnum); @@ -344,6 +345,7 @@ FImageSource * FImageSource::GetImage(int lumpnum, bool isflat) { PCXImage_TryCreate, false }, { StbImage_TryCreate, false }, { QOIImage_TryCreate, false }, + { WebPImage_TryCreate, false }, { TGAImage_TryCreate, false }, { AnmImage_TryCreate, false }, { StartupPageImage_TryCreate, false }, diff --git a/vcpkg.json b/vcpkg.json index 941888414..d89c12d12 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -46,6 +46,10 @@ { "name": "libvpx", "platform": "!windows" + }, + { + "name": "libwebp", + "platform": "!windows | (windows & static & staticcrt)" } ] } \ No newline at end of file