From 450ca5f5ec8289bf492f663fdc31cde7ede6ae99 Mon Sep 17 00:00:00 2001 From: owenisas Date: Fri, 23 Oct 2026 16:04:51 +0800 Subject: [PATCH 1/5] Fix backlog crash on entries without glyphs --- src/ui/backlogmenu.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ui/backlogmenu.cpp b/src/ui/backlogmenu.cpp index a86c27e35..7d411cd83 100644 --- a/src/ui/backlogmenu.cpp +++ b/src/ui/backlogmenu.cpp @@ -359,12 +359,16 @@ void BacklogMenu::AddMessage(Vm::BufferOffsetContext scrCtx, auto onClick = [this](auto* btn) { return MenuButtonOnClick(btn); }; + // SG0 adds empty entries with SetRevMes. + const auto entryBottom = [](const EntryType& entry) { + return entry.Page.Glyphs.empty() + ? entry.Bounds.Bottom() + : entry.Page.Glyphs.back().DestRect.Bottom(); + }; const glm::vec2 entryPos = - Entries.empty() - ? EntriesStart - : glm::vec2(EntriesStart.x, - Entries.front().Page.Glyphs.back().DestRect.Bottom() + - EntryYPadding); + Entries.empty() ? EntriesStart + : glm::vec2(EntriesStart.x, + entryBottom(Entries.front()) + EntryYPadding); if (Entries.full()) { ItemsHeight -= Entries.back().Bounds.Height + EntryYPadding; From f3d0247dc8364cc3a59536823fe6a3c3df8cafc1 Mon Sep 17 00:00:00 2001 From: owenisas Date: Fri, 23 Oct 2026 16:04:51 +0800 Subject: [PATCH 2/5] Make DDS loading thread safe --- src/texture/ddsloader.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/texture/ddsloader.cpp b/src/texture/ddsloader.cpp index 7810919e3..7350a1b3f 100644 --- a/src/texture/ddsloader.cpp +++ b/src/texture/ddsloader.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause // https://github.com/OpenImageIO/oiio/blob/master/LICENSE.md +#include #include #include "../log.h" @@ -200,6 +201,10 @@ bool internal_readimg(Stream* stream, uint8_t* dst, int w, int h, int d) { } bool TextureLoadDDS(Stream* stream, Texture* outTexture) { + // The decoder state is global and spritesheets load concurrently. + static std::mutex loaderMutex; + std::lock_guard lock(loaderMutex); + stream->Seek(0, IoSeek::Set); m_dds.fourCC = ReadLE(stream); From 59c82331b94028b5de5616aafb214d54c1153d68 Mon Sep 17 00:00:00 2001 From: owenisas Date: Fri, 23 Oct 2026 16:04:51 +0800 Subject: [PATCH 3/5] Support full-range and YUVA420P video frames --- src/video/ffmpegplayer.cpp | 72 ++++++++++++++++++++++++++++++++++++-- src/video/ffmpegplayer.h | 6 ++++ 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/video/ffmpegplayer.cpp b/src/video/ffmpegplayer.cpp index e162e3726..73d26865d 100644 --- a/src/video/ffmpegplayer.cpp +++ b/src/video/ffmpegplayer.cpp @@ -1,5 +1,6 @@ #include "ffmpegplayer.h" +#include #include #include #include @@ -786,6 +787,11 @@ void FFmpegPlayer::Update(float dt) { VideoTexture = Renderer->CreateYUVFrame( (float)VideoStream->CodecContext.width(), (float)VideoStream->CodecContext.height()); + } else if (frame->Frame.pixelFormat() == AV_PIX_FMT_YUVA420P) { + VideoTexture = Renderer->CreateYUVFrame( + (float)VideoStream->CodecContext.width(), + (float)VideoStream->CodecContext.height() * + (IsAlpha ? 2.0f : 1.0f)); } else if (frame->Frame.pixelFormat() == AV_PIX_FMT_NV12) { VideoTexture = Renderer->CreateNV12Frame( (float)VideoStream->CodecContext.width(), @@ -800,9 +806,15 @@ void FFmpegPlayer::Update(float dt) { nv12Frame->Submit(frame->Frame.data(0), frame->Frame.raw()->linesize[0], frame->Frame.data(1), frame->Frame.raw()->linesize[1]); } else if (frame->Frame.pixelFormat() == AV_PIX_FMT_YUV420P) { - auto& yuvFrame = std::get(VideoTexture); - yuvFrame->Submit(frame->Frame.data(0), frame->Frame.data(1), - frame->Frame.data(2)); + if (frame->Frame.raw()->color_range == AVCOL_RANGE_JPEG) { + SubmitRepackedFrame(frame->Frame.raw()); + } else { + auto& yuvFrame = std::get(VideoTexture); + yuvFrame->Submit(frame->Frame.data(0), frame->Frame.data(1), + frame->Frame.data(2)); + } + } else if (frame->Frame.pixelFormat() == AV_PIX_FMT_YUVA420P) { + SubmitRepackedFrame(frame->Frame.raw()); } else { ImpLog(LogLevel::Warning, LogChannel::Video, "Unsupported frame pixel format, video will not display!\n"); @@ -816,6 +828,60 @@ void FFmpegPlayer::Update(float dt) { } } +void FFmpegPlayer::SubmitRepackedFrame(const AVFrame* frame) { + // Lookup tables from full range to video range. + static const auto tables = [] { + std::array, 4> t{}; + for (int v = 0; v < 256; v++) { + t[0][v] = static_cast(v); + t[1][v] = static_cast(16 + (v * 219 + 127) / 255); + t[2][v] = static_cast( + 128 + ((v - 128) * 224 + (v >= 128 ? 127 : -127)) / 255); + } + t[3] = t[1]; + return t; + }(); + const bool fullRange = frame->color_range == AVCOL_RANGE_JPEG; + const auto& lumaTable = tables[fullRange ? 1 : 0]; + const auto& chromaTable = tables[fullRange ? 2 : 0]; + + const int width = frame->width; + const int height = frame->height; + const int chromaWidth = (width + 1) / 2; + const int chromaHeight = (height + 1) / 2; + const bool withAlpha = IsAlpha && frame->format == AV_PIX_FMT_YUVA420P; + const int halves = withAlpha ? 2 : 1; + PackedLuma.resize(static_cast(width) * height * halves); + PackedCb.assign(static_cast(chromaWidth) * chromaHeight * halves, + 128); + PackedCr.assign(PackedCb.size(), 128); + + const auto copyPlane = [](uint8_t* dst, const uint8_t* src, int srcStride, + int rowBytes, int rows, + const std::array& table) { + for (int y = 0; y < rows; y++) { + const uint8_t* in = src + static_cast(y) * srcStride; + uint8_t* out = dst + static_cast(y) * rowBytes; + for (int x = 0; x < rowBytes; x++) out[x] = table[in[x]]; + } + }; + copyPlane(PackedLuma.data(), frame->data[0], frame->linesize[0], width, + height, lumaTable); + copyPlane(PackedCb.data(), frame->data[1], frame->linesize[1], chromaWidth, + chromaHeight, chromaTable); + copyPlane(PackedCr.data(), frame->data[2], frame->linesize[2], chromaWidth, + chromaHeight, chromaTable); + if (withAlpha) { + // The shader reads alpha through its YUV matrix, so store it as + // video-range luma. + copyPlane(PackedLuma.data() + static_cast(width) * height, + frame->data[3], frame->linesize[3], width, height, tables[3]); + } + + std::get(VideoTexture) + ->Submit(PackedLuma.data(), PackedCb.data(), PackedCr.data()); +} + void FFmpegPlayer::UpdateSubtitles() { for (auto& subtitleStream : EmbeddedSubtitleStreams) { Video::AVDecodedItem subtitle; diff --git a/src/video/ffmpegplayer.h b/src/video/ffmpegplayer.h index af1871a71..78579c0db 100644 --- a/src/video/ffmpegplayer.h +++ b/src/video/ffmpegplayer.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -99,6 +100,11 @@ class FFmpegPlayer : public VideoPlayer { std::variant VideoTexture; bool IsAlpha = false; + // Full-range and YUVA420P frames get repacked into what the shader expects. + void SubmitRepackedFrame(const AVFrame* frame); + std::vector PackedLuma; + std::vector PackedCb; + std::vector PackedCr; bool Looping = false; bool ReaderEOF = false; bool PlaybackStarted = false; From bcc93a1bf1a204f923be0f7c8b85ab47f092c1c3 Mon Sep 17 00:00:00 2001 From: owenisas Date: Fri, 23 Oct 2026 16:04:51 +0800 Subject: [PATCH 4/5] Add the Bink 2 decoder to the FFmpeg port --- .../ffmpeg/0001-create-lib-libraries.patch | 27 + portfiles/ffmpeg/0002-fix-msvc-link.patch | 11 + .../ffmpeg/0003-fix-windowsinclude.patch | 13 + portfiles/ffmpeg/0004-dependencies.patch | 65 + portfiles/ffmpeg/0005-fix-nasm.patch | 78 + portfiles/ffmpeg/0007-fix-lib-naming.patch | 12 + portfiles/ffmpeg/0013-define-WINVER.patch | 15 + .../ffmpeg/0020-fix-aarch64-libswscale.patch | 28 + portfiles/ffmpeg/0024-fix-osx-host-c11.patch | 15 + ...av_stream_get_first_dts-for-chromium.patch | 35 + ...0041-add-const-for-opengl-definition.patch | 13 + portfiles/ffmpeg/0042-fix-arm64-linux.patch | 9 + portfiles/ffmpeg/0043-fix-miss-head.patch | 12 + .../0044-fix-vulkan-debug-callback-abi.patch | 13 + portfiles/ffmpeg/1000-bink2-decoder.patch | 3865 +++++++++++++++++ .../ffmpeg/1001-bink2-alpha-boolean.patch | 11 + portfiles/ffmpeg/FindFFMPEG.cmake.in | 166 + portfiles/ffmpeg/build.sh.in | 142 + portfiles/ffmpeg/portfile.cmake | 1039 +++++ portfiles/ffmpeg/usage | 29 + portfiles/ffmpeg/vcpkg-cmake-wrapper.cmake | 334 ++ portfiles/ffmpeg/vcpkg.json | 754 ++++ 22 files changed, 6686 insertions(+) create mode 100644 portfiles/ffmpeg/0001-create-lib-libraries.patch create mode 100644 portfiles/ffmpeg/0002-fix-msvc-link.patch create mode 100644 portfiles/ffmpeg/0003-fix-windowsinclude.patch create mode 100644 portfiles/ffmpeg/0004-dependencies.patch create mode 100644 portfiles/ffmpeg/0005-fix-nasm.patch create mode 100644 portfiles/ffmpeg/0007-fix-lib-naming.patch create mode 100644 portfiles/ffmpeg/0013-define-WINVER.patch create mode 100644 portfiles/ffmpeg/0020-fix-aarch64-libswscale.patch create mode 100644 portfiles/ffmpeg/0024-fix-osx-host-c11.patch create mode 100644 portfiles/ffmpeg/0040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch create mode 100644 portfiles/ffmpeg/0041-add-const-for-opengl-definition.patch create mode 100644 portfiles/ffmpeg/0042-fix-arm64-linux.patch create mode 100644 portfiles/ffmpeg/0043-fix-miss-head.patch create mode 100644 portfiles/ffmpeg/0044-fix-vulkan-debug-callback-abi.patch create mode 100644 portfiles/ffmpeg/1000-bink2-decoder.patch create mode 100644 portfiles/ffmpeg/1001-bink2-alpha-boolean.patch create mode 100644 portfiles/ffmpeg/FindFFMPEG.cmake.in create mode 100644 portfiles/ffmpeg/build.sh.in create mode 100644 portfiles/ffmpeg/portfile.cmake create mode 100644 portfiles/ffmpeg/usage create mode 100644 portfiles/ffmpeg/vcpkg-cmake-wrapper.cmake create mode 100644 portfiles/ffmpeg/vcpkg.json diff --git a/portfiles/ffmpeg/0001-create-lib-libraries.patch b/portfiles/ffmpeg/0001-create-lib-libraries.patch new file mode 100644 index 000000000..ced7ba86b --- /dev/null +++ b/portfiles/ffmpeg/0001-create-lib-libraries.patch @@ -0,0 +1,27 @@ +diff --git a/configure b/configure +index 1f0b9497cb..3243e23021 100644 +--- a/configure ++++ b/configure +@@ -5697,17 +5697,19 @@ case $target_os in + ;; + win32|win64) + disable symver +- if enabled shared; then ++# if enabled shared; then + # Link to the import library instead of the normal static library + # for shared libs. + LD_LIB='%.lib' + # Cannot build both shared and static libs with MSVC or icl. +- disable static +- fi ++# disable static ++# fi + ! enabled small && test_cmd $windres --version && enable gnu_windres + enabled x86_32 && check_ldflags -LARGEADDRESSAWARE + add_cppflags -DWIN32_LEAN_AND_MEAN + shlibdir_default="$bindir_default" ++ LIBPREF="" ++ LIBSUF=".lib" + SLIBPREF="" + SLIBSUF=".dll" + SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME)-$(LIBVERSION)$(SLIBSUF)' diff --git a/portfiles/ffmpeg/0002-fix-msvc-link.patch b/portfiles/ffmpeg/0002-fix-msvc-link.patch new file mode 100644 index 000000000..c9aa7e752 --- /dev/null +++ b/portfiles/ffmpeg/0002-fix-msvc-link.patch @@ -0,0 +1,11 @@ +diff --git a/configure b/configure +--- a/configure ++++ b/configure +@@ -6162,6 +6162,7 @@ EOF + test -n "$extern_prefix" && append X86ASMFLAGS "-DPREFIX" + case "$objformat" in + elf*) enabled debug && append X86ASMFLAGS $x86asm_debug ;; ++ win*) enabled debug && append X86ASMFLAGS "-g" ;; + esac + + enabled avx512 && check_x86asm avx512_external "vmovdqa32 [eax]{k1}{z}, zmm0" diff --git a/portfiles/ffmpeg/0003-fix-windowsinclude.patch b/portfiles/ffmpeg/0003-fix-windowsinclude.patch new file mode 100644 index 000000000..8b2e22b47 --- /dev/null +++ b/portfiles/ffmpeg/0003-fix-windowsinclude.patch @@ -0,0 +1,13 @@ +diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c +--- a/fftools/cmdutils.c ++++ b/fftools/cmdutils.c +@@ -51,6 +51,8 @@ + #include "fopen_utf8.h" + #include "opt_common.h" + #ifdef _WIN32 ++#define _WIN32_WINNT 0x0502 ++#define WIN32_LEAN_AND_MEAN + #include + #include "compat/w32dlfcn.h" + #endif + diff --git a/portfiles/ffmpeg/0004-dependencies.patch b/portfiles/ffmpeg/0004-dependencies.patch new file mode 100644 index 000000000..f1f6e72be --- /dev/null +++ b/portfiles/ffmpeg/0004-dependencies.patch @@ -0,0 +1,65 @@ +diff --git a/configure b/configure +index a8b74e0..c99f41c 100755 +--- a/configure ++++ b/configure +@@ -6633,7 +6633,7 @@ fi + + enabled zlib && { check_pkg_config zlib zlib "zlib.h" zlibVersion || + check_lib zlib zlib.h zlibVersion -lz; } +-enabled bzlib && check_lib bzlib bzlib.h BZ2_bzlibVersion -lbz2 ++enabled bzlib && require_pkg_config bzlib bzip2 bzlib.h BZ2_bzlibVersion + enabled lzma && check_lib lzma lzma.h lzma_version_number -llzma + + enabled zlib && test_exec $zlib_extralibs <= 3.98.3" lame/lame.h lame_set_VBR_quality -lmp3lame $libm_extralibs ++enabled libmp3lame && { check_lib libmp3lame lame/lame.h lame_set_VBR_quality -lmp3lame $libm_extralibs || ++ require libmp3lame lame/lame.h lame_set_VBR_quality -llibmp3lame-static -llibmpghip-static $libm_extralibs; } + enabled libmysofa && { check_pkg_config libmysofa libmysofa mysofa.h mysofa_neighborhood_init_withstepdefine || + require libmysofa mysofa.h mysofa_neighborhood_init_withstepdefine -lmysofa $zlib_extralibs; } + enabled libnpp && { check_lib libnpp npp.h nppGetLibVersion -lnppig -lnppicc -lnppc -lnppidei -lnppif || +@@ -6772,7 +6773,7 @@ require_pkg_config libopencv opencv opencv/cxcore.h cvCreateImageHeader; } + enabled libopenh264 && require_pkg_config libopenh264 "openh264 >= 1.3.0" wels/codec_api.h WelsGetCodecVersion + enabled libopenjpeg && { check_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version || + { require_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } } +-enabled libopenmpt && require_pkg_config libopenmpt "libopenmpt >= 0.2.6557" libopenmpt/libopenmpt.h openmpt_module_create -lstdc++ && append libopenmpt_extralibs "-lstdc++" ++enabled libopenmpt && require_pkg_config libopenmpt "libopenmpt >= 0.2.6557" libopenmpt/libopenmpt.h openmpt_module_create + enabled libopenvino && { { check_pkg_config libopenvino openvino openvino/c/openvino.h ov_core_create && enable openvino2; } || + { check_pkg_config libopenvino openvino c_api/ie_c_api.h ie_c_api_version || + require libopenvino c_api/ie_c_api.h ie_c_api_version -linference_engine_c_api; } } +@@ -6796,8 +6797,8 @@ enabled libshaderc && require_pkg_config spirv_compiler "shaderc >= 2019. + enabled libshine && require_pkg_config libshine shine shine/layer3.h shine_encode_buffer + enabled libsmbclient && { check_pkg_config libsmbclient smbclient libsmbclient.h smbc_init || + require libsmbclient libsmbclient.h smbc_init -lsmbclient; } +-enabled libsnappy && require libsnappy snappy-c.h snappy_compress -lsnappy -lstdc++ +-enabled libsoxr && require libsoxr soxr.h soxr_create -lsoxr ++enabled libsnappy && require_pkg_config libsnappy snappy snappy-c.h snappy_compress ++enabled libsoxr && require libsoxr soxr.h soxr_create -lsoxr $libm_extralibs + enabled libssh && require_pkg_config libssh "libssh >= 0.6.0" libssh/sftp.h sftp_init + enabled libspeex && require_pkg_config libspeex speex speex/speex.h speex_decoder_init + enabled libsrt && require_pkg_config libsrt "srt >= 1.3.0" srt/srt.h srt_socket +@@ -6880,6 +6881,8 @@ enabled openal && { check_pkg_config openal "openal >= 1.1" "AL/al.h" + enabled opencl && { check_pkg_config opencl OpenCL CL/cl.h clEnqueueNDRangeKernel || + check_lib opencl OpenCL/cl.h clEnqueueNDRangeKernel "-framework OpenCL" || + check_lib opencl CL/cl.h clEnqueueNDRangeKernel -lOpenCL || ++ check_lib opencl CL/cl.h clEnqueueNDRangeKernel -lOpenCL -lAdvapi32 -lOle32 -lCfgmgr32|| ++ check_lib opencl CL/cl.h clEnqueueNDRangeKernel -lOpenCL -pthread -ldl || + die "ERROR: opencl not found"; } && + { test_cpp_condition "OpenCL/cl.h" "defined(CL_VERSION_1_2)" || + test_cpp_condition "CL/cl.h" "defined(CL_VERSION_1_2)" || +@@ -7204,10 +7207,10 @@ enabled amf && + "(AMF_VERSION_MAJOR << 48 | AMF_VERSION_MINOR << 32 | AMF_VERSION_RELEASE << 16 | AMF_VERSION_BUILD_NUM) >= 0x0001000400210000" + + # Funny iconv installations are not unusual, so check it after all flags have been set +-if enabled libc_iconv; then ++if enabled libc_iconv && disabled iconv; then + check_func_headers iconv.h iconv + elif enabled iconv; then +- check_func_headers iconv.h iconv || check_lib iconv iconv.h iconv -liconv ++ check_func_headers iconv.h iconv || check_lib iconv iconv.h iconv -liconv || check_lib iconv iconv.h iconv -liconv -lcharset + fi + + enabled debug && add_cflags -g"$debuglevel" && add_asflags -g"$debuglevel" diff --git a/portfiles/ffmpeg/0005-fix-nasm.patch b/portfiles/ffmpeg/0005-fix-nasm.patch new file mode 100644 index 000000000..68b7503b2 --- /dev/null +++ b/portfiles/ffmpeg/0005-fix-nasm.patch @@ -0,0 +1,78 @@ +diff --git a/libavcodec/x86/mlpdsp.asm b/libavcodec/x86/mlpdsp.asm +index 3dc641e..609b834 100644 +--- a/libavcodec/x86/mlpdsp.asm ++++ b/libavcodec/x86/mlpdsp.asm +@@ -23,7 +23,9 @@ + + SECTION .text + +-%if ARCH_X86_64 ++%ifn ARCH_X86_64 ++mlpdsp_placeholder: times 4 db 0 ++%else + + %macro SHLX 2 + %if cpuflag(bmi2) +diff --git a/libavcodec/x86/proresdsp.asm b/libavcodec/x86/proresdsp.asm +index 65c9fad..5ad73f3 100644 +--- a/libavcodec/x86/proresdsp.asm ++++ b/libavcodec/x86/proresdsp.asm +@@ -24,7 +24,10 @@ + + %include "libavutil/x86/x86util.asm" + +-%if ARCH_X86_64 ++%ifn ARCH_X86_64 ++SECTION .rdata ++proresdsp_placeholder: times 4 db 0 ++%else + + SECTION_RODATA + +diff --git a/libavcodec/x86/vvc/vvc_mc.asm b/libavcodec/x86/vvc/vvc_mc.asm +index 30aa97c..3975f98 100644 +--- a/libavcodec/x86/vvc/vvc_mc.asm ++++ b/libavcodec/x86/vvc/vvc_mc.asm +@@ -31,7 +31,9 @@ + + SECTION_RODATA 32 + +-%if ARCH_X86_64 ++%ifn ARCH_X86_64 ++vvc_mc_placeholder: times 4 db 0 ++%else + + %if HAVE_AVX2_EXTERNAL + +diff --git a/libavfilter/x86/vf_atadenoise.asm b/libavfilter/x86/vf_atadenoise.asm +index 4945ad3..748b65a 100644 +--- a/libavfilter/x86/vf_atadenoise.asm ++++ b/libavfilter/x86/vf_atadenoise.asm +@@ -20,7 +20,10 @@ + ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + ;****************************************************************************** + +-%if ARCH_X86_64 ++%ifn ARCH_X86_64 ++SECTION .rdata ++vf_atadenoise_placeholder: times 4 db 0 ++%else + + %include "libavutil/x86/x86util.asm" + +diff --git a/libavfilter/x86/vf_nlmeans.asm b/libavfilter/x86/vf_nlmeans.asm +index 8f57801..9aef3a4 100644 +--- a/libavfilter/x86/vf_nlmeans.asm ++++ b/libavfilter/x86/vf_nlmeans.asm +@@ -21,7 +21,10 @@ + + %include "libavutil/x86/x86util.asm" + +-%if HAVE_AVX2_EXTERNAL && ARCH_X86_64 ++%ifn HAVE_AVX2_EXTERNAL && ARCH_X86_64 ++SECTION .rdata ++vf_nlmeans_placeholder: times 4 db 0 ++%else + + SECTION_RODATA 32 + diff --git a/portfiles/ffmpeg/0007-fix-lib-naming.patch b/portfiles/ffmpeg/0007-fix-lib-naming.patch new file mode 100644 index 000000000..c22f9c199 --- /dev/null +++ b/portfiles/ffmpeg/0007-fix-lib-naming.patch @@ -0,0 +1,12 @@ +diff --git a/configure b/configure +index d6c4388..75b96c3 100644 +--- a/configure ++++ b/configure +@@ -4781,6 +4781,7 @@ msvc_common_flags(){ + -mfp16-format=*) ;; + -lz) echo zlib.lib ;; + -lx264) echo libx264.lib ;; ++ -lmp3lame) echo libmp3lame.lib ;; + -lstdc++) ;; + -l*) echo ${flag#-l}.lib ;; + -LARGEADDRESSAWARE) echo $flag ;; diff --git a/portfiles/ffmpeg/0013-define-WINVER.patch b/portfiles/ffmpeg/0013-define-WINVER.patch new file mode 100644 index 000000000..295a738e7 --- /dev/null +++ b/portfiles/ffmpeg/0013-define-WINVER.patch @@ -0,0 +1,15 @@ +diff --color -Naur src_old/libavcodec/mf_utils.c src/libavcodec/mf_utils.c +--- src_old/libavcodec/mf_utils.c 2020-07-11 05:26:17.000000000 +0700 ++++ src/libavcodec/mf_utils.c 2020-11-13 12:55:57.226976400 +0700 +@@ -22,6 +22,11 @@ + #define _WIN32_WINNT 0x0602 + #endif + ++#if !defined(WINVER) || WINVER < 0x0602 ++#undef WINVER ++#define WINVER 0x0602 ++#endif ++ + #include "mf_utils.h" + #include "libavutil/pixdesc.h" + diff --git a/portfiles/ffmpeg/0020-fix-aarch64-libswscale.patch b/portfiles/ffmpeg/0020-fix-aarch64-libswscale.patch new file mode 100644 index 000000000..f47e82ed8 --- /dev/null +++ b/portfiles/ffmpeg/0020-fix-aarch64-libswscale.patch @@ -0,0 +1,28 @@ +diff --git a/libswscale/aarch64/yuv2rgb_neon.S b/libswscale/aarch64/yuv2rgb_neon.S +index 89d69e7f6c..4bc1607a7a 100644 +--- a/libswscale/aarch64/yuv2rgb_neon.S ++++ b/libswscale/aarch64/yuv2rgb_neon.S +@@ -169,19 +169,19 @@ function ff_\ifmt\()_to_\ofmt\()_neon, export=1 + sqdmulh v26.8h, v26.8h, v0.8h // ((Y1*(1<<3) - y_offset) * y_coeff) >> 15 + sqdmulh v27.8h, v27.8h, v0.8h // ((Y2*(1<<3) - y_offset) * y_coeff) >> 15 + +-.ifc \ofmt,argb // 1 2 3 0 ++.ifc \ofmt,argb + compute_rgba v5.8b,v6.8b,v7.8b,v4.8b, v17.8b,v18.8b,v19.8b,v16.8b + .endif + +-.ifc \ofmt,rgba // 0 1 2 3 ++.ifc \ofmt,rgba + compute_rgba v4.8b,v5.8b,v6.8b,v7.8b, v16.8b,v17.8b,v18.8b,v19.8b + .endif + +-.ifc \ofmt,abgr // 3 2 1 0 ++.ifc \ofmt,abgr + compute_rgba v7.8b,v6.8b,v5.8b,v4.8b, v19.8b,v18.8b,v17.8b,v16.8b + .endif + +-.ifc \ofmt,bgra // 2 1 0 3 ++.ifc \ofmt,bgra + compute_rgba v6.8b,v5.8b,v4.8b,v7.8b, v18.8b,v17.8b,v16.8b,v19.8b + .endif + diff --git a/portfiles/ffmpeg/0024-fix-osx-host-c11.patch b/portfiles/ffmpeg/0024-fix-osx-host-c11.patch new file mode 100644 index 000000000..dbce2f53b --- /dev/null +++ b/portfiles/ffmpeg/0024-fix-osx-host-c11.patch @@ -0,0 +1,15 @@ +diff --git a/configure b/configure +index 4f5353f84b..dd9147c677 100755 +--- a/configure ++++ b/configure +@@ -5607,8 +5607,8 @@ check_cppflags -D_FILE_OFFSET_BITS=64 + check_cppflags -D_LARGEFILE_SOURCE + + add_host_cppflags -D_ISOC11_SOURCE + check_host_cflags_cc -std=$stdc ctype.h "__STDC_VERSION__ >= 201112L" || +- check_host_cflags_cc -std=c11 ctype.h "__STDC_VERSION__ >= 201112L" || die "Host compiler lacks C11 support" ++ check_host_cflags_cc -std=c11 ctype.h "__STDC_VERSION__ >= 201112L" + + check_host_cflags -Wall + check_host_cflags $host_cflags_speed + diff --git a/portfiles/ffmpeg/0040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch b/portfiles/ffmpeg/0040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch new file mode 100644 index 000000000..c2e1d8ff0 --- /dev/null +++ b/portfiles/ffmpeg/0040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch @@ -0,0 +1,35 @@ +diff --git a/libavformat/avformat.h b/libavformat/avformat.h +index cd7b0d941c..b4a6dce885 100644 +--- a/libavformat/avformat.h ++++ b/libavformat/avformat.h +@@ -1169,7 +1169,11 @@ typedef struct AVStreamGroup { + } AVStreamGroup; + + struct AVCodecParserContext *av_stream_get_parser(const AVStream *s); + ++// Chromium: We use the internal field first_dts vvv ++int64_t av_stream_get_first_dts(const AVStream *st); ++// Chromium: We use the internal field first_dts ^^^ ++ + #define AV_PROGRAM_RUNNING 1 + + /** +diff --git a/libavformat/mux_utils.c b/libavformat/mux_utils.c +index de7580c32d..0ef0fe530e 100644 +--- a/libavformat/mux_utils.c ++++ b/libavformat/mux_utils.c +@@ -29,7 +29,14 @@ #include "avformat.h" + #include "avio.h" + #include "internal.h" + #include "mux.h" + ++// Chromium: We use the internal field first_dts vvv ++int64_t av_stream_get_first_dts(const AVStream *st) ++{ ++ return cffstream(st)->first_dts; ++} ++// Chromium: We use the internal field first_dts ^^^ ++ + int avformat_query_codec(const AVOutputFormat *ofmt, enum AVCodecID codec_id, + int std_compliance) + { diff --git a/portfiles/ffmpeg/0041-add-const-for-opengl-definition.patch b/portfiles/ffmpeg/0041-add-const-for-opengl-definition.patch new file mode 100644 index 000000000..b22b40d1f --- /dev/null +++ b/portfiles/ffmpeg/0041-add-const-for-opengl-definition.patch @@ -0,0 +1,13 @@ +diff --git a/libavdevice/opengl_enc.c b/libavdevice/opengl_enc.c +index b2ac6eb..6351614 100644 +--- a/libavdevice/opengl_enc.c ++++ b/libavdevice/opengl_enc.c +@@ -116,7 +116,7 @@ typedef void (APIENTRY *FF_PFNGLATTACHSHADERPROC) (GLuint program, GLuint shad + typedef GLuint (APIENTRY *FF_PFNGLCREATESHADERPROC) (GLenum type); + typedef void (APIENTRY *FF_PFNGLDELETESHADERPROC) (GLuint shader); + typedef void (APIENTRY *FF_PFNGLCOMPILESHADERPROC) (GLuint shader); +-typedef void (APIENTRY *FF_PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const char* *string, const GLint *length); ++typedef void (APIENTRY *FF_PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const char* const *string, const GLint *length); + typedef void (APIENTRY *FF_PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); + typedef void (APIENTRY *FF_PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, char *infoLog); + diff --git a/portfiles/ffmpeg/0042-fix-arm64-linux.patch b/portfiles/ffmpeg/0042-fix-arm64-linux.patch new file mode 100644 index 000000000..6ff63c371 --- /dev/null +++ b/portfiles/ffmpeg/0042-fix-arm64-linux.patch @@ -0,0 +1,9 @@ +diff --git a/ffbuild/libversion.sh b/ffbuild/libversion.sh +index a94ab58..ecaa90c 100644 +--- a/ffbuild/libversion.sh ++++ b/ffbuild/libversion.sh +@@ -1,3 +1,4 @@ ++#!/bin/sh + toupper(){ + echo "$@" | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ + } diff --git a/portfiles/ffmpeg/0043-fix-miss-head.patch b/portfiles/ffmpeg/0043-fix-miss-head.patch new file mode 100644 index 000000000..bad42798c --- /dev/null +++ b/portfiles/ffmpeg/0043-fix-miss-head.patch @@ -0,0 +1,12 @@ +diff --git a/libavfilter/textutils.c b/libavfilter/textutils.c +index ef658d0..c61b0ad 100644 +--- a/libavfilter/textutils.c ++++ b/libavfilter/textutils.c +@@ -31,6 +31,7 @@ + #include "libavutil/file.h" + #include "libavutil/mem.h" + #include "libavutil/time.h" ++#include "libavutil/time_internal.h" + + static int ff_expand_text_function_internal(FFExpandTextContext *expand_text, AVBPrint *bp, + char *name, unsigned argc, char **argv) diff --git a/portfiles/ffmpeg/0044-fix-vulkan-debug-callback-abi.patch b/portfiles/ffmpeg/0044-fix-vulkan-debug-callback-abi.patch new file mode 100644 index 000000000..d80e468a6 --- /dev/null +++ b/portfiles/ffmpeg/0044-fix-vulkan-debug-callback-abi.patch @@ -0,0 +1,13 @@ +diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c +index 6317ab7d0e..f1f70e9b96 100644 +--- a/libavutil/hwcontext_vulkan.c ++++ b/libavutil/hwcontext_vulkan.c +@@ -453,7 +453,7 @@ static const VulkanOptExtension optional_device_exts[] = { + { VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_AV1 }, + }; + +-static VkBool32 VKAPI_CALL vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, ++static VKAPI_ATTR VkBool32 VKAPI_CALL vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT *data, + void *priv) diff --git a/portfiles/ffmpeg/1000-bink2-decoder.patch b/portfiles/ffmpeg/1000-bink2-decoder.patch new file mode 100644 index 000000000..95710788f --- /dev/null +++ b/portfiles/ffmpeg/1000-bink2-decoder.patch @@ -0,0 +1,3865 @@ +diff --git a/configure b/configure +index 98b582a5d5..89ac08f611 100755 +--- a/configure ++++ b/configure +@@ -2919,6 +2919,7 @@ atrac3p_decoder_select="sinewin" + atrac3pal_decoder_select="sinewin" + av1_decoder_select="atsc_a53 cbs_av1 dovi_rpudec" + bink_decoder_select="blockdsp hpeldsp" ++bink2_decoder_select="blockdsp" + binkaudio_dct_decoder_select="wma_freqs" + binkaudio_rdft_decoder_select="wma_freqs" + cavs_decoder_select="blockdsp golomb h264chroma idctdsp qpeldsp videodsp" +diff --git a/libavcodec/Makefile b/libavcodec/Makefile +index 153a9e3881..ebff3c239a 100644 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -277,6 +277,7 @@ OBJS-$(CONFIG_AVUI_ENCODER) += avuienc.o + OBJS-$(CONFIG_BETHSOFTVID_DECODER) += bethsoftvideo.o + OBJS-$(CONFIG_BFI_DECODER) += bfi.o + OBJS-$(CONFIG_BINK_DECODER) += bink.o binkdsp.o ++OBJS-$(CONFIG_BINK2_DECODER) += bink2.o + OBJS-$(CONFIG_BINKAUDIO_DCT_DECODER) += binkaudio.o + OBJS-$(CONFIG_BINKAUDIO_RDFT_DECODER) += binkaudio.o + OBJS-$(CONFIG_BINTEXT_DECODER) += bintext.o cga_data.o +diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c +index aa0fc47647..0b806a1458 100644 +--- a/libavcodec/allcodecs.c ++++ b/libavcodec/allcodecs.c +@@ -63,6 +63,7 @@ extern const FFCodec ff_avui_decoder; + extern const FFCodec ff_bethsoftvid_decoder; + extern const FFCodec ff_bfi_decoder; + extern const FFCodec ff_bink_decoder; ++extern const FFCodec ff_bink2_decoder; + extern const FFCodec ff_bitpacked_decoder; + extern const FFCodec ff_bitpacked_encoder; + extern const FFCodec ff_bmp_encoder; +diff --git a/libavcodec/bink2.c b/libavcodec/bink2.c +new file mode 100644 +index 0000000000..6519efa335 +--- /dev/null ++++ b/libavcodec/bink2.c +@@ -0,0 +1,480 @@ ++/* ++ * Bink video 2 decoder ++ * Copyright (c) 2014 Konstantin Shishkov ++ * Copyright (c) 2019 Paul B Mahol ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include "libavutil/avassert.h" ++#include "libavutil/attributes.h" ++#include "libavutil/emms.h" ++#include "libavutil/imgutils.h" ++#include "libavutil/internal.h" ++#include "libavutil/mem.h" ++#include "avcodec.h" ++#include "blockdsp.h" ++#include "codec_internal.h" ++#include "copy_block.h" ++#include "decode.h" ++#include "idctdsp.h" ++#include "internal.h" ++#include "mathops.h" ++ ++#define BITSTREAM_READER_LE ++#include "get_bits.h" ++#include "unary.h" ++#include "bink2.h" ++ ++#include "bink2f.h" ++#include "bink2g.h" ++ ++static void bink2_get_block_flags(GetBitContext *gb, int offset, int size, uint8_t *dst) ++{ ++ int flags_left, mode = 0; ++ unsigned flag = 0; ++ ++ if (get_bits1(gb) == 0) { ++ for (int i = 0; i < size; i++, offset++) { ++ const unsigned value = get_bits1(gb); ++ ++ dst[offset >> 3] |= value << (offset & 7); ++ } ++ ++ return; ++ } ++ ++ flags_left = size; ++ while (flags_left > 0) { ++ if (get_bits1(gb) == 0) { ++ int count; ++ ++ if (mode == 3) { ++ flag ^= 1; ++ } else { ++ flag = get_bits1(gb); ++ } ++ ++ dst[offset >> 3] |= flag << (offset & 7); ++ offset++; ++ flags_left--; ++ ++ count = FFMIN(flags_left, 4); ++ for (int i = 0; i < count; i++, offset++, flags_left--) { ++ const unsigned value = get_bits1(gb); ++ ++ dst[offset >> 3] |= value << (offset & 7); ++ } ++ mode = 2; ++ } else { ++ int bits, run; ++ ++ bits = flags_left < 4 ? 2 : flags_left < 16 ? 4 : 5; ++ if (mode == 3) { ++ flag ^= 1; ++ run = bits + 1; ++ } else { ++ flag = get_bits1(gb); ++ run = bits + 2; ++ } ++ ++ run = FFMIN(run, flags_left); ++ if (run != flags_left) { ++ const unsigned extra = get_bits(gb, bits); ++ ++ run += extra; ++ mode = extra == (1U << bits) - 1 ? 1 : 3; ++ } ++ ++ for (int i = 0; i < run; i++, offset++) ++ dst[offset >> 3] |= flag << (offset & 7); ++ flags_left -= run; ++ } ++ } ++} ++ ++typedef struct Bink2ThreadData { ++ AVFrame *frame; ++ int is_kf; ++ int slice_end[BINK2_MAX_SLICES]; ++} Bink2ThreadData; ++ ++static int bink2_decode_slice(AVCodecContext *avctx, void *arg, ++ int jobnr, int threadnr) ++{ ++ Bink2Context *parent = avctx->priv_data; ++ Bink2ThreadData *td = arg; ++ Bink2Context *c = parent->slice_ctx[jobnr]; ++ GetBitContext *gb = &c->gb; ++ AVFrame *frame = td->frame; ++ uint8_t *dst[4]; ++ uint8_t *src[4]; ++ int stride[4]; ++ int sstride[4]; ++ const int start = jobnr ? parent->slice_height[jobnr - 1] : 0; ++ const int end = parent->slice_height[jobnr]; ++ int bits_left, ret; ++ ++ (void)threadnr; ++ ++ for (int i = 0; i < 4; i++) { ++ src[i] = parent->last->data[i]; ++ dst[i] = frame->data[i]; ++ stride[i] = frame->linesize[i]; ++ sstride[i] = parent->last->linesize[i]; ++ } ++ ++ dst[0] += start * stride[0]; ++ dst[1] += start / 2 * stride[1]; ++ dst[2] += start / 2 * stride[2]; ++ if (c->has_alpha) ++ dst[3] += start * stride[3]; ++ ++ if (c->version <= 'f' || !(c->frame_flags & 0x2000)) ++ ret = bink2f_decode_slice(c, dst, stride, src, sstride, ++ td->is_kf, start, end); ++ else ++ ret = bink2g_decode_slice(c, dst, stride, src, sstride, ++ td->is_kf, start, end); ++ if (ret < 0) ++ return ret; ++ ++ align_get_bits(gb); ++ bits_left = 8 * td->slice_end[jobnr] - get_bits_count(gb); ++ if (bits_left < 0) ++ av_log(avctx, AV_LOG_WARNING, "slice %d: overread\n", jobnr); ++ else if (bits_left > 24) ++ av_log(avctx, AV_LOG_WARNING, "slice %d: underread %d\n", ++ jobnr, bits_left); ++ ++ return 0; ++} ++ ++static int bink2_decode_frame(AVCodecContext *avctx, AVFrame *frame, ++ int *got_frame, AVPacket *pkt) ++{ ++ Bink2Context * const c = avctx->priv_data; ++ GetBitContext *gb = &c->gb; ++ Bink2ThreadData td = { .frame = frame }; ++ int thread_ret[BINK2_MAX_SLICES] = { 0 }; ++ int is_kf = !!(pkt->flags & AV_PKT_FLAG_KEY); ++ int first_slice_bit, ret, w, h; ++ int height_a; ++ ++ if (pkt->size < 4) ++ return AVERROR_INVALIDDATA; ++ ++ w = avctx->width; ++ h = avctx->height; ++ ret = ff_set_dimensions(avctx, FFALIGN(w, 32), FFALIGN(h, 32)); ++ if (ret < 0) ++ return ret; ++ avctx->width = w; ++ avctx->height = h; ++ ++ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) ++ return ret; ++ ++ if (!is_kf && (!c->last->data[0] || ++ !c->last->data[1] || ++ !c->last->data[2])) ++ return AVERROR_INVALIDDATA; ++ ++ c->frame_flags = AV_RL32(pkt->data); ++ ff_dlog(avctx, "frame flags %X\n", c->frame_flags); ++ ++ if ((ret = init_get_bits8(gb, pkt->data, pkt->size)) < 0) ++ return ret; ++ ++ height_a = (avctx->height + 31) & 0xFFFFFFE0; ++ if (c->version <= 'f') { ++ c->num_slices = 2; ++ c->slice_height[0] = (avctx->height / 2 + 16) & 0xFFFFFFE0; ++ } else if (c->version == 'g') { ++ if (height_a < 128) { ++ c->num_slices = 1; ++ } else { ++ c->num_slices = 2; ++ c->slice_height[0] = (avctx->height / 2 + 16) & 0xFFFFFFE0; ++ } ++ } else { ++ int start, end; ++ ++ c->num_slices = kb2h_num_slices[c->flags & 3]; ++ start = 0; ++ end = height_a + 32 * c->num_slices - 1; ++ for (int i = 0; i < c->num_slices - 1; i++) { ++ start += ((end - start) / (c->num_slices - i)) & 0xFFFFFFE0; ++ end -= 32; ++ c->slice_height[i] = start; ++ } ++ } ++ c->slice_height[c->num_slices - 1] = height_a; ++ ++ if (pkt->size < 4 + 4 * (c->num_slices - 1)) ++ return AVERROR_INVALIDDATA; ++ ++ skip_bits_long(gb, 32 + 32 * (c->num_slices - 1)); ++ ++ memset(c->row_cbp, 0, ++ ((((avctx->height + 31) >> 3) + 7) >> 3) * sizeof(*c->row_cbp)); ++ memset(c->col_cbp, 0, ++ ((((avctx->width + 31) >> 3) + 7) >> 3) * sizeof(*c->col_cbp)); ++ ++ if (c->frame_flags & 0x10000) { ++ if (!(c->frame_flags & 0x8000)) ++ bink2_get_block_flags(gb, 1, (((avctx->height + 15) & ~15) >> 3) - 1, c->row_cbp); ++ if (!(c->frame_flags & 0x4000)) ++ bink2_get_block_flags(gb, 1, (((avctx->width + 31) & ~31) >> 3) - 1, c->col_cbp); ++ } ++ ++ if (get_bits_left(gb) < 0) ++ return AVERROR_INVALIDDATA; ++ ++ td.is_kf = is_kf; ++ first_slice_bit = get_bits_count(gb); ++ for (int i = 0; i < c->num_slices; i++) { ++ Bink2Context *sc = c->slice_ctx[i]; ++ const int start = i ? td.slice_end[i - 1] : 0; ++ const int start_bit = i ? 8 * start : first_slice_bit; ++ ++ td.slice_end[i] = i == c->num_slices - 1 ? ++ pkt->size : AV_RL32(pkt->data + 4 + 4 * i); ++ if (td.slice_end[i] < start || ++ td.slice_end[i] > pkt->size || ++ 8 * td.slice_end[i] < start_bit) ++ return AVERROR_INVALIDDATA; ++ ++ sc->frame_flags = c->frame_flags; ++ if (i) { ++ if ((ret = init_get_bits8(&sc->gb, pkt->data, pkt->size)) < 0) ++ return ret; ++ skip_bits_long(&sc->gb, start_bit); ++ } ++ } ++ ++ if ((ret = avctx->execute2(avctx, bink2_decode_slice, &td, ++ thread_ret, c->num_slices)) < 0) ++ return ret; ++ for (int i = 0; i < c->num_slices; i++) ++ if (thread_ret[i] < 0) ++ return thread_ret[i]; ++ ++ if (c->version > 'f' && (c->frame_flags & 0x2000)) { ++ bink2g_postprocess_frame(c, frame->data, frame->linesize); ++ } ++ ++ if (is_kf) ++ frame->flags |= AV_FRAME_FLAG_KEY; ++ else ++ frame->flags &= ~AV_FRAME_FLAG_KEY; ++ frame->pict_type = is_kf ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; ++ ++ av_frame_unref(c->last); ++ if ((ret = av_frame_ref(c->last, frame)) < 0) ++ return ret; ++ ++ frame->colorspace = avctx->colorspace; ++ frame->color_range = avctx->color_range; ++ ++ *got_frame = 1; ++ ++ /* always report that the buffer was completely consumed */ ++ return pkt->size; ++} ++ ++#define INIT_VLC_STATIC_LE(vlc, nb_bits, nb_codes, \ ++ bits, bits_wrap, bits_size, \ ++ codes, codes_wrap, codes_size, \ ++ symbols, symbols_wrap, symbols_size, \ ++ static_size) \ ++ do { \ ++ static VLCElem table[static_size]; \ ++ (vlc)->table = table; \ ++ (vlc)->table_allocated = static_size; \ ++ ff_vlc_init_sparse(vlc, nb_bits, nb_codes, \ ++ bits, bits_wrap, bits_size, \ ++ codes, codes_wrap, codes_size, \ ++ symbols, symbols_wrap, symbols_size, \ ++ VLC_INIT_LE | VLC_INIT_USE_STATIC); \ ++ } while (0) ++ ++static int bink2_alloc_slice_state(Bink2Context *c, int width) ++{ ++ const int mb_width = (width + 31) / 32; ++ ++ c->current_q = av_malloc_array(mb_width, sizeof(*c->current_q)); ++ c->prev_q = av_malloc_array(mb_width, sizeof(*c->prev_q)); ++ c->current_dc = av_malloc_array(mb_width, sizeof(*c->current_dc)); ++ c->prev_dc = av_malloc_array(mb_width, sizeof(*c->prev_dc)); ++ c->current_idc = av_malloc_array(mb_width, sizeof(*c->current_idc)); ++ c->prev_idc = av_malloc_array(mb_width, sizeof(*c->prev_idc)); ++ c->current_mv = av_malloc_array(mb_width, sizeof(*c->current_mv)); ++ c->prev_mv = av_malloc_array(mb_width, sizeof(*c->prev_mv)); ++ ++ if (!c->current_q || !c->prev_q || ++ !c->current_dc || !c->prev_dc || ++ !c->current_idc || !c->prev_idc || ++ !c->current_mv || !c->prev_mv) ++ return AVERROR(ENOMEM); ++ ++ return 0; ++} ++ ++static void bink2_free_slice_state(Bink2Context *c) ++{ ++ av_freep(&c->current_q); ++ av_freep(&c->prev_q); ++ av_freep(&c->current_dc); ++ av_freep(&c->prev_dc); ++ av_freep(&c->current_idc); ++ av_freep(&c->prev_idc); ++ av_freep(&c->current_mv); ++ av_freep(&c->prev_mv); ++} ++ ++static av_cold int bink2_decode_init(AVCodecContext *avctx) ++{ ++ Bink2Context * const c = avctx->priv_data; ++ int ret; ++ ++ c->version = avctx->codec_tag >> 24; ++ if (avctx->extradata_size < 4) { ++ av_log(avctx, AV_LOG_ERROR, "Extradata missing or too short\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ c->flags = AV_RL32(avctx->extradata); ++ av_log(avctx, AV_LOG_DEBUG, "flags: 0x%X\n", c->flags); ++ c->has_alpha = c->flags & BINK_FLAG_ALPHA; ++ c->avctx = avctx; ++ c->slice_ctx[0] = c; ++ ++ c->last = av_frame_alloc(); ++ if (!c->last) ++ return AVERROR(ENOMEM); ++ ++ if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0) ++ return ret; ++ ++ avctx->pix_fmt = c->has_alpha ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P; ++ avctx->colorspace = AVCOL_SPC_SMPTE170M; ++ avctx->color_range = c->flags & BINK_FLAG_YCRCB_NEW ? ++ AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; ++ ++ ff_blockdsp_init(&c->dsp); ++ ++ INIT_VLC_STATIC_LE(&bink2f_quant_vlc, 9, FF_ARRAY_ELEMS(bink2f_quant_codes), ++ bink2f_quant_bits, 1, 1, bink2f_quant_codes, 1, 1, NULL, 0, 0, 512); ++ INIT_VLC_STATIC_LE(&bink2f_ac_val0_vlc, 9, FF_ARRAY_ELEMS(bink2f_ac_val_bits[0]), ++ bink2f_ac_val_bits[0], 1, 1, bink2f_ac_val_codes[0], 2, 2, NULL, 0, 0, 512); ++ INIT_VLC_STATIC_LE(&bink2f_ac_val1_vlc, 9, FF_ARRAY_ELEMS(bink2f_ac_val_bits[1]), ++ bink2f_ac_val_bits[1], 1, 1, bink2f_ac_val_codes[1], 2, 2, NULL, 0, 0, 512); ++ INIT_VLC_STATIC_LE(&bink2f_ac_skip0_vlc, 9, FF_ARRAY_ELEMS(bink2f_ac_skip_bits[0]), ++ bink2f_ac_skip_bits[0], 1, 1, bink2f_ac_skip_codes[0], 2, 2, NULL, 0, 0, 512); ++ INIT_VLC_STATIC_LE(&bink2f_ac_skip1_vlc, 9, FF_ARRAY_ELEMS(bink2f_ac_skip_bits[1]), ++ bink2f_ac_skip_bits[1], 1, 1, bink2f_ac_skip_codes[1], 2, 2, NULL, 0, 0, 512); ++ ++ INIT_VLC_STATIC_LE(&bink2g_ac_skip0_vlc, 9, FF_ARRAY_ELEMS(bink2g_ac_skip_bits[0]), ++ bink2g_ac_skip_bits[0], 1, 1, bink2g_ac_skip_codes[0], 2, 2, NULL, 0, 0, 512); ++ INIT_VLC_STATIC_LE(&bink2g_ac_skip1_vlc, 9, FF_ARRAY_ELEMS(bink2g_ac_skip_bits[1]), ++ bink2g_ac_skip_bits[1], 1, 1, bink2g_ac_skip_codes[1], 2, 2, NULL, 0, 0, 512); ++ INIT_VLC_STATIC_LE(&bink2g_mv_vlc, 9, FF_ARRAY_ELEMS(bink2g_mv_bits), ++ bink2g_mv_bits, 1, 1, bink2g_mv_codes, 1, 1, NULL, 0, 0, 512); ++ ++ if ((ret = bink2_alloc_slice_state(c, avctx->width)) < 0) ++ return ret; ++ ++ { ++ const size_t mb_count = (size_t)((avctx->width + 31) >> 5) * ++ ((avctx->height + 31) >> 5); ++ ++ c->frame_idc = av_malloc_array(mb_count, sizeof(*c->frame_idc)); ++ c->frame_mv = av_malloc_array(mb_count, sizeof(*c->frame_mv)); ++ if (!c->frame_idc || !c->frame_mv) ++ return AVERROR(ENOMEM); ++ } ++ ++ c->col_cbp = av_calloc((((avctx->width + 31) >> 3) + 7) >> 3, sizeof(*c->col_cbp)); ++ if (!c->col_cbp) ++ return AVERROR(ENOMEM); ++ ++ c->row_cbp = av_calloc((((avctx->height + 31) >> 3) + 7) >> 3, sizeof(*c->row_cbp)); ++ if (!c->row_cbp) ++ return AVERROR(ENOMEM); ++ ++ for (int i = 1; i < BINK2_MAX_SLICES; i++) { ++ Bink2Context *sc = av_mallocz(sizeof(*sc)); ++ ++ if (!sc) ++ return AVERROR(ENOMEM); ++ c->slice_ctx[i] = sc; ++ sc->avctx = avctx; ++ sc->version = c->version; ++ sc->has_alpha = c->has_alpha; ++ sc->flags = c->flags; ++ sc->dsp = c->dsp; ++ sc->col_cbp = c->col_cbp; ++ sc->row_cbp = c->row_cbp; ++ sc->frame_idc = c->frame_idc; ++ sc->frame_mv = c->frame_mv; ++ if ((ret = bink2_alloc_slice_state(sc, avctx->width)) < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void bink2_flush(AVCodecContext *avctx) ++{ ++ Bink2Context *c = avctx->priv_data; ++ ++ av_frame_unref(c->last); ++} ++ ++static av_cold int bink2_decode_end(AVCodecContext *avctx) ++{ ++ Bink2Context * const c = avctx->priv_data; ++ ++ av_frame_free(&c->last); ++ for (int i = 1; i < BINK2_MAX_SLICES; i++) { ++ if (c->slice_ctx[i]) { ++ bink2_free_slice_state(c->slice_ctx[i]); ++ av_freep(&c->slice_ctx[i]); ++ } ++ } ++ bink2_free_slice_state(c); ++ av_freep(&c->frame_idc); ++ av_freep(&c->frame_mv); ++ av_freep(&c->col_cbp); ++ av_freep(&c->row_cbp); ++ ++ return 0; ++} ++ ++const FFCodec ff_bink2_decoder = { ++ .p.name = "binkvideo2", ++ .p.long_name = NULL_IF_CONFIG_SMALL("Bink video 2"), ++ .p.type = AVMEDIA_TYPE_VIDEO, ++ .p.id = AV_CODEC_ID_BINKVIDEO2, ++ .priv_data_size = sizeof(Bink2Context), ++ .init = bink2_decode_init, ++ .close = bink2_decode_end, ++ FF_CODEC_DECODE_CB(bink2_decode_frame), ++ .flush = bink2_flush, ++ .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS, ++ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, ++}; +diff --git a/libavcodec/bink2.h b/libavcodec/bink2.h +new file mode 100644 +index 0000000000..67d7603370 +--- /dev/null ++++ b/libavcodec/bink2.h +@@ -0,0 +1,147 @@ ++/* ++ * Bink video 2 decoder ++ * Copyright (c) 2014 Konstantin Shishkov ++ * Copyright (c) 2019 Paul B Mahol ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#ifndef AVCODEC_BINK2_H ++#define AVCODEC_BINK2_H ++ ++#include ++#include "libavutil/mem_internal.h" ++#include "avcodec.h" ++#include "blockdsp.h" ++#include "copy_block.h" ++#include "unary.h" ++#include "get_bits.h" ++ ++static VLC bink2f_quant_vlc; ++static VLC bink2f_ac_val0_vlc; ++static VLC bink2f_ac_val1_vlc; ++static VLC bink2f_ac_skip0_vlc; ++static VLC bink2f_ac_skip1_vlc; ++static VLC bink2g_ac_skip0_vlc; ++static VLC bink2g_ac_skip1_vlc; ++static VLC bink2g_mv_vlc; ++ ++static const uint8_t kb2h_num_slices[] = { ++ 2, 3, 4, 8, ++}; ++ ++static const uint8_t luma_repos[] = { ++ 0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15, ++}; ++ ++static const uint8_t dq_patterns[8] = { 8, 0, 1, 0, 2, 0, 1, 0 }; ++ ++static const uint8_t bink2_next_skips[] = { ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, ++}; ++ ++#define NUM_AC_SKIPS 14 ++#define BINK2_MAX_SLICES 8 ++#define BINK_FLAG_YCRCB_NEW 0x00000010 ++#define BINK_FLAG_ALPHA 0x00100000 ++#define DC_MPRED(A, B, C) FFMIN(FFMAX((C) + (B) - (A), FFMIN3(A, B, C)), FFMAX3(A, B, C)) ++#define DC_MPRED2(A, B) FFMIN(FFMAX((A), (B)), FFMAX(FFMIN((A), (B)), 2 * (A) - (B))) ++#define LHFILTER(src) (((((src)[0]+(src)[1])*19 >> 1)-((src)[-1]+(src)[2 ])*2+(((src)[-2 ]+(src)[3 ])>>1)+8)>>4) ++#define LVFILTER(src, i) (((((src)[0]+(src)[i])*19 >> 1)-((src)[-i]+(src)[2*i])*2+(((src)[-2*i]+(src)[3*i])>>1)+8)>>4) ++ ++typedef struct QuantPredict { ++ int8_t intra_q; ++ int8_t inter_q; ++} QuantPredict; ++ ++typedef struct DCPredict { ++ float dc[4][16]; ++ int block_type; ++} DCPredict; ++ ++typedef struct DCIPredict { ++ int dc[4][16]; ++ uint16_t state[4][16]; ++ int block_type; ++} DCIPredict; ++ ++typedef struct MVectors { ++ int v[4][2]; ++ int nb_vectors; ++} MVectors; ++ ++typedef struct MVPredict { ++ MVectors mv; ++} MVPredict; ++ ++/* ++ * Decoder context ++ */ ++typedef struct Bink2Context { ++ AVCodecContext *avctx; ++ GetBitContext gb; ++ BlockDSPContext dsp; ++ AVFrame *last; ++ int version; ///< internal Bink file version ++ int has_alpha; ++ ++ DECLARE_ALIGNED(16, float, block[4][64]); ++ DECLARE_ALIGNED(16, int16_t, iblock[4][64]); ++ ++ QuantPredict *current_q; ++ QuantPredict *prev_q; ++ ++ DCPredict *current_dc; ++ DCPredict *prev_dc; ++ ++ DCIPredict *current_idc; ++ DCIPredict *prev_idc; ++ ++ MVPredict *current_mv; ++ MVPredict *prev_mv; ++ ++ /* Modern Bink2 reconstruction and filtering need the neighbouring rows ++ * even when those rows belong to different bitstream slices. Slice jobs ++ * write disjoint rows here; the parent context post-processes the complete ++ * frame after every slice has finished. */ ++ DCIPredict *frame_idc; ++ MVPredict *frame_mv; ++ ++ uint8_t *col_cbp; ++ uint8_t *row_cbp; ++ ++ int num_slices; ++ int slice_height[BINK2_MAX_SLICES]; ++ struct Bink2Context *slice_ctx[BINK2_MAX_SLICES]; ++ ++ int comp; ++ int mb_pos; ++ unsigned flags; ++ unsigned frame_flags; ++} Bink2Context; ++ ++/** ++ * Bink2 video block types ++ */ ++enum BlockTypes { ++ INTRA_BLOCK = 0, ///< intra DCT block ++ SKIP_BLOCK, ///< skipped block ++ MOTION_BLOCK, ///< block is copied from previous frame with some offset ++ RESIDUE_BLOCK, ///< motion block with some difference added ++}; ++ ++#endif /* AVCODEC_BINK2_H */ +diff --git a/libavcodec/bink2f.h b/libavcodec/bink2f.h +new file mode 100644 +index 0000000000..4fa42d0b71 +--- /dev/null ++++ b/libavcodec/bink2f.h +@@ -0,0 +1,1241 @@ ++/* ++ * Bink video 2 decoder ++ * Copyright (c) 2014 Konstantin Shishkov ++ * Copyright (c) 2019 Paul B Mahol ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#ifndef AVCODEC_BINK2F_H ++#define AVCODEC_BINK2F_H ++ ++#include ++#include "avcodec.h" ++#include "get_bits.h" ++#include "bink2.h" ++ ++static const uint8_t bink2f_quant_codes[16] = { ++ 0x01, 0x02, 0x04, 0x08, 0x10, 0x30, 0x50, 0x70, ++ 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0, ++}; ++ ++static const uint8_t bink2f_quant_bits[16] = { ++ 1, 2, 3, 4, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, ++}; ++ ++static const uint16_t bink2f_ac_val_codes[2][13] = { ++ { ++ 0x04, 0x01, 0x02, 0x00, 0x08, 0x18, 0xF8, 0x178, 0x138, ++ 0x38, 0x1B8, 0x78, 0xB8 ++ }, ++ { ++ 0x0A, 0x01, 0x04, 0x08, 0x06, 0x00, 0x02, 0x1A, 0x2A, ++ 0x16A, 0x1EA, 0x6A, 0xEA ++ }, ++}; ++ ++static const uint8_t bink2f_ac_val_bits[2][13] = { ++ { 3, 1, 2, 4, 5, 6, 8, 9, 9, 9, 9, 9, 9 }, ++ { 6, 1, 3, 4, 3, 4, 4, 5, 7, 9, 9, 9, 9 }, ++}; ++ ++static const uint16_t bink2f_ac_skip_codes[2][NUM_AC_SKIPS] = { ++ { ++ 0x00, 0x01, 0x0D, 0x15, 0x45, 0x85, 0xA5, 0x165, ++ 0x65, 0x1E5, 0xE5, 0x25, 0x03, 0x05 ++ }, ++ { ++ 0x00, 0x01, 0x03, 0x07, 0x1F, 0x1B, 0x0F, 0x2F, ++ 0x5B, 0xDB, 0x1DB, 0x3B, 0x05, 0x0B ++ } ++}; ++ ++static const uint8_t bink2f_ac_skip_bits[2][NUM_AC_SKIPS] = { ++ { 1, 3, 4, 5, 7, 8, 8, 9, 9, 9, 9, 8, 2, 8 }, ++ { 1, 3, 4, 4, 5, 7, 6, 6, 8, 9, 9, 6, 3, 5 } ++}; ++ ++static const uint8_t bink2f_skips[] = { ++ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 62, 0, 0, 0, ++}; ++ ++static const float bink2f_dc_quant[16] = { ++ 4, 4, 4, 4, 4, 6, 7, 8, 10, 12, 16, 24, 32, 48, 64, 128 ++}; ++ ++static const float bink2f_ac_quant[16] = { ++ 1.0, 2.0, 2.5, 3.0, 3.5, 4.0, 6.0, 7.0, 8.0, 12.0, 16.0, 24.0, 32.0, 48.0, 64.0, 128.0 ++}; ++ ++static const float bink2f_luma_intra_qmat[64] = { ++ 0.125, 0.190718, 0.16332, 0.235175, 0.3, 0.392847, 0.345013, 0.210373, ++ 0.208056, 0.288582, 0.317145, 0.387359, 0.450788, 0.790098, 0.562995, 0.263095, ++ 0.228649, 0.294491, 0.341421, 0.460907, 0.653281, 0.731424, 0.60988, 0.252336, ++ 0.205778, 0.346585, 0.422498, 0.501223, 0.749621, 1.004719, 0.636379, 0.251428, ++ 0.225, 0.381436, 0.604285, 0.823113, 0.85, 1.070509, 0.69679, 0.265553, ++ 0.235708, 0.476783, 0.70576, 0.739104, 0.795516, 0.802512, 0.600616, 0.249289, ++ 0.331483, 0.600528, 0.689429, 0.692062, 0.69679, 0.643138, 0.43934, 0.188511, ++ 0.248309, 0.440086, 0.42807, 0.397419, 0.386259, 0.270966, 0.192244, 0.094199, ++}; ++ ++static const float bink2f_luma_inter_qmat[64] = { ++ 0.125, 0.17338, 0.16332, 0.146984, 0.128475, 0.106393, 0.077046, 0.043109, ++ 0.17338, 0.240485, 0.226532, 0.203873, 0.1782, 0.147571, 0.109474, 0.062454, ++ 0.16332, 0.226532, 0.219321, 0.202722, 0.181465, 0.149711, 0.112943, 0.062584, ++ 0.146984, 0.203873, 0.202722, 0.201647, 0.183731, 0.153976, 0.11711, 0.065335, ++ 0.128475, 0.1782, 0.181465, 0.183731, 0.177088, 0.155499, 0.120267, 0.068016, ++ 0.106393, 0.147571, 0.149711, 0.153976, 0.155499, 0.145756, 0.116636, 0.068495, ++ 0.077046, 0.109474, 0.112943, 0.11711, 0.120267, 0.116636, 0.098646, 0.060141, ++ 0.043109, 0.062454, 0.062584, 0.065335, 0.068016, 0.068495, 0.060141, 0.038853, ++}; ++ ++static const float bink2f_chroma_qmat[64] = { ++ 0.125, 0.17338, 0.217761, 0.383793, 0.6875, 0.54016501, 0.37207201, 0.18968099, ++ 0.17338, 0.28056601, 0.32721299, 0.74753499, 0.95358998, 0.74923098, 0.51607901, 0.26309499, ++ 0.217761, 0.32721299, 0.66387498, 1.056244, 0.89826202, 0.70576, 0.48613599, 0.24783, ++ 0.383793, 0.74753499, 1.056244, 0.95059502, 0.80841398, 0.635167, 0.437511, 0.223041, ++ 0.6875, 0.95358998, 0.89826202, 0.80841398, 0.6875, 0.54016501, 0.37207201, 0.18968099, ++ 0.54016501, 0.74923098, 0.70576, 0.635167, 0.54016501, 0.42440501, 0.292335, 0.149031, ++ 0.37207201, 0.51607901, 0.48613599, 0.437511, 0.37207201, 0.292335, 0.201364, 0.102655, ++ 0.18968099, 0.26309499, 0.24783, 0.223041, 0.18968099, 0.149031, 0.102655, 0.052333001 ++}; ++ ++static const uint8_t bink2f_luma_scan[64] = { ++ 0, 2, 1, 8, 9, 17, 10, 16, ++ 24, 3, 18, 25, 32, 11, 33, 26, ++ 4, 40, 19, 12, 27, 41, 34, 5, ++ 20, 48, 6, 28, 15, 42, 23, 35, ++ 21, 13, 14, 7, 31, 43, 49, 36, ++ 22, 56, 39, 50, 30, 44, 29, 51, ++ 57, 47, 58, 59, 63, 61, 55, 38, ++ 52, 62, 45, 37, 60, 46, 54, 53 ++}; ++ ++static const uint8_t bink2f_chroma_scan[64] = { ++ 0, 1, 8, 2, 9, 16, 10, 17, ++ 3, 24, 11, 18, 25, 13, 14, 4, ++ 15, 5, 6, 7, 12, 19, 20, 21, ++ 22, 23, 26, 27, 28, 29, 30, 31, ++ 32, 33, 34, 35, 36, 37, 38, 39, ++ 40, 41, 42, 43, 44, 45, 46, 47, ++ 48, 49, 50, 51, 52, 53, 54, 55, ++ 56, 57, 58, 59, 60, 61, 62, 63 ++}; ++ ++static inline void bink2f_idct_1d(float *blk, int step) ++{ ++ float t00 = blk[2 * step] + blk[6 * step]; ++ float t01 = (blk[2 * step] - blk[6 * step]) * 1.4142135f - t00; ++ float t02 = blk[0 * step] + blk[4 * step]; ++ float t03 = blk[0 * step] - blk[4 * step]; ++ float t04 = blk[3 * step] + blk[5 * step]; ++ float t05 = blk[3 * step] - blk[5 * step]; ++ float t06 = blk[1 * step] + blk[7 * step]; ++ float t07 = blk[1 * step] - blk[7 * step]; ++ float t08 = t02 + t00; ++ float t09 = t02 - t00; ++ float t10 = t03 + t01; ++ float t11 = t03 - t01; ++ float t12 = t06 + t04; ++ float t13 = (t06 - t04) * 1.4142135f; ++ float t14 = (t07 - t05) * 1.847759f; ++ float t15 = t05 * 2.613126f + t14 - t12; ++ float t16 = t13 - t15; ++ float t17 = t07 * 1.0823922f - t14 + t16; ++ ++ blk[0*step] = t08 + t12; ++ blk[1*step] = t10 + t15; ++ blk[2*step] = t11 + t16; ++ blk[3*step] = t09 - t17; ++ blk[4*step] = t09 + t17; ++ blk[5*step] = t11 - t16; ++ blk[6*step] = t10 - t15; ++ blk[7*step] = t08 - t12; ++} ++ ++static void bink2f_idct_put(uint8_t *dst, int stride, float *block) ++{ ++ block[0] += 512.f; ++ ++ for (int i = 0; i < 8; i++) ++ bink2f_idct_1d(block + i, 8); ++ for (int i = 0; i < 8; i++) { ++ bink2f_idct_1d(block, 1); ++ for (int j = 0; j < 8; j++) ++ dst[j] = av_clip_uint8(lrintf(block[j] - 512.0f)); ++ block += 8; ++ dst += stride; ++ } ++} ++ ++static void bink2f_idct_add(uint8_t *dst, int stride, ++ float *block) ++{ ++ block[0] += 512.f; ++ ++ for (int i = 0; i < 8; i++) ++ bink2f_idct_1d(block + i, 8); ++ for (int i = 0; i < 8; i++) { ++ bink2f_idct_1d(block, 1); ++ for (int j = 0; j < 8; j++) ++ dst[j] = av_clip_uint8(dst[j] + lrintf(block[j] - 512.0f)); ++ block += 8; ++ dst += stride; ++ } ++} ++ ++static int bink2f_decode_delta_q(GetBitContext *gb) ++{ ++ int dq = get_vlc2(gb, bink2f_quant_vlc.table, bink2f_quant_vlc.bits, 1); ++ ++ if (dq < 0) ++ return AVERROR_INVALIDDATA; ++ if (dq && get_bits1(gb)) ++ dq = -dq; ++ ++ return dq; ++} ++ ++static unsigned bink2f_decode_cbp_luma(GetBitContext *gb, unsigned prev_cbp) ++{ ++ unsigned cbp, cbp4, cbplo, cbphi; ++ ++ if (get_bits1(gb)) { ++ if (get_bits1(gb)) ++ return prev_cbp; ++ cbplo = prev_cbp & 0xFFFF; ++ } else { ++ cbplo = 0; ++ cbp4 = (prev_cbp >> 4) & 0xF; ++ for (int i = 0; i < 4; i++) { ++ if (!get_bits1(gb)) ++ cbp4 = get_bits(gb, 4); ++ cbplo |= cbp4 << (i * 4); ++ } ++ } ++ cbphi = 0; ++ cbp = cbplo; ++ cbp4 = prev_cbp >> 20 & 0xF; ++ for (int i = 0; i < 4; i++) { ++ if (av_popcount(cbp & 0xF)) { ++ if (av_popcount(cbp & 0xF) == 1) { ++ cbp4 = 0; ++ for (int j = 1; j < 16; j <<= 1) { ++ if ((j & cbp) && get_bits1(gb)) ++ cbp4 |= j; ++ } ++ } else if (!get_bits1(gb)) { ++ cbp4 = 0; ++ for (int j = 1; j < 16; j <<= 1) { ++ if ((j & cbp) && get_bits1(gb)) ++ cbp4 |= j; ++ } ++ } ++ } else { ++ cbp4 = 0; ++ } ++ cbp4 &= cbp; ++ cbphi = (cbphi >> 4) | (cbp4 << 0x1c); ++ cbp >>= 4; ++ } ++ return cbphi | cbplo; ++} ++ ++static unsigned bink2f_decode_cbp_chroma(GetBitContext *gb, unsigned prev_cbp) ++{ ++ unsigned cbplo, cbphi; ++ ++ if (get_bits1(gb)) { ++ if (get_bits1(gb)) ++ return prev_cbp; ++ cbplo = prev_cbp & 0xF; ++ } else { ++ cbplo = get_bits(gb, 4); ++ } ++ ++ cbphi = 0; ++ if (av_popcount(cbplo & 0xF)) { ++ if (av_popcount(cbplo & 0xF) != 1) { ++ cbphi = (prev_cbp >> 16) & cbplo; ++ if (get_bits1(gb)) ++ return cbplo | (cbphi << 16); ++ } ++ cbphi = 0; ++ for (int j = 1; j < 16; j <<= 1) { ++ if ((j & cbplo) && get_bits1(gb)) ++ cbphi |= j; ++ } ++ } ++ return cbplo | (cbphi << 16); ++} ++ ++static const uint8_t q_dc_bits[16] = { ++ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 6, ++}; ++ ++static void bink2f_predict_dc(Bink2Context *c, ++ int is_luma, float mindc, float maxdc, ++ int flags, float tdc[16]) ++{ ++ float *LTdc = c->prev_dc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp]; ++ float *Tdc = c->prev_dc[c->mb_pos].dc[c->comp]; ++ float *Ldc = c->current_dc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp]; ++ float *dc = c->current_dc[c->mb_pos].dc[c->comp]; ++ ++ if (is_luma && (flags & 0x20) && (flags & 0x80)) { ++ dc[0] = av_clipf((mindc < 0 ? 0 : 1024.f) + tdc[0], mindc, maxdc); ++ dc[1] = av_clipf(dc[0] + tdc[1], mindc, maxdc); ++ dc[2] = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ dc[4] = av_clipf(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc); ++ dc[5] = av_clipf(dc[4] + tdc[5], mindc, maxdc); ++ dc[6] = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); ++ dc[7] = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); ++ dc[8] = av_clipf(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc); ++ dc[9] = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); ++ dc[10] = av_clipf(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc); ++ dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); ++ dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); ++ dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); ++ dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); ++ dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); ++ } else if (is_luma && (flags & 0x80)) { ++ dc[0] = av_clipf(DC_MPRED2(Ldc[5], Ldc[7]) + tdc[0], mindc, maxdc); ++ dc[1] = av_clipf(dc[0] + tdc[1], mindc, maxdc); ++ dc[2] = av_clipf(DC_MPRED(Ldc[5], Ldc[7], dc[0]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ dc[4] = av_clipf(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc); ++ dc[5] = av_clipf(dc[4] + tdc[5], mindc, maxdc); ++ dc[6] = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); ++ dc[7] = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); ++ dc[8] = av_clipf(DC_MPRED(Ldc[7], Ldc[13], dc[2]) + tdc[8], mindc, maxdc); ++ dc[9] = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); ++ dc[10] = av_clipf(DC_MPRED(Ldc[13], Ldc[15], dc[8]) + tdc[10], mindc, maxdc); ++ dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); ++ dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); ++ dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); ++ dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); ++ dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); ++ } else if (is_luma && (flags & 0x20)) { ++ dc[0] = av_clipf(DC_MPRED2(Tdc[10], Tdc[11]) + tdc[0], mindc, maxdc); ++ dc[1] = av_clipf(DC_MPRED(Tdc[10], dc[0], Tdc[11]) + tdc[1], mindc, maxdc); ++ dc[2] = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ dc[4] = av_clipf(DC_MPRED(Tdc[11], dc[1], Tdc[14]) + tdc[4], mindc, maxdc); ++ dc[5] = av_clipf(DC_MPRED(Tdc[14], dc[4], Tdc[15]) + tdc[5], mindc, maxdc); ++ dc[6] = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); ++ dc[7] = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); ++ dc[8] = av_clipf(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc); ++ dc[9] = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); ++ dc[10] = av_clipf(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc); ++ dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); ++ dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); ++ dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); ++ dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); ++ dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); ++ } else if (is_luma) { ++ dc[0] = av_clipf(DC_MPRED(LTdc[15], Ldc[5], Tdc[10]) + tdc[0], mindc, maxdc); ++ dc[1] = av_clipf(DC_MPRED(Tdc[10], dc[0], Tdc[11]) + tdc[1], mindc, maxdc); ++ dc[2] = av_clipf(DC_MPRED(Ldc[5], Ldc[7], dc[0]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ dc[4] = av_clipf(DC_MPRED(Tdc[11], dc[1], Tdc[14]) + tdc[4], mindc, maxdc); ++ dc[5] = av_clipf(DC_MPRED(Tdc[14], dc[4], Tdc[15]) + tdc[5], mindc, maxdc); ++ dc[6] = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); ++ dc[7] = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); ++ dc[8] = av_clipf(DC_MPRED(Ldc[7], Ldc[13], dc[2]) + tdc[8], mindc, maxdc); ++ dc[9] = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); ++ dc[10] = av_clipf(DC_MPRED(Ldc[13], Ldc[15], dc[8]) + tdc[10], mindc, maxdc); ++ dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); ++ dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); ++ dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); ++ dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); ++ dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); ++ } else if (!is_luma && (flags & 0x20) && (flags & 0x80)) { ++ dc[0] = av_clipf((mindc < 0 ? 0 : 1024.f) + tdc[0], mindc, maxdc); ++ dc[1] = av_clipf(dc[0] + tdc[1], mindc, maxdc); ++ dc[2] = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ } else if (!is_luma && (flags & 0x80)) { ++ dc[0] = av_clipf(DC_MPRED2(Ldc[1], Ldc[3]) + tdc[0], mindc, maxdc); ++ dc[1] = av_clipf(dc[0] + tdc[1], mindc, maxdc); ++ dc[2] = av_clipf(DC_MPRED(Ldc[1], Ldc[3], dc[0]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ } else if (!is_luma && (flags & 0x20)) { ++ dc[0] = av_clipf(DC_MPRED2(Tdc[2], Tdc[3]) + tdc[0], mindc, maxdc); ++ dc[1] = av_clipf(DC_MPRED(Tdc[2], dc[0], Tdc[3]) + tdc[1], mindc, maxdc); ++ dc[2] = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ } else if (!is_luma) { ++ dc[0] = av_clipf(DC_MPRED(LTdc[3], Ldc[1], Tdc[2]) + tdc[0], mindc, maxdc); ++ dc[1] = av_clipf(DC_MPRED(Tdc[2], dc[0], Tdc[3]) + tdc[1], mindc, maxdc); ++ dc[2] = av_clipf(DC_MPRED(Ldc[1], Ldc[3], dc[0]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ } ++} ++ ++static void bink2f_decode_dc(Bink2Context *c, GetBitContext *gb, float *dc, ++ int is_luma, int q, int mindc, int maxdc, ++ int flags) ++{ ++ const int num_dc = is_luma ? 16 : 4; ++ float tdc[16] = { 0 }; ++ int dc_bits; ++ ++ dc_bits = get_bits(gb, 3); ++ if (dc_bits == 7) ++ dc_bits += get_bits(gb, 2); ++ if (!dc_bits) { ++ memset(dc, 0, sizeof(*dc) * num_dc); ++ } else { ++ for (int j = 0; j < num_dc; j += 4) { ++ for (int i = 0; i < 4; i++) ++ tdc[i + j] = get_bits(gb, dc_bits); ++ ++ for (int i = 0; i < 4; i++) ++ if (tdc[i + j] && get_bits1(gb)) ++ tdc[i + j] = -tdc[i + j]; ++ } ++ } ++ ++ if ((flags & 0x20) && (flags & 0x80) && mindc >= 0) { ++ int bits = q_dc_bits[q] + dc_bits; ++ ++ if (bits < 10) { ++ int dc_val = get_bits(gb, 10 - bits); ++ ++ if (dc_val) { ++ dc_val <<= dc_bits; ++ if (get_bits1(gb)) ++ dc_val = -dc_val; ++ } ++ tdc[0] += dc_val; ++ } ++ } ++ ++ for (int i = 0; i < num_dc; i++) ++ tdc[i] *= bink2f_dc_quant[q]; ++ ++ bink2f_predict_dc(c, is_luma, mindc, maxdc, flags, tdc); ++} ++ ++static int bink2f_decode_ac(GetBitContext *gb, const uint8_t *scan, ++ float block[4][64], unsigned cbp, ++ float q, const float qmat[64]) ++{ ++ int idx, next, val, skip; ++ VLC *val_vlc, *skip_vlc; ++ ++ for (int i = 0; i < 4; i++, cbp >>= 1) { ++ memset(block[i], 0, sizeof(**block) * 64); ++ ++ if (!(cbp & 1)) ++ continue; ++ ++ if (cbp & 0x10000) { ++ val_vlc = &bink2f_ac_val1_vlc; ++ skip_vlc = &bink2f_ac_skip1_vlc; ++ } else { ++ val_vlc = &bink2f_ac_val0_vlc; ++ skip_vlc = &bink2f_ac_skip0_vlc; ++ } ++ ++ next = 0; ++ idx = 1; ++ while (idx < 64) { ++ val = get_vlc2(gb, val_vlc->table, val_vlc->bits, 1); ++ if (val < 0) ++ return AVERROR_INVALIDDATA; ++ if (val) { ++ if (val >= 4) { ++ val -= 3; ++ val = get_bits(gb, val) + (1 << val) + 2; ++ } ++ if (get_bits1(gb)) ++ val = -val; ++ } ++ ++ block[i][scan[idx]] = val * q * qmat[scan[idx]]; ++ if (idx > 62) ++ break; ++ idx++; ++ next--; ++ if (next < 1) { ++ skip = get_vlc2(gb, skip_vlc->table, skip_vlc->bits, 1); ++ if (skip < 0) ++ return AVERROR_INVALIDDATA; ++ next = bink2_next_skips[skip]; ++ skip = bink2f_skips[skip]; ++ if (skip == 11) ++ skip = get_bits(gb, 6); ++ idx += skip; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int bink2f_decode_intra_luma(Bink2Context *c, ++ float block[4][64], ++ unsigned *prev_cbp, int *prev_q, ++ uint8_t *dst, int stride, ++ int flags) ++{ ++ GetBitContext *gb = &c->gb; ++ float *dc = c->current_dc[c->mb_pos].dc[c->comp]; ++ int q, dq, ret; ++ unsigned cbp; ++ ++ *prev_cbp = cbp = bink2f_decode_cbp_luma(gb, *prev_cbp); ++ dq = bink2f_decode_delta_q(gb); ++ q = *prev_q + dq; ++ if (q < 0 || q >= 16) ++ return AVERROR_INVALIDDATA; ++ *prev_q = q; ++ ++ bink2f_decode_dc(c, gb, dc, 1, q, 0, 2047, flags); ++ ++ for (int i = 0; i < 4; i++) { ++ ret = bink2f_decode_ac(gb, bink2f_luma_scan, block, cbp >> (4 * i), ++ bink2f_ac_quant[q], bink2f_luma_intra_qmat); ++ if (ret < 0) ++ return ret; ++ ++ for (int j = 0; j < 4; j++) { ++ block[j][0] = dc[i * 4 + j] * 0.125f; ++ bink2f_idct_put(dst + (luma_repos[i*4+j]&3) * 8 + ++ (luma_repos[i*4+j]>>2) * 8 * stride, stride, block[j]); ++ } ++ } ++ ++ return 0; ++} ++ ++static int bink2f_decode_intra_chroma(Bink2Context *c, ++ float block[4][64], ++ unsigned *prev_cbp, int *prev_q, ++ uint8_t *dst, int stride, ++ int flags) ++{ ++ GetBitContext *gb = &c->gb; ++ float *dc = c->current_dc[c->mb_pos].dc[c->comp]; ++ int q, dq, ret; ++ unsigned cbp; ++ ++ *prev_cbp = cbp = bink2f_decode_cbp_chroma(gb, *prev_cbp); ++ dq = bink2f_decode_delta_q(gb); ++ q = *prev_q + dq; ++ if (q < 0 || q >= 16) ++ return AVERROR_INVALIDDATA; ++ *prev_q = q; ++ ++ bink2f_decode_dc(c, gb, dc, 0, q, 0, 2047, flags); ++ ++ ret = bink2f_decode_ac(gb, bink2f_chroma_scan, block, cbp, ++ bink2f_ac_quant[q], bink2f_chroma_qmat); ++ if (ret < 0) ++ return ret; ++ ++ for (int j = 0; j < 4; j++) { ++ block[j][0] = dc[j] * 0.125f; ++ bink2f_idct_put(dst + (j & 1) * 8 + (j >> 1) * 8 * stride, stride, block[j]); ++ } ++ ++ return 0; ++} ++ ++static int bink2f_decode_inter_luma(Bink2Context *c, ++ float block[4][64], ++ unsigned *prev_cbp, int *prev_q, ++ uint8_t *dst, int stride, ++ int flags) ++{ ++ GetBitContext *gb = &c->gb; ++ float *dc = c->current_dc[c->mb_pos].dc[c->comp]; ++ unsigned cbp; ++ int q, dq; ++ ++ *prev_cbp = cbp = bink2f_decode_cbp_luma(gb, *prev_cbp); ++ dq = bink2f_decode_delta_q(gb); ++ q = *prev_q + dq; ++ if (q < 0 || q >= 16) ++ return AVERROR_INVALIDDATA; ++ *prev_q = q; ++ ++ bink2f_decode_dc(c, gb, dc, 1, q, -1023, 1023, 0xA8); ++ ++ for (int i = 0; i < 4; i++) { ++ bink2f_decode_ac(gb, bink2f_luma_scan, block, cbp >> (i * 4), ++ bink2f_ac_quant[q], bink2f_luma_inter_qmat); ++ for (int j = 0; j < 4; j++) { ++ block[j][0] = dc[i * 4 + j] * 0.125f; ++ bink2f_idct_add(dst + (luma_repos[i*4+j]&3) * 8 + ++ (luma_repos[i*4+j]>>2) * 8 * stride, stride, ++ block[j]); ++ } ++ } ++ ++ return 0; ++} ++ ++static int bink2f_decode_inter_chroma(Bink2Context *c, ++ float block[4][64], ++ unsigned *prev_cbp, int *prev_q, ++ uint8_t *dst, int stride, ++ int flags) ++{ ++ GetBitContext *gb = &c->gb; ++ float *dc = c->current_dc[c->mb_pos].dc[c->comp]; ++ unsigned cbp; ++ int q, dq; ++ ++ *prev_cbp = cbp = bink2f_decode_cbp_chroma(gb, *prev_cbp); ++ dq = bink2f_decode_delta_q(gb); ++ q = *prev_q + dq; ++ if (q < 0 || q >= 16) ++ return AVERROR_INVALIDDATA; ++ *prev_q = q; ++ ++ bink2f_decode_dc(c, gb, dc, 0, q, -1023, 1023, 0xA8); ++ ++ bink2f_decode_ac(gb, bink2f_chroma_scan, block, cbp, ++ bink2f_ac_quant[q], bink2f_chroma_qmat); ++ ++ for (int i = 0; i < 4; i++) { ++ block[i][0] = dc[i] * 0.125f; ++ bink2f_idct_add(dst + (i & 1) * 8 + (i >> 1) * 8 * stride, stride, ++ block[i]); ++ } ++ ++ return 0; ++} ++ ++static void bink2f_predict_mv(Bink2Context *c, int x, int y, int flags, MVectors mv) ++{ ++ MVectors *c_mv = &c->current_mv[c->mb_pos].mv; ++ MVectors *l_mv = &c->current_mv[FFMAX(c->mb_pos - 1, 0)].mv; ++ MVectors *lt_mv = &c->prev_mv[FFMAX(c->mb_pos - 1, 0)].mv; ++ MVectors *t_mv = &c->prev_mv[c->mb_pos].mv; ++ ++ if (!(flags & 0x80)) { ++ if (flags & 0x20) { ++ c_mv->v[0][0] = mv.v[0][0] + mid_pred(t_mv->v[0][0], t_mv->v[2][0], t_mv->v[3][0]); ++ c_mv->v[0][1] = mv.v[0][1] + mid_pred(t_mv->v[0][1], t_mv->v[2][1], t_mv->v[3][1]); ++ c_mv->v[1][0] = mv.v[1][0] + mid_pred(t_mv->v[2][0], t_mv->v[3][0], c_mv->v[0][0]); ++ c_mv->v[1][1] = mv.v[1][1] + mid_pred(t_mv->v[2][1], t_mv->v[3][1], c_mv->v[0][1]); ++ c_mv->v[2][0] = mv.v[2][0] + mid_pred(t_mv->v[2][0], c_mv->v[0][0], c_mv->v[1][0]); ++ c_mv->v[2][1] = mv.v[2][1] + mid_pred(t_mv->v[2][1], c_mv->v[0][1], c_mv->v[1][1]); ++ c_mv->v[3][0] = mv.v[3][0] + mid_pred(c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]); ++ c_mv->v[3][1] = mv.v[3][1] + mid_pred(c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]); ++ } else { ++ c_mv->v[0][0] = mv.v[0][0] + mid_pred(lt_mv->v[3][0], t_mv->v[2][0], l_mv->v[1][0]); ++ c_mv->v[0][1] = mv.v[0][1] + mid_pred(lt_mv->v[3][1], t_mv->v[2][1], l_mv->v[1][1]); ++ c_mv->v[1][0] = mv.v[1][0] + mid_pred( t_mv->v[2][0], t_mv->v[3][0], c_mv->v[0][0]); ++ c_mv->v[1][1] = mv.v[1][1] + mid_pred( t_mv->v[2][1], t_mv->v[3][1], c_mv->v[0][1]); ++ c_mv->v[2][0] = mv.v[2][0] + mid_pred( t_mv->v[2][0], c_mv->v[0][0], c_mv->v[1][0]); ++ c_mv->v[2][1] = mv.v[2][1] + mid_pred( t_mv->v[2][1], c_mv->v[0][1], c_mv->v[1][1]); ++ c_mv->v[3][0] = mv.v[3][0] + mid_pred( c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]); ++ c_mv->v[3][1] = mv.v[3][1] + mid_pred( c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]); ++ } ++ } else { ++ if (flags & 0x20) { ++ c_mv->v[0][0] = mv.v[0][0]; ++ c_mv->v[0][1] = mv.v[0][1]; ++ c_mv->v[1][0] = mv.v[1][0]; ++ c_mv->v[1][1] = mv.v[1][1]; ++ c_mv->v[2][0] = mv.v[2][0]; ++ c_mv->v[2][1] = mv.v[2][1]; ++ c_mv->v[3][0] = mv.v[3][0]; ++ c_mv->v[3][1] = mv.v[3][1]; ++ } else { ++ c_mv->v[0][0] = mv.v[0][0] + mid_pred(l_mv->v[0][0], l_mv->v[1][0], l_mv->v[3][0]); ++ c_mv->v[0][1] = mv.v[0][1] + mid_pred(l_mv->v[0][1], l_mv->v[1][1], l_mv->v[3][1]); ++ c_mv->v[2][0] = mv.v[2][0] + mid_pred(l_mv->v[1][0], l_mv->v[3][0], c_mv->v[0][0]); ++ c_mv->v[2][1] = mv.v[2][1] + mid_pred(l_mv->v[1][1], l_mv->v[3][1], c_mv->v[0][1]); ++ c_mv->v[1][0] = mv.v[1][0] + mid_pred(l_mv->v[1][0], c_mv->v[0][0], c_mv->v[2][0]); ++ c_mv->v[1][1] = mv.v[1][1] + mid_pred(l_mv->v[1][1], c_mv->v[0][1], c_mv->v[2][1]); ++ c_mv->v[3][0] = mv.v[3][0] + mid_pred(c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]); ++ c_mv->v[3][1] = mv.v[3][1] + mid_pred(c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]); ++ } ++ } ++} ++ ++#define CH1FILTER(src) ((6*(src)[0] + 2*(src)[1] + 4) >> 3) ++#define CH2FILTER(src) (( (src)[0] + (src)[1] + 1) >> 1) ++#define CH3FILTER(src) ((2*(src)[0] + 6*(src)[1] + 4) >> 3) ++ ++#define CV1FILTER(src, i) ((6*(src)[0] + 2*(src)[i] + 4) >> 3) ++#define CV2FILTER(src, i) (( (src)[0] + (src)[i] + 1) >> 1) ++#define CV3FILTER(src, i) ((2*(src)[0] + 6*(src)[i] + 4) >> 3) ++ ++static void bink2f_c_mc(Bink2Context *c, int x, int y, ++ uint8_t *dst, int stride, ++ uint8_t *src, int sstride, ++ int width, int height, ++ int mv_x, int mv_y, ++ int mode) ++{ ++ uint8_t *msrc; ++ uint8_t temp[8*9]; ++ ++ if (mv_x < 0 || mv_x >= width || ++ mv_y < 0 || mv_y >= height) ++ return; ++ ++ msrc = src + mv_x + mv_y * sstride; ++ ++ switch (mode) { ++ case 0: ++ copy_block8(dst, msrc, stride, sstride, 8); ++ break; ++ case 1: ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i] = av_clip_uint8(CH1FILTER(msrc + i)); ++ dst += stride; ++ msrc += sstride; ++ } ++ break; ++ case 2: ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i] = av_clip_uint8(CH2FILTER(msrc + i)); ++ dst += stride; ++ msrc += sstride; ++ } ++ break; ++ case 3: ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i] = av_clip_uint8(CH3FILTER(msrc + i)); ++ dst += stride; ++ msrc += sstride; ++ } ++ break; ++ case 4: ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i*stride] = av_clip_uint8(CV1FILTER(msrc + i*sstride, sstride)); ++ dst += 1; ++ msrc += 1; ++ } ++ break; ++ case 5: ++ for (int i = 0; i < 9; i++) { ++ for (int j = 0; j < 8; j++) ++ temp[i*8+j] = av_clip_uint8(CH1FILTER(msrc + j)); ++ msrc += sstride; ++ } ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i] = av_clip_uint8(CV1FILTER(temp+j*8+i, 8)); ++ dst += stride; ++ } ++ break; ++ case 6: ++ for (int i = 0; i < 9; i++) { ++ for (int j = 0; j < 8; j++) ++ temp[i*8+j] = av_clip_uint8(CH2FILTER(msrc + j)); ++ msrc += sstride; ++ } ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i] = av_clip_uint8(CV1FILTER(temp+j*8+i, 8)); ++ dst += stride; ++ } ++ break; ++ case 7: ++ for (int i = 0; i < 9; i++) { ++ for (int j = 0; j < 8; j++) ++ temp[i*8+j] = av_clip_uint8(CH3FILTER(msrc + j)); ++ msrc += sstride; ++ } ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i] = av_clip_uint8(CV1FILTER(temp+j*8+i, 8)); ++ dst += stride; ++ } ++ break; ++ case 8: ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i*stride] = av_clip_uint8(CV2FILTER(msrc + i*sstride, sstride)); ++ dst += 1; ++ msrc += 1; ++ } ++ break; ++ case 9: ++ for (int i = 0; i < 9; i++) { ++ for (int j = 0; j < 8; j++) ++ temp[i*8+j] = av_clip_uint8(CH1FILTER(msrc + j)); ++ msrc += sstride; ++ } ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i] = av_clip_uint8(CV2FILTER(temp+j*8+i, 8)); ++ dst += stride; ++ } ++ break; ++ case 10: ++ for (int i = 0; i < 9; i++) { ++ for (int j = 0; j < 8; j++) ++ temp[i*8+j] = av_clip_uint8(CH2FILTER(msrc + j)); ++ msrc += sstride; ++ } ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i] = av_clip_uint8(CV2FILTER(temp+j*8+i, 8)); ++ dst += stride; ++ } ++ break; ++ case 11: ++ for (int i = 0; i < 9; i++) { ++ for (int j = 0; j < 8; j++) ++ temp[i*8+j] = av_clip_uint8(CH3FILTER(msrc + j)); ++ msrc += sstride; ++ } ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i] = av_clip_uint8(CV2FILTER(temp+j*8+i, 8)); ++ dst += stride; ++ } ++ break; ++ case 12: ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i*stride] = av_clip_uint8(CV3FILTER(msrc + i*sstride, sstride)); ++ dst += 1; ++ msrc += 1; ++ } ++ break; ++ case 13: ++ for (int i = 0; i < 9; i++) { ++ for (int j = 0; j < 8; j++) ++ temp[i*8+j] = av_clip_uint8(CH1FILTER(msrc + j)); ++ msrc += sstride; ++ } ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i] = av_clip_uint8(CV3FILTER(temp+j*8+i, 8)); ++ dst += stride; ++ } ++ break; ++ case 14: ++ for (int i = 0; i < 9; i++) { ++ for (int j = 0; j < 8; j++) ++ temp[i*8+j] = av_clip_uint8(CH2FILTER(msrc + j)); ++ msrc += sstride; ++ } ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i] = av_clip_uint8(CV3FILTER(temp+j*8+i, 8)); ++ dst += stride; ++ } ++ break; ++ case 15: ++ for (int i = 0; i < 9; i++) { ++ for (int j = 0; j < 8; j++) ++ temp[i*8+j] = av_clip_uint8(CH3FILTER(msrc + j)); ++ msrc += sstride; ++ } ++ for (int j = 0; j < 8; j++) { ++ for (int i = 0; i < 8; i++) ++ dst[i] = av_clip_uint8(CV3FILTER(temp+j*8+i, 8)); ++ dst += stride; ++ } ++ break; ++ } ++} ++ ++static void bink2f_y_mc(Bink2Context *c, int x, int y, ++ uint8_t *dst, int stride, ++ uint8_t *src, int sstride, ++ int width, int height, ++ int mv_x, int mv_y, int mode) ++{ ++ uint8_t *msrc; ++ ++ if (mv_x < 0 || mv_x >= width || ++ mv_y < 0 || mv_y >= height) ++ return; ++ ++ msrc = src + mv_x + mv_y * sstride; ++ ++ if (mode == 0) { ++ copy_block16(dst, msrc, stride, sstride, 16); ++ } else if (mode == 1) { ++ for (int j = 0; j < 16; j++) { ++ for (int i = 0; i < 16; i++) ++ dst[i] = av_clip_uint8(LHFILTER(msrc + i)); ++ dst += stride; ++ msrc += sstride; ++ } ++ } else if (mode == 2) { ++ for (int j = 0; j < 16; j++) { ++ for (int i = 0; i < 16; i++) ++ dst[i*stride] = av_clip_uint8(LVFILTER(msrc + i*sstride, sstride)); ++ dst += 1; ++ msrc += 1; ++ } ++ } else if (mode == 3) { ++ uint8_t temp[21 * 16]; ++ ++ msrc -= 2 * sstride; ++ for (int i = 0; i < 21; i++) { ++ for (int j = 0; j < 16; j++) ++ temp[i*16+j] = av_clip_uint8(LHFILTER(msrc + j)); ++ msrc += sstride; ++ } ++ for (int j = 0; j < 16; j++) { ++ for (int i = 0; i < 16; i++) ++ dst[i] = av_clip_uint8(LVFILTER(temp+(j+2)*16+i, 16)); ++ dst += stride; ++ } ++ } ++} ++ ++static int bink2f_mcompensate_chroma(Bink2Context *c, int x, int y, ++ uint8_t *dst, int stride, ++ uint8_t *src, int sstride, ++ int width, int height) ++{ ++ MVectors *mv = &c->current_mv[c->mb_pos].mv; ++ int mv_x, mv_y, mode; ++ ++ mv_x = (mv->v[0][0] >> 2) + x; ++ mv_y = (mv->v[0][1] >> 2) + y; ++ mode = mv->v[0][0] & 3; ++ mode |= (mv->v[0][1] & 3) << 2; ++ bink2f_c_mc(c, x, y, dst + x, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ mv_x = (mv->v[1][0] >> 2) + x + 8; ++ mv_y = (mv->v[1][1] >> 2) + y; ++ mode = mv->v[1][0] & 3; ++ mode |= (mv->v[1][1] & 3) << 2; ++ bink2f_c_mc(c, x, y, dst + x + 8, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ mv_x = (mv->v[2][0] >> 2) + x; ++ mv_y = (mv->v[2][1] >> 2) + y + 8; ++ mode = mv->v[2][0] & 3; ++ mode |= (mv->v[2][1] & 3) << 2; ++ bink2f_c_mc(c, x, y, dst + x + 8 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ mv_x = (mv->v[3][0] >> 2) + x + 8; ++ mv_y = (mv->v[3][1] >> 2) + y + 8; ++ mode = mv->v[3][0] & 3; ++ mode |= (mv->v[3][1] & 3) << 2; ++ bink2f_c_mc(c, x, y, dst + x + 8 + 8 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ return 0; ++} ++ ++static float bink2f_average_block(uint8_t *src, int stride) ++{ ++ int sum = 0; ++ ++ for (int i = 0; i < 8; i++) { ++ int avg_a = (src[i+0*stride] + src[i+1*stride] + 1) >> 1; ++ int avg_b = (src[i+2*stride] + src[i+3*stride] + 1) >> 1; ++ int avg_c = (src[i+4*stride] + src[i+5*stride] + 1) >> 1; ++ int avg_d = (src[i+6*stride] + src[i+7*stride] + 1) >> 1; ++ int avg_e = (avg_a + avg_b + 1) >> 1; ++ int avg_f = (avg_c + avg_d + 1) >> 1; ++ int avg_g = (avg_e + avg_f + 1) >> 1; ++ sum += avg_g; ++ } ++ ++ return sum; ++} ++ ++static void bink2f_average_chroma(Bink2Context *c, int x, int y, ++ uint8_t *src, int stride, ++ float *dc) ++{ ++ for (int i = 0; i < 4; i++) { ++ int X = i & 1; ++ int Y = i >> 1; ++ dc[i] = bink2f_average_block(src + x + X * 8 + (y + Y * 8) * stride, stride); ++ } ++} ++ ++static void bink2f_average_luma(Bink2Context *c, int x, int y, ++ uint8_t *src, int stride, ++ float *dc) ++{ ++ for (int i = 0; i < 16; i++) { ++ int I = luma_repos[i]; ++ int X = I & 3; ++ int Y = I >> 2; ++ dc[i] = bink2f_average_block(src + x + X * 8 + (y + Y * 8) * stride, stride); ++ } ++} ++ ++static int bink2f_mcompensate_luma(Bink2Context *c, int x, int y, ++ uint8_t *dst, int stride, ++ uint8_t *src, int sstride, ++ int width, int height) ++{ ++ MVectors *mv = &c->current_mv[c->mb_pos].mv; ++ int mv_x, mv_y, mode; ++ ++ mv_x = (mv->v[0][0] >> 1) + x; ++ mv_y = (mv->v[0][1] >> 1) + y; ++ mode = mv->v[0][0] & 1; ++ mode |= (mv->v[0][1] & 1) << 1; ++ bink2f_y_mc(c, x, y, dst + x, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ mv_x = (mv->v[1][0] >> 1) + x + 16; ++ mv_y = (mv->v[1][1] >> 1) + y; ++ mode = mv->v[1][0] & 1; ++ mode |= (mv->v[1][1] & 1) << 1; ++ bink2f_y_mc(c, x, y, dst + x + 16, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ mv_x = (mv->v[2][0] >> 1) + x; ++ mv_y = (mv->v[2][1] >> 1) + y + 16; ++ mode = mv->v[2][0] & 1; ++ mode |= (mv->v[2][1] & 1) << 1; ++ bink2f_y_mc(c, x, y, dst + x + 16 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ mv_x = (mv->v[3][0] >> 1) + x + 16; ++ mv_y = (mv->v[3][1] >> 1) + y + 16; ++ mode = mv->v[3][0] & 1; ++ mode |= (mv->v[3][1] & 1) << 1; ++ bink2f_y_mc(c, x, y, dst + x + 16 + 16 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ return 0; ++} ++ ++static int bink2f_decode_mv(Bink2Context *c, GetBitContext *gb, int x, int y, ++ int flags, MVectors *mv) ++{ ++ for (int i = 0; i < 2; i++) { ++ int val = 0, bits = get_bits(gb, 3); ++ ++ if (bits == 7) ++ bits += get_bits(gb, 2); ++ if (bits) { ++ for (int j = 0; j < 4; j++) ++ mv->v[j][i] = get_bits(gb, bits); ++ for (int j = 0; j < 4; j++) ++ if (mv->v[j][i] && get_bits1(gb)) ++ mv->v[j][i] = -mv->v[j][i]; ++ } ++ ++ if ((flags & 0x80) && (flags & 0x20)) { ++ val = get_bits(gb, 5) * 16; ++ if (val && get_bits1(gb)) ++ val = -val; ++ } ++ ++ mv->v[0][i] += val; ++ mv->v[1][i] += val; ++ mv->v[2][i] += val; ++ mv->v[3][i] += val; ++ } ++ ++ return 0; ++} ++ ++static int bink2f_decode_slice(Bink2Context *c, ++ uint8_t *dst[4], int stride[4], ++ uint8_t *src[4], int sstride[4], ++ int is_kf, int start, int end) ++{ ++ GetBitContext *gb = &c->gb; ++ int w = c->avctx->width; ++ int h = c->avctx->height; ++ int flags, ret = 0; ++ ++ memset(c->prev_mv, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->prev_mv)); ++ ++ for (int y = start; y < end; y += 32) { ++ unsigned y_cbp_intra = 0, u_cbp_intra = 0, v_cbp_intra = 0, a_cbp_intra = 0; ++ unsigned y_cbp_inter = 0, u_cbp_inter = 0, v_cbp_inter = 0, a_cbp_inter = 0; ++ int y_intra_q = 8, u_intra_q = 8, v_intra_q = 8, a_intra_q = 8; ++ int y_inter_q = 8, u_inter_q = 8, v_inter_q = 8, a_inter_q = 8; ++ ++ memset(c->current_mv, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->current_mv)); ++ ++ for (int x = 0; x < c->avctx->width; x += 32) { ++ MVectors mv = { 0 }; ++ int type = is_kf ? INTRA_BLOCK : get_bits(gb, 2); ++ ++ c->mb_pos = x / 32; ++ c->current_dc[c->mb_pos].block_type = type; ++ flags = 0; ++ if (y == start) ++ flags |= 0x80; ++ if (!x) ++ flags |= 0x20; ++ if (x == 32) ++ flags |= 0x200; ++ if (x + 32 >= c->avctx->width) ++ flags |= 0x40; ++ ++ switch (type) { ++ case INTRA_BLOCK: ++ if (!(flags & 0xA0) && c->prev_dc[c->mb_pos - 1].block_type != INTRA_BLOCK) { ++ bink2f_average_luma (c, x -32, -32, dst[0], stride[0], c->prev_dc[c->mb_pos - 1].dc[0]); ++ bink2f_average_chroma(c, x/2-16, -16, dst[2], stride[2], c->prev_dc[c->mb_pos - 1].dc[1]); ++ bink2f_average_chroma(c, x/2-16, -16, dst[1], stride[1], c->prev_dc[c->mb_pos - 1].dc[2]); ++ } ++ if (!(flags & 0x20) && c->current_dc[c->mb_pos - 1].block_type != INTRA_BLOCK) { ++ bink2f_average_luma (c, x -32, 0, dst[0], stride[0], c->current_dc[c->mb_pos - 1].dc[0]); ++ bink2f_average_chroma(c, x/2-16, 0, dst[2], stride[2], c->current_dc[c->mb_pos - 1].dc[1]); ++ bink2f_average_chroma(c, x/2-16, 0, dst[1], stride[1], c->current_dc[c->mb_pos - 1].dc[2]); ++ } ++ if ((flags & 0x20) && !(flags & 0x80) && c->prev_dc[c->mb_pos + 1].block_type != INTRA_BLOCK) { ++ bink2f_average_luma (c, x +32, -32, dst[0], stride[0], c->prev_dc[c->mb_pos + 1].dc[0]); ++ bink2f_average_chroma(c, x/2+16, -16, dst[2], stride[2], c->prev_dc[c->mb_pos + 1].dc[1]); ++ bink2f_average_chroma(c, x/2+16, -16, dst[1], stride[1], c->prev_dc[c->mb_pos + 1].dc[2]); ++ } ++ if (!(flags & 0x80) && c->prev_dc[c->mb_pos].block_type != INTRA_BLOCK) { ++ bink2f_average_luma (c, x, -32, dst[0], stride[0], c->prev_dc[c->mb_pos].dc[0]); ++ bink2f_average_chroma(c, x/2, -16, dst[2], stride[2], c->prev_dc[c->mb_pos].dc[1]); ++ bink2f_average_chroma(c, x/2, -16, dst[1], stride[1], c->prev_dc[c->mb_pos].dc[2]); ++ } ++ ++ bink2f_predict_mv(c, x, y, flags, mv); ++ c->comp = 0; ++ ret = bink2f_decode_intra_luma(c, c->block, &y_cbp_intra, &y_intra_q, ++ dst[0] + x, stride[0], flags); ++ if (ret < 0) ++ goto fail; ++ c->comp = 1; ++ ret = bink2f_decode_intra_chroma(c, c->block, &u_cbp_intra, &u_intra_q, ++ dst[2] + x/2, stride[2], flags); ++ if (ret < 0) ++ goto fail; ++ c->comp = 2; ++ ret = bink2f_decode_intra_chroma(c, c->block, &v_cbp_intra, &v_intra_q, ++ dst[1] + x/2, stride[1], flags); ++ if (ret < 0) ++ goto fail; ++ if (c->has_alpha) { ++ c->comp = 3; ++ ret = bink2f_decode_intra_luma(c, c->block, &a_cbp_intra, &a_intra_q, ++ dst[3] + x, stride[3], flags); ++ if (ret < 0) ++ goto fail; ++ } ++ break; ++ case SKIP_BLOCK: ++ copy_block16(dst[0] + x, src[0] + x + sstride[0] * y, ++ stride[0], sstride[0], 32); ++ copy_block16(dst[0] + x + 16, src[0] + x + 16 + sstride[0] * y, ++ stride[0], sstride[0], 32); ++ copy_block16(dst[1] + (x/2), src[1] + (x/2) + sstride[1] * (y/2), ++ stride[1], sstride[1], 16); ++ copy_block16(dst[2] + (x/2), src[2] + (x/2) + sstride[2] * (y/2), ++ stride[2], sstride[2], 16); ++ if (c->has_alpha) { ++ copy_block16(dst[3] + x, src[3] + x + sstride[3] * y, ++ stride[3], sstride[3], 32); ++ copy_block16(dst[3] + x + 16, src[3] + x + 16 + sstride[3] * y, ++ stride[3], sstride[3], 32); ++ } ++ break; ++ case MOTION_BLOCK: ++ bink2f_decode_mv(c, gb, x, y, flags, &mv); ++ bink2f_predict_mv(c, x, y, flags, mv); ++ c->comp = 0; ++ ret = bink2f_mcompensate_luma(c, x, y, ++ dst[0], stride[0], ++ src[0], sstride[0], ++ w, h); ++ if (ret < 0) ++ goto fail; ++ c->comp = 1; ++ ret = bink2f_mcompensate_chroma(c, x/2, y/2, ++ dst[2], stride[2], ++ src[2], sstride[2], ++ w/2, h/2); ++ if (ret < 0) ++ goto fail; ++ c->comp = 2; ++ ret = bink2f_mcompensate_chroma(c, x/2, y/2, ++ dst[1], stride[1], ++ src[1], sstride[1], ++ w/2, h/2); ++ if (ret < 0) ++ goto fail; ++ break; ++ case RESIDUE_BLOCK: ++ bink2f_decode_mv(c, gb, x, y, flags, &mv); ++ bink2f_predict_mv(c, x, y, flags, mv); ++ ret = bink2f_mcompensate_luma(c, x, y, ++ dst[0], stride[0], ++ src[0], sstride[0], ++ w, h); ++ if (ret < 0) ++ goto fail; ++ ret = bink2f_mcompensate_chroma(c, x/2, y/2, ++ dst[2], stride[2], ++ src[2], sstride[2], ++ w/2, h/2); ++ if (ret < 0) ++ goto fail; ++ ret = bink2f_mcompensate_chroma(c, x/2, y/2, ++ dst[1], stride[1], ++ src[1], sstride[1], ++ w/2, h/2); ++ if (ret < 0) ++ goto fail; ++ c->comp = 0; ++ ret = bink2f_decode_inter_luma(c, c->block, &y_cbp_inter, &y_inter_q, ++ dst[0] + x, stride[0], flags); ++ if (ret < 0) ++ goto fail; ++ c->comp = 1; ++ ret = bink2f_decode_inter_chroma(c, c->block, &u_cbp_inter, &u_inter_q, ++ dst[2] + x/2, stride[2], flags); ++ if (ret < 0) ++ goto fail; ++ c->comp = 2; ++ ret = bink2f_decode_inter_chroma(c, c->block, &v_cbp_inter, &v_inter_q, ++ dst[1] + x/2, stride[1], flags); ++ if (ret < 0) ++ goto fail; ++ if (c->has_alpha) { ++ c->comp = 3; ++ ret = bink2f_decode_inter_luma(c, c->block, &a_cbp_inter, &a_inter_q, ++ dst[3] + x, stride[3], flags); ++ if (ret < 0) ++ goto fail; ++ } ++ break; ++ default: ++ return AVERROR_INVALIDDATA; ++ } ++ } ++ ++ dst[0] += stride[0] * 32; ++ dst[1] += stride[1] * 16; ++ dst[2] += stride[2] * 16; ++ if (c->has_alpha) ++ dst[3] += stride[3] * 32; ++ ++ FFSWAP(MVPredict *, c->current_mv, c->prev_mv); ++ FFSWAP(DCPredict *, c->current_dc, c->prev_dc); ++ } ++fail: ++ emms_c(); ++ ++ return ret; ++} ++ ++#endif /* AVCODEC_BINK2F_H */ +diff --git a/libavcodec/bink2g.h b/libavcodec/bink2g.h +new file mode 100644 +index 0000000000..be50146e4f +--- /dev/null ++++ b/libavcodec/bink2g.h +@@ -0,0 +1,1870 @@ ++/* ++ * Bink video 2 decoder ++ * Copyright (c) 2014 Konstantin Shishkov ++ * Copyright (c) 2019 Paul B Mahol ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#ifndef AVCODEC_BINK2G_H ++#define AVCODEC_BINK2G_H ++ ++#include ++#include "avcodec.h" ++#include "get_bits.h" ++#include "bink2.h" ++ ++static const uint8_t bink2g_scan[64] = { ++ 0, 8, 1, 2, 9, 16, 24, 17, ++ 10, 3, 4, 11, 18, 25, 32, 40, ++ 33, 26, 19, 12, 5, 6, 13, 20, ++ 27, 34, 41, 48, 56, 49, 42, 35, ++ 28, 21, 14, 7, 15, 22, 29, 36, ++ 43, 50, 57, 58, 51, 44, 37, 30, ++ 23, 31, 38, 45, 52, 59, 60, 53, ++ 46, 39, 47, 54, 61, 62, 55, 63, ++}; ++ ++static const uint16_t bink2g_ac_skip_codes[2][NUM_AC_SKIPS] = { ++ { ++ 0x01, 0x00, 0x004, 0x02C, 0x06C, 0x0C, 0x4C, ++ 0xAC, 0xEC, 0x12C, 0x16C, 0x1AC, 0x02, 0x1C, ++ }, ++ { ++ 0x01, 0x04, 0x00, 0x08, 0x02, 0x32, 0x0A, ++ 0x12, 0x3A, 0x7A, 0xFA, 0x72, 0x06, 0x1A, ++ }, ++}; ++ ++static const uint8_t bink2g_ac_skip_bits[2][NUM_AC_SKIPS] = { ++ { 1, 3, 4, 9, 9, 7, 7, 9, 8, 9, 9, 9, 2, 5 }, ++ { 1, 3, 4, 4, 5, 7, 5, 6, 7, 8, 8, 7, 3, 6 }, ++}; ++ ++static const uint8_t bink2g_mv_codes[] = { ++ 0x01, 0x06, 0x0C, 0x1C, 0x18, 0x38, 0x58, 0x78, ++ 0x68, 0x48, 0x28, 0x08, 0x14, 0x04, 0x02, 0x00, ++}; ++ ++static const uint8_t bink2g_mv_bits[] = { ++ 1, 3, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 3, 4, ++}; ++ ++static const uint8_t bink2g_skips[] = { ++ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 64, 0, 0, 0, ++}; ++ ++static uint8_t bink2g_chroma_cbp_pat[16] = { ++ 0x00, 0x00, 0x00, 0x0F, ++ 0x00, 0x0F, 0x0F, 0x0F, ++ 0x00, 0x0F, 0x0F, 0x0F, ++ 0x0F, 0x0F, 0x0F, 0x0F, ++}; ++ ++static const int32_t bink2g_dc_pat[] = { ++ 1024, 1218, 1448, 1722, 2048, ++ 2435, 2896, 3444, 4096, 4871, ++ 5793, 6889, 8192, 9742, 11585, 13777, 16384, ++ 19484, 23170, 27555, 32768, 38968, 46341, ++ 55109, 65536, 77936, 92682, 110218, 131072, ++ 155872, 185364, 220436, 262144, 311744, ++ 370728, 440872, 524288, ++}; ++ ++static const uint16_t bink2g_luma_intra_qmat[4][64] = { ++ { ++ 1024, 1432, 1506, 1181, ++ 1843, 2025, 5271, 8592, ++ 1313, 1669, 1630, 1672, ++ 2625, 3442, 8023, 12794, ++ 1076, 1755, 1808, 1950, ++ 3980, 4875, 8813, 11909, ++ 1350, 1868, 2127, 2016, ++ 4725, 4450, 7712, 9637, ++ 2458, 3103, 4303, 4303, ++ 6963, 6835, 11079, 13365, ++ 3375, 5704, 5052, 6049, ++ 9198, 7232, 10725, 9834, ++ 5486, 7521, 7797, 7091, ++ 11079, 10016, 13559, 12912, ++ 7279, 7649, 7020, 6097, ++ 9189, 9047, 12661, 13768, ++ }, ++ { ++ 1218, 1703, 1791, 1405, ++ 2192, 2408, 6268, 10218, ++ 1561, 1985, 1938, 1988, ++ 3122, 4093, 9541, 15215, ++ 1279, 2087, 2150, 2319, ++ 4733, 5798, 10481, 14162, ++ 1606, 2222, 2530, 2398, ++ 5619, 5292, 9171, 11460, ++ 2923, 3690, 5117, 5118, ++ 8281, 8128, 13176, 15894, ++ 4014, 6783, 6008, 7194, ++ 10938, 8600, 12755, 11694, ++ 6524, 8944, 9272, 8433, ++ 13176, 11911, 16125, 15354, ++ 8657, 9096, 8348, 7250, ++ 10927, 10759, 15056, 16373, ++ }, ++ { ++ 1448, 2025, 2130, 1671, ++ 2607, 2864, 7454, 12151, ++ 1856, 2360, 2305, 2364, ++ 3713, 4867, 11346, 18094, ++ 1521, 2482, 2557, 2758, ++ 5628, 6894, 12464, 16841, ++ 1909, 2642, 3008, 2852, ++ 6683, 6293, 10906, 13629, ++ 3476, 4388, 6085, 6086, ++ 9847, 9666, 15668, 18901, ++ 4773, 8066, 7145, 8555, ++ 13007, 10227, 15168, 13907, ++ 7758, 10637, 11026, 10028, ++ 15668, 14165, 19175, 18259, ++ 10294, 10817, 9927, 8622, ++ 12995, 12794, 17905, 19470, ++ }, ++ { ++ 1722, 2408, 2533, 1987, ++ 3100, 3406, 8864, 14450, ++ 2208, 2807, 2741, 2811, ++ 4415, 5788, 13493, 21517, ++ 1809, 2951, 3041, 3280, ++ 6693, 8199, 14822, 20028, ++ 2271, 3142, 3578, 3391, ++ 7947, 7484, 12969, 16207, ++ 4133, 5218, 7236, 7238, ++ 11711, 11495, 18633, 22478, ++ 5677, 9592, 8497, 10174, ++ 15469, 12162, 18038, 16538, ++ 9226, 12649, 13112, 11926, ++ 18633, 16845, 22804, 21715, ++ 12242, 12864, 11806, 10254, ++ 15454, 15215, 21293, 23155, ++ }, ++}; ++ ++static const uint16_t bink2g_chroma_intra_qmat[4][64] = { ++ { ++ 1024, 1193, 1434, 2203, ++ 5632, 4641, 5916, 6563, ++ 1193, 1622, 1811, 3606, ++ 6563, 5408, 6894, 7649, ++ 1434, 1811, 3515, 4875, ++ 5916, 4875, 6215, 6894, ++ 2203, 3606, 4875, 3824, ++ 4641, 3824, 4875, 5408, ++ 5632, 6563, 5916, 4641, ++ 5632, 4641, 5916, 6563, ++ 4641, 5408, 4875, 3824, ++ 4641, 3824, 4875, 5408, ++ 5916, 6894, 6215, 4875, ++ 5916, 4875, 6215, 6894, ++ 6563, 7649, 6894, 5408, ++ 6563, 5408, 6894, 7649, ++ }, ++ { ++ 1218, 1419, 1706, 2620, ++ 6698, 5519, 7035, 7805, ++ 1419, 1929, 2153, 4288, ++ 7805, 6432, 8199, 9096, ++ 1706, 2153, 4180, 5798, ++ 7035, 5798, 7390, 8199, ++ 2620, 4288, 5798, 4548, ++ 5519, 4548, 5798, 6432, ++ 6698, 7805, 7035, 5519, ++ 6698, 5519, 7035, 7805, ++ 5519, 6432, 5798, 4548, ++ 5519, 4548, 5798, 6432, ++ 7035, 8199, 7390, 5798, ++ 7035, 5798, 7390, 8199, ++ 7805, 9096, 8199, 6432, ++ 7805, 6432, 8199, 9096, ++ }, ++ { ++ 1448, 1688, 2028, 3116, ++ 7965, 6563, 8367, 9282, ++ 1688, 2294, 2561, 5099, ++ 9282, 7649, 9750, 10817, ++ 2028, 2561, 4971, 6894, ++ 8367, 6894, 8789, 9750, ++ 3116, 5099, 6894, 5408, ++ 6563, 5408, 6894, 7649, ++ 7965, 9282, 8367, 6563, ++ 7965, 6563, 8367, 9282, ++ 6563, 7649, 6894, 5408, ++ 6563, 5408, 6894, 7649, ++ 8367, 9750, 8789, 6894, ++ 8367, 6894, 8789, 9750, ++ 9282, 10817, 9750, 7649, ++ 9282, 7649, 9750, 10817, ++ }, ++ { ++ 1722, 2007, 2412, 3706, ++ 9472, 7805, 9950, 11038, ++ 2007, 2729, 3045, 6064, ++ 11038, 9096, 11595, 12864, ++ 2412, 3045, 5912, 8199, ++ 9950, 8199, 10452, 11595, ++ 3706, 6064, 8199, 6432, ++ 7805, 6432, 8199, 9096, ++ 9472, 11038, 9950, 7805, ++ 9472, 7805, 9950, 11038, ++ 7805, 9096, 8199, 6432, ++ 7805, 6432, 8199, 9096, ++ 9950, 11595, 10452, 8199, ++ 9950, 8199, 10452, 11595, ++ 11038, 12864, 11595, 9096, ++ 11038, 9096, 11595, 12864, ++ }, ++}; ++ ++static const uint16_t bink2g_inter_qmat[4][64] = { ++ { ++ 1024, 1193, 1076, 844, ++ 1052, 914, 1225, 1492, ++ 1193, 1391, 1254, 983, ++ 1227, 1065, 1463, 1816, ++ 1076, 1254, 1161, 936, ++ 1195, 1034, 1444, 1741, ++ 844, 983, 936, 811, ++ 1055, 927, 1305, 1584, ++ 1052, 1227, 1195, 1055, ++ 1451, 1336, 1912, 2354, ++ 914, 1065, 1034, 927, ++ 1336, 1313, 1945, 2486, ++ 1225, 1463, 1444, 1305, ++ 1912, 1945, 3044, 4039, ++ 1492, 1816, 1741, 1584, ++ 2354, 2486, 4039, 5679, ++ }, ++ { ++ 1218, 1419, 1279, 1003, ++ 1252, 1087, 1457, 1774, ++ 1419, 1654, 1491, 1169, ++ 1459, 1267, 1739, 2159, ++ 1279, 1491, 1381, 1113, ++ 1421, 1230, 1717, 2070, ++ 1003, 1169, 1113, 965, ++ 1254, 1103, 1552, 1884, ++ 1252, 1459, 1421, 1254, ++ 1725, 1589, 2274, 2799, ++ 1087, 1267, 1230, 1103, ++ 1589, 1562, 2313, 2956, ++ 1457, 1739, 1717, 1552, ++ 2274, 2313, 3620, 4803, ++ 1774, 2159, 2070, 1884, ++ 2799, 2956, 4803, 6753, ++ }, ++ { ++ 1448, 1688, 1521, 1193, ++ 1488, 1293, 1732, 2110, ++ 1688, 1967, 1773, 1391, ++ 1735, 1507, 2068, 2568, ++ 1521, 1773, 1642, 1323, ++ 1690, 1462, 2042, 2462, ++ 1193, 1391, 1323, 1147, ++ 1492, 1311, 1845, 2241, ++ 1488, 1735, 1690, 1492, ++ 2052, 1889, 2704, 3328, ++ 1293, 1507, 1462, 1311, ++ 1889, 1857, 2751, 3515, ++ 1732, 2068, 2042, 1845, ++ 2704, 2751, 4306, 5712, ++ 2110, 2568, 2462, 2241, ++ 3328, 3515, 5712, 8031, ++ }, ++ { ++ 1722, 2007, 1809, 1419, ++ 1770, 1537, 2060, 2509, ++ 2007, 2339, 2108, 1654, ++ 2063, 1792, 2460, 3054, ++ 1809, 2108, 1953, 1574, ++ 2010, 1739, 2428, 2928, ++ 1419, 1654, 1574, 1364, ++ 1774, 1559, 2195, 2664, ++ 1770, 2063, 2010, 1774, ++ 2440, 2247, 3216, 3958, ++ 1537, 1792, 1739, 1559, ++ 2247, 2209, 3271, 4181, ++ 2060, 2460, 2428, 2195, ++ 3216, 3271, 5120, 6793, ++ 2509, 3054, 2928, 2664, ++ 3958, 4181, 6793, 9550, ++ }, ++}; ++ ++static inline void bink2g_idct_1d(int16_t *blk, int step, int shift) ++{ ++#define idct_mul_a(val) ((val) + ((val) >> 2)) ++#define idct_mul_b(val) ((val) >> 1) ++#define idct_mul_c(val) ((val) - ((val) >> 2) - ((val) >> 4)) ++#define idct_mul_d(val) ((val) + ((val) >> 2) - ((val) >> 4)) ++#define idct_mul_e(val) ((val) >> 2) ++ int tmp00 = blk[3*step] + blk[5*step]; ++ int tmp01 = blk[3*step] - blk[5*step]; ++ int tmp02 = idct_mul_a(blk[2*step]) + idct_mul_b(blk[6*step]); ++ int tmp03 = idct_mul_b(blk[2*step]) - idct_mul_a(blk[6*step]); ++ int tmp0 = (blk[0*step] + blk[4*step]) + tmp02; ++ int tmp1 = (blk[0*step] + blk[4*step]) - tmp02; ++ int tmp2 = blk[0*step] - blk[4*step]; ++ int tmp3 = blk[1*step] + tmp00; ++ int tmp4 = blk[1*step] - tmp00; ++ int tmp5 = tmp01 + blk[7*step]; ++ int tmp6 = tmp01 - blk[7*step]; ++ int tmp7 = tmp4 + idct_mul_c(tmp6); ++ int tmp8 = idct_mul_c(tmp4) - tmp6; ++ int tmp9 = idct_mul_d(tmp3) + idct_mul_e(tmp5); ++ int tmp10 = idct_mul_e(tmp3) - idct_mul_d(tmp5); ++ int tmp11 = tmp2 + tmp03; ++ int tmp12 = tmp2 - tmp03; ++ ++ blk[0*step] = (tmp0 + tmp9) >> shift; ++ blk[1*step] = (tmp11 + tmp7) >> shift; ++ blk[2*step] = (tmp12 + tmp8) >> shift; ++ blk[3*step] = (tmp1 + tmp10) >> shift; ++ blk[4*step] = (tmp1 - tmp10) >> shift; ++ blk[5*step] = (tmp12 - tmp8) >> shift; ++ blk[6*step] = (tmp11 - tmp7) >> shift; ++ blk[7*step] = (tmp0 - tmp9) >> shift; ++} ++ ++static void bink2g_idct_put(uint8_t *dst, int stride, int16_t *block) ++{ ++ for (int i = 0; i < 8; i++) ++ bink2g_idct_1d(block + i, 8, 0); ++ for (int i = 0; i < 8; i++) ++ bink2g_idct_1d(block + i * 8, 1, 6); ++ for (int i = 0; i < 8; i++) { ++ for (int j = 0; j < 8; j++) ++ dst[j] = av_clip_uint8(block[j * 8 + i]); ++ dst += stride; ++ } ++} ++ ++static void bink2g_idct_add(uint8_t *dst, int stride, int16_t *block) ++{ ++ for (int i = 0; i < 8; i++) ++ bink2g_idct_1d(block + i, 8, 0); ++ for (int i = 0; i < 8; i++) ++ bink2g_idct_1d(block + i * 8, 1, 6); ++ for (int i = 0; i < 8; i++) { ++ for (int j = 0; j < 8; j++) ++ dst[j] = av_clip_uint8(dst[j] + block[j * 8 + i]); ++ dst += stride; ++ } ++} ++ ++static int bink2g_get_type(GetBitContext *gb, int *lru) ++{ ++ int val; ++ ++ switch (get_unary(gb, 1, 3)) { ++ case 0: ++ val = lru[0]; ++ break; ++ case 1: ++ val = lru[1]; ++ FFSWAP(int, lru[0], lru[1]); ++ break; ++ case 2: ++ val = lru[3]; ++ FFSWAP(int, lru[2], lru[3]); ++ break; ++ case 3: ++ val = lru[2]; ++ FFSWAP(int, lru[1], lru[2]); ++ break; ++ } ++ ++ return val; ++} ++ ++static int bink2g_decode_dq(GetBitContext *gb) ++{ ++ int dq = get_unary(gb, 1, 4); ++ ++ if (dq == 3) ++ dq += get_bits1(gb); ++ else if (dq == 4) ++ dq += get_bits(gb, 5) + 1; ++ if (dq && get_bits1(gb)) ++ dq = -dq; ++ ++ return dq; ++} ++ ++static unsigned bink2g_decode_cbp_luma(Bink2Context *c, ++ GetBitContext *gb, unsigned prev_cbp) ++{ ++ unsigned ones = 0, cbp, mask; ++ ++ for (int i = 0; i < 16; i++) { ++ if (prev_cbp & (1 << i)) ++ ones += 1; ++ } ++ ++ cbp = 0; ++ mask = 0; ++ if (ones > 7) { ++ ones = 16 - ones; ++ mask = 0xFFFF; ++ } ++ ++ if (get_bits1(gb) == 0) { ++ if (ones < 4) { ++ for (int j = 0; j < 16; j += 4) ++ if (!get_bits1(gb)) ++ cbp |= get_bits(gb, 4) << j; ++ } else { ++ cbp = get_bits(gb, 16); ++ } ++ } ++ ++ cbp ^= mask; ++ if (!(c->frame_flags & 0x40000) || cbp) { ++ if (get_bits1(gb)) ++ cbp = cbp | cbp << 16; ++ } ++ ++ return cbp; ++} ++ ++static unsigned bink2g_decode_cbp_chroma(GetBitContext *gb, unsigned prev_cbp) ++{ ++ unsigned cbp; ++ ++ cbp = prev_cbp & 0xF0000 | bink2g_chroma_cbp_pat[prev_cbp & 0xF]; ++ if (get_bits1(gb) == 0) { ++ cbp = get_bits(gb, 4); ++ if (get_bits1(gb)) ++ cbp |= cbp << 16; ++ } ++ ++ return cbp; ++} ++ ++static void bink2g_predict_dc(Bink2Context *c, ++ int is_luma, int mindc, int maxdc, ++ int flags, int tdc[16]) ++{ ++ int *LTdc = c->prev_idc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp]; ++ int *Tdc = c->prev_idc[c->mb_pos].dc[c->comp]; ++ int *Ldc = c->current_idc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp]; ++ int *dc = c->current_idc[c->mb_pos].dc[c->comp]; ++ ++ if (is_luma && (flags & 0x20) && (flags & 0x80)) { ++ dc[0] = av_clip((mindc < 0 ? 0 : 1024) + tdc[0], mindc, maxdc); ++ dc[1] = av_clip(dc[0] + tdc[1], mindc, maxdc); ++ dc[2] = av_clip(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ dc[4] = av_clip(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc); ++ dc[5] = av_clip(dc[4] + tdc[5], mindc, maxdc); ++ dc[6] = av_clip(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); ++ dc[7] = av_clip(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); ++ dc[8] = av_clip(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc); ++ dc[9] = av_clip(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); ++ dc[10] = av_clip(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc); ++ dc[11] = av_clip(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); ++ dc[12] = av_clip(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); ++ dc[13] = av_clip(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); ++ dc[14] = av_clip(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); ++ dc[15] = av_clip(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); ++ } else if (is_luma && (flags & 0x80)) { ++ dc[0] = av_clip(DC_MPRED2(Ldc[5], Ldc[7]) + tdc[0], mindc, maxdc); ++ dc[1] = av_clip(dc[0] + tdc[1], mindc, maxdc); ++ dc[2] = av_clip(DC_MPRED(Ldc[5], Ldc[7], dc[0]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ dc[4] = av_clip(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc); ++ dc[5] = av_clip(dc[4] + tdc[5], mindc, maxdc); ++ dc[6] = av_clip(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); ++ dc[7] = av_clip(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); ++ dc[8] = av_clip(DC_MPRED(Ldc[7], Ldc[13], dc[2]) + tdc[8], mindc, maxdc); ++ dc[9] = av_clip(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); ++ dc[10] = av_clip(DC_MPRED(Ldc[13], Ldc[15], dc[8]) + tdc[10], mindc, maxdc); ++ dc[11] = av_clip(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); ++ dc[12] = av_clip(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); ++ dc[13] = av_clip(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); ++ dc[14] = av_clip(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); ++ dc[15] = av_clip(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); ++ } else if (is_luma && (flags & 0x20)) { ++ dc[0] = av_clip(DC_MPRED2(Tdc[10], Tdc[11]) + tdc[0], mindc, maxdc); ++ dc[1] = av_clip(DC_MPRED(Tdc[10], dc[0], Tdc[11]) + tdc[1], mindc, maxdc); ++ dc[2] = av_clip(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ dc[4] = av_clip(DC_MPRED(Tdc[11], dc[1], Tdc[14]) + tdc[4], mindc, maxdc); ++ dc[5] = av_clip(DC_MPRED(Tdc[14], dc[4], Tdc[15]) + tdc[5], mindc, maxdc); ++ dc[6] = av_clip(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); ++ dc[7] = av_clip(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); ++ dc[8] = av_clip(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc); ++ dc[9] = av_clip(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); ++ dc[10] = av_clip(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc); ++ dc[11] = av_clip(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); ++ dc[12] = av_clip(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); ++ dc[13] = av_clip(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); ++ dc[14] = av_clip(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); ++ dc[15] = av_clip(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); ++ } else if (is_luma) { ++ dc[0] = av_clip(DC_MPRED(LTdc[15], Ldc[5], Tdc[10]) + tdc[0], mindc, maxdc); ++ dc[1] = av_clip(DC_MPRED(Tdc[10], dc[0], Tdc[11]) + tdc[1], mindc, maxdc); ++ dc[2] = av_clip(DC_MPRED(Ldc[5], Ldc[7], dc[0]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ dc[4] = av_clip(DC_MPRED(Tdc[11], dc[1], Tdc[14]) + tdc[4], mindc, maxdc); ++ dc[5] = av_clip(DC_MPRED(Tdc[14], dc[4], Tdc[15]) + tdc[5], mindc, maxdc); ++ dc[6] = av_clip(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); ++ dc[7] = av_clip(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); ++ dc[8] = av_clip(DC_MPRED(Ldc[7], Ldc[13], dc[2]) + tdc[8], mindc, maxdc); ++ dc[9] = av_clip(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); ++ dc[10] = av_clip(DC_MPRED(Ldc[13], Ldc[15], dc[8]) + tdc[10], mindc, maxdc); ++ dc[11] = av_clip(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); ++ dc[12] = av_clip(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); ++ dc[13] = av_clip(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); ++ dc[14] = av_clip(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); ++ dc[15] = av_clip(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); ++ } else if (!is_luma && (flags & 0x20) && (flags & 0x80)) { ++ dc[0] = av_clip((mindc < 0 ? 0 : 1024) + tdc[0], mindc, maxdc); ++ dc[1] = av_clip(dc[0] + tdc[1], mindc, maxdc); ++ dc[2] = av_clip(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ } else if (!is_luma && (flags & 0x80)) { ++ dc[0] = av_clip(DC_MPRED2(Ldc[1], Ldc[3]) + tdc[0], mindc, maxdc); ++ dc[1] = av_clip(dc[0] + tdc[1], mindc, maxdc); ++ dc[2] = av_clip(DC_MPRED(Ldc[1], Ldc[3], dc[0]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ } else if (!is_luma && (flags & 0x20)) { ++ dc[0] = av_clip(DC_MPRED2(Tdc[2], Tdc[3]) + tdc[0], mindc, maxdc); ++ dc[1] = av_clip(DC_MPRED(Tdc[2], dc[0], Tdc[3]) + tdc[1], mindc, maxdc); ++ dc[2] = av_clip(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ } else if (!is_luma) { ++ dc[0] = av_clip(DC_MPRED(LTdc[3], Ldc[1], Tdc[2]) + tdc[0], mindc, maxdc); ++ dc[1] = av_clip(DC_MPRED(Tdc[2], dc[0], Tdc[3]) + tdc[1], mindc, maxdc); ++ dc[2] = av_clip(DC_MPRED(Ldc[1], Ldc[3], dc[0]) + tdc[2], mindc, maxdc); ++ dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); ++ } ++} ++ ++static void bink2g_decode_dc(Bink2Context *c, GetBitContext *gb, int *dc, ++ int is_luma, int q, int mindc, int maxdc, ++ int flags) ++{ ++ const int num_dc = is_luma ? 16 : 4; ++ int tdc[16]; ++ int pat; ++ ++ q = FFMAX(q, 8); ++ pat = bink2g_dc_pat[q]; ++ ++ memset(tdc, 0, sizeof(tdc)); ++ ++ if (get_bits1(gb)) { ++ for (int i = 0; i < num_dc; i++) { ++ int cnt = get_unary(gb, 0, 12); ++ ++ if (cnt > 3) ++ cnt = (1 << (cnt - 3)) + get_bits(gb, cnt - 3) + 2; ++ if (cnt && get_bits1(gb)) ++ cnt = -cnt; ++ tdc[i] = (cnt * pat + 0x1FF) >> 10; ++ } ++ } ++ ++ bink2g_predict_dc(c, is_luma, mindc, maxdc, flags, tdc); ++} ++ ++static int bink2g_decode_ac(GetBitContext *gb, const uint8_t scan[64], ++ int16_t block[4][64], unsigned cbp, ++ int q, const uint16_t qmat[4][64], ++ uint8_t ac_count[4]) ++{ ++ int idx, next, val, skip; ++ VLC *skip_vlc; ++ ++ for (int i = 0; i < 4; i++) { ++ memset(block[i], 0, sizeof(int16_t) * 64); ++ ac_count[i] = 0; ++ } ++ ++ if ((cbp & 0xf) == 0) ++ return 0; ++ ++ skip_vlc = &bink2g_ac_skip0_vlc; ++ if (cbp & 0xffff0000) ++ skip_vlc = &bink2g_ac_skip1_vlc; ++ ++ for (int i = 0; i < 4; i++, cbp >>= 1) { ++ if (!(cbp & 1)) ++ continue; ++ ++ next = 0; ++ idx = 1; ++ while (idx < 64) { ++ next--; ++ if (next < 1) { ++ skip = get_vlc2(gb, skip_vlc->table, skip_vlc->bits, 1); ++ if (skip < 0) ++ return AVERROR_INVALIDDATA; ++ next = bink2_next_skips[skip]; ++ skip = bink2g_skips[skip]; ++ if (skip == 11) ++ skip = get_bits(gb, 6); ++ idx += skip; ++ if (idx >= 64) ++ break; ++ } ++ ++ val = get_unary(gb, 0, 12) + 1; ++ if (val > 3) ++ val = get_bits(gb, val - 3) + (1 << (val - 3)) + 2; ++ if (get_bits1(gb)) ++ val = -val; ++ block[i][scan[idx]] = ((val * qmat[q & 3][scan[idx]] * (1 << (q >> 2))) + 64) >> 7; ++ ac_count[i]++; ++ idx++; ++ } ++ } ++ ++ return 0; ++} ++ ++static inline uint16_t bink2g_block_state(int dc, unsigned ac_count, int intra) ++{ ++ const unsigned strength = (ac_count < 8) + (ac_count < 4) + !ac_count; ++ ++ return (dc & 0x1FFF) | (strength << 13) | (intra ? 0x8000 : 0); ++} ++ ++static int bink2g_decode_intra_luma(Bink2Context *c, ++ GetBitContext *gb, int16_t block[4][64], ++ unsigned *prev_cbp, int q, ++ BlockDSPContext *dsp, uint8_t *dst, int stride, ++ int flags) ++{ ++ int *dc = c->current_idc[c->mb_pos].dc[c->comp]; ++ uint16_t *state = c->current_idc[c->mb_pos].state[c->comp]; ++ unsigned cbp; ++ int ret; ++ ++ *prev_cbp = cbp = bink2g_decode_cbp_luma(c, gb, *prev_cbp); ++ ++ bink2g_decode_dc(c, gb, dc, 1, q, 0, 2047, flags); ++ ++ for (int i = 0; i < 4; i++) { ++ uint8_t ac_count[4]; ++ ++ ret = bink2g_decode_ac(gb, bink2g_scan, block, cbp >> (4*i), ++ q, bink2g_luma_intra_qmat, ac_count); ++ if (ret < 0) ++ return ret; ++ ++ for (int j = 0; j < 4; j++) { ++ const int block_index = i * 4 + j; ++ const int raster_index = luma_repos[block_index]; ++ ++ state[raster_index] = bink2g_block_state(dc[block_index], ac_count[j], 1); ++ block[j][0] = dc[block_index] * 8 + 32; ++ bink2g_idct_put(dst + (raster_index & 3) * 8 + ++ (raster_index >> 2) * 8 * stride, stride, block[j]); ++ } ++ } ++ ++ return 0; ++} ++ ++static int bink2g_decode_intra_chroma(Bink2Context *c, ++ GetBitContext *gb, int16_t block[4][64], ++ unsigned *prev_cbp, int q, ++ BlockDSPContext *dsp, uint8_t *dst, int stride, ++ int flags) ++{ ++ int *dc = c->current_idc[c->mb_pos].dc[c->comp]; ++ uint16_t *state = c->current_idc[c->mb_pos].state[c->comp]; ++ uint8_t ac_count[4]; ++ unsigned cbp; ++ int ret; ++ ++ *prev_cbp = cbp = bink2g_decode_cbp_chroma(gb, *prev_cbp); ++ ++ bink2g_decode_dc(c, gb, dc, 0, q, 0, 2047, flags); ++ ++ ret = bink2g_decode_ac(gb, bink2g_scan, block, cbp, ++ q, bink2g_chroma_intra_qmat, ac_count); ++ if (ret < 0) ++ return ret; ++ ++ for (int j = 0; j < 4; j++) { ++ state[j] = bink2g_block_state(dc[j], ac_count[j], 1); ++ block[j][0] = dc[j] * 8 + 32; ++ bink2g_idct_put(dst + (j & 1) * 8 + ++ (j >> 1) * 8 * stride, stride, block[j]); ++ } ++ ++ return 0; ++} ++ ++static int bink2g_decode_inter_luma(Bink2Context *c, ++ GetBitContext *gb, int16_t block[4][64], ++ unsigned *prev_cbp, int q, ++ BlockDSPContext *dsp, uint8_t *dst, int stride, ++ int flags) ++{ ++ int *dc = c->current_idc[c->mb_pos].dc[c->comp]; ++ uint16_t *state = c->current_idc[c->mb_pos].state[c->comp]; ++ const int maxdc = c->frame_flags & 0x40000 ? 2047 : 1023; ++ unsigned cbp; ++ int ret; ++ ++ *prev_cbp = cbp = bink2g_decode_cbp_luma(c, gb, *prev_cbp); ++ ++ bink2g_decode_dc(c, gb, dc, 1, q, -maxdc, maxdc, 0xA8); ++ ++ for (int i = 0; i < 4; i++) { ++ uint8_t ac_count[4]; ++ ++ ret = bink2g_decode_ac(gb, bink2g_scan, block, cbp >> (4 * i), ++ q, bink2g_inter_qmat, ac_count); ++ if (ret < 0) ++ return ret; ++ ++ for (int j = 0; j < 4; j++) { ++ const int block_index = i * 4 + j; ++ const int raster_index = luma_repos[block_index]; ++ ++ state[raster_index] = bink2g_block_state(dc[block_index], ac_count[j], 0); ++ block[j][0] = dc[block_index] * 8 + 32; ++ bink2g_idct_add(dst + (raster_index & 3) * 8 + ++ (raster_index >> 2) * 8 * stride, ++ stride, block[j]); ++ } ++ } ++ ++ return 0; ++} ++ ++static int bink2g_decode_inter_chroma(Bink2Context *c, ++ GetBitContext *gb, int16_t block[4][64], ++ unsigned *prev_cbp, int q, ++ BlockDSPContext *dsp, uint8_t *dst, int stride, ++ int flags) ++{ ++ int *dc = c->current_idc[c->mb_pos].dc[c->comp]; ++ uint16_t *state = c->current_idc[c->mb_pos].state[c->comp]; ++ uint8_t ac_count[4]; ++ const int maxdc = c->frame_flags & 0x40000 ? 2047 : 1023; ++ unsigned cbp; ++ int ret; ++ ++ *prev_cbp = cbp = bink2g_decode_cbp_chroma(gb, *prev_cbp); ++ ++ bink2g_decode_dc(c, gb, dc, 0, q, -maxdc, maxdc, 0xA8); ++ ++ ret = bink2g_decode_ac(gb, bink2g_scan, block, cbp, ++ q, bink2g_inter_qmat, ac_count); ++ if (ret < 0) ++ return ret; ++ ++ for (int j = 0; j < 4; j++) { ++ state[j] = bink2g_block_state(dc[j], ac_count[j], 0); ++ block[j][0] = dc[j] * 8 + 32; ++ bink2g_idct_add(dst + (j & 1) * 8 + ++ (j >> 1) * 8 * stride, stride, block[j]); ++ } ++ ++ return 0; ++} ++ ++static void bink2g_predict_mv(Bink2Context *c, int x, int y, int flags, MVectors mv) ++{ ++ MVectors *c_mv = &c->current_mv[c->mb_pos].mv; ++ MVectors *l_mv = &c->current_mv[FFMAX(c->mb_pos - 1, 0)].mv; ++ MVectors *lt_mv = &c->prev_mv[FFMAX(c->mb_pos - 1, 0)].mv; ++ MVectors *t_mv = &c->prev_mv[c->mb_pos].mv; ++ ++ if (mv.nb_vectors == 1) { ++ if (flags & 0x80) { ++ if (!(flags & 0x20)) { ++ mv.v[0][0] += mid_pred(l_mv->v[0][0], l_mv->v[1][0], l_mv->v[3][0]); ++ mv.v[0][1] += mid_pred(l_mv->v[0][1], l_mv->v[1][1], l_mv->v[3][1]); ++ } ++ } else { ++ if (!(flags & 0x20)) { ++ mv.v[0][0] += mid_pred(lt_mv->v[3][0], t_mv->v[2][0], l_mv->v[1][0]); ++ mv.v[0][1] += mid_pred(lt_mv->v[3][1], t_mv->v[2][1], l_mv->v[1][1]); ++ } else { ++ mv.v[0][0] += mid_pred(t_mv->v[0][0], t_mv->v[2][0], t_mv->v[3][0]); ++ mv.v[0][1] += mid_pred(t_mv->v[0][1], t_mv->v[2][1], t_mv->v[3][1]); ++ } ++ } ++ ++ c_mv->v[0][0] = mv.v[0][0]; ++ c_mv->v[0][1] = mv.v[0][1]; ++ c_mv->v[1][0] = mv.v[0][0]; ++ c_mv->v[1][1] = mv.v[0][1]; ++ c_mv->v[2][0] = mv.v[0][0]; ++ c_mv->v[2][1] = mv.v[0][1]; ++ c_mv->v[3][0] = mv.v[0][0]; ++ c_mv->v[3][1] = mv.v[0][1]; ++ ++ return; ++ } ++ ++ if (!(flags & 0x80)) { ++ if (flags & 0x20) { ++ c_mv->v[0][0] = mv.v[0][0] + mid_pred(t_mv->v[0][0], t_mv->v[2][0], t_mv->v[3][0]); ++ c_mv->v[0][1] = mv.v[0][1] + mid_pred(t_mv->v[0][1], t_mv->v[2][1], t_mv->v[3][1]); ++ c_mv->v[1][0] = mv.v[1][0] + mid_pred(t_mv->v[2][0], t_mv->v[3][0], c_mv->v[0][0]); ++ c_mv->v[1][1] = mv.v[1][1] + mid_pred(t_mv->v[2][1], t_mv->v[3][1], c_mv->v[0][1]); ++ c_mv->v[2][0] = mv.v[2][0] + mid_pred(t_mv->v[2][0], c_mv->v[0][0], c_mv->v[1][0]); ++ c_mv->v[2][1] = mv.v[2][1] + mid_pred(t_mv->v[2][1], c_mv->v[0][1], c_mv->v[1][1]); ++ c_mv->v[3][0] = mv.v[3][0] + mid_pred(c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]); ++ c_mv->v[3][1] = mv.v[3][1] + mid_pred(c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]); ++ } else { ++ c_mv->v[0][0] = mv.v[0][0] + mid_pred(t_mv->v[2][0], lt_mv->v[3][0], l_mv->v[1][0]); ++ c_mv->v[0][1] = mv.v[0][1] + mid_pred(t_mv->v[2][1], lt_mv->v[3][1], l_mv->v[1][1]); ++ c_mv->v[1][0] = mv.v[1][0] + mid_pred(t_mv->v[2][0], t_mv->v[3][0], c_mv->v[0][0]); ++ c_mv->v[1][1] = mv.v[1][1] + mid_pred(t_mv->v[2][1], t_mv->v[3][1], c_mv->v[0][1]); ++ c_mv->v[2][0] = mv.v[2][0] + mid_pred(l_mv->v[1][0], l_mv->v[3][0], c_mv->v[0][0]); ++ c_mv->v[2][1] = mv.v[2][1] + mid_pred(l_mv->v[1][1], l_mv->v[3][1], c_mv->v[0][1]); ++ c_mv->v[3][0] = mv.v[3][0] + mid_pred(c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]); ++ c_mv->v[3][1] = mv.v[3][1] + mid_pred(c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]); ++ } ++ } else { ++ if (flags & 0x20) { ++ c_mv->v[0][0] = mv.v[0][0]; ++ c_mv->v[0][1] = mv.v[0][1]; ++ c_mv->v[1][0] = mv.v[1][0] + mv.v[0][0]; ++ c_mv->v[1][1] = mv.v[1][1] + mv.v[0][1]; ++ c_mv->v[2][0] = mv.v[2][0] + mv.v[0][0]; ++ c_mv->v[2][1] = mv.v[2][1] + mv.v[0][1]; ++ c_mv->v[3][0] = mv.v[3][0] + mid_pred(c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]); ++ c_mv->v[3][1] = mv.v[3][1] + mid_pred(c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]); ++ } else { ++ const int left_v1 = mv.nb_vectors == 0 ? 3 : 1; ++ ++ c_mv->v[0][0] = mv.v[0][0] + mid_pred(l_mv->v[0][0], l_mv->v[1][0], l_mv->v[3][0]); ++ c_mv->v[0][1] = mv.v[0][1] + mid_pred(l_mv->v[0][1], l_mv->v[1][1], l_mv->v[3][1]); ++ c_mv->v[2][0] = mv.v[2][0] + mid_pred(l_mv->v[1][0], l_mv->v[3][0], c_mv->v[0][0]); ++ c_mv->v[2][1] = mv.v[2][1] + mid_pred(l_mv->v[1][1], l_mv->v[3][1], c_mv->v[0][1]); ++ c_mv->v[1][0] = mv.v[1][0] + mid_pred(l_mv->v[left_v1][0], c_mv->v[0][0], c_mv->v[2][0]); ++ c_mv->v[1][1] = mv.v[1][1] + mid_pred(l_mv->v[left_v1][1], c_mv->v[0][1], c_mv->v[2][1]); ++ c_mv->v[3][0] = mv.v[3][0] + mid_pred(c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]); ++ c_mv->v[3][1] = mv.v[3][1] + mid_pred(c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]); ++ } ++ } ++} ++ ++static int bink2g_decode_mv(Bink2Context *c, GetBitContext *gb, int x, int y, ++ MVectors *mv) ++{ ++ int num_mvs = get_bits1(gb) ? 1 : 4; ++ ++ mv->nb_vectors = num_mvs; ++ ++ for (int i = 0; i < 2; i++) { ++ for (int j = 0; j < num_mvs; j++) { ++ int val = get_vlc2(gb, bink2g_mv_vlc.table, bink2g_mv_vlc.bits, 1); ++ ++ if (val < 0) ++ return AVERROR_INVALIDDATA; ++ if (val >= 8 && val != 15) ++ val = val - 15; ++ if (val == 15) { ++ int bits = get_unary(gb, 1, 12) + 4; ++ val = get_bits(gb, bits) + (1 << bits) - 1; ++ if (val & 1) ++ val = (-(val >> 1) - 1); ++ else ++ val = val >> 1; ++ } ++ mv->v[j][i] = val; ++ } ++ } ++ ++ return 0; ++} ++ ++static void update_intra_q(Bink2Context *c, int8_t *intra_q, int dq, int flags) ++{ ++ if (flags & 0x20 && flags & 0x80) ++ *intra_q = 16 + dq; ++ else if (flags & 0x80) ++ *intra_q = c->current_q[c->mb_pos - 1].intra_q + dq; ++ else if (flags & 0x20) ++ *intra_q = c->prev_q[c->mb_pos].intra_q + dq; ++ else ++ *intra_q = mid_pred(c->prev_q[c->mb_pos].intra_q, ++ c->current_q[c->mb_pos - 1].intra_q, ++ c->prev_q[c->mb_pos - 1].intra_q) + dq; ++} ++ ++static void update_inter_q(Bink2Context *c, int8_t *inter_q, int dq, int flags) ++{ ++ if (flags & 0x20 && flags & 0x80) ++ *inter_q = 16 + dq; ++ else if (flags & 0x80) ++ *inter_q = c->current_q[c->mb_pos - 1].inter_q + dq; ++ else if (flags & 0x20) ++ *inter_q = c->prev_q[c->mb_pos].inter_q + dq; ++ else ++ *inter_q = mid_pred(c->prev_q[c->mb_pos].inter_q, ++ c->current_q[c->mb_pos - 1].inter_q, ++ c->prev_q[c->mb_pos - 1].inter_q) + dq; ++} ++ ++static const uint8_t bink2g_chroma_weights[4][2] = { ++ { 1, 0 }, ++ { 3, 1 }, ++ { 1, 1 }, ++ { 1, 3 }, ++}; ++ ++static const uint8_t bink2g_chroma_shifts[4] = { 0, 2, 1, 2 }; ++ ++static void bink2g_c_mc(Bink2Context *c, int x, int y, ++ uint8_t *dst, int stride, ++ uint8_t *src, int sstride, ++ int width, int height, ++ int mv_x, int mv_y, ++ int mode) ++{ ++ const uint8_t *msrc; ++ int hphase, vphase, shift, rounding; ++ ++ if (mv_x < 0 || mv_x >= width || ++ mv_y < 0 || mv_y >= height) ++ return; ++ ++ msrc = src + mv_x + mv_y * sstride; ++ ++ if (mode == 0) { ++ copy_block8(dst, msrc, stride, sstride, 8); ++ return; ++ } ++ ++ hphase = mode & 3; ++ vphase = mode >> 2; ++ shift = bink2g_chroma_shifts[hphase] + bink2g_chroma_shifts[vphase]; ++ rounding = 1 << (shift - 1); ++ ++ for (int y = 0; y < 8; y++) { ++ const uint8_t *top = msrc + y * sstride; ++ const uint8_t *bottom = top + (vphase != 0) * sstride; ++ ++ for (int x = 0; x < 8; x++) { ++ const int top_value = bink2g_chroma_weights[hphase][0] * top[x] + ++ bink2g_chroma_weights[hphase][1] * top[x + (hphase != 0)]; ++ const int bottom_value = bink2g_chroma_weights[hphase][0] * bottom[x] + ++ bink2g_chroma_weights[hphase][1] * bottom[x + (hphase != 0)]; ++ const int value = bink2g_chroma_weights[vphase][0] * top_value + ++ bink2g_chroma_weights[vphase][1] * bottom_value; ++ ++ dst[x] = (value + rounding) >> shift; ++ } ++ dst += stride; ++ } ++} ++ ++static void bink2g_filter_vertical_edge(uint8_t *p, int stride, ++ unsigned left, unsigned right) ++{ ++ const unsigned index = left | (right << 2); ++ ++ if (!index || index == 15) ++ return; ++ ++ for (int y = 0; y < 8; y++, p += stride) { ++ const int b = p[-1]; ++ const int c = p[0]; ++ const int delta = c - b; ++ const int outer = (2 * delta + 8) >> 4; ++ const int inner = (4 * delta + 8) >> 4; ++ ++ if (left >= 2) ++ p[-2] = av_clip_uint8(p[-2] + outer); ++ if (left >= 1) ++ p[-1] = av_clip_uint8(b + inner); ++ if (right >= 1) ++ p[0] = av_clip_uint8(c - inner); ++ if (right >= 2) ++ p[1] = av_clip_uint8(p[1] - outer); ++ } ++} ++ ++static void bink2g_filter_horizontal_edge(uint8_t *p, int stride, ++ unsigned top, unsigned bottom) ++{ ++ const unsigned index = top | (bottom << 2); ++ ++ if (!index || index == 15) ++ return; ++ ++ for (int x = 0; x < 8; x++, p++) { ++ const int b = p[-stride]; ++ const int c = p[0]; ++ const int delta = c - b; ++ const int outer = (2 * delta + 8) >> 4; ++ const int inner = (4 * delta + 8) >> 4; ++ ++ if (top >= 2) ++ p[-2 * stride] = av_clip_uint8(p[-2 * stride] + outer); ++ if (top >= 1) ++ p[-stride] = av_clip_uint8(b + inner); ++ if (bottom >= 1) ++ p[0] = av_clip_uint8(c - inner); ++ if (bottom >= 2) ++ p[stride] = av_clip_uint8(p[stride] - outer); ++ } ++} ++ ++static int bink2g_mcompensate_chroma(Bink2Context *c, int x, int y, ++ uint8_t *dst, int stride, ++ uint8_t *src, int sstride, ++ int width, int height) ++{ ++ MVectors *mv = &c->current_mv[c->mb_pos].mv; ++ int mv_x, mv_y, mode; ++ ++ mv_x = (mv->v[0][0] >> 2) + x; ++ mv_y = (mv->v[0][1] >> 2) + y; ++ mode = mv->v[0][0] & 3; ++ mode |= (mv->v[0][1] & 3) << 2; ++ bink2g_c_mc(c, x, y, dst + x, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ mv_x = (mv->v[1][0] >> 2) + x + 8; ++ mv_y = (mv->v[1][1] >> 2) + y; ++ mode = mv->v[1][0] & 3; ++ mode |= (mv->v[1][1] & 3) << 2; ++ bink2g_c_mc(c, x, y, dst + x + 8, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ mv_x = (mv->v[2][0] >> 2) + x; ++ mv_y = (mv->v[2][1] >> 2) + y + 8; ++ mode = mv->v[2][0] & 3; ++ mode |= (mv->v[2][1] & 3) << 2; ++ bink2g_c_mc(c, x, y, dst + x + 8 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ mv_x = (mv->v[3][0] >> 2) + x + 8; ++ mv_y = (mv->v[3][1] >> 2) + y + 8; ++ mode = mv->v[3][0] & 3; ++ mode |= (mv->v[3][1] & 3) << 2; ++ bink2g_c_mc(c, x, y, dst + x + 8 + 8 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ return 0; ++} ++ ++static void bink2g_y_mc(Bink2Context *c, int x, int y, ++ uint8_t *dst, int stride, ++ uint8_t *src, int sstride, ++ int width, int height, ++ int mv_x, int mv_y, int mode) ++{ ++ uint8_t *msrc; ++ ++ if (mv_x < 0 || mv_x >= width || ++ mv_y < 0 || mv_y >= height) ++ return; ++ ++ msrc = src + mv_x + mv_y * sstride; ++ ++ if (mode == 0) { ++ copy_block16(dst, msrc, stride, sstride, 16); ++ } else if (mode == 1) { ++ for (int j = 0; j < 16; j++) { ++ for (int i = 0; i < 16; i++) ++ dst[i] = av_clip_uint8(LHFILTER(msrc + i)); ++ dst += stride; ++ msrc += sstride; ++ } ++ } else if (mode == 2) { ++ for (int j = 0; j < 16; j++) { ++ for (int i = 0; i < 16; i++) ++ dst[i*stride] = av_clip_uint8(LVFILTER(msrc + i*sstride, sstride)); ++ dst += 1; ++ msrc += 1; ++ } ++ } else if (mode == 3) { ++ int16_t temp[21 * 16]; ++ ++ msrc -= 2 * sstride; ++ for (int i = 0; i < 21; i++) { ++ for (int j = 0; j < 16; j++) ++ temp[i*16+j] = LHFILTER(msrc + j); ++ msrc += sstride; ++ } ++ for (int j = 0; j < 16; j++) { ++ for (int i = 0; i < 16; i++) ++ dst[i] = av_clip_uint8(LVFILTER(temp+(j+2)*16+i, 16)); ++ dst += stride; ++ } ++ } ++} ++ ++static int bink2g_mcompensate_luma(Bink2Context *c, int x, int y, ++ uint8_t *dst, int stride, ++ uint8_t *src, int sstride, ++ int width, int height) ++{ ++ MVectors *mv = &c->current_mv[c->mb_pos].mv; ++ int mv_x, mv_y, mode; ++ ++ mv_x = (mv->v[0][0] >> 1) + x; ++ mv_y = (mv->v[0][1] >> 1) + y; ++ mode = mv->v[0][0] & 1; ++ mode |= (mv->v[0][1] & 1) << 1; ++ bink2g_y_mc(c, x, y, dst + x, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ mv_x = (mv->v[1][0] >> 1) + x + 16; ++ mv_y = (mv->v[1][1] >> 1) + y; ++ mode = mv->v[1][0] & 1; ++ mode |= (mv->v[1][1] & 1) << 1; ++ bink2g_y_mc(c, x, y, dst + x + 16, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ mv_x = (mv->v[2][0] >> 1) + x; ++ mv_y = (mv->v[2][1] >> 1) + y + 16; ++ mode = mv->v[2][0] & 1; ++ mode |= (mv->v[2][1] & 1) << 1; ++ bink2g_y_mc(c, x, y, dst + x + 16 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ mv_x = (mv->v[3][0] >> 1) + x + 16; ++ mv_y = (mv->v[3][1] >> 1) + y + 16; ++ mode = mv->v[3][0] & 1; ++ mode |= (mv->v[3][1] & 1) << 1; ++ bink2g_y_mc(c, x, y, dst + x + 16 + 16 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode); ++ ++ return 0; ++} ++ ++static int bink2g_average_block(uint8_t *src, int stride) ++{ ++ int sum = 0; ++ ++ for (int i = 0; i < 8; i++) { ++ int avg_a = (src[i+0*stride] + src[i+1*stride] + 1) >> 1; ++ int avg_b = (src[i+2*stride] + src[i+3*stride] + 1) >> 1; ++ int avg_c = (src[i+4*stride] + src[i+5*stride] + 1) >> 1; ++ int avg_d = (src[i+6*stride] + src[i+7*stride] + 1) >> 1; ++ int avg_e = (avg_a + avg_b + 1) >> 1; ++ int avg_f = (avg_c + avg_d + 1) >> 1; ++ int avg_g = (avg_e + avg_f + 1) >> 1; ++ sum += avg_g; ++ } ++ ++ return sum; ++} ++ ++static void bink2g_average_chroma(Bink2Context *c, int x, int y, ++ uint8_t *src, int stride, ++ int *dc) ++{ ++ for (int i = 0; i < 4; i++) { ++ int X = i & 1; ++ int Y = i >> 1; ++ dc[i] = bink2g_average_block(src + x + X * 8 + (y + Y * 8) * stride, stride); ++ } ++} ++ ++static void bink2g_average_luma(Bink2Context *c, int x, int y, ++ uint8_t *src, int stride, ++ int *dc) ++{ ++ for (int i = 0; i < 16; i++) { ++ int I = luma_repos[i]; ++ int X = I & 3; ++ int Y = I >> 2; ++ dc[i] = bink2g_average_block(src + x + X * 8 + (y + Y * 8) * stride, stride); ++ } ++} ++ ++static inline unsigned bink2g_filter_strength(uint16_t state) ++{ ++ return (state >> 13) & 3; ++} ++ ++static inline int bink2g_filter_map_skip(const uint8_t *map, int position) ++{ ++ const unsigned bit = position >> 3; ++ ++ return (map[bit >> 3] >> (bit & 7)) & 1; ++} ++ ++static inline int bink2g_mv_discontinuity(const MVectors *a, int ai, ++ const MVectors *b, int bi) ++{ ++ return FFABS(a->v[ai][0] - b->v[bi][0]) > 1 || ++ FFABS(a->v[ai][1] - b->v[bi][1]) > 1; ++} ++ ++static inline void bink2g_force_mv_edge(const MVectors *a, int ai, ++ const MVectors *b, int bi, ++ uint16_t left_state, ++ uint16_t right_state, ++ unsigned *left, unsigned *right) ++{ ++ if (!(left_state & 0x8000) && !(right_state & 0x8000) && ++ bink2g_mv_discontinuity(a, ai, b, bi)) ++ *left = *right = 2; ++} ++ ++static inline void bink2g_select_coding_edge(uint16_t left_state, ++ uint16_t right_state, ++ unsigned *left, ++ unsigned *right) ++{ ++ const int left_intra = !!(left_state & 0x8000); ++ const int right_intra = !!(right_state & 0x8000); ++ ++ if (!left_intra) ++ *left = 0; ++ if (!right_intra) ++ *right = 0; ++} ++ ++static inline int bink2g_recon_near(uint16_t a, uint16_t b, int threshold) ++{ ++ const int16_t ab = (int16_t)(uint16_t)(a - b); ++ const int16_t ba = (int16_t)(uint16_t)(b - a); ++ ++ return FFMAX(ab, ba) < threshold; ++} ++ ++static inline int bink2g_recon_mulhi(int k, int v) ++{ ++ return ((int32_t)(int16_t)k * (int16_t)v) >> 16; ++} ++ ++static inline int bink2g_recon_curve(int base, int left, int right, int pos) ++{ ++ switch (pos) { ++ case 0: return base + bink2g_recon_mulhi(26624, left); ++ case 1: return base + bink2g_recon_mulhi(18432, left) + (right >> 7); ++ case 2: return base + bink2g_recon_mulhi(12288, left) + (right >> 5); ++ case 3: return base + bink2g_recon_mulhi( 7168, left) + (right >> 4); ++ case 4: return base + bink2g_recon_mulhi( 7168, right) + (left >> 4); ++ case 5: return base + bink2g_recon_mulhi(12288, right) + (left >> 5); ++ case 6: return base + bink2g_recon_mulhi(18432, right) + (left >> 7); ++ default:return base + bink2g_recon_mulhi(26624, right); ++ } ++} ++ ++static inline uint16_t bink2g_recon_state(const DCIPredict *row, int comp, ++ int blocks_per_mb, int blocks_w, ++ int block_x, int block_y) ++{ ++ block_x = av_clip(block_x, 0, blocks_w - 1); ++ return row[block_x / blocks_per_mb].state[comp] ++ [block_y * blocks_per_mb + block_x % blocks_per_mb]; ++} ++ ++static void bink2g_reconstruct_block(uint8_t *dst, int stride, ++ int width, int height, ++ uint16_t left, uint16_t target, ++ uint16_t right, uint16_t up_left, ++ uint16_t up, uint16_t up_right, ++ uint16_t down_left, uint16_t down, ++ uint16_t down_right, int threshold) ++{ ++ int center[8], top[8], bottom[8]; ++ int d, l, r, u, v, ul, ur, dl, dr; ++ ++ if (target < 0xE000 || width <= 0 || height <= 0) ++ return; ++ ++ d = target & 0x1FFF; ++ l = bink2g_recon_near(target, left, threshold) ? left & 0x1FFF : d; ++ r = bink2g_recon_near(target, right, threshold) ? right & 0x1FFF : d; ++ u = bink2g_recon_near(target, up, threshold) ? up & 0x1FFF : d; ++ v = bink2g_recon_near(target, down, threshold) ? down & 0x1FFF : d; ++ ul = bink2g_recon_near(target, up_left, threshold) ? up_left & 0x1FFF : l; ++ ur = bink2g_recon_near(target, up_right, threshold) ? up_right & 0x1FFF : r; ++ dl = bink2g_recon_near(target, down_left, threshold) ? down_left & 0x1FFF : l; ++ dr = bink2g_recon_near(target, down_right, threshold) ? down_right & 0x1FFF : r; ++ ++ for (int x = 0; x < 8; x++) { ++ center[x] = bink2g_recon_curve(d + 4, l - d, r - d, x); ++ top[x] = bink2g_recon_curve(u + 4, ul - u, ur - u, x) - center[x]; ++ bottom[x] = bink2g_recon_curve(v + 4, dl - v, dr - v, x) - center[x]; ++ } ++ ++ for (int y = 0; y < FFMIN(height, 8); y++) { ++ for (int x = 0; x < FFMIN(width, 8); x++) ++ dst[x] = av_clip_uint8(bink2g_recon_curve(center[x], top[x], ++ bottom[x], y) >> 3); ++ dst += stride; ++ } ++} ++ ++static void bink2g_reconstruct_blocks(Bink2Context *c, uint8_t *dst, ++ int stride, int comp, int global_y, ++ const DCIPredict *up_row, int up_by, ++ const DCIPredict *row, int by, ++ const DCIPredict *down_row, int down_by) ++{ ++ const int chroma = comp == 1 || comp == 2; ++ const int blocks_per_mb = chroma ? 2 : 4; ++ const int plane_w = chroma ? (c->avctx->width + 1) >> 1 : c->avctx->width; ++ const int plane_h = chroma ? (c->avctx->height + 1) >> 1 : c->avctx->height; ++ const int visible_blocks_w = (plane_w + 7) >> 3; ++ const int coded_blocks_w = ((c->avctx->width + 31) >> 5) * blocks_per_mb; ++ const int coded_plane_h = ((c->avctx->height + 31) >> 5) * ++ blocks_per_mb * 8; ++ const int threshold = (c->frame_flags & 0xFF) << 3; ++ const int have_up = global_y >= 8; ++ const int have_down = global_y + 8 < coded_plane_h; ++ ++ for (int bx = 0; bx < visible_blocks_w; bx++) { ++ const uint16_t target = bink2g_recon_state(row, comp, blocks_per_mb, ++ coded_blocks_w, bx, by); ++ const uint16_t left = bx ? ++ bink2g_recon_state(row, comp, blocks_per_mb, ++ coded_blocks_w, bx - 1, by) : target; ++ const uint16_t right = bx + 1 < coded_blocks_w ? ++ bink2g_recon_state(row, comp, blocks_per_mb, ++ coded_blocks_w, bx + 1, by) : target; ++ const uint16_t up_left = have_up && bx ? ++ bink2g_recon_state(up_row, comp, blocks_per_mb, ++ coded_blocks_w, bx - 1, up_by) : 0; ++ const uint16_t up = have_up ? ++ bink2g_recon_state(up_row, comp, blocks_per_mb, ++ coded_blocks_w, bx, up_by) : target; ++ const uint16_t up_right = have_up && bx + 1 < coded_blocks_w ? ++ bink2g_recon_state(up_row, comp, blocks_per_mb, ++ coded_blocks_w, bx + 1, up_by) : 0; ++ const uint16_t down_left = bx ? ++ have_down ? ++ bink2g_recon_state(down_row, comp, blocks_per_mb, ++ coded_blocks_w, bx - 1, down_by) : ++ (target & 0xE000) | (left & 0x1FFF) : 0; ++ const uint16_t down = have_down ? ++ bink2g_recon_state(down_row, comp, blocks_per_mb, ++ coded_blocks_w, bx, down_by) : target; ++ const uint16_t down_right = bx + 1 < coded_blocks_w ? ++ have_down ? ++ bink2g_recon_state(down_row, comp, blocks_per_mb, ++ coded_blocks_w, bx + 1, down_by) : ++ (target & 0xE000) | (right & 0x1FFF) : 0; ++ ++ bink2g_reconstruct_block(dst + bx * 8, stride, ++ plane_w - bx * 8, plane_h - global_y, ++ left, target, right, up_left, up, up_right, ++ down_left, down, down_right, threshold); ++ } ++} ++ ++static void bink2g_reconstruct_row(Bink2Context *c, uint8_t *dst[4], ++ const int stride[4], int y, ++ const DCIPredict *prev_idc, ++ const DCIPredict *current_idc, ++ int is_last) ++{ ++ for (int comp = 0; comp < 3 + c->has_alpha; comp++) { ++ const int chroma = comp == 1 || comp == 2; ++ const int plane = comp == 1 ? 2 : comp == 2 ? 1 : comp; ++ const int blocks_per_mb = chroma ? 2 : 4; ++ const int plane_y = chroma ? y >> 1 : y; ++ ++ if (y > 0) { ++ const int by = blocks_per_mb - 1; ++ ++ bink2g_reconstruct_blocks(c, dst[plane] - 8 * stride[plane], ++ stride[plane], comp, plane_y - 8, ++ prev_idc, by - 1, ++ prev_idc, by, ++ current_idc, 0); ++ } ++ ++ for (int by = 0; by < blocks_per_mb - 1; by++) { ++ const DCIPredict *up_row = by ? current_idc : ++ y > 0 ? prev_idc : current_idc; ++ const int up_by = by ? by - 1 : ++ y > 0 ? blocks_per_mb - 1 : 0; ++ ++ bink2g_reconstruct_blocks(c, dst[plane] + by * 8 * stride[plane], ++ stride[plane], comp, plane_y + by * 8, ++ up_row, up_by, ++ current_idc, by, ++ current_idc, by + 1); ++ } ++ ++ if (is_last) { ++ const int by = blocks_per_mb - 1; ++ ++ bink2g_reconstruct_blocks(c, dst[plane] + by * 8 * stride[plane], ++ stride[plane], comp, plane_y + by * 8, ++ current_idc, by - 1, ++ current_idc, by, ++ current_idc, by); ++ } ++ } ++} ++ ++static void bink2g_filter_vertical_row(Bink2Context *c, uint8_t *dst[4], ++ const int stride[4], int comp, ++ const DCIPredict *row, ++ const MVPredict *mv_row, ++ int by, int rel_y) ++{ ++ const int chroma = comp != 0; ++ const int plane = comp == 1 ? 2 : comp == 2 ? 1 : 0; ++ const int blocks_per_mb = chroma ? 2 : 4; ++ const int plane_w = chroma ? (c->avctx->width + 1) >> 1 : c->avctx->width; ++ const int blocks_w = (plane_w + 7) >> 3; ++ ++ if (c->frame_flags & 0x4000) ++ return; ++ ++ for (int bx = 1; bx < blocks_w; bx++) { ++ const int mb = bx / blocks_per_mb; ++ const int local_x = bx % blocks_per_mb; ++ const int left_mb = local_x ? mb : mb - 1; ++ const int left_x = local_x ? local_x - 1 : blocks_per_mb - 1; ++ const uint16_t left_state = row[left_mb].state[comp] ++ [by * blocks_per_mb + left_x]; ++ const uint16_t right_state = row[mb].state[comp] ++ [by * blocks_per_mb + local_x]; ++ unsigned left = bink2g_filter_strength(left_state); ++ unsigned right = bink2g_filter_strength(right_state); ++ const int edge_x = bx * (chroma ? 16 : 8); ++ ++ bink2g_select_coding_edge(left_state, right_state, &left, &right); ++ ++ if (edge_x >= c->avctx->width || ++ bink2g_filter_map_skip(c->col_cbp, edge_x)) ++ continue; ++ ++ if (chroma || !(bx & 1)) { ++ const int qrow = chroma ? by : by >> 1; ++ const int left_q = 2 * qrow + (local_x ? 0 : 1); ++ const int right_q = 2 * qrow + (local_x ? 1 : 0); ++ ++ bink2g_force_mv_edge(&mv_row[left_mb].mv, left_q, ++ &mv_row[mb].mv, right_q, ++ left_state, right_state, &left, &right); ++ } ++ ++ bink2g_filter_vertical_edge(dst[plane] + bx * 8 + ++ rel_y * stride[plane], ++ stride[plane], left, right); ++ } ++} ++ ++static void bink2g_filter_horizontal_row(Bink2Context *c, uint8_t *dst[4], ++ const int stride[4], int comp, ++ const DCIPredict *top_row, int top_by, ++ const MVPredict *top_mv, ++ const DCIPredict *bottom_row, int bottom_by, ++ const MVPredict *bottom_mv, ++ int rel_y, int edge_y, int slice_start) ++{ ++ const int chroma = comp != 0; ++ const int plane = comp == 1 ? 2 : comp == 2 ? 1 : 0; ++ const int blocks_per_mb = chroma ? 2 : 4; ++ const int plane_w = chroma ? (c->avctx->width + 1) >> 1 : c->avctx->width; ++ const int blocks_w = (plane_w + 7) >> 3; ++ ++ if ((c->frame_flags & 0x8000) || edge_y == slice_start || ++ edge_y >= c->avctx->height || ++ bink2g_filter_map_skip(c->row_cbp, edge_y)) ++ return; ++ ++ for (int bx = 0; bx < blocks_w; bx++) { ++ const int mb = bx / blocks_per_mb; ++ const int local_x = bx % blocks_per_mb; ++ const uint16_t top_state = top_row[mb].state[comp] ++ [top_by * blocks_per_mb + local_x]; ++ const uint16_t bottom_state = bottom_row[mb].state[comp] ++ [bottom_by * blocks_per_mb + local_x]; ++ unsigned top = bink2g_filter_strength(top_state); ++ unsigned bottom = bink2g_filter_strength(bottom_state); ++ ++ bink2g_select_coding_edge(top_state, bottom_state, &top, &bottom); ++ ++ if (chroma || bottom_by == 0 || bottom_by == 2) { ++ const int qcol = chroma ? local_x : local_x >> 1; ++ const int top_q = (bottom_by ? 0 : 2) + qcol; ++ const int bottom_q = (bottom_by ? 2 : 0) + qcol; ++ ++ bink2g_force_mv_edge(&top_mv[mb].mv, top_q, ++ &bottom_mv[mb].mv, bottom_q, ++ top_state, bottom_state, &top, &bottom); ++ } ++ ++ bink2g_filter_horizontal_edge(dst[plane] + bx * 8 + ++ rel_y * stride[plane], ++ stride[plane], top, bottom); ++ } ++} ++ ++static void bink2g_postprocess_row(Bink2Context *c, uint8_t *dst[4], ++ const int stride[4], int y, ++ int frame_end, ++ const DCIPredict *prev_idc, ++ const DCIPredict *current_idc, ++ const MVPredict *prev_mv, ++ const MVPredict *current_mv) ++{ ++ const int is_last = y + 32 >= frame_end; ++ ++ bink2g_reconstruct_row(c, dst, stride, y, ++ prev_idc, current_idc, is_last); ++ ++ for (int comp = 0; comp < 3; comp++) { ++ const int chroma = comp != 0; ++ const int blocks_per_mb = chroma ? 2 : 4; ++ ++ if (y > 0) ++ bink2g_filter_vertical_row(c, dst, stride, comp, prev_idc, ++ prev_mv, ++ blocks_per_mb - 1, -8); ++ for (int by = 0; by < blocks_per_mb - 1; by++) ++ bink2g_filter_vertical_row(c, dst, stride, comp, current_idc, ++ current_mv, by, by * 8); ++ if (is_last) ++ bink2g_filter_vertical_row(c, dst, stride, comp, current_idc, ++ current_mv, ++ blocks_per_mb - 1, ++ (blocks_per_mb - 1) * 8); ++ } ++ ++ if (y > 0) { ++ bink2g_filter_horizontal_row(c, dst, stride, 0, ++ prev_idc, 2, prev_mv, ++ prev_idc, 3, prev_mv, ++ -8, y - 8, 0); ++ bink2g_filter_horizontal_row(c, dst, stride, 0, ++ prev_idc, 3, prev_mv, ++ current_idc, 0, current_mv, ++ 0, y, 0); ++ for (int comp = 1; comp <= 2; comp++) { ++ bink2g_filter_horizontal_row(c, dst, stride, comp, ++ prev_idc, 0, prev_mv, ++ prev_idc, 1, prev_mv, ++ -8, y - 16, 0); ++ bink2g_filter_horizontal_row(c, dst, stride, comp, ++ prev_idc, 1, prev_mv, ++ current_idc, 0, current_mv, ++ 0, y, 0); ++ } ++ } ++ ++ bink2g_filter_horizontal_row(c, dst, stride, 0, ++ current_idc, 0, current_mv, ++ current_idc, 1, current_mv, ++ 8, y + 8, 0); ++ bink2g_filter_horizontal_row(c, dst, stride, 0, ++ current_idc, 1, current_mv, ++ current_idc, 2, current_mv, ++ 16, y + 16, 0); ++ ++ if (is_last) { ++ bink2g_filter_horizontal_row(c, dst, stride, 0, ++ current_idc, 2, current_mv, ++ current_idc, 3, current_mv, ++ 24, y + 24, 0); ++ for (int comp = 1; comp <= 2; comp++) ++ bink2g_filter_horizontal_row(c, dst, stride, comp, ++ current_idc, 0, current_mv, ++ current_idc, 1, current_mv, ++ 8, y + 16, 0); ++ } ++} ++ ++static void bink2g_postprocess_frame(Bink2Context *c, uint8_t *dst[4], ++ const int stride[4]) ++{ ++ const int mb_width = (c->avctx->width + 31) >> 5; ++ const int mb_height = (c->avctx->height + 31) >> 5; ++ const int frame_end = mb_height << 5; ++ ++ for (int mb_y = 0; mb_y < mb_height; mb_y++) { ++ const int y = mb_y << 5; ++ const int prev_y = mb_y ? mb_y - 1 : 0; ++ const DCIPredict *prev_idc = c->frame_idc + prev_y * mb_width; ++ const DCIPredict *current_idc = c->frame_idc + mb_y * mb_width; ++ const MVPredict *prev_mv = c->frame_mv + prev_y * mb_width; ++ const MVPredict *current_mv = c->frame_mv + mb_y * mb_width; ++ uint8_t *row_dst[4] = { ++ dst[0] + y * stride[0], ++ dst[1] + (y >> 1) * stride[1], ++ dst[2] + (y >> 1) * stride[2], ++ c->has_alpha ? dst[3] + y * stride[3] : NULL, ++ }; ++ ++ bink2g_postprocess_row(c, row_dst, stride, y, frame_end, ++ prev_idc, current_idc, prev_mv, current_mv); ++ } ++} ++ ++static int bink2g_decode_slice(Bink2Context *c, ++ uint8_t *dst[4], int stride[4], ++ uint8_t *src[4], int sstride[4], ++ int is_kf, int start, int end) ++{ ++ GetBitContext *gb = &c->gb; ++ int w = c->avctx->width; ++ int h = c->avctx->height; ++ const int mb_width = (w + 31) / 32; ++ int ret = 0, dq, flags; ++ ++ memset(c->prev_q, 0, mb_width * sizeof(*c->prev_q)); ++ memset(c->prev_mv, 0, mb_width * sizeof(*c->prev_mv)); ++ memset(c->prev_idc, 0, mb_width * sizeof(*c->prev_idc)); ++ memset(c->current_idc, 0, mb_width * sizeof(*c->current_idc)); ++ ++ for (int y = start; y < end; y += 32) { ++ int types_lru[4] = { MOTION_BLOCK, RESIDUE_BLOCK, SKIP_BLOCK, INTRA_BLOCK }; ++ unsigned y_cbp_intra = 0, u_cbp_intra = 0, v_cbp_intra = 0, a_cbp_intra = 0; ++ unsigned y_cbp_inter = 0, u_cbp_inter = 0, v_cbp_inter = 0, a_cbp_inter = 0; ++ ++ memset(c->current_q, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->current_q)); ++ memset(c->current_mv, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->current_mv)); ++ ++ for (int x = 0; x < c->avctx->width; x += 32) { ++ int type = is_kf ? INTRA_BLOCK : bink2g_get_type(gb, types_lru); ++ int8_t *intra_q = &c->current_q[x / 32].intra_q; ++ int8_t *inter_q = &c->current_q[x / 32].inter_q; ++ MVectors mv = { 0 }; ++ ++ c->mb_pos = x / 32; ++ memset(c->current_idc[c->mb_pos].state, 0, ++ sizeof(c->current_idc[c->mb_pos].state)); ++ c->current_idc[c->mb_pos].block_type = type; ++ flags = 0; ++ if (y == start) ++ flags |= 0x80; ++ if (!x) ++ flags |= 0x20; ++ if (x == 32) ++ flags |= 0x200; ++ if (x + 32 >= c->avctx->width) ++ flags |= 0x40; ++ switch (type) { ++ case INTRA_BLOCK: ++ if (!(flags & 0xA0) && c->prev_idc[c->mb_pos - 1].block_type != INTRA_BLOCK) { ++ bink2g_average_luma (c, x -32, -32, dst[0], stride[0], c->prev_idc[c->mb_pos - 1].dc[0]); ++ bink2g_average_chroma(c, x/2-16, -16, dst[2], stride[2], c->prev_idc[c->mb_pos - 1].dc[1]); ++ bink2g_average_chroma(c, x/2-16, -16, dst[1], stride[1], c->prev_idc[c->mb_pos - 1].dc[2]); ++ if (c->has_alpha) ++ bink2g_average_luma(c, x-32, -32, dst[3], stride[3], c->prev_idc[c->mb_pos - 1].dc[3]); ++ } ++ if (!(flags & 0x20) && c->current_idc[c->mb_pos - 1].block_type != INTRA_BLOCK) { ++ bink2g_average_luma (c, x -32, 0, dst[0], stride[0], c->current_idc[c->mb_pos - 1].dc[0]); ++ bink2g_average_chroma(c, x/2-16, 0, dst[2], stride[2], c->current_idc[c->mb_pos - 1].dc[1]); ++ bink2g_average_chroma(c, x/2-16, 0, dst[1], stride[1], c->current_idc[c->mb_pos - 1].dc[2]); ++ if (c->has_alpha) ++ bink2g_average_luma(c, x-32, 0, dst[3], stride[3], c->current_idc[c->mb_pos - 1].dc[3]); ++ } ++ if ((flags & 0x20) && !(flags & 0x80) && c->prev_idc[c->mb_pos + 1].block_type != INTRA_BLOCK) { ++ bink2g_average_luma (c, x +32, -32, dst[0], stride[0], c->prev_idc[c->mb_pos + 1].dc[0]); ++ bink2g_average_chroma(c, x/2+16, -16, dst[2], stride[2], c->prev_idc[c->mb_pos + 1].dc[1]); ++ bink2g_average_chroma(c, x/2+16, -16, dst[1], stride[1], c->prev_idc[c->mb_pos + 1].dc[2]); ++ if (c->has_alpha) ++ bink2g_average_luma(c, x+32, -32, dst[3], stride[3], c->prev_idc[c->mb_pos + 1].dc[3]); ++ } ++ if (!(flags & 0x80) && c->prev_idc[c->mb_pos].block_type != INTRA_BLOCK) { ++ bink2g_average_luma (c, x, -32, dst[0], stride[0], c->prev_idc[c->mb_pos].dc[0]); ++ bink2g_average_chroma(c, x/2, -16, dst[2], stride[2], c->prev_idc[c->mb_pos].dc[1]); ++ bink2g_average_chroma(c, x/2, -16, dst[1], stride[1], c->prev_idc[c->mb_pos].dc[2]); ++ if (c->has_alpha) ++ bink2g_average_luma(c, x, -32, dst[3], stride[3], c->prev_idc[c->mb_pos].dc[3]); ++ } ++ ++ bink2g_predict_mv(c, x, y, flags, mv); ++ update_inter_q(c, inter_q, 0, flags); ++ dq = bink2g_decode_dq(gb); ++ update_intra_q(c, intra_q, dq, flags); ++ if (*intra_q < 0 || *intra_q >= 37) { ++ ret = AVERROR_INVALIDDATA; ++ goto fail; ++ } ++ c->comp = 0; ++ ret = bink2g_decode_intra_luma(c, gb, c->iblock, &y_cbp_intra, *intra_q, &c->dsp, ++ dst[0] + x, stride[0], flags); ++ if (ret < 0) ++ goto fail; ++ c->comp = 1; ++ ret = bink2g_decode_intra_chroma(c, gb, c->iblock, &u_cbp_intra, *intra_q, &c->dsp, ++ dst[2] + x/2, stride[2], flags); ++ if (ret < 0) ++ goto fail; ++ c->comp = 2; ++ ret = bink2g_decode_intra_chroma(c, gb, c->iblock, &v_cbp_intra, *intra_q, &c->dsp, ++ dst[1] + x/2, stride[1], flags); ++ if (ret < 0) ++ goto fail; ++ if (c->has_alpha) { ++ c->comp = 3; ++ ret = bink2g_decode_intra_luma(c, gb, c->iblock, &a_cbp_intra, *intra_q, &c->dsp, ++ dst[3] + x, stride[3], flags); ++ if (ret < 0) ++ goto fail; ++ } ++ break; ++ case SKIP_BLOCK: ++ update_inter_q(c, inter_q, 0, flags); ++ update_intra_q(c, intra_q, 0, flags); ++ copy_block16(dst[0] + x, src[0] + x + sstride[0] * y, ++ stride[0], sstride[0], 32); ++ copy_block16(dst[0] + x + 16, src[0] + x + 16 + sstride[0] * y, ++ stride[0], sstride[0], 32); ++ copy_block16(dst[1] + (x/2), src[1] + (x/2) + sstride[1] * (y/2), ++ stride[1], sstride[1], 16); ++ copy_block16(dst[2] + (x/2), src[2] + (x/2) + sstride[2] * (y/2), ++ stride[2], sstride[2], 16); ++ if (c->has_alpha) { ++ copy_block16(dst[3] + x, src[3] + x + sstride[3] * y, ++ stride[3], sstride[3], 32); ++ copy_block16(dst[3] + x + 16, src[3] + x + 16 + sstride[3] * y, ++ stride[3], sstride[3], 32); ++ } ++ break; ++ case MOTION_BLOCK: ++ update_intra_q(c, intra_q, 0, flags); ++ update_inter_q(c, inter_q, 0, flags); ++ ret = bink2g_decode_mv(c, gb, x, y, &mv); ++ if (ret < 0) ++ goto fail; ++ bink2g_predict_mv(c, x, y, flags, mv); ++ c->comp = 0; ++ ret = bink2g_mcompensate_luma(c, x, y, ++ dst[0], stride[0], ++ src[0], sstride[0], ++ w, h); ++ if (ret < 0) ++ goto fail; ++ c->comp = 1; ++ ret = bink2g_mcompensate_chroma(c, x/2, y/2, ++ dst[2], stride[2], ++ src[2], sstride[2], ++ w/2, h/2); ++ if (ret < 0) ++ goto fail; ++ c->comp = 2; ++ ret = bink2g_mcompensate_chroma(c, x/2, y/2, ++ dst[1], stride[1], ++ src[1], sstride[1], ++ w/2, h/2); ++ if (ret < 0) ++ goto fail; ++ if (c->has_alpha) { ++ c->comp = 3; ++ ret = bink2g_mcompensate_luma(c, x, y, ++ dst[3], stride[3], ++ src[3], sstride[3], ++ w, h); ++ if (ret < 0) ++ goto fail; ++ } ++ break; ++ case RESIDUE_BLOCK: ++ update_intra_q(c, intra_q, 0, flags); ++ ret = bink2g_decode_mv(c, gb, x, y, &mv); ++ if (ret < 0) ++ goto fail; ++ bink2g_predict_mv(c, x, y, flags, mv); ++ dq = bink2g_decode_dq(gb); ++ update_inter_q(c, inter_q, dq, flags); ++ if (*inter_q < 0 || *inter_q >= 37) { ++ ret = AVERROR_INVALIDDATA; ++ goto fail; ++ } ++ c->comp = 0; ++ ret = bink2g_mcompensate_luma(c, x, y, ++ dst[0], stride[0], ++ src[0], sstride[0], ++ w, h); ++ if (ret < 0) ++ goto fail; ++ c->comp = 1; ++ ret = bink2g_mcompensate_chroma(c, x/2, y/2, ++ dst[2], stride[2], ++ src[2], sstride[2], ++ w/2, h/2); ++ if (ret < 0) ++ goto fail; ++ c->comp = 2; ++ ret = bink2g_mcompensate_chroma(c, x/2, y/2, ++ dst[1], stride[1], ++ src[1], sstride[1], ++ w/2, h/2); ++ if (ret < 0) ++ goto fail; ++ if (c->has_alpha) { ++ c->comp = 3; ++ ret = bink2g_mcompensate_luma(c, x, y, ++ dst[3], stride[3], ++ src[3], sstride[3], ++ w, h); ++ if (ret < 0) ++ goto fail; ++ } ++ c->comp = 0; ++ ret = bink2g_decode_inter_luma(c, gb, c->iblock, &y_cbp_inter, *inter_q, &c->dsp, ++ dst[0] + x, stride[0], flags); ++ if (ret < 0) ++ goto fail; ++ if (get_bits1(gb)) { ++ c->comp = 1; ++ ret = bink2g_decode_inter_chroma(c, gb, c->iblock, &u_cbp_inter, *inter_q, &c->dsp, ++ dst[2] + x/2, stride[2], flags); ++ if (ret < 0) ++ goto fail; ++ c->comp = 2; ++ ret = bink2g_decode_inter_chroma(c, gb, c->iblock, &v_cbp_inter, *inter_q, &c->dsp, ++ dst[1] + x/2, stride[1], flags); ++ if (ret < 0) ++ goto fail; ++ } else { ++ u_cbp_inter = 0; ++ v_cbp_inter = 0; ++ } ++ if (c->has_alpha) { ++ c->comp = 3; ++ ret = bink2g_decode_inter_luma(c, gb, c->iblock, &a_cbp_inter, *inter_q, &c->dsp, ++ dst[3] + x, stride[3], flags); ++ if (ret < 0) ++ goto fail; ++ } ++ break; ++ default: ++ return AVERROR_INVALIDDATA; ++ } ++ ++ } ++ ++ memcpy(c->frame_idc + (y >> 5) * mb_width, c->current_idc, ++ mb_width * sizeof(*c->frame_idc)); ++ memcpy(c->frame_mv + (y >> 5) * mb_width, c->current_mv, ++ mb_width * sizeof(*c->frame_mv)); ++ ++ dst[0] += stride[0] * 32; ++ dst[1] += stride[1] * 16; ++ dst[2] += stride[2] * 16; ++ if (c->has_alpha) ++ dst[3] += stride[3] * 32; ++ ++ FFSWAP(MVPredict *, c->current_mv, c->prev_mv); ++ FFSWAP(QuantPredict *, c->current_q, c->prev_q); ++ FFSWAP(DCIPredict *, c->current_idc, c->prev_idc); ++ } ++fail: ++ emms_c(); ++ ++ return ret; ++} ++ ++#endif /* AVCODEC_BINK2G_H */ +diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c +index d58c3d889c..92c27e58d4 100644 +--- a/libavcodec/codec_desc.c ++++ b/libavcodec/codec_desc.c +@@ -1959,6 +1959,13 @@ static const AVCodecDescriptor codec_descriptors[] = { + .long_name = NULL_IF_CONFIG_SMALL("LEAD MCMP"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, ++ { ++ .id = AV_CODEC_ID_BINKVIDEO2, ++ .type = AVMEDIA_TYPE_VIDEO, ++ .name = "binkvideo2", ++ .long_name = NULL_IF_CONFIG_SMALL("Bink video 2"), ++ .props = AV_CODEC_PROP_LOSSY, ++ }, + + /* various PCM "codecs" */ + { +diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h +index 0a8d3bed1e..a7e874c890 100644 +--- a/libavcodec/codec_id.h ++++ b/libavcodec/codec_id.h +@@ -322,6 +322,7 @@ enum AVCodecID { + AV_CODEC_ID_RTV1, + AV_CODEC_ID_VMIX, + AV_CODEC_ID_LEAD, ++ AV_CODEC_ID_BINKVIDEO2, + + /* various PCM "codecs" */ + AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs +diff --git a/libavformat/bink.c b/libavformat/bink.c +index 0632d390a2..fbb0238795 100644 +--- a/libavformat/bink.c ++++ b/libavformat/bink.c +@@ -72,7 +72,7 @@ static int probe(const AVProbeData *p) + b[3] == 'k')) || + (b[0] == 'K' && b[1] == 'B' && b[2] == '2' && /* Bink 2 */ + (b[3] == 'a' || b[3] == 'd' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' || +- b[3] == 'i' || b[3] == 'j' || b[3] == 'k'))) && ++ b[3] == 'i' || b[3] == 'j' || b[3] == 'k' || b[3] == 'm' || b[3] == 'n'))) && + AV_RL32(b+8) > 0 && // num_frames + AV_RL32(b+20) > 0 && AV_RL32(b+20) <= BINK_MAX_WIDTH && + AV_RL32(b+24) > 0 && AV_RL32(b+24) <= BINK_MAX_HEIGHT && +@@ -149,8 +149,7 @@ static int read_header(AVFormatContext *s) + vst->codecpar->codec_id = AV_CODEC_ID_BINKVIDEO; + + if ((vst->codecpar->codec_tag & 0xFFFFFF) == MKTAG('K', 'B', '2', 0)) { +- av_log(s, AV_LOG_WARNING, "Bink 2 video is not implemented\n"); +- vst->codecpar->codec_id = AV_CODEC_ID_NONE; ++ vst->codecpar->codec_id = AV_CODEC_ID_BINKVIDEO2; + } + + if ((ret = ff_get_extradata(s, vst->codecpar, pb, 4)) < 0) +@@ -168,8 +167,11 @@ static int read_header(AVFormatContext *s) + signature = (vst->codecpar->codec_tag & 0xFFFFFF); + revision = ((vst->codecpar->codec_tag >> 24) % 0xFF); + +- if ((signature == AV_RL32("BIK") && (revision == 'k')) || +- (signature == AV_RL32("KB2") && (revision == 'i' || revision == 'j' || revision == 'k'))) ++ if (signature == AV_RL32("KB2") && revision == 'm') ++ avio_skip(pb, 16); /* opaque KB2m header extension */ ++ else if ((signature == AV_RL32("BIK") && revision == 'k') || ++ (signature == AV_RL32("KB2") && ++ (revision == 'i' || revision == 'j' || revision == 'k' || revision == 'n'))) + avio_skip(pb, 4); /* unknown new field */ + + if (bink->num_audio_tracks) { diff --git a/portfiles/ffmpeg/1001-bink2-alpha-boolean.patch b/portfiles/ffmpeg/1001-bink2-alpha-boolean.patch new file mode 100644 index 000000000..8253b803e --- /dev/null +++ b/portfiles/ffmpeg/1001-bink2-alpha-boolean.patch @@ -0,0 +1,11 @@ +--- a/libavcodec/bink2.c ++++ b/libavcodec/bink2.c +@@ -359,7 +359,7 @@ + } + c->flags = AV_RL32(avctx->extradata); + av_log(avctx, AV_LOG_DEBUG, "flags: 0x%X\n", c->flags); +- c->has_alpha = c->flags & BINK_FLAG_ALPHA; ++ c->has_alpha = !!(c->flags & BINK_FLAG_ALPHA); + c->avctx = avctx; + c->slice_ctx[0] = c; + diff --git a/portfiles/ffmpeg/FindFFMPEG.cmake.in b/portfiles/ffmpeg/FindFFMPEG.cmake.in new file mode 100644 index 000000000..7461a3cec --- /dev/null +++ b/portfiles/ffmpeg/FindFFMPEG.cmake.in @@ -0,0 +1,166 @@ +# Distributed under the OSI-approved BSD 3-Clause License. +# +#.rst: +# FindFFMPEG +# -------- +# +# Find the FFPMEG libraries +# +# Result Variables +# ^^^^^^^^^^^^^^^^ +# +# The following variables will be defined: +# +# ``FFMPEG_FOUND`` +# True if FFMPEG found on the local system +# +# ``FFMPEG_INCLUDE_DIRS`` +# Location of FFMPEG header files +# +# ``FFMPEG_LIBRARY_DIRS`` +# Location of FFMPEG libraries +# +# ``FFMPEG_LIBRARIES`` +# List of the FFMPEG libraries found +# +# + +include(FindPackageHandleStandardArgs) +include(SelectLibraryConfigurations) +include(CMakeFindDependencyMacro) + +if(NOT FFMPEG_FOUND) + +# Compute the installation path relative to this file. +get_filename_component(SEARCH_PATH "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(SEARCH_PATH "${SEARCH_PATH}" PATH) +get_filename_component(SEARCH_PATH "${SEARCH_PATH}" PATH) +if(SEARCH_PATH STREQUAL "/") + set(SEARCH_PATH "") +endif() + +set(FFMPEG_VERSION "@FFMPEG_VERSION@") + +function(append_dependencies out) + cmake_parse_arguments(PARSE_ARGV 1 "arg" "DEBUG" "NAMES" "") + if(${arg_DEBUG}) + set(config DEBUG) + set(path "${SEARCH_PATH}/debug/lib/") + else() + set(config RELEASE) + set(path "${SEARCH_PATH}/lib/") + endif() + if("${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES}" STREQUAL "") + enable_language(CXX) + endif() + set(pass_through + ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES} + advapi32 bcrypt crypt32 gdi32 mfuuid ole32 oleaut32 psapi secur32 shlwapi strmiids user32 uuid vfw32 ws2_32 usp10 cfgmgr32 rpcrt4 + -pthread -pthreads pthread atomic m + ) + cmake_policy(SET CMP0057 NEW) + foreach(lib_name IN LISTS arg_NAMES) + if(lib_name IN_LIST CMAKE_C_IMPLICIT_LINK_LIBRARIES) + continue() # implicit even for C + elseif(lib_name IN_LIST pass_through) + list(APPEND ${out} "${lib_name}") + elseif(EXISTS "${lib_name}") + list(APPEND ${out} "${lib_name}") + else() + # first look in ${path} specifically to ensure we find the right release/debug variant + find_library(FFMPEG_DEPENDENCY_${lib_name}_${config} NAMES "${lib_name}" PATHS "${path}" NO_DEFAULT_PATH) + # if not found there, must be a system dependency, so look elsewhere + find_library(FFMPEG_DEPENDENCY_${lib_name}_${config} NAMES "${lib_name}" REQUIRED) + list(APPEND ${out} "${FFMPEG_DEPENDENCY_${lib_name}_${config}}") + endif() + endforeach() + set("${out}" "${${out}}" PARENT_SCOPE) +endfunction() + +macro(FFMPEG_FIND varname shortname headername) + if(NOT FFMPEG_${varname}_INCLUDE_DIRS) + find_path(FFMPEG_${varname}_INCLUDE_DIRS NAMES lib${shortname}/${headername} ${headername} PATHS ${SEARCH_PATH}/include NO_DEFAULT_PATH) + endif() + if(NOT FFMPEG_${varname}_LIBRARY) + find_library(FFMPEG_${varname}_LIBRARY_RELEASE NAMES ${shortname} PATHS ${SEARCH_PATH}/lib/ NO_DEFAULT_PATH) + find_library(FFMPEG_${varname}_LIBRARY_DEBUG NAMES ${shortname}d ${shortname} PATHS ${SEARCH_PATH}/debug/lib/ NO_DEFAULT_PATH) + get_filename_component(FFMPEG_${varname}_LIBRARY_RELEASE_DIR ${FFMPEG_${varname}_LIBRARY_RELEASE} DIRECTORY) + get_filename_component(FFMPEG_${varname}_LIBRARY_DEBUG_DIR ${FFMPEG_${varname}_LIBRARY_DEBUG} DIRECTORY) + select_library_configurations(FFMPEG_${varname}) + set(FFMPEG_${varname}_LIBRARY ${FFMPEG_${varname}_LIBRARY} CACHE STRING "") + endif() + if (FFMPEG_${varname}_LIBRARY AND FFMPEG_${varname}_INCLUDE_DIRS) + set(FFMPEG_${varname}_FOUND TRUE BOOL) + list(APPEND FFMPEG_INCLUDE_DIRS ${FFMPEG_${varname}_INCLUDE_DIRS}) + list(APPEND FFMPEG_LIBRARIES ${FFMPEG_${varname}_LIBRARY}) + list(APPEND FFMPEG_LIBRARY_DIRS ${FFMPEG_${varname}_LIBRARY_RELEASE_DIR} ${FFMPEG_${varname}_LIBRARY_DEBUG_DIR}) + endif() +endmacro(FFMPEG_FIND) + +if(@ENABLE_AVDEVICE@) + FFMPEG_FIND(libavdevice avdevice avdevice.h) +endif() +if(@ENABLE_AVFILTER@) + FFMPEG_FIND(libavfilter avfilter avfilter.h) +endif() +if(@ENABLE_AVFORMAT@) + FFMPEG_FIND(libavformat avformat avformat.h) +endif() +if(@ENABLE_AVCODEC@) + FFMPEG_FIND(libavcodec avcodec avcodec.h) +endif() +if(@ENABLE_POSTPROC@) + FFMPEG_FIND(libpostproc postproc postprocess.h) +endif() +if(@ENABLE_SWRESAMPLE@) + FFMPEG_FIND(libswresample swresample swresample.h) +endif() +if(@ENABLE_SWSCALE@) + FFMPEG_FIND(libswscale swscale swscale.h) +endif() +FFMPEG_FIND(libavutil avutil avutil.h) + +if (FFMPEG_libavutil_FOUND) + list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS) + list(REMOVE_DUPLICATES FFMPEG_LIBRARY_DIRS) + set(FFMPEG_libavutil_VERSION "@LIBAVUTIL_VERSION@" CACHE STRING "") + + if(FFMPEG_libavcodec_FOUND) + set(FFMPEG_libavcodec_VERSION "@LIBAVCODEC_VERSION@" CACHE STRING "") + endif() + if(FFMPEG_libavdevice_FOUND) + set(FFMPEG_libavdevice_VERSION "@LIBAVDEVICE_VERSION@" CACHE STRING "") + endif() + if(FFMPEG_libavfilter_FOUND) + set(FFMPEG_libavfilter_VERSION "@LIBAVFILTER_VERSION@" CACHE STRING "") + endif() + if(FFMPEG_libavformat_FOUND) + set(FFMPEG_libavformat_VERSION "@LIBAVFORMAT_VERSION@" CACHE STRING "") + endif() + if(FFMPEG_libswresample_FOUND) + set(FFMPEG_libswresample_VERSION "@LIBSWRESAMPLE_VERSION@" CACHE STRING "") + endif() + if(FFMPEG_libswscale_FOUND) + set(FFMPEG_libswscale_VERSION "@LIBSWSCALE_VERSION@" CACHE STRING "") + endif() + + append_dependencies(FFMPEG_DEPS_LIBRARY_RELEASE NAMES "@FFMPEG_DEPENDENCIES_RELEASE@") + append_dependencies(FFMPEG_DEPS_LIBRARY_DEBUG NAMES "@FFMPEG_DEPENDENCIES_DEBUG@" DEBUG) + if(FFMPEG_DEPS_LIBRARY_RELEASE OR FFMPEG_DEPS_LIBRARY_DEBUG) + select_library_configurations(FFMPEG_DEPS) + list(APPEND FFMPEG_LIBRARIES ${FFMPEG_DEPS_LIBRARY}) + endif() + + set(FFMPEG_LIBRARY ${FFMPEG_LIBRARIES}) + + set(FFMPEG_FOUND TRUE CACHE BOOL "") + set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} CACHE STRING "") + set(FFMPEG_INCLUDE_DIRS ${FFMPEG_INCLUDE_DIRS} CACHE STRING "") + set(FFMPEG_LIBRARY_DIRS ${FFMPEG_LIBRARY_DIRS} CACHE STRING "") +endif() + +find_package_handle_standard_args(FFMPEG REQUIRED_VARS FFMPEG_LIBRARIES FFMPEG_LIBRARY_DIRS FFMPEG_INCLUDE_DIRS) + +set(z_vcpkg_using_vcpkg_find_ffmpeg ${FFMPEG_FOUND}) + +endif() diff --git a/portfiles/ffmpeg/build.sh.in b/portfiles/ffmpeg/build.sh.in new file mode 100644 index 000000000..fd794d41c --- /dev/null +++ b/portfiles/ffmpeg/build.sh.in @@ -0,0 +1,142 @@ +#!/usr/bin/env bash + +set -e + +move_binary() { + SOURCE=$1 + TARGET=$2 + BINARY=$3 + + # run lipo over the command to check whether it really + # is a binary that we need to merge architectures + lipo $SOURCE/$BINARY -info &> /dev/null || return 0 + + # get the directory name the file is in + DIRNAME=$(dirname $BINARY) + + # ensure the directory to move the binary to exists + mkdir -p $TARGET/$DIRNAME + + # now finally move the binary + mv $SOURCE/$BINARY $TARGET/$BINARY +} + +move_binaries() { + SOURCE=$1 + TARGET=$2 + + [ ! -d $SOURCE ] && return 0 + pushd $SOURCE + + for BINARY in $(find . -type f); do + move_binary $SOURCE $TARGET $BINARY + done + + popd +} + +merge_binaries() { + TARGET=$1 + SOURCE=$2 + + shift + shift + + pushd $SOURCE/$1 + BINARIES=$(find . -type f) + popd + + for BINARY in $BINARIES; do + COMMAND="lipo -create -output $TARGET/$BINARY" + + for ARCH in $@; do + COMMAND="$COMMAND -arch $ARCH $SOURCE/$ARCH/$BINARY" + done + + $($COMMAND) + done +} + +PATH_TO_BUILD_DIR="@BUILD_DIR@" +PATH_TO_SRC_DIR="@SOURCE_PATH@" +PATH_TO_PACKAGE_DIR="@INST_PREFIX@" + +JOBS=@VCPKG_CONCURRENCY@ + +OSX_ARCHS="@OSX_ARCHS@" +OSX_ARCH_COUNT=0@OSX_ARCH_COUNT@ + +# Default to hardware concurrency if unset. +: ${JOBS:=$(nproc)} + +# Disable asm and x86asm on all android targets because they trigger build failures: +# arm64 Android build fails with 'relocation R_AARCH64_ADR_PREL_PG_HI21 cannot be used against symbol ff_cos_32; recompile with -fPIC' +# x86 Android build fails with 'error: inline assembly requires more registers than available'. +# x64 Android build fails with 'relocation R_X86_64_PC32 cannot be used against symbol ff_h264_cabac_tables; recompile with -fPIC' +if [ "@VCPKG_CMAKE_SYSTEM_NAME@" = "Android" ]; then + OPTIONS_arm=" --disable-asm --disable-x86asm" + OPTIONS_arm64=" --disable-asm --disable-x86asm" + OPTIONS_x86=" --disable-asm --disable-x86asm" + OPTIONS_x86_64="${OPTIONS_x86}" +else + OPTIONS_arm=" --disable-asm --disable-x86asm" + OPTIONS_arm64=" --enable-asm --disable-x86asm" + OPTIONS_x86=" --enable-asm --enable-x86asm" + OPTIONS_x86_64="${OPTIONS_x86}" +fi + +case "@VCPKG_CMAKE_SYSTEM_NAME@" in + *BSD) + MAKE_BINARY="gmake" + ;; + *) + MAKE_BINARY="make" + ;; +esac + +build_ffmpeg() { + # extract build architecture + BUILD_ARCH=$1 + shift + + echo "BUILD_ARCH=${BUILD_ARCH}" + + # get architecture-specific options + OPTION_VARIABLE="OPTIONS_${BUILD_ARCH}" + echo "OPTION_VARIABLE=${OPTION_VARIABLE}" + + echo "=== CONFIGURING ===" + + sh "$PATH_TO_SRC_DIR/configure" "--prefix=$PATH_TO_PACKAGE_DIR" @CONFIGURE_OPTIONS@ --arch=${BUILD_ARCH} ${!OPTION_VARIABLE} $@ + + echo "=== BUILDING ===" + + $MAKE_BINARY -j${JOBS} V=1 + + echo "=== INSTALLING ===" + + $MAKE_BINARY install +} + +cd "$PATH_TO_BUILD_DIR" + +if [ $OSX_ARCH_COUNT -gt 0 ]; then + for ARCH in $OSX_ARCHS; do + echo "=== CLEANING FOR $ARCH ===" + + $MAKE_BINARY clean && $MAKE_BINARY distclean + + build_ffmpeg $ARCH --extra-cflags=-arch --extra-cflags=$ARCH --extra-ldflags=-arch --extra-ldflags=$ARCH + + echo "=== COLLECTING BINARIES FOR $ARCH ===" + + move_binaries $PATH_TO_PACKAGE_DIR/lib $PATH_TO_BUILD_DIR/stage/$ARCH/lib + move_binaries $PATH_TO_PACKAGE_DIR/bin $PATH_TO_BUILD_DIR/stage/$ARCH/bin + done + + echo "=== MERGING ARCHITECTURES ===" + + merge_binaries $PATH_TO_PACKAGE_DIR $PATH_TO_BUILD_DIR/stage $OSX_ARCHS +else + build_ffmpeg @BUILD_ARCH@ +fi diff --git a/portfiles/ffmpeg/portfile.cmake b/portfiles/ffmpeg/portfile.cmake new file mode 100644 index 000000000..f0cdd3669 --- /dev/null +++ b/portfiles/ffmpeg/portfile.cmake @@ -0,0 +1,1039 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO ffmpeg/ffmpeg + REF "n${VERSION}" + SHA512 8411c45f71d2d61184b11e2a786137044a80d9b979a7e2e8513efc5e716b3360bff4533a13875dd4bca492b97b97f0384f7fb4f3d796802e81981b0857d18a2b + HEAD_REF master + PATCHES + 0001-create-lib-libraries.patch + 0002-fix-msvc-link.patch + 0003-fix-windowsinclude.patch + 0004-dependencies.patch + 0005-fix-nasm.patch + 0007-fix-lib-naming.patch + 0013-define-WINVER.patch + 0020-fix-aarch64-libswscale.patch + 0024-fix-osx-host-c11.patch + 0040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch # Do not remove this patch. It is required by chromium + 0041-add-const-for-opengl-definition.patch + 0043-fix-miss-head.patch + 0044-fix-vulkan-debug-callback-abi.patch + # Bink 2 decoder from sharpemu/ffmpeg-core 3b502d4 (LGPL-2.1-or-later) + 1000-bink2-decoder.patch + 1001-bink2-alpha-boolean.patch +) + +if(SOURCE_PATH MATCHES " ") + message(FATAL_ERROR "Error: ffmpeg will not build with spaces in the path. Please use a directory with no spaces") +endif() + +if (VCPKG_TARGET_ARCHITECTURE STREQUAL "x86" OR VCPKG_TARGET_ARCHITECTURE STREQUAL "x64") + vcpkg_find_acquire_program(NASM) + get_filename_component(NASM_EXE_PATH "${NASM}" DIRECTORY) + vcpkg_add_to_path("${NASM_EXE_PATH}") +endif() + +set(OPTIONS "--enable-pic --disable-doc --enable-debug --enable-runtime-cpudetect --disable-autodetect") + +if(VCPKG_TARGET_IS_MINGW) + if(VCPKG_TARGET_ARCHITECTURE STREQUAL "x86") + string(APPEND OPTIONS " --target-os=mingw32") + elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "x64") + string(APPEND OPTIONS " --target-os=mingw64") + endif() +elseif(VCPKG_TARGET_IS_LINUX) + string(APPEND OPTIONS " --target-os=linux --enable-pthreads") +elseif(VCPKG_TARGET_IS_UWP) + string(APPEND OPTIONS " --target-os=win32 --enable-w32threads --enable-d3d11va --enable-d3d12va --enable-mediafoundation") +elseif(VCPKG_TARGET_IS_WINDOWS) + string(APPEND OPTIONS " --target-os=win32 --enable-w32threads --enable-d3d11va --enable-d3d12va --enable-dxva2 --enable-mediafoundation") +elseif(VCPKG_TARGET_IS_OSX) + string(APPEND OPTIONS " --target-os=darwin --enable-appkit --enable-avfoundation --enable-coreimage --enable-audiotoolbox --enable-videotoolbox") +elseif(VCPKG_TARGET_IS_IOS) + string(APPEND OPTIONS " --enable-avfoundation --enable-coreimage --enable-videotoolbox") +elseif(VCPKG_CMAKE_SYSTEM_NAME STREQUAL "Android") + string(APPEND OPTIONS " --target-os=android --enable-jni --enable-mediacodec") +elseif(VCPKG_CMAKE_SYSTEM_NAME STREQUAL "QNX") + string(APPEND OPTIONS " --target-os=qnx") +endif() + +if(VCPKG_TARGET_IS_OSX) + list(JOIN VCPKG_OSX_ARCHITECTURES " " OSX_ARCHS) + list(LENGTH VCPKG_OSX_ARCHITECTURES OSX_ARCH_COUNT) +endif() + +vcpkg_cmake_get_vars(cmake_vars_file) +include("${cmake_vars_file}") +if(VCPKG_DETECTED_MSVC) + string(APPEND OPTIONS " --disable-inline-asm") # clang-cl has inline assembly but this leads to undefined symbols. + set(OPTIONS "--toolchain=msvc ${OPTIONS}") + # This is required because ffmpeg depends upon optimizations to link correctly + string(APPEND VCPKG_COMBINED_C_FLAGS_DEBUG " -O2") + string(REGEX REPLACE "(^| )-RTC1( |$)" " " VCPKG_COMBINED_C_FLAGS_DEBUG "${VCPKG_COMBINED_C_FLAGS_DEBUG}") + string(REGEX REPLACE "(^| )-Od( |$)" " " VCPKG_COMBINED_C_FLAGS_DEBUG "${VCPKG_COMBINED_C_FLAGS_DEBUG}") + string(REGEX REPLACE "(^| )-Ob0( |$)" " " VCPKG_COMBINED_C_FLAGS_DEBUG "${VCPKG_COMBINED_C_FLAGS_DEBUG}") +endif() + +string(APPEND VCPKG_COMBINED_C_FLAGS_DEBUG " -I \"${CURRENT_INSTALLED_DIR}/include\"") +string(APPEND VCPKG_COMBINED_C_FLAGS_RELEASE " -I \"${CURRENT_INSTALLED_DIR}/include\"") + +## Setup vcpkg toolchain + +set(prog_env "") + +if(VCPKG_DETECTED_CMAKE_C_COMPILER) + get_filename_component(CC_path "${VCPKG_DETECTED_CMAKE_C_COMPILER}" DIRECTORY) + get_filename_component(CC_filename "${VCPKG_DETECTED_CMAKE_C_COMPILER}" NAME) + set(ENV{CC} "${CC_filename}") + string(APPEND OPTIONS " --cc=${CC_filename}") + string(APPEND OPTIONS " --host_cc=${CC_filename}") + list(APPEND prog_env "${CC_path}") +endif() + +if(VCPKG_DETECTED_CMAKE_CXX_COMPILER) + get_filename_component(CXX_path "${VCPKG_DETECTED_CMAKE_CXX_COMPILER}" DIRECTORY) + get_filename_component(CXX_filename "${VCPKG_DETECTED_CMAKE_CXX_COMPILER}" NAME) + set(ENV{CXX} "${CXX_filename}") + string(APPEND OPTIONS " --cxx=${CXX_filename}") + #string(APPEND OPTIONS " --host_cxx=${CC_filename}") + list(APPEND prog_env "${CXX_path}") +endif() + +if(VCPKG_DETECTED_CMAKE_RC_COMPILER) + get_filename_component(RC_path "${VCPKG_DETECTED_CMAKE_RC_COMPILER}" DIRECTORY) + get_filename_component(RC_filename "${VCPKG_DETECTED_CMAKE_RC_COMPILER}" NAME) + set(ENV{WINDRES} "${RC_filename}") + string(APPEND OPTIONS " --windres=${RC_filename}") + list(APPEND prog_env "${RC_path}") +endif() + +if(VCPKG_DETECTED_CMAKE_LINKER AND VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_MINGW) + get_filename_component(LD_path "${VCPKG_DETECTED_CMAKE_LINKER}" DIRECTORY) + get_filename_component(LD_filename "${VCPKG_DETECTED_CMAKE_LINKER}" NAME) + set(ENV{LD} "${LD_filename}") + string(APPEND OPTIONS " --ld=${LD_filename}") + #string(APPEND OPTIONS " --host_ld=${LD_filename}") + list(APPEND prog_env "${LD_path}") +endif() + +if(VCPKG_DETECTED_CMAKE_NM) + get_filename_component(NM_path "${VCPKG_DETECTED_CMAKE_NM}" DIRECTORY) + get_filename_component(NM_filename "${VCPKG_DETECTED_CMAKE_NM}" NAME) + set(ENV{NM} "${NM_filename}") + string(APPEND OPTIONS " --nm=${NM_filename}") + list(APPEND prog_env "${NM_path}") +endif() + +if(VCPKG_DETECTED_CMAKE_AR) + get_filename_component(AR_path "${VCPKG_DETECTED_CMAKE_AR}" DIRECTORY) + get_filename_component(AR_filename "${VCPKG_DETECTED_CMAKE_AR}" NAME) + if(AR_filename MATCHES [[^(llvm-)?lib\.exe$]]) + set(ENV{AR} "ar-lib ${AR_filename}") + string(APPEND OPTIONS " --ar='ar-lib ${AR_filename}'") + else() + set(ENV{AR} "${AR_filename}") + string(APPEND OPTIONS " --ar='${AR_filename}'") + endif() + list(APPEND prog_env "${AR_path}") +endif() + +if(VCPKG_DETECTED_CMAKE_RANLIB) + get_filename_component(RANLIB_path "${VCPKG_DETECTED_CMAKE_RANLIB}" DIRECTORY) + get_filename_component(RANLIB_filename "${VCPKG_DETECTED_CMAKE_RANLIB}" NAME) + set(ENV{RANLIB} "${RANLIB_filename}") + string(APPEND OPTIONS " --ranlib=${RANLIB_filename}") + list(APPEND prog_env "${RANLIB_path}") +endif() + +if(VCPKG_DETECTED_CMAKE_STRIP) + get_filename_component(STRIP_path "${VCPKG_DETECTED_CMAKE_STRIP}" DIRECTORY) + get_filename_component(STRIP_filename "${VCPKG_DETECTED_CMAKE_STRIP}" NAME) + set(ENV{STRIP} "${STRIP_filename}") + string(APPEND OPTIONS " --strip=${STRIP_filename}") + list(APPEND prog_env "${STRIP_path}") +endif() + +if(VCPKG_HOST_IS_WINDOWS) + vcpkg_acquire_msys(MSYS_ROOT PACKAGES automake) + set(SHELL "${MSYS_ROOT}/usr/bin/bash.exe") + vcpkg_execute_required_process( + COMMAND "${SHELL}" -c "'/usr/bin/automake' --print-lib" + OUTPUT_VARIABLE automake_lib + OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY "${MSYS_ROOT}" + LOGNAME automake-print-lib + ) + list(APPEND prog_env "${MSYS_ROOT}/usr/bin" "${MSYS_ROOT}${automake_lib}") +else() + find_program(SHELL bash) +endif() + +list(REMOVE_DUPLICATES prog_env) +vcpkg_add_to_path(PREPEND ${prog_env}) + +# More? OBJCC BIN2C + +file(REMOVE_RECURSE "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg" "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel") + +set(FFMPEG_PKGCONFIG_MODULES libavutil) + +if("nonfree" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-nonfree") +endif() + +if("gpl" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-gpl") +endif() + +if("version3" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-version3") +endif() + +if("ffmpeg" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-ffmpeg") +else() + set(OPTIONS "${OPTIONS} --disable-ffmpeg") +endif() + +if("ffplay" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-ffplay") +else() + set(OPTIONS "${OPTIONS} --disable-ffplay") +endif() + +if("ffprobe" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-ffprobe") +else() + set(OPTIONS "${OPTIONS} --disable-ffprobe") +endif() + +if("avcodec" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-avcodec") + set(ENABLE_AVCODEC ON) + list(APPEND FFMPEG_PKGCONFIG_MODULES libavcodec) +else() + set(OPTIONS "${OPTIONS} --disable-avcodec") + set(ENABLE_AVCODEC OFF) +endif() + +if("avdevice" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-avdevice") + set(ENABLE_AVDEVICE ON) + list(APPEND FFMPEG_PKGCONFIG_MODULES libavdevice) +else() + set(OPTIONS "${OPTIONS} --disable-avdevice") + set(ENABLE_AVDEVICE OFF) +endif() + +if("avformat" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-avformat") + set(ENABLE_AVFORMAT ON) + list(APPEND FFMPEG_PKGCONFIG_MODULES libavformat) +else() + set(OPTIONS "${OPTIONS} --disable-avformat") + set(ENABLE_AVFORMAT OFF) +endif() + +if("avfilter" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-avfilter") + set(ENABLE_AVFILTER ON) + list(APPEND FFMPEG_PKGCONFIG_MODULES libavfilter) +else() + set(OPTIONS "${OPTIONS} --disable-avfilter") + set(ENABLE_AVFILTER OFF) +endif() + +if("postproc" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-postproc") + set(ENABLE_POSTPROC ON) + list(APPEND FFMPEG_PKGCONFIG_MODULES libpostproc) +else() + set(OPTIONS "${OPTIONS} --disable-postproc") + set(ENABLE_POSTPROC OFF) +endif() + +if("swresample" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-swresample") + set(ENABLE_SWRESAMPLE ON) + list(APPEND FFMPEG_PKGCONFIG_MODULES libswresample) +else() + set(OPTIONS "${OPTIONS} --disable-swresample") + set(ENABLE_SWRESAMPLE OFF) +endif() + +if("swscale" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-swscale") + set(ENABLE_SWSCALE ON) + list(APPEND FFMPEG_PKGCONFIG_MODULES libswscale) +else() + set(OPTIONS "${OPTIONS} --disable-swscale") + set(ENABLE_SWSCALE OFF) +endif() + +if ("alsa" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-alsa") +else() + set(OPTIONS "${OPTIONS} --disable-alsa") +endif() + +if("amf" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-amf") +else() + set(OPTIONS "${OPTIONS} --disable-amf") +endif() + +if("aom" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libaom") + set(WITH_AOM ON) +else() + set(OPTIONS "${OPTIONS} --disable-libaom") + set(WITH_AOM OFF) +endif() + +if("ass" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libass") + set(WITH_ASS ON) +else() + set(OPTIONS "${OPTIONS} --disable-libass") + set(WITH_ASS OFF) +endif() + +if("avisynthplus" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-avisynth") +else() + set(OPTIONS "${OPTIONS} --disable-avisynth") +endif() + +if("bzip2" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-bzlib") +else() + set(OPTIONS "${OPTIONS} --disable-bzlib") +endif() + +if("dav1d" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libdav1d") + set(WITH_DAV1D ON) +else() + set(OPTIONS "${OPTIONS} --disable-libdav1d") + set(WITH_DAV1D OFF) +endif() + +if("fdk-aac" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libfdk-aac") + set(WITH_AAC ON) +else() + set(OPTIONS "${OPTIONS} --disable-libfdk-aac") + set(WITH_AAC OFF) +endif() + +if("fontconfig" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libfontconfig") +else() + set(OPTIONS "${OPTIONS} --disable-libfontconfig") +endif() + +if("drawtext" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libharfbuzz") +else() + set(OPTIONS "${OPTIONS} --disable-libharfbuzz") +endif() + +if("freetype" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libfreetype") +else() + set(OPTIONS "${OPTIONS} --disable-libfreetype") +endif() + +if("fribidi" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libfribidi") +else() + set(OPTIONS "${OPTIONS} --disable-libfribidi") +endif() + +if("iconv" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-iconv") + set(WITH_ICONV ON) +else() + set(OPTIONS "${OPTIONS} --disable-iconv") + set(WITH_ICONV OFF) +endif() + +if("ilbc" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libilbc") + set(WITH_ILBC ON) +else() + set(OPTIONS "${OPTIONS} --disable-libilbc") + set(WITH_ILBC OFF) +endif() + +if("lzma" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-lzma") + set(WITH_LZMA ON) +else() + set(OPTIONS "${OPTIONS} --disable-lzma") + set(WITH_LZMA OFF) +endif() + +if("mp3lame" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libmp3lame") + set(WITH_MP3LAME ON) +else() + set(OPTIONS "${OPTIONS} --disable-libmp3lame") + set(WITH_MP3LAME OFF) +endif() + +if("modplug" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libmodplug") + set(WITH_MODPLUG ON) +else() + set(OPTIONS "${OPTIONS} --disable-libmodplug") + set(WITH_MODPLUG OFF) +endif() + +if("nvcodec" IN_LIST FEATURES) + #Note: the --enable-cuda option does not actually require the cuda sdk or toolset port dependency as ffmpeg uses runtime detection and dynamic loading + set(OPTIONS "${OPTIONS} --enable-cuda --enable-nvenc --enable-nvdec --enable-cuvid --enable-ffnvcodec") +else() + set(OPTIONS "${OPTIONS} --disable-cuda --disable-nvenc --disable-nvdec --disable-cuvid --disable-ffnvcodec") +endif() + +if("opencl" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-opencl") + set(WITH_OPENCL ON) +else() + set(OPTIONS "${OPTIONS} --disable-opencl") + set(WITH_OPENCL OFF) +endif() + +if("opengl" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-opengl") +else() + set(OPTIONS "${OPTIONS} --disable-opengl") +endif() + +if("openh264" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libopenh264") + set(WITH_OPENH264 ON) +else() + set(OPTIONS "${OPTIONS} --disable-libopenh264") + set(WITH_OPENH264 OFF) +endif() + +if("openjpeg" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libopenjpeg") + set(WITH_OPENJPEG ON) +else() + set(OPTIONS "${OPTIONS} --disable-libopenjpeg") + set(WITH_OPENJPEG OFF) +endif() + +if("openmpt" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libopenmpt") + set(WITH_OPENMPT ON) +else() + set(OPTIONS "${OPTIONS} --disable-libopenmpt") + set(WITH_OPENMPT OFF) +endif() + +if("openssl" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-openssl") +else() + set(OPTIONS "${OPTIONS} --disable-openssl") + if(VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_UWP) + string(APPEND OPTIONS " --enable-schannel") + endif() +endif() + +if("opus" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libopus") + set(WITH_OPUS ON) +else() + set(OPTIONS "${OPTIONS} --disable-libopus") + set(WITH_OPUS OFF) +endif() + +if("sdl2" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-sdl2") +else() + set(OPTIONS "${OPTIONS} --disable-sdl2") +endif() + +if("snappy" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libsnappy") + set(WITH_SNAPPY ON) +else() + set(OPTIONS "${OPTIONS} --disable-libsnappy") + set(WITH_SNAPPY OFF) +endif() + +if("soxr" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libsoxr") + set(WITH_SOXR ON) +else() + set(OPTIONS "${OPTIONS} --disable-libsoxr") + set(WITH_SOXR OFF) +endif() + +if("speex" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libspeex") + set(WITH_SPEEX ON) +else() + set(OPTIONS "${OPTIONS} --disable-libspeex") + set(WITH_SPEEX OFF) +endif() + +if("ssh" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libssh") + set(WITH_SSH ON) +else() + set(OPTIONS "${OPTIONS} --disable-libssh") + set(WITH_SSH OFF) +endif() + +if("tensorflow" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libtensorflow") +else() + set(OPTIONS "${OPTIONS} --disable-libtensorflow") +endif() + +if("tesseract" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libtesseract") +else() + set(OPTIONS "${OPTIONS} --disable-libtesseract") +endif() + +if("theora" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libtheora") + set(WITH_THEORA ON) +else() + set(OPTIONS "${OPTIONS} --disable-libtheora") + set(WITH_THEORA OFF) +endif() + +if("vorbis" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libvorbis") + set(WITH_VORBIS ON) +else() + set(OPTIONS "${OPTIONS} --disable-libvorbis") + set(WITH_VORBIS OFF) +endif() + +if("vpx" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libvpx") + set(WITH_VPX ON) +else() + set(OPTIONS "${OPTIONS} --disable-libvpx") + set(WITH_VPX OFF) +endif() + +if("vulkan" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-vulkan") +else() + set(OPTIONS "${OPTIONS} --disable-vulkan") +endif() + +if("webp" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libwebp") + set(WITH_WEBP ON) +else() + set(OPTIONS "${OPTIONS} --disable-libwebp") + set(WITH_WEBP OFF) +endif() + +if("x264" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libx264") + set(WITH_X264 ON) +else() + set(OPTIONS "${OPTIONS} --disable-libx264") + set(WITH_X264 OFF) +endif() + +if("x265" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libx265") + set(WITH_X265 ON) +else() + set(OPTIONS "${OPTIONS} --disable-libx265") + set(WITH_X265 OFF) +endif() + +if("xml2" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libxml2") + set(WITH_XML2 ON) +else() + set(OPTIONS "${OPTIONS} --disable-libxml2") + set(WITH_XML2 OFF) +endif() + +if("zlib" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-zlib") +else() + set(OPTIONS "${OPTIONS} --disable-zlib") +endif() + +if ("srt" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libsrt") + set(WITH_SRT ON) +else() + set(OPTIONS "${OPTIONS} --disable-libsrt") + set(WITH_SRT OFF) +endif() + +if ("qsv" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libmfx --enable-encoder=h264_qsv --enable-decoder=h264_qsv") + set(WITH_MFX ON) +else() + set(OPTIONS "${OPTIONS} --disable-libmfx") + set(WITH_MFX OFF) +endif() + +if ("vaapi" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-vaapi") + set(WITH_VAAPI ON) +else() + set(OPTIONS "${OPTIONS} --disable-vaapi") + set(WITH_VAAPI OFF) +endif() + +if("zmq" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-libzmq") + set(WITH_ZMQ ON) +else() + set(OPTIONS "${OPTIONS} --disable-libzmq") + set(WITH_ZMQ OFF) +endif() + +if("rubberband" IN_LIST FEATURES) + set(OPTIONS "${OPTIONS} --enable-librubberband") + set(WITH_RUBBERBAND ON) +else() + set(OPTIONS "${OPTIONS} --disable-librubberband") + set(WITH_RUBBERBAND OFF) +endif() + +set(OPTIONS_CROSS "--enable-cross-compile") + +# ffmpeg needs --cross-prefix option to use appropriate tools for cross-compiling. +if(VCPKG_DETECTED_CMAKE_C_COMPILER MATCHES "([^\/]*-)gcc$") + string(APPEND OPTIONS_CROSS " --cross-prefix=${CMAKE_MATCH_1}") +endif() + +if(VCPKG_TARGET_ARCHITECTURE STREQUAL "x64") + set(BUILD_ARCH "x86_64") +else() + set(BUILD_ARCH ${VCPKG_TARGET_ARCHITECTURE}) +endif() + +if (VCPKG_TARGET_ARCHITECTURE STREQUAL "arm" OR VCPKG_TARGET_ARCHITECTURE STREQUAL "arm64") + if(VCPKG_TARGET_IS_WINDOWS) + vcpkg_find_acquire_program(GASPREPROCESSOR) + foreach(GAS_PATH ${GASPREPROCESSOR}) + get_filename_component(GAS_ITEM_PATH ${GAS_PATH} DIRECTORY) + vcpkg_add_to_path("${GAS_ITEM_PATH}") + endforeach(GAS_PATH) + endif() +endif() + +if(VCPKG_TARGET_IS_UWP) + set(ENV{LIBPATH} "$ENV{LIBPATH};$ENV{_WKITS10}references\\windows.foundation.foundationcontract\\2.0.0.0\\;$ENV{_WKITS10}references\\windows.foundation.universalapicontract\\3.0.0.0\\") + string(APPEND OPTIONS " --disable-programs") + string(APPEND OPTIONS " --extra-cflags=-DWINAPI_FAMILY=WINAPI_FAMILY_APP --extra-cflags=-D_WIN32_WINNT=0x0A00") + string(APPEND OPTIONS " --extra-ldflags=-APPCONTAINER --extra-ldflags=WindowsApp.lib") +endif() + +if (VCPKG_TARGET_IS_IOS) + set(vcpkg_target_arch "${VCPKG_TARGET_ARCHITECTURE}") + if (VCPKG_TARGET_ARCHITECTURE STREQUAL "x64") + set(vcpkg_target_arch "x86_64") + elseif (VCPKG_TARGET_ARCHITECTURE STREQUAL "arm") + message(FATAL_ERROR "You can build for arm up to iOS 10 but ffmpeg can only be built for iOS 11.0 and later. + Did you mean arm64?") + elseif (VCPKG_TARGET_ARCHITECTURE STREQUAL "x86") + message(FATAL_ERROR "You can build for x86 up to iOS 10 but ffmpeg can only be built for iOS 11.0 and later. + Did you mean x64") + endif () + + set(vcpkg_osx_deployment_target "${VCPKG_OSX_DEPLOYMENT_TARGET}") + if (NOT VCPKG_OSX_DEPLOYMENT_TARGET) + set(vcpkg_osx_deployment_target 11.0) + elseif (VCPKG_OSX_DEPLOYMENT_TARGET LESS 11.0) # nowadays ffmpeg needs to be built for ios 11.0 and later + message(FATAL_ERROR "ffmpeg can be built only for iOS 11.0 and later but you set VCPKG_OSX_DEPLOYMENT_TARGET to + ${VCPKG_OSX_DEPLOYMENT_TARGET}") + endif () + + if (VCPKG_OSX_SYSROOT STREQUAL "iphonesimulator") + set(simulator "-simulator") + endif () + + set(OPTIONS "${OPTIONS} --extra-cflags=--target=${vcpkg_target_arch}-apple-ios${vcpkg_osx_deployment_target}${simulator}") + set(OPTIONS "${OPTIONS} --extra-ldflags=--target=${vcpkg_target_arch}-apple-ios${vcpkg_osx_deployment_target}${simulator}") + + set(vcpkg_osx_sysroot "${VCPKG_OSX_SYSROOT}") + # only on x64 for some reason you need to specify the sdk path, otherwise it will try to build with the MacOS sdk + # (on apple silicon it's not required but shouldn't cause any problems) + if ((VCPKG_OSX_SYSROOT MATCHES "^(iphoneos|iphonesimulator)$") OR (NOT VCPKG_OSX_SYSROOT) OR (VCPKG_OSX_SYSROOT STREQUAL "")) # if it's not a path + if (VCPKG_OSX_SYSROOT MATCHES "^(iphoneos|iphonesimulator)$") + set(requested_sysroot "${VCPKG_OSX_SYSROOT}") + elseif (VCPKG_TARGET_ARCHITECTURE STREQUAL "arm64") # if the sysroot is not specified we have to guess + set(requested_sysroot "iphoneos") + elseif (VCPKG_TARGET_ARCHITECTURE STREQUAL "x64") + set(requested_sysroot "iphonesimulator") + else () + message(FATAL_ERROR "Unsupported build arch: ${VCPKG_TARGET_ARCHITECTURE}") + endif () + message(STATUS "Retrieving default SDK for ${requested_sysroot}") + execute_process( + COMMAND /usr/bin/xcrun --sdk ${requested_sysroot} --show-sdk-path + OUTPUT_VARIABLE sdk_path + ERROR_VARIABLE xcrun_error + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE + ) + if (sdk_path) + message(STATUS "Found!") + set(vcpkg_osx_sysroot "${sdk_path}") + else () + message(FATAL_ERROR "Can't determine ${CMAKE_OSX_SYSROOT} SDK path. Error: ${xcrun_error}") + endif () + endif () + set(OPTIONS "${OPTIONS} --extra-cflags=-isysroot\"${vcpkg_osx_sysroot}\"") + set(OPTIONS "${OPTIONS} --extra-ldflags=-isysroot\"${vcpkg_osx_sysroot}\"") +endif () + +set(OPTIONS_DEBUG "--disable-optimizations") +set(OPTIONS_RELEASE "--enable-optimizations") + +set(OPTIONS "${OPTIONS} ${OPTIONS_CROSS}") + +if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic") + set(OPTIONS "${OPTIONS} --disable-static --enable-shared") +endif() + +if(VCPKG_TARGET_IS_MINGW) + set(OPTIONS "${OPTIONS} --extra_cflags=-D_WIN32_WINNT=0x0601") +elseif(VCPKG_TARGET_IS_WINDOWS) + set(OPTIONS "${OPTIONS} --extra-cflags=-DHAVE_UNISTD_H=0") +endif() + +set(maybe_needed_libraries -lm) +separate_arguments(standard_libraries NATIVE_COMMAND "${VCPKG_DETECTED_CMAKE_C_STANDARD_LIBRARIES}") +foreach(item IN LISTS standard_libraries) + if(item IN_LIST maybe_needed_libraries) + set(OPTIONS "${OPTIONS} \"--extra-libs=${item}\"") + endif() +endforeach() + +vcpkg_find_acquire_program(PKGCONFIG) +set(OPTIONS "${OPTIONS} --pkg-config=\"${PKGCONFIG}\"") +if(VCPKG_LIBRARY_LINKAGE STREQUAL "static") + set(OPTIONS "${OPTIONS} --pkg-config-flags=--static") +endif() + +message(STATUS "Building Options: ${OPTIONS}") + +# Release build +if (NOT VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release") + if (VCPKG_DETECTED_MSVC) + set(OPTIONS_RELEASE "${OPTIONS_RELEASE} --extra-ldflags=-libpath:\"${CURRENT_INSTALLED_DIR}/lib\"") + else() + set(OPTIONS_RELEASE "${OPTIONS_RELEASE} --extra-ldflags=-L\"${CURRENT_INSTALLED_DIR}/lib\"") + endif() + message(STATUS "Building Release Options: ${OPTIONS_RELEASE}") + message(STATUS "Building ${PORT} for Release") + file(MAKE_DIRECTORY "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel") + # We use response files here as the only known way to handle spaces in paths + set(crsp "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel/cflags.rsp") + string(REGEX REPLACE "-arch [A-Za-z0-9_]+" "" VCPKG_COMBINED_C_FLAGS_RELEASE_SANITIZED "${VCPKG_COMBINED_C_FLAGS_RELEASE}") + file(WRITE "${crsp}" "${VCPKG_COMBINED_C_FLAGS_RELEASE_SANITIZED}") + set(ldrsp "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel/ldflags.rsp") + string(REGEX REPLACE "-arch [A-Za-z0-9_]+" "" VCPKG_COMBINED_SHARED_LINKER_FLAGS_RELEASE_SANITIZED "${VCPKG_COMBINED_SHARED_LINKER_FLAGS_RELEASE}") + file(WRITE "${ldrsp}" "${VCPKG_COMBINED_SHARED_LINKER_FLAGS_RELEASE_SANITIZED}") + set(ENV{CFLAGS} "@${crsp}") + # All tools except the msvc arm{,64} assembler accept @... as response file syntax. + # For that assembler, there is no known way to pass in flags. We must hope that not passing flags will work acceptably. + if(NOT VCPKG_DETECTED_MSVC OR NOT VCPKG_TARGET_ARCHITECTURE MATCHES "^arm") + set(ENV{ASFLAGS} "@${crsp}") + endif() + set(ENV{LDFLAGS} "@${ldrsp}") + set(ENV{ARFLAGS} "${VCPKG_COMBINED_STATIC_LINKER_FLAGS_RELEASE}") + + set(BUILD_DIR "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel") + set(CONFIGURE_OPTIONS "${OPTIONS} ${OPTIONS_RELEASE}") + set(INST_PREFIX "${CURRENT_PACKAGES_DIR}") + + configure_file("${CMAKE_CURRENT_LIST_DIR}/build.sh.in" "${BUILD_DIR}/build.sh" @ONLY) + + z_vcpkg_setup_pkgconfig_path(CONFIG RELEASE) + + vcpkg_execute_required_process( + COMMAND "${SHELL}" ./build.sh + WORKING_DIRECTORY "${BUILD_DIR}" + LOGNAME "build-${TARGET_TRIPLET}-rel" + SAVE_LOG_FILES ffbuild/config.log + ) + + z_vcpkg_restore_pkgconfig_path() +endif() + +# Debug build +if (NOT VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug") + if (VCPKG_DETECTED_MSVC) + set(OPTIONS_DEBUG "${OPTIONS_DEBUG} --extra-ldflags=-libpath:\"${CURRENT_INSTALLED_DIR}/debug/lib\"") + else() + set(OPTIONS_DEBUG "${OPTIONS_DEBUG} --extra-ldflags=-L\"${CURRENT_INSTALLED_DIR}/debug/lib\"") + endif() + message(STATUS "Building Debug Options: ${OPTIONS_DEBUG}") + message(STATUS "Building ${PORT} for Debug") + file(MAKE_DIRECTORY "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg") + set(crsp "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg/cflags.rsp") + string(REGEX REPLACE "-arch [A-Za-z0-9_]+" "" VCPKG_COMBINED_C_FLAGS_DEBUG_SANITIZED "${VCPKG_COMBINED_C_FLAGS_DEBUG}") + file(WRITE "${crsp}" "${VCPKG_COMBINED_C_FLAGS_DEBUG_SANITIZED}") + set(ldrsp "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg/ldflags.rsp") + string(REGEX REPLACE "-arch [A-Za-z0-9_]+" "" VCPKG_COMBINED_SHARED_LINKER_FLAGS_DEBUG_SANITIZED "${VCPKG_COMBINED_SHARED_LINKER_FLAGS_DEBUG}") + file(WRITE "${ldrsp}" "${VCPKG_COMBINED_SHARED_LINKER_FLAGS_DEBUG_SANITIZED}") + set(ENV{CFLAGS} "@${crsp}") + if(NOT VCPKG_DETECTED_MSVC OR NOT VCPKG_TARGET_ARCHITECTURE MATCHES "^arm") + set(ENV{ASFLAGS} "@${crsp}") + endif() + set(ENV{LDFLAGS} "@${ldrsp}") + set(ENV{ARFLAGS} "${VCPKG_COMBINED_STATIC_LINKER_FLAGS_DEBUG}") + + set(BUILD_DIR "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg") + set(CONFIGURE_OPTIONS "${OPTIONS} ${OPTIONS_DEBUG}") + set(INST_PREFIX "${CURRENT_PACKAGES_DIR}/debug") + + configure_file("${CMAKE_CURRENT_LIST_DIR}/build.sh.in" "${BUILD_DIR}/build.sh" @ONLY) + + z_vcpkg_setup_pkgconfig_path(CONFIG DEBUG) + + vcpkg_execute_required_process( + COMMAND "${SHELL}" ./build.sh + WORKING_DIRECTORY "${BUILD_DIR}" + LOGNAME "build-${TARGET_TRIPLET}-dbg" + SAVE_LOG_FILES ffbuild/config.log + ) + + z_vcpkg_restore_pkgconfig_path() +endif() + +if(VCPKG_TARGET_IS_WINDOWS) + file(GLOB DEF_FILES "${CURRENT_PACKAGES_DIR}/lib/*.def" "${CURRENT_PACKAGES_DIR}/debug/lib/*.def") + + if(NOT VCPKG_TARGET_IS_MINGW) + if(VCPKG_TARGET_ARCHITECTURE STREQUAL "arm") + set(LIB_MACHINE_ARG /machine:ARM) + elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "arm64") + set(LIB_MACHINE_ARG /machine:ARM64) + elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "x86") + set(LIB_MACHINE_ARG /machine:x86) + elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "x64") + set(LIB_MACHINE_ARG /machine:x64) + else() + message(FATAL_ERROR "Unsupported target architecture") + endif() + + foreach(DEF_FILE ${DEF_FILES}) + get_filename_component(DEF_FILE_DIR "${DEF_FILE}" DIRECTORY) + get_filename_component(DEF_FILE_NAME "${DEF_FILE}" NAME) + string(REGEX REPLACE "-[0-9]*\\.def" "${VCPKG_TARGET_STATIC_LIBRARY_SUFFIX}" OUT_FILE_NAME "${DEF_FILE_NAME}") + file(TO_NATIVE_PATH "${DEF_FILE}" DEF_FILE_NATIVE) + file(TO_NATIVE_PATH "${DEF_FILE_DIR}/${OUT_FILE_NAME}" OUT_FILE_NATIVE) + message(STATUS "Generating ${OUT_FILE_NATIVE}") + vcpkg_execute_required_process( + COMMAND lib.exe "/def:${DEF_FILE_NATIVE}" "/out:${OUT_FILE_NATIVE}" ${LIB_MACHINE_ARG} + WORKING_DIRECTORY "${CURRENT_PACKAGES_DIR}" + LOGNAME "libconvert-${TARGET_TRIPLET}" + ) + endforeach() + endif() + + file(GLOB EXP_FILES "${CURRENT_PACKAGES_DIR}/lib/*.exp" "${CURRENT_PACKAGES_DIR}/debug/lib/*.exp") + file(GLOB LIB_FILES "${CURRENT_PACKAGES_DIR}/bin/*${VCPKG_TARGET_STATIC_LIBRARY_SUFFIX}" "${CURRENT_PACKAGES_DIR}/debug/bin/*${VCPKG_TARGET_STATIC_LIBRARY_SUFFIX}") + if(VCPKG_TARGET_IS_MINGW) + file(GLOB LIB_FILES_2 "${CURRENT_PACKAGES_DIR}/bin/*.lib" "${CURRENT_PACKAGES_DIR}/debug/bin/*.lib") + endif() + set(files_to_remove ${EXP_FILES} ${LIB_FILES} ${LIB_FILES_2} ${DEF_FILES}) + if(files_to_remove) + file(REMOVE ${files_to_remove}) + endif() +endif() + +if("ffmpeg" IN_LIST FEATURES) + vcpkg_copy_tools(TOOL_NAMES ffmpeg AUTO_CLEAN) +endif() +if("ffprobe" IN_LIST FEATURES) + vcpkg_copy_tools(TOOL_NAMES ffprobe AUTO_CLEAN) +endif() +if("ffplay" IN_LIST FEATURES) + vcpkg_copy_tools(TOOL_NAMES ffplay AUTO_CLEAN) +endif() + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include" "${CURRENT_PACKAGES_DIR}/debug/share") + +if(VCPKG_LIBRARY_LINKAGE STREQUAL "static") + file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/bin" "${CURRENT_PACKAGES_DIR}/debug/bin") +endif() + +vcpkg_copy_pdbs() + +if(VCPKG_TARGET_IS_WINDOWS) + file(GLOB pc_files "${CURRENT_PACKAGES_DIR}/lib/pkgconfig/*.pc" "${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/*.pc") + foreach(file IN LISTS pc_files) + # ffmpeg exports -libpath:foo and bar.lib for transitive deps. + # But CMake's pkg_check_modules cannot handle this properly. + # pc files generally use non-msvc syntax with -Lfoo -lbar. + file(READ "${file}" content) + foreach(entry IN ITEMS Libs Libs.private) + if(content MATCHES "${entry}:( [^\n]*)") + set(old_value "${CMAKE_MATCH_1}") + string(REGEX REPLACE "-libpath:" "-L" new_value "${old_value}") + string(REGEX REPLACE " ([^ /]+)[.]lib" " -l\\1" new_value "${new_value}") + string(REPLACE "${entry}:${old_value}" "${entry}:${new_value}" content "${content}") + endif() + endforeach() + file(WRITE "${file}" "${content}") + endforeach() +endif() +vcpkg_fixup_pkgconfig() + +# Handle dependencies + +x_vcpkg_pkgconfig_get_modules(PREFIX FFMPEG_PKGCONFIG MODULES ${FFMPEG_PKGCONFIG_MODULES} LIBS) + +function(append_dependencies_from_libs out) + cmake_parse_arguments(PARSE_ARGV 1 "arg" "" "LIBS" "") + separate_arguments(contents UNIX_COMMAND "${arg_LIBS}") + list(FILTER contents EXCLUDE REGEX "^-F.+") + list(FILTER contents EXCLUDE REGEX "^-framework$") + list(FILTER contents EXCLUDE REGEX "^-L.+") + list(FILTER contents EXCLUDE REGEX "^-libpath:.+") + list(TRANSFORM contents REPLACE "^-Wl,-framework," "-l") + list(FILTER contents EXCLUDE REGEX "^-Wl,.+") + list(TRANSFORM contents REPLACE "^-l" "") + list(FILTER contents EXCLUDE REGEX "^avutil$") + list(FILTER contents EXCLUDE REGEX "^avcodec$") + list(FILTER contents EXCLUDE REGEX "^avdevice$") + list(FILTER contents EXCLUDE REGEX "^avfilter$") + list(FILTER contents EXCLUDE REGEX "^avformat$") + list(FILTER contents EXCLUDE REGEX "^postproc$") + list(FILTER contents EXCLUDE REGEX "^swresample$") + list(FILTER contents EXCLUDE REGEX "^swscale$") + if(VCPKG_TARGET_IS_WINDOWS) + list(TRANSFORM contents TOLOWER) + endif() + if(contents) + list(APPEND "${out}" "${contents}") + set("${out}" "${${out}}" PARENT_SCOPE) + endif() +endfunction() + +append_dependencies_from_libs(FFMPEG_DEPENDENCIES_RELEASE LIBS "${FFMPEG_PKGCONFIG_LIBS_RELEASE}") +append_dependencies_from_libs(FFMPEG_DEPENDENCIES_DEBUG LIBS "${FFMPEG_PKGCONFIG_LIBS_DEBUG}") + +# must remove duplicates from the front to respect link order so reverse first +list(REVERSE FFMPEG_DEPENDENCIES_RELEASE) +list(REVERSE FFMPEG_DEPENDENCIES_DEBUG) +list(REMOVE_DUPLICATES FFMPEG_DEPENDENCIES_RELEASE) +list(REMOVE_DUPLICATES FFMPEG_DEPENDENCIES_DEBUG) +list(REVERSE FFMPEG_DEPENDENCIES_RELEASE) +list(REVERSE FFMPEG_DEPENDENCIES_DEBUG) + +message(STATUS "Dependencies (release): ${FFMPEG_DEPENDENCIES_RELEASE}") +message(STATUS "Dependencies (debug): ${FFMPEG_DEPENDENCIES_DEBUG}") + +# Handle version strings + +function(extract_regex_from_file out) + cmake_parse_arguments(PARSE_ARGV 1 "arg" "MAJOR" "FILE_WITHOUT_EXTENSION;REGEX" "") + file(READ "${arg_FILE_WITHOUT_EXTENSION}.h" contents) + if (contents MATCHES "${arg_REGEX}") + if(NOT CMAKE_MATCH_COUNT EQUAL 1) + message(FATAL_ERROR "Could not identify match group in regular expression \"${arg_REGEX}\"") + endif() + else() + if (arg_MAJOR) + file(READ "${arg_FILE_WITHOUT_EXTENSION}_major.h" contents) + if (contents MATCHES "${arg_REGEX}") + if(NOT CMAKE_MATCH_COUNT EQUAL 1) + message(FATAL_ERROR "Could not identify match group in regular expression \"${arg_REGEX}\"") + endif() + else() + message(WARNING "Could not find line matching \"${arg_REGEX}\" in file \"${arg_FILE_WITHOUT_EXTENSION}_major.h\"") + endif() + else() + message(WARNING "Could not find line matching \"${arg_REGEX}\" in file \"${arg_FILE_WITHOUT_EXTENSION}.h\"") + endif() + endif() + set("${out}" "${CMAKE_MATCH_1}" PARENT_SCOPE) +endfunction() + +function(extract_version_from_component out) + cmake_parse_arguments(PARSE_ARGV 1 "arg" "" "COMPONENT" "") + string(TOLOWER "${arg_COMPONENT}" component_lower) + string(TOUPPER "${arg_COMPONENT}" component_upper) + extract_regex_from_file(major_version + FILE_WITHOUT_EXTENSION "${SOURCE_PATH}/${component_lower}/version" + MAJOR + REGEX "#define ${component_upper}_VERSION_MAJOR[ ]+([0-9]+)" + ) + extract_regex_from_file(minor_version + FILE_WITHOUT_EXTENSION "${SOURCE_PATH}/${component_lower}/version" + REGEX "#define ${component_upper}_VERSION_MINOR[ ]+([0-9]+)" + ) + extract_regex_from_file(micro_version + FILE_WITHOUT_EXTENSION "${SOURCE_PATH}/${component_lower}/version" + REGEX "#define ${component_upper}_VERSION_MICRO[ ]+([0-9]+)" + ) + set("${out}" "${major_version}.${minor_version}.${micro_version}" PARENT_SCOPE) +endfunction() + +extract_regex_from_file(FFMPEG_VERSION + FILE_WITHOUT_EXTENSION "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel/libavutil/ffversion" + REGEX "#define FFMPEG_VERSION[ ]+\"(.+)\"" +) + +extract_version_from_component(LIBAVUTIL_VERSION + COMPONENT libavutil) +extract_version_from_component(LIBAVCODEC_VERSION + COMPONENT libavcodec) +extract_version_from_component(LIBAVDEVICE_VERSION + COMPONENT libavdevice) +extract_version_from_component(LIBAVFILTER_VERSION + COMPONENT libavfilter) +extract_version_from_component(LIBAVFORMAT_VERSION + COMPONENT libavformat) +extract_version_from_component(LIBSWRESAMPLE_VERSION + COMPONENT libswresample) +extract_version_from_component(LIBSWSCALE_VERSION + COMPONENT libswscale) + +# Handle copyright +file(STRINGS "${CURRENT_BUILDTREES_DIR}/build-${TARGET_TRIPLET}-rel-out.log" LICENSE_STRING REGEX "License: .*" LIMIT_COUNT 1) +if(LICENSE_STRING STREQUAL "License: LGPL version 2.1 or later") + set(LICENSE_FILE "COPYING.LGPLv2.1") +elseif(LICENSE_STRING STREQUAL "License: LGPL version 3 or later") + set(LICENSE_FILE "COPYING.LGPLv3") +elseif(LICENSE_STRING STREQUAL "License: GPL version 2 or later") + set(LICENSE_FILE "COPYING.GPLv2") +elseif(LICENSE_STRING STREQUAL "License: GPL version 3 or later") + set(LICENSE_FILE "COPYING.GPLv3") +elseif(LICENSE_STRING STREQUAL "License: nonfree and unredistributable") + set(LICENSE_FILE "COPYING.NONFREE") + file(WRITE "${SOURCE_PATH}/${LICENSE_FILE}" "${LICENSE_STRING}") +else() + message(FATAL_ERROR "Failed to identify license (${LICENSE_STRING})") +endif() + +configure_file("${CMAKE_CURRENT_LIST_DIR}/FindFFMPEG.cmake.in" "${CURRENT_PACKAGES_DIR}/share/${PORT}/FindFFMPEG.cmake" @ONLY) +configure_file("${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake" "${CURRENT_PACKAGES_DIR}/share/${PORT}/vcpkg-cmake-wrapper.cmake" @ONLY) + +file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}") +if(VCPKG_LIBRARY_LINKAGE STREQUAL "static" AND NOT VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_OSX AND NOT VCPKG_TARGET_IS_IOS) + file(APPEND "${CURRENT_PACKAGES_DIR}/share/${PORT}/usage" " +To use the static libraries to build your own shared library, +you may need to add the following link option for your library: + + -Wl,-Bsymbolic +") +endif() + +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/${LICENSE_FILE}") diff --git a/portfiles/ffmpeg/usage b/portfiles/ffmpeg/usage new file mode 100644 index 000000000..b2d02a089 --- /dev/null +++ b/portfiles/ffmpeg/usage @@ -0,0 +1,29 @@ +ffmpeg provides CMake integration: + + find_package(FFMPEG REQUIRED) + target_include_directories(main PRIVATE ${FFMPEG_INCLUDE_DIRS}) + target_link_directories(main PRIVATE ${FFMPEG_LIBRARY_DIRS}) + target_link_libraries(main PRIVATE ${FFMPEG_LIBRARIES}) + +ffmpeg provides pkg-config modules: + + # FFmpeg codec library + libavcodec + + # FFmpeg device handling library + libavdevice + + # FFmpeg audio/video filtering library + libavfilter + + # FFmpeg container format library + libavformat + + # FFmpeg utility library + libavutil + + # FFmpeg audio resampling library + libswresample + + # FFmpeg image rescaling library + libswscale diff --git a/portfiles/ffmpeg/vcpkg-cmake-wrapper.cmake b/portfiles/ffmpeg/vcpkg-cmake-wrapper.cmake new file mode 100644 index 000000000..2f1843a4c --- /dev/null +++ b/portfiles/ffmpeg/vcpkg-cmake-wrapper.cmake @@ -0,0 +1,334 @@ +set(FFMPEG_PREV_MODULE_PATH ${CMAKE_MODULE_PATH}) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) + +cmake_policy(SET CMP0012 NEW) + +# Detect if we use "our" find module or a vendored one +set(z_vcpkg_using_vcpkg_find_ffmpeg OFF) + +# Detect targets created e.g. by VTK/CMake/FindFFMPEG.cmake +set(vcpkg_no_avcodec_target ON) +set(vcpkg_no_avformat_target ON) +set(vcpkg_no_avutil_target ON) +set(vcpkg_no_swresample_target ON) +if(TARGET FFmpeg::avcodec) + set(vcpkg_no_avcodec_target OFF) +endif() +if(TARGET FFmpeg::avformat) + set(vcpkg_no_avformat_target OFF) +endif() +if(TARGET FFmpeg::avutil) + set(vcpkg_no_avutil_target OFF) +endif() +if(TARGET FFmpeg::swresample) + set(vcpkg_no_swresample_target OFF) +endif() + +_find_package(${ARGS}) + +# Fixup of variables and targets for (some) vendored find modules +if(NOT z_vcpkg_using_vcpkg_find_ffmpeg AND NOT "@BUILD_SHARED_LIBS@") + +include(SelectLibraryConfigurations) + +if(CMAKE_HOST_WIN32) + set(PKG_CONFIG_EXECUTABLE "${CMAKE_CURRENT_LIST_DIR}/../../../@_HOST_TRIPLET@/tools/pkgconf/pkgconf.exe" CACHE STRING "" FORCE) +endif() +set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH ON) # Required for CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 3.1 which otherwise ignores CMAKE_PREFIX_PATH +find_package(PkgConfig) + +pkg_check_modules(PKG_libavcodec libavcodec) +if(APPLE) + list(FILTER PKG_libavcodec_LIBRARIES INCLUDE REGEX "^-framework ") + if(PKG_libavcodec_LIBRARIES) + list(APPEND FFMPEG_LIBRARIES ${PKG_libavcodec_LIBRARIES}) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE ${PKG_libavcodec_LIBRARIES}) + endif() + endif() +elseif(WIN32) + foreach(z_libavcodec_link_lib IN ITEMS bcrypt crypt32 mfuuid psapi secur32 shlwapi strmiids vfw32 ws2_32 usp10 cfgmgr32 rpcrt4) + if("-l${z_libavcodec_link_lib}" IN_LIST PKG_libavcodec_LDFLAGS) + list(APPEND FFMPEG_LIBRARIES "${z_libavcodec_link_lib}") + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE "$") + endif() + endif() + endforeach() +endif() + +if(@WITH_MP3LAME@) + find_package(mp3lame CONFIG ) + list(APPEND FFMPEG_LIBRARIES mp3lame::mp3lame) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + # target exists after find_package and wasn't defined before + target_link_libraries(FFmpeg::avcodec INTERFACE mp3lame::mp3lame) + endif() +endif() + +if(@WITH_XML2@) + find_package(LibXml2 ) + list(APPEND FFMPEG_LIBRARIES LibXml2::LibXml2) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE LibXml2::LibXml2) + endif() + if(vcpkg_no_avformat_target AND TARGET FFmpeg::avformat) + target_link_libraries(FFmpeg::avformat INTERFACE LibXml2::LibXml2) + endif() +endif() + +if(@WITH_ICONV@) + find_package(Iconv ) + list(APPEND FFMPEG_LIBRARIES Iconv::Iconv) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE Iconv::Iconv) + endif() + if(vcpkg_no_avformat_target AND TARGET FFmpeg::avformat) + target_link_libraries(FFmpeg::avformat INTERFACE Iconv::Iconv) + endif() +endif() + +if(@WITH_LZMA@) + find_package(liblzma CONFIG ) + list(APPEND FFMPEG_LIBRARIES liblzma::liblzma) + if(vcpkg_no_avformat_target AND TARGET FFmpeg::avformat) + target_link_libraries(FFmpeg::avformat INTERFACE liblzma::liblzma) + endif() +endif() + +if(@WITH_SSH@) + find_package(libssh CONFIG ) + list(APPEND FFMPEG_LIBRARIES ssh) + if(vcpkg_no_avformat_target AND TARGET FFmpeg::avformat) + target_link_libraries(FFmpeg::avformat INTERFACE ssh) + endif() +endif() + +if(@WITH_OPENMPT@) + find_package(libopenmpt CONFIG ) + list(APPEND FFMPEG_LIBRARIES libopenmpt::libopenmpt) + if(vcpkg_no_avformat_target AND TARGET FFmpeg::avformat) + target_link_libraries(FFmpeg::avformat INTERFACE libopenmpt::libopenmpt) + endif() +endif() + +if(@WITH_MODPLUG@) + pkg_check_modules(modplug IMPORTED_TARGET libmodplug) + list(APPEND FFMPEG_LIBRARIES PkgConfig::modplug) + if(vcpkg_no_avformat_target AND TARGET FFmpeg::avformat) + target_link_libraries(FFmpeg::avformat INTERFACE PkgConfig::modplug) + endif() +endif() + +if(@WITH_SRT@) + pkg_check_modules(srt IMPORTED_TARGET srt) + list(APPEND FFMPEG_LIBRARIES PkgConfig::srt) + if(vcpkg_no_avformat_target AND TARGET FFmpeg::avformat) + target_link_libraries(FFmpeg::avformat INTERFACE PkgConfig::srt) + endif() +endif() + +if(@WITH_DAV1D@) + pkg_check_modules(dav1d IMPORTED_TARGET dav1d) + list(APPEND FFMPEG_LIBRARIES PkgConfig::dav1d) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE PkgConfig::dav1d) + endif() +endif() + +if(@WITH_OPENH264@) + pkg_check_modules(openh264 IMPORTED_TARGET openh264) + list(APPEND FFMPEG_LIBRARIES PkgConfig::openh264) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE PkgConfig::openh264) + endif() +endif() + +if(@WITH_WEBP@) + find_package(WebP CONFIG ) + list(APPEND FFMPEG_LIBRARIES WebP::webp WebP::webpdecoder WebP::webpdemux WebP::libwebpmux) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE WebP::webp WebP::webpdecoder WebP::webpdemux WebP::libwebpmux) + endif() +endif() + +if(@WITH_SOXR@) + find_library(SOXR_LIBRARY_RELEASE NAMES soxr PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" NO_DEFAULT_PATH) + find_library(SOXR_LIBRARY_DEBUG NAMES soxr PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib" NO_DEFAULT_PATH) + select_library_configurations(SOXR) + if(SOXR_LIBRARY_RELEASE) + list(APPEND FFMPEG_LIBRARIES $<$>:${SOXR_LIBRARY_RELEASE}>) + endif() + if(SOXR_LIBRARY_DEBUG) + list(APPEND FFMPEG_LIBRARIES $<$:${SOXR_LIBRARY_DEBUG}>) + endif() + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE ${SOXR_LIBRARIES}) + endif() + if(vcpkg_no_swresample_target AND TARGET FFmpeg::swresample) + target_link_libraries(FFmpeg::swresample INTERFACE ${SOXR_LIBRARIES}) + endif() +endif() + +if(@WITH_THEORA@) + pkg_check_modules(theora IMPORTED_TARGET theora) + list(APPEND FFMPEG_LIBRARIES PkgConfig::theora) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE PkgConfig::theora) + endif() +endif() + +if(@WITH_MFX@) + pkg_check_modules(libmfx IMPORTED_TARGET libmfx) + list(APPEND FFMPEG_LIBRARIES PkgConfig::libmfx) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE PkgConfig::libmfx) + endif() + if(vcpkg_no_avutil_target AND TARGET FFmpeg::avutil) + target_link_libraries(FFmpeg::avutil INTERFACE PkgConfig::libmfx) + endif() +endif() + +if(@WITH_ILBC@) + pkg_check_modules(libilbc IMPORTED_TARGET libilbc) + list(APPEND FFMPEG_LIBRARIES PkgConfig::libilbc) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE PkgConfig::libilbc) + endif() +endif() + +if(@WITH_THEORA@) + pkg_check_modules(theora IMPORTED_TARGET theora) + list(APPEND FFMPEG_LIBRARIES PkgConfig::theora) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE PkgConfig::theora) + endif() +endif() + +if(@WITH_VORBIS@) + find_package(Vorbis CONFIG ) + list(APPEND FFMPEG_LIBRARIES Vorbis::vorbis Vorbis::vorbisenc) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE Vorbis::vorbis Vorbis::vorbisenc) + endif() +endif() + +if(@WITH_VPX@) + pkg_check_modules(vpx IMPORTED_TARGET vpx) + list(APPEND FFMPEG_LIBRARIES PkgConfig::vpx) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE PkgConfig::vpx) + endif() +endif() + +if(@WITH_OPUS@) + find_package(Opus CONFIG ) + list(APPEND FFMPEG_LIBRARIES Opus::opus) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE Opus::opus) + endif() +endif() + +if(@WITH_SPEEX@) + pkg_check_modules(speex IMPORTED_TARGET speex) + list(APPEND FFMPEG_LIBRARIES PkgConfig::speex) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE PkgConfig::speex) + endif() +endif() + +if(@WITH_OPENJPEG@) + find_package(OpenJPEG CONFIG ) + list(APPEND FFMPEG_LIBRARIES openjp2) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE openjp2) + endif() +endif() + +if(@WITH_SNAPPY@) + find_package(Snappy CONFIG ) + list(APPEND FFMPEG_LIBRARIES Snappy::snappy) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE Snappy::snappy) + endif() +endif() + +if(@WITH_AOM@) + pkg_check_modules(aom IMPORTED_TARGET aom) + list(APPEND FFMPEG_LIBRARIES PkgConfig::aom) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE PkgConfig::aom) + endif() +endif() + +if(@WITH_X264@) + pkg_check_modules(x264 IMPORTED_TARGET x264) + list(APPEND FFMPEG_LIBRARIES PkgConfig::x264) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE PkgConfig::x264) + endif() +endif() + +if(@WITH_X265@) + pkg_check_modules(x265 IMPORTED_TARGET x265) + list(APPEND FFMPEG_LIBRARIES PkgConfig::x265) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE PkgConfig::x265) + endif() +endif() + +if(@WITH_AAC@) + find_package(fdk-aac CONFIG) + list(APPEND FFMPEG_LIBRARIES FDK-AAC::fdk-aac) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE FDK-AAC::fdk-aac) + endif() +endif() + +if(@WITH_OPENCL@) + find_package(OpenCL ) + list(APPEND FFMPEG_LIBRARIES OpenCL::OpenCL) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE OpenCL::OpenCL) + endif() + if(vcpkg_no_avutil_target AND TARGET FFmpeg::avutil) + target_link_libraries(FFmpeg::avutil INTERFACE OpenCL::OpenCL) + endif() +endif() + +if(@WITH_VAAPI@) + pkg_check_modules(libva IMPORTED_TARGET libva) + pkg_check_modules(libva-drm IMPORTED_TARGET libva-drm) + list(APPEND FFMPEG_LIBRARIES PkgConfig::libva PkgConfig::libva-drm) + if(vcpkg_no_avcodec_target AND TARGET FFmpeg::avcodec) + target_link_libraries(FFmpeg::avcodec INTERFACE PkgConfig::libva PkgConfig::libva-drm) + endif() +endif() + +if(@WITH_ZMQ@) + pkg_check_modules(libzmq IMPORTED_TARGET libzmq) + list(APPEND FFMPEG_LIBRARIES PkgConfig::libzmq) + if(vcpkg_no_avformat_target AND TARGET FFmpeg::avformat) + target_link_libraries(FFmpeg::avformat INTERFACE PkgConfig::libzmq) + endif() +endif() + +if(@WITH_RUBBERBAND@) + pkg_check_modules(rubberband IMPORTED_TARGET rubberband) + list(APPEND FFMPEG_LIBRARIES PkgConfig::rubberband) + if(vcpkg_no_avfilter_target AND TARGET FFmpeg::avfilter) + target_link_libraries(FFmpeg::avfilter INTERFACE PkgConfig::rubberband) + endif() +endif() + +endif() +unset(z_vcpkg_using_vcpkg_find_ffmpeg) + +set(FFMPEG_LIBRARY ${FFMPEG_LIBRARIES}) + +set(CMAKE_MODULE_PATH ${FFMPEG_PREV_MODULE_PATH}) + +unset(vcpkg_no_avcodec_target) +unset(vcpkg_no_avformat_target) +unset(vcpkg_no_avutil_target) +unset(vcpkg_no_swresample_target) diff --git a/portfiles/ffmpeg/vcpkg.json b/portfiles/ffmpeg/vcpkg.json new file mode 100644 index 000000000..c769a95fc --- /dev/null +++ b/portfiles/ffmpeg/vcpkg.json @@ -0,0 +1,754 @@ +{ + "name": "ffmpeg", + "version": "7.1.2", + "port-version": 5, + "description": [ + "A library to decode, encode, transcode, mux, demux, stream, filter and play pretty much anything that humans and machines have created.", + "FFmpeg is the leading multimedia framework, able to decode, encode, transcode, mux, demux, stream, filter and play pretty much anything that humans and machines have created. It supports the most obscure ancient formats up to the cutting edge. No matter if they were designed by some standards committee, the community or a corporation. It is also highly portable: FFmpeg compiles, runs, and passes our testing infrastructure FATE across Linux, Mac OS X, Microsoft Windows, the BSDs, Solaris, etc. under a wide variety of build environments, machine architectures, and configurations." + ], + "homepage": "https://ffmpeg.org", + "license": null, + "dependencies": [ + { + "name": "vcpkg-cmake-get-vars", + "host": true + }, + { + "name": "vcpkg-pkgconfig-get-modules", + "host": true + } + ], + "default-features": [ + "avcodec", + "avdevice", + "avfilter", + "avformat", + "swresample", + "swscale" + ], + "features": { + "all": { + "description": "Build with all allowed dependencies selected that are compatible with the lgpl license", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "sdl2" + ] + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "aom", + "avcodec", + "avdevice", + "avfilter", + "avformat", + "bzip2", + "freetype", + "iconv", + "lzma", + "mp3lame", + "openjpeg", + "openmpt", + "opus", + "snappy", + "soxr", + "speex", + "swresample", + "swscale", + "theora", + "vorbis", + "vpx", + "vulkan", + "webp", + "xml2", + "zlib" + ] + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "alsa" + ], + "platform": "linux" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "ass" + ], + "platform": "!uwp" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "fontconfig" + ], + "platform": "!uwp" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "fribidi" + ], + "platform": "!uwp" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "modplug" + ], + "platform": "!uwp" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "openh264" + ], + "platform": "!uwp" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "srt" + ], + "platform": "!uwp" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "ilbc" + ], + "platform": "!(arm & uwp)" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "ssh" + ], + "platform": "!(uwp | arm)" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "amf" + ], + "platform": "!osx & !uwp" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "opencl" + ], + "platform": "!uwp & !osx" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "opengl" + ], + "platform": "!uwp & !(arm64 & windows)" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "tensorflow" + ], + "platform": "x64 & !static & !uwp & !windows" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "dav1d" + ], + "platform": "!(uwp | (windows & x86 & !static))" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "tesseract" + ], + "platform": "!(windows & arm) & !static & !uwp" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "qsv" + ], + "platform": "linux | (!osx & !uwp & !(arm & windows))" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "nvcodec" + ], + "platform": "linux | (!osx & !uwp & !(arm64 & windows))" + } + ] + }, + "all-gpl": { + "description": "Build with all allowed dependencies selected that are compatible with the gpl license", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "all", + "gpl", + "postproc" + ] + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "x264" + ], + "platform": "!(arm & windows)" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "x265" + ], + "platform": "!uwp & !(arm & windows)" + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "avisynthplus" + ], + "platform": "windows & !arm & !uwp & !static" + } + ] + }, + "all-nonfree": { + "description": "Build with all allowed dependencies selected with a non-redistributable license", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "all-gpl", + "fdk-aac", + "nonfree", + "openssl" + ] + } + ] + }, + "alsa": { + "description": "Enable ALSA support", + "dependencies": [ + "alsa" + ] + }, + "amf": { + "description": "AMD AMF codec support", + "dependencies": [ + "amd-amf" + ] + }, + "aom": { + "description": "AV1 video encoding/decoding via libaom support in ffmpeg", + "dependencies": [ + "aom" + ] + }, + "ass": { + "description": "Libass subtitles rendering, needed for subtitles and ass filter support in ffmpeg", + "dependencies": [ + "libass" + ] + }, + "avcodec": { + "description": "Build the avcodec library" + }, + "avdevice": { + "description": "Build the avdevice library", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "avcodec", + "avformat" + ] + } + ] + }, + "avfilter": { + "description": "Build the avfilter library" + }, + "avformat": { + "description": "Build the avformat library", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "avcodec" + ] + } + ] + }, + "avisynthplus": { + "description": "Reading of AviSynth script files", + "supports": "windows & !static", + "dependencies": [ + "avisynthplus", + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "gpl" + ] + } + ] + }, + "avresample": { + "description": "Build the avresample library" + }, + "bzip2": { + "description": "Bzip2 support", + "dependencies": [ + "bzip2" + ] + }, + "dav1d": { + "description": "AV1 decoding via libdav1d", + "dependencies": [ + "dav1d" + ] + }, + "drawtext": { + "description": "Enable the drawtext filter", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "freetype" + ] + }, + "harfbuzz" + ] + }, + "dvdvideo": { + "description": "DVD-Video demuxer", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "gpl" + ] + }, + "libdvdnav", + "libdvdread" + ] + }, + "fdk-aac": { + "description": "AAC de/encoding via libfdk-aac, **including GPL-incompatible patent-encumbered HE-AAC**. If you do not require HE-AAC, use the built-in FFmpeg AAC codec.", + "dependencies": [ + { + "name": "fdk-aac", + "default-features": false, + "features": [ + "he-aac" + ] + }, + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "nonfree" + ] + } + ] + }, + "ffmpeg": { + "description": "Build the ffmpeg application", + "supports": "!uwp", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "avcodec", + "avfilter", + "avformat" + ] + } + ] + }, + "ffplay": { + "description": "Build the ffplay application", + "supports": "!uwp", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "avcodec", + "avfilter", + "avformat", + "sdl2", + "swresample", + "swscale" + ] + } + ] + }, + "ffprobe": { + "description": "Build the ffprobe application", + "supports": "!uwp", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "avcodec", + "avformat" + ] + } + ] + }, + "fontconfig": { + "description": "Useful for drawtext filter", + "dependencies": [ + "fontconfig" + ] + }, + "freetype": { + "description": "Needed for drawtext filter", + "dependencies": [ + "freetype" + ] + }, + "fribidi": { + "description": "Improves drawtext filter", + "dependencies": [ + "fribidi" + ] + }, + "gpl": { + "description": "Allow use of GPL code, the resulting libs and binaries will be under GPL" + }, + "iconv": { + "description": "Iconv support", + "dependencies": [ + "libiconv" + ] + }, + "ilbc": { + "description": "iLBC de/encoding via libilbc", + "dependencies": [ + "libilbc" + ] + }, + "lzma": { + "description": "lzma support", + "dependencies": [ + "liblzma" + ] + }, + "modplug": { + "description": "ModPlug via libmodplug", + "dependencies": [ + "libmodplug" + ] + }, + "mp3lame": { + "description": "MP3 encoding via libmp3lame", + "dependencies": [ + "mp3lame" + ] + }, + "nonfree": { + "description": "Allow use of nonfree code, the resulting libs and binaries will be unredistributable" + }, + "nvcodec": { + "description": "Nvidia video decoding/encoding acceleration", + "supports": "linux | (!osx & !uwp & !(arm64 & windows))", + "dependencies": [ + "ffnvcodec" + ] + }, + "opencl": { + "description": "OpenCL processing", + "supports": "!uwp", + "dependencies": [ + "opencl" + ] + }, + "opengl": { + "description": "OpenGL rendering", + "supports": "!uwp", + "dependencies": [ + "opengl", + "opengl-registry" + ] + }, + "openh264": { + "description": "H.264 de/encoding via openh264", + "dependencies": [ + "openh264" + ] + }, + "openjpeg": { + "description": "JPEG 2000 de/encoding via OpenJPEG", + "dependencies": [ + "openjpeg" + ] + }, + "openmpt": { + "description": "Decoding tracked files via libopenmpt", + "dependencies": [ + "libopenmpt" + ] + }, + "openssl": { + "description": "Needed for https support if gnutls, libtls or mbedtls is not used", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "version3" + ] + }, + "openssl" + ] + }, + "opus": { + "description": "Opus de/encoding via libopus", + "dependencies": [ + "opus" + ] + }, + "postproc": { + "description": "Build the postproc library", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "gpl" + ] + } + ] + }, + "qsv": { + "description": "Intel QSV Codec", + "dependencies": [ + "mfx-dispatch" + ] + }, + "rubberband": { + "description": "Enable rubberband support", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "gpl" + ] + }, + "rubberband" + ] + }, + "sdl2": { + "description": "Sdl2 support", + "dependencies": [ + { + "name": "sdl2", + "default-features": false, + "features": [ + "x11" + ], + "platform": "linux" + }, + { + "name": "sdl2", + "platform": "!linux" + } + ] + }, + "snappy": { + "description": "Snappy compression, needed for hap encoding", + "dependencies": [ + "snappy" + ] + }, + "soxr": { + "description": "Include libsoxr resampling", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "swresample" + ] + }, + "soxr" + ] + }, + "speex": { + "description": "Speex de/encoding via libspeex", + "dependencies": [ + "speex" + ] + }, + "srt": { + "description": "Haivision SRT protocol", + "supports": "!uwp", + "dependencies": [ + "libsrt" + ] + }, + "ssh": { + "description": "SFTP protocol via libssh", + "dependencies": [ + "libssh" + ] + }, + "swresample": { + "description": "Build the swresample library" + }, + "swscale": { + "description": "Build the swscale library" + }, + "tensorflow": { + "description": "TensorFlow as a DNN module backend for DNN based filters like sr", + "supports": "!static", + "dependencies": [ + "tensorflow" + ] + }, + "tesseract": { + "description": "Tesseract, needed for ocr filter", + "supports": "!static", + "dependencies": [ + "tesseract" + ] + }, + "theora": { + "description": "Theora encoding via libtheora", + "dependencies": [ + "libtheora" + ] + }, + "vaapi": { + "description": "VAAPI video decoding/encoding acceleration", + "supports": "linux", + "dependencies": [ + { + "name": "libva", + "default-features": false, + "platform": "linux" + } + ] + }, + "version3": { + "description": "Upgrade (L)GPL to version 3" + }, + "vorbis": { + "description": "Vorbis en/decoding via libvorbis, native implementation exists", + "dependencies": [ + "libvorbis" + ] + }, + "vpx": { + "description": "VP8 and VP9 de/encoding via libvpx", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "avcodec" + ] + }, + "libvpx" + ] + }, + "vulkan": { + "description": "H.264, HEVC and AV1 de/encoding via Vulkan", + "dependencies": [ + "vulkan-headers" + ] + }, + "webp": { + "description": "WebP encoding via libwebp", + "dependencies": [ + "libwebp" + ] + }, + "x264": { + "description": "H.264 encoding via x264", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "gpl" + ] + }, + "x264" + ] + }, + "x265": { + "description": "HEVC encoding via x265", + "dependencies": [ + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "gpl" + ] + }, + "x265" + ] + }, + "xml2": { + "description": "XML parsing using the C library libxml2, needed for dash demuxing support", + "dependencies": [ + "libxml2" + ] + }, + "zlib": { + "description": "zlib support", + "dependencies": [ + "zlib" + ] + }, + "zmq": { + "description": "Enable ZeroMQ support", + "dependencies": [ + "zeromq" + ] + } + } +} From 542947d4069afb23f01ad0d227fc28fb557a5deb Mon Sep 17 00:00:00 2001 From: owenisas Date: Fri, 23 Oct 2026 16:30:30 +0800 Subject: [PATCH 5/5] Add STEINS;GATE 0 profile, instruction set and title menu --- CMakeLists.txt | 12 + profiles/sg0/charset.lua | 49 ++ profiles/sg0/dialogue.lua | 175 ++++++ profiles/sg0/font.lua | 57 ++ profiles/sg0/game.lua | 63 ++ profiles/sg0/hud/backlogmenu.lua | 42 ++ profiles/sg0/hud/datedisplay.lua | 178 ++++++ profiles/sg0/hud/loadingdisplay.lua | 78 +++ profiles/sg0/hud/saveicon.lua | 30 + profiles/sg0/hud/selectiondisplay.lua | 75 +++ profiles/sg0/hud/sysmesboxdisplay.lua | 25 + profiles/sg0/hud/tipsnotification.lua | 3 + profiles/sg0/hud/titlemenu.lua | 56 ++ profiles/sg0/movie.cls | 33 ++ profiles/sg0/savedata.lua | 37 ++ profiles/sg0/scriptvars.lua | 25 + profiles/sg0/sprites.lua | 47 ++ profiles/sg0/tipssystem.lua | 7 + profiles/sg0/vfs.lua | 21 + profiles/sg0/waveeffects.lua | 4 + src/background2d.cpp | 3 + src/data/savesystem.cpp | 3 +- src/game.cpp | 5 + src/games/sg0/backlogmenu.cpp | 91 +++ src/games/sg0/backlogmenu.h | 23 + src/games/sg0/sysmesbox.cpp | 180 ++++++ src/games/sg0/sysmesbox.h | 33 ++ src/games/sg0/titlemenu.cpp | 202 +++++++ src/games/sg0/titlemenu.h | 38 ++ src/profile/fonts.cpp | 7 +- src/profile/games/sg0/backlogmenu.cpp | 31 + src/profile/games/sg0/backlogmenu.h | 21 + src/profile/games/sg0/sysmesbox.cpp | 33 ++ src/profile/games/sg0/sysmesbox.h | 25 + src/profile/games/sg0/titlemenu.cpp | 47 ++ src/profile/games/sg0/titlemenu.h | 30 + src/profile/sprites.cpp | 53 +- src/profile/ui/backlogmenu.cpp | 5 + src/profile/ui/backlogmenu.h | 1 + src/profile/ui/sysmesbox.cpp | 3 + src/profile/ui/titlemenu.cpp | 3 + src/text/fonts/font.h | 12 + src/ui/ui.h | 2 + src/vm/inst_controlflow.cpp | 61 ++ src/vm/inst_controlflow.h | 2 + src/vm/inst_dialogue.cpp | 6 +- src/vm/inst_gamespecific.cpp | 109 ++++ src/vm/inst_gamespecific.h | 4 + src/vm/inst_misc.cpp | 14 + src/vm/inst_system.cpp | 4 +- src/vm/opcodetables_sg0.h | 799 ++++++++++++++++++++++++++ src/vm/vm.cpp | 7 + src/vm/vm.h | 1 + 53 files changed, 2868 insertions(+), 7 deletions(-) create mode 100644 profiles/sg0/charset.lua create mode 100644 profiles/sg0/dialogue.lua create mode 100644 profiles/sg0/font.lua create mode 100644 profiles/sg0/game.lua create mode 100644 profiles/sg0/hud/backlogmenu.lua create mode 100644 profiles/sg0/hud/datedisplay.lua create mode 100644 profiles/sg0/hud/loadingdisplay.lua create mode 100644 profiles/sg0/hud/saveicon.lua create mode 100644 profiles/sg0/hud/selectiondisplay.lua create mode 100644 profiles/sg0/hud/sysmesboxdisplay.lua create mode 100644 profiles/sg0/hud/tipsnotification.lua create mode 100644 profiles/sg0/hud/titlemenu.lua create mode 100644 profiles/sg0/movie.cls create mode 100644 profiles/sg0/savedata.lua create mode 100644 profiles/sg0/scriptvars.lua create mode 100644 profiles/sg0/sprites.lua create mode 100644 profiles/sg0/tipssystem.lua create mode 100644 profiles/sg0/vfs.lua create mode 100644 profiles/sg0/waveeffects.lua create mode 100644 src/games/sg0/backlogmenu.cpp create mode 100644 src/games/sg0/backlogmenu.h create mode 100644 src/games/sg0/sysmesbox.cpp create mode 100644 src/games/sg0/sysmesbox.h create mode 100644 src/games/sg0/titlemenu.cpp create mode 100644 src/games/sg0/titlemenu.h create mode 100644 src/profile/games/sg0/backlogmenu.cpp create mode 100644 src/profile/games/sg0/backlogmenu.h create mode 100644 src/profile/games/sg0/sysmesbox.cpp create mode 100644 src/profile/games/sg0/sysmesbox.h create mode 100644 src/profile/games/sg0/titlemenu.cpp create mode 100644 src/profile/games/sg0/titlemenu.h create mode 100644 src/vm/opcodetables_sg0.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c02efeac..61cac35a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,6 +145,9 @@ set(Impacto_Src src/profile/games/cc/backlogmenu.cpp src/profile/games/cc/dialoguebox.cpp src/profile/games/cc/titlemenu.cpp + src/profile/games/sg0/titlemenu.cpp + src/profile/games/sg0/sysmesbox.cpp + src/profile/games/sg0/backlogmenu.cpp src/profile/games/cc/sysmesbox.cpp src/profile/games/cclcc/systemmenu.cpp @@ -212,6 +215,9 @@ set(Impacto_Src src/games/cc/backlogmenu.cpp src/games/cc/titlemenu.cpp + src/games/sg0/titlemenu.cpp + src/games/sg0/sysmesbox.cpp + src/games/sg0/backlogmenu.cpp src/games/cc/sysmesbox.cpp src/games/cclcc/commonmenu.cpp @@ -522,6 +528,9 @@ set(Impacto_Header src/profile/games/cc/backlogmenu.h src/profile/games/cc/dialoguebox.h src/profile/games/cc/titlemenu.h + src/profile/games/sg0/titlemenu.h + src/profile/games/sg0/sysmesbox.h + src/profile/games/sg0/backlogmenu.h src/profile/games/cc/sysmesbox.h src/profile/games/cclcc/titlemenu.h @@ -586,6 +595,9 @@ set(Impacto_Header src/games/chlcc/introsequence.h src/games/cc/titlemenu.h + src/games/sg0/titlemenu.h + src/games/sg0/sysmesbox.h + src/games/sg0/backlogmenu.h src/games/cc/sysmesbox.h src/games/cclcc/commonmenu.h diff --git a/profiles/sg0/charset.lua b/profiles/sg0/charset.lua new file mode 100644 index 000000000..4c16f558e --- /dev/null +++ b/profiles/sg0/charset.lua @@ -0,0 +1,49 @@ +-- Same glyph order as CHAOS;CHILD Love Chu Chu's charset. +include(root.BasePaths.RootProfilesDir .. '/common/charset.lua'); +include(root.BasePaths.RootProfilesDir .. '/cclcc/charset.lua'); +local characterToSc3 = root.Charset.CharacterToSc3; + +root.Charset = { + Flags = {}, + CharacterToSc3 = characterToSc3 +}; + +for i = 0, (64 * 117) - 1 do root.Charset.Flags[i] = 0; end + +local spaces = {[0]=0, 63}; +for i = 0, #spaces do + root.Charset.Flags[spaces[i]] = root.Charset.Flags[spaces[i]] | CharacterTypeFlags.Space; +end + +-- 、 。 . , ? ! 〜 ” ー ) 〕 ] } 〉 》 」 』 】☆ ★ ♪ 々 ぁ ぃ ぅ ぇ +-- ぉ っ ゃ ゅ ょ ァ ィ ゥ ェ ォ ッ ャ ュ ョ – +local wordEndingPuncts = { + [0]=0x00BE, 0x00BF, 0x00C1, + 0x00C0, 0x00C4, 0x00C5, + 0x00E4, 0x00CB, 0x00E5, + 0x00CD, 0x00CF, 0x00D1, + 0x00D3, 0x00D5, 0x00D7, + 0x00D9, 0x00DB, 0x00DD, + 0x01A5, 0x01A6, 0x00E6, + 0x0187, 0x00E8, 0x00E9, + 0x00EA, 0x00EB, 0x00EC, + 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F2, 0x00F3, + 0x00F4, 0x00F5, 0x00F6, + 0x00F7, 0x00F8, 0x00F9, + 0x00FA, 0x0113 +}; +for i = 0, #wordEndingPuncts do + root.Charset.Flags[wordEndingPuncts[i]] = root.Charset.Flags[wordEndingPuncts[i]] | CharacterTypeFlags.WordEndingPunct; +end + +-- space(63) space(0) “ ( 〔 [ { 〈 《 「 +local wordStartingPuncts = { + [0]=63, 0, 0x00CA, + 0x00CC, 0x00CE, 0x00D0, + 0x00D2, 0x00D4, 0x00D6, + 0x00D8, 0x00DA, 0x00DC +}; +for i = 0, #wordStartingPuncts do + root.Charset.Flags[wordStartingPuncts[i]] = root.Charset.Flags[wordStartingPuncts[i]] | CharacterTypeFlags.WordStartingPunct; +end \ No newline at end of file diff --git a/profiles/sg0/dialogue.lua b/profiles/sg0/dialogue.lua new file mode 100644 index 000000000..4f1337b97 --- /dev/null +++ b/profiles/sg0/dialogue.lua @@ -0,0 +1,175 @@ +root.Sprites["ADVBox"] = { + Sheet = "MesBox", + Bounds = { X = 0, Y = 884, Width = 1920, Height = 328 } +}; + +root.Sprites["ADVBoxMask"] = { + Sheet = "MesBox", + Bounds = { X = 0, Y = 1212, Width = 1920, Height = 328 } +}; + +root.Sprites["WaitIconSprite"] = { + Sheet = "Data", + Bounds = { X = 1, Y = 456, Width = 112, Height = 64 }, +}; + +root.Dialogue = { + TipsMessageModeIdx = 7, + + REVMessageModeIdx = 9, + REVColor = 0, + REVNameColor = 61, -- Unsure + REVOutlineMode = 1, + REVNameOutlineMode = 1, + ADVBoxSprite = "ADVBox", + ADVBoxMask = "ADVBoxMask", + ADVBoxEffectDuration = 10, + ADVBoxPos = { X = 0, Y = 752 }, + FadeOutDuration = 0.33, + FadeInDuration = 0.33, + TextFadeInDuration = 0.33, + TextFadeOutDuration = 0.33, + DialogueBoxCurrentType = DialogueBoxType.CC, + NVLBoxMaxOpacity = 0.55, + + NametagCurrentType = NametagType.None, + + NametagMainSprites = {}, + NametagLabelSprites = {}, + + NametagMainPos = { X = -1, Y = 764 }, + NametagLabelPos = { X = 0, Y = 988 }, + + NametagShowDuration = 16 / 60; + + WaitIconCurrentType = WaitIconType.None, + + AutoIconCurrentType = AutoIconType.None, -- Not mapped yet + AutoIconSpriteAnim = "AutoIconSpriteAnim", + AutoIconOffset = { X = 1570, Y = 696 }, + SkipIconCurrentType = SkipIconType.None, -- Not mapped yet + SkipIconSpriteAnim = "SkipIconSpriteAnim", + SkipIconOffset = { X = 1712, Y = 702 }, + DialogueFont = "Default", + SetFontSizeRatio = 800.0, + DefaultFontSize = 48, + ColorTable = { + {0xFFFFFF, 0x000000}, {0x5080FF, 0x000000}, + {0xFF7080, 0x000000}, {0xFFA0F8, 0x000000}, + {0x46FF80, 0x000000}, {0x90FFFF, 0x000000}, + {0xFFFF70, 0x000000}, {0x80FFC0, 0x000000}, + {0xFFB080, 0x000000}, {0xB080FF, 0x000000}, + {0x000000, 0x808080}, {0x000000, 0x5080FF}, + {0x000000, 0xFF7080}, {0x000000, 0xFFA0F8}, + {0x000000, 0x268840}, {0x000000, 0x409999}, + {0x000000, 0x888830}, {0x000000, 0x80FFC0}, + {0x000000, 0xFFB080}, {0x000000, 0xB080FF}, + {0xD0D0D0, 0x000000}, {0xD0D0FF, 0x000000}, + {0xFFD0D0, 0x000000}, {0xFFD0FF, 0x000000}, + {0xD0FFD0, 0x000000}, {0xD0FFFF, 0x000000}, + {0xFFFFD0, 0x000000}, {0xE8FFD0, 0x000000}, + {0xFFE8D0, 0x000000}, {0xD0E8FF, 0x000000}, + {0xFFFFFF, 0x808080}, {0xFFFFFF, 0x5080FF}, + {0xFFFFFF, 0xFF7080}, {0xFFFFFF, 0xFFA0F8}, + {0xFFFFFF, 0x46FF80}, {0xFFFFFF, 0x90FFFF}, + {0xFFFFFF, 0xFFFF70}, {0xFFFFFF, 0x80FFC0}, + {0xFFFFFF, 0xFFB080}, {0xFFFFFF, 0xB080FF}, + {0xFFEEEE, 0x000000}, {0xFFCCCC, 0x000000}, + {0xFFAAAA, 0x000000}, {0xFF9999, 0x000000}, + {0xFF8888, 0x000000}, {0xFFFF00, 0x000000}, + {0xFEF000, 0x000000}, {0xFF7777, 0x000000}, + {0xFF6666, 0x000000}, {0xFF5555, 0x000000}, + {0xFF4444, 0x000000}, {0xFF3333, 0x000000}, + {0xFF2222, 0x000000}, {0xFF0000, 0x000000}, + {0xDD0000, 0x000000}, {0xBB0000, 0x000000}, + {0xB00000, 0x000000}, {0xAA0000, 0x000000}, + {0x950000, 0x000000}, {0x808080, 0x000000}, + {0xAAAAAA, 0x000000}, {0xAAC1C9, 0x000000}, + {0x000000, 0x000000}, {0x000000, 0x000000}, + {0x000000, 0x000000}, {0x000000, 0x000000}, + {0x000000, 0x000000}, {0xF80B0B, 0x000000}, + {0xF8910B, 0x000000}, {0x33F12A, 0x000000} + }, + MaxPageSize = 2000, + PageCount = 3, + ColorTagIsUint8 = false, +}; + +MakeAnimation({ + Name = "SkipIconSpriteAnim", + Sheet = "Data", + FirstFrameX = 0, + FirstFrameY = 812, + FrameWidth = 160, + ColWidth = 160, + FrameHeight = 154, + RowHeight = 154, + Frames = 9, + Duration = 0.7, + Rows = 1, + Columns = 9, + PrimaryDirection = AnimationDirections.Right +}); + +MakeAnimation({ + Name = "AutoIconSpriteAnim", + Sheet = "Data", + FirstFrameX = 0, + FirstFrameY = 966, + FrameWidth = 160, + ColWidth = 160, + FrameHeight = 154, + RowHeight = 154, + Frames = 9, + Duration = 0.7, + Rows = 1, + Columns = 9, + PrimaryDirection = AnimationDirections.Right +}); + +local nametagMainX = 0; +local nametagMainY = 0; +local nametagLabelX = 3600; +local nametagLabelY = 0; +local nametagMainWidth = 448; +local nametagMainHeight = 218; +local nametagLabelWidth = 240; +local nametagLabelHeight = 40; + +for i = 1, 80 do + root.Sprites["NametagMainSprite" .. i] = { + Sheet = "NamePlate", + Bounds = { + X = nametagMainX, + Y = nametagMainY, + Width = nametagMainWidth, + Height = nametagMainHeight + } + }; + root.Dialogue.NametagMainSprites[#root.Dialogue.NametagMainSprites + 1] = "NametagMainSprite" .. i; + + if i % 8 == 0 then + nametagMainY = nametagMainY + nametagMainHeight; + nametagMainX = 0; + else + nametagMainX = nametagMainX + nametagMainWidth; + end + + root.Sprites["NametagLabelSprite" .. i] = { + Sheet = "NamePlate", + Bounds = { + X = nametagLabelX, + Y = nametagLabelY, + Width = nametagLabelWidth, + Height = nametagLabelHeight + } + }; + root.Dialogue.NametagLabelSprites[#root.Dialogue.NametagLabelSprites + 1] = "NametagLabelSprite" .. i; + + if i % 2 == 0 then + nametagLabelX = 3600; + nametagLabelY = nametagLabelY + nametagLabelHeight; + else + nametagLabelX = nametagLabelX + nametagLabelWidth; + end +end diff --git a/profiles/sg0/font.lua b/profiles/sg0/font.lua new file mode 100644 index 000000000..e867cacf0 --- /dev/null +++ b/profiles/sg0/font.lua @@ -0,0 +1,57 @@ +root.Fonts = { + ["Default"] = { + Type = FontType.SingleSheet, + Sheet = "Font", + GridSize = { X = 64, Y = 125 }, + AdvanceWidthsTable = {}, + }, + + ["LanguageBarrier"] = { + Type = FontType.LanguageBarrier, + ForegroundSheet = "FontLBForeground", + OutlineSheet = "FontLBOutline", + ForegroundGridSize = { X = 64, Y = 125 }, + AdvanceWidthsBinary = { + Path = "resources/cc/font-lb/widths.bin", + BytesPerGlyph = 1, + EmWidth = 48, + }, + OutlineOffset = { X = -4, Y = -4 }, + } +}; + +root.SpriteSheets["FontLBForeground"] = { + Path = "resources/cc/font-lb/foreground.png", + DesignWidth = 3072, + DesignHeight = 6000 +}; + +root.SpriteSheets["FontLBOutline"] = { + Path = "resources/cc/font-lb/outline.png", + DesignWidth = 3648, + DesignHeight = 7128 +}; + +-- {left bearing, advance} for glyph rows 0-6 (Latin, digits, punctuation). +-- Other glyphs use the full 48 px cell. +local glyphMetrics = { + [1]={0,15}, [2]={0,25}, [3]={5,14}, [4]={0,24}, [5]={0,24}, [6]={0,26}, [7]={0,24}, [8]={0,25}, [9]={0,25}, [10]={0,25}, [11]={0,24}, [12]={0,27}, [13]={0,26}, [14]={0,28}, [15]={0,28}, [16]={2,23}, [17]={2,22}, [18]={0,27}, [19]={0,28}, [20]={7,10}, [21]={1,21}, [22]={0,27}, [23]={1,23}, [24]={0,28}, [25]={0,27}, [26]={0,27}, [27]={0,25}, [28]={0,27}, [29]={0,27}, [30]={0,24}, [31]={0,27}, [32]={0,27}, [33]={0,27}, [34]={0,48}, [35]={0,26}, [36]={0,27}, [37]={0,26}, [38]={1,25}, [39]={0,28}, [40]={0,27}, [41]={0,28}, [42]={0,28}, [43]={3,21}, [44]={0,28}, [45]={1,25}, [46]={8,11}, [47]={4,15}, [48]={0,26}, [49]={8,11}, [50]={0,28}, [51]={1,26}, [52]={0,27}, [53]={0,28}, [54]={0,29}, [55]={6,19}, [56]={1,25}, [57]={3,21}, [58]={0,26}, [59]={0,28}, [60]={0,28}, [61]={0,28}, [62]={0,27}, [63]={1,25}, [64]={0,15}, + [65]={0,27}, [66]={7,11}, [67]={1,21}, [68]={8,11}, [69]={8,11}, [70]={0,26}, [71]={8,11}, [72]={8,11}, [73]={0,27}, [74]={0,27}, [75]={0,26}, [76]={1,25}, [77]={3,20}, [78]={0,26}, [79]={5,16}, [80]={5,17}, [81]={6,16}, [82]={6,13}, [83]={0,27}, [84]={1,25}, [85]={0,28}, [86]={1,25}, [87]={1,24}, [88]={6,15}, [89]={0,26}, [90]={4,20}, [91]={0,25}, [92]={7,12}, [93]={6,13}, [94]={4,15}, [95]={1,23}, [96]={6,16}, [97]={0,29}, [98]={3,18}, [99]={8,9}, [100]={6,18}, [101]={0,15}, [102]={0,15}, [103]={0,15}, [104]={0,15}, [105]={0,15}, [106]={0,15}, [107]={0,15}, [108]={0,15}, [109]={0,15}, [110]={0,15}, [111]={0,15}, [112]={0,15}, [113]={0,15}, [114]={0,15}, [115]={0,15}, [116]={0,15}, [117]={0,15}, [118]={0,15}, [119]={0,15}, [120]={0,15}, [121]={0,15}, [122]={0,15}, [123]={0,15}, [124]={0,15}, [125]={0,15}, [126]={0,15}, [127]={0,15}, [128]={0,15}, + [129]={2,31}, [130]={2,17}, [131]={2,29}, [132]={2,29}, [133]={2,31}, [134]={2,29}, [135]={2,29}, [136]={2,29}, [137]={2,31}, [138]={2,29}, [139]={1,39}, [140]={2,30}, [141]={2,33}, [142]={2,34}, [143]={2,29}, [144]={2,27}, [145]={2,35}, [146]={2,31}, [147]={2,11}, [148]={2,25}, [149]={2,30}, [150]={2,27}, [151]={2,41}, [152]={2,33}, [153]={2,37}, [154]={2,29}, [155]={2,39}, [156]={2,31}, [157]={1,31}, [158]={2,33}, [159]={2,33}, [160]={2,35}, [161]={1,47}, [162]={1,37}, [163]={2,37}, [164]={2,29}, [165]={2,25}, [166]={1,29}, [167]={2,27}, [168]={2,29}, [169]={2,29}, [170]={2,21}, [171]={2,29}, [172]={3,25}, [173]={2,11}, [174]={2,15}, [175]={2,26}, [176]={2,11}, [177]={2,43}, [178]={3,26}, [179]={2,29}, [180]={2,29}, [181]={1,29}, [182]={2,19}, [183]={2,25}, [184]={2,21}, [185]={2,26}, [186]={2,29}, [187]={1,47}, [188]={2,31}, [189]={3,29}, [190]={2,25}, [191]={0,18}, [192]={0,18}, + [193]={1,11}, [194]={1,11}, [195]={3,11}, [196]={3,11}, [197]={1,31}, [198]={3,11}, [199]={0,17}, [200]={0,15}, [201]={2,11}, [202]={2,11}, [203]={1,19}, [204]={1,18}, [205]={2,19}, [206]={2,19}, [207]={1,19}, [208]={1,19}, [209]={1,18}, [210]={1,19}, [211]={1,17}, [212]={1,18}, [213]={1,23}, [214]={1,22}, [215]={1,25}, [216]={1,25}, [217]={1,19}, [218]={1,19}, [219]={0,23}, [220]={1,22}, [221]={0,19}, [222]={1,18}, [223]={1,39}, [224]={1,39}, [225]={0,19}, [226]={0,18}, [227]={6,15}, [228]={3,44}, [229]={0,48}, [230]={2,46}, [231]={8,34}, [232]={0,48}, [233]={1,37}, [234]={2,35}, [235]={2,30}, [236]={2,37}, [237]={2,37}, [238]={2,37}, [239]={2,39}, [240]={2,35}, [241]={2,35}, [242]={2,39}, [243]={2,37}, [244]={2,34}, [245]={2,33}, [246]={2,37}, [247]={2,37}, [248]={2,37}, [249]={2,39}, [250]={1,39}, [251]={2,31}, [252]={2,33}, [253]={2,35}, [254]={2,38}, [255]={0,48}, [256]={0,48}, + [257]={0,48}, [258]={0,48}, [259]={0,48}, [260]={0,48}, [261]={0,48}, [262]={0,48}, [263]={0,48}, [264]={0,48}, [265]={0,48}, [266]={0,48}, [267]={3,29}, [268]={2,19}, [269]={1,26}, [270]={2,15}, [271]={2,26}, [272]={2,29}, [273]={0,48}, [274]={0,29}, [275]={3,45}, [276]={0,48}, [277]={0,48}, [278]={0,48}, [279]={1,47}, [280]={11,28}, [281]={0,48}, [282]={0,48}, [283]={0,48}, [284]={0,48}, [285]={0,48}, [286]={0,48}, [287]={0,48}, [288]={0,48}, [289]={0,48}, [290]={0,48}, [291]={0,48}, [292]={0,48}, [293]={0,48}, [294]={0,48}, [295]={0,48}, [296]={0,48}, [297]={0,48}, [298]={0,48}, [299]={0,48}, [300]={0,48}, [301]={0,48}, [302]={0,48}, [303]={0,48}, [304]={0,48}, [305]={0,15}, [306]={2,29}, [307]={2,28}, [308]={0,48}, [309]={0,48}, [310]={0,48}, [311]={0,48}, [312]={0,48}, [313]={0,48}, [314]={0,48}, [315]={0,48}, [316]={0,48}, [317]={0,48}, [318]={0,48}, [319]={0,48}, [320]={0,48}, + [321]={0,48}, [322]={0,48}, [323]={0,48}, [324]={0,48}, [325]={0,48}, [326]={0,48}, [327]={0,48}, [328]={0,48}, [329]={0,48}, [330]={0,48}, [331]={0,48}, [332]={0,48}, [333]={0,48}, [334]={0,48}, [335]={0,48}, [336]={0,48}, [337]={0,48}, [338]={0,48}, [339]={0,48}, [340]={0,48}, [341]={0,48}, [342]={0,48}, [343]={0,48}, [344]={0,48}, [345]={0,48}, [346]={0,48}, [347]={0,48}, [348]={0,48}, [349]={0,48}, [350]={0,48}, [351]={0,48}, [352]={10,31}, [353]={9,33}, [354]={12,27}, [355]={11,30}, [356]={8,35}, [357]={12,27}, [358]={11,29}, [359]={8,34}, [360]={11,29}, [361]={12,27}, [362]={8,34}, [363]={10,31}, [364]={7,37}, [365]={6,39}, [366]={6,39}, [367]={0,48}, [368]={0,48}, [369]={16,19}, [370]={16,19}, [371]={0,48}, [372]={21,9}, [373]={0,48}, [374]={7,37}, [375]={15,21}, [376]={9,33}, [377]={11,28}, [378]={13,24}, [379]={11,29}, [380]={13,25}, [381]={10,31}, [382]={9,34}, [383]={11,29}, [384]={11,29}, + [385]={7,36}, [386]={12,26}, [387]={12,31}, [388]={12,28}, [389]={12,31}, [390]={13,25}, [391]={1,47}, [392]={6,37}, [393]={5,41}, [394]={2,46}, [395]={1,47}, [396]={4,43}, [397]={4,43}, [398]={4,43}, [399]={7,37}, [400]={4,43}, [401]={4,43}, [402]={4,43}, [403]={7,37}, [404]={7,37}, [405]={4,43}, [406]={4,43}, [407]={0,48}, [408]={6,39}, [409]={5,41}, [410]={7,37}, [411]={1,45}, [412]={8,35}, [413]={11,29}, [414]={12,27}, [415]={11,30}, [416]={3,45}, [417]={9,33}, [418]={6,39}, [419]={9,33}, [420]={5,41}, [421]={13,25}, [422]={2,46}, [423]={2,46}, [424]={1,47}, [425]={1,47}, [426]={1,47}, [427]={1,47}, [428]={0,48}, [429]={5,41}, [430]={5,41}, [431]={2,46}, [432]={2,46}, [433]={2,46}, [434]={2,46}, [435]={3,45}, [436]={4,43}, [437]={1,47}, [438]={1,47}, [439]={13,25}, [440]={13,25}, [441]={8,35}, [442]={4,43}, [443]={3,44}, [444]={4,43}, [445]={4,43}, [446]={4,43}, [447]={4,43}, [448]={8,35}, +} + +local font = root.Fonts["Default"]; +font.LeftBearingsTable = {}; +for i = 1, (64 * 125) do + local metric = glyphMetrics[i]; + if metric then + font.LeftBearingsTable[i] = metric[1]; + font.AdvanceWidthsTable[i] = metric[2]; + else + font.AdvanceWidthsTable[i] = 48; + end +end diff --git a/profiles/sg0/game.lua b/profiles/sg0/game.lua new file mode 100644 index 000000000..f9e02b3f3 --- /dev/null +++ b/profiles/sg0/game.lua @@ -0,0 +1,63 @@ + + +root.LayerCount = 100; +root.GameFeatures = GameFeature.Sc3VirtualMachine | GameFeature.Renderer2D | GameFeature.Input | GameFeature.Audio | GameFeature.Video; +root.DesignWidth = 1920; +root.DesignHeight = 1080; + +root.WindowName = "STEINS;GATE 0"; +root.WindowIconPath = "resources/cc/icondata/icon.png"; +root.CursorArrowPath = "resources/cc/icondata/cursor_arrow.png"; +root.CursorPointerPath = "resources/cc/icondata/cursor_pointer.png"; +root.UseMoviePriority = true; +root.UseWaveEffects = true; + +root.CharaIsMvl = false; +root.LayFileBigEndian = false; +root.LayFileTexXMultiplier = 1; +root.LayFileTexYMultiplier = 1; + +root.ScreenCaptureCount = 2; + +root.Vm = { + StartScript = 6, -- _Startup_win.scx + StartScriptBuffer = 0, + GameInstructionSet = InstructionSet.SG0, + UseReturnIds = true, + + ScrWorkChaStructSize = 40, + ScrWorkChaOffsetStructSize = 10, + ScrWorkBgStructSize = 40, + ScrWorkBgOffsetStructSize = 10, + ScrWorkCaptureStructSize = 20, + ScrWorkCaptureOffsetStructSize = 10, + ScrWorkCaptureEffectInfoStructSize = 3, + ScrWorkBgEffStructSize = 30, + ScrWorkBgEffOffsetStructSize = 20, + + MaxLinkedBgBuffers = 2 +}; + +root.PlatformId = 131072; + +include(root.BasePaths.RootProfilesDir .. '/common/scriptinput.lua'); +include(root.BasePaths.RootProfilesDir .. '/common/scriptvars.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/scriptvars.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/savedata.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/tipssystem.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/vfs.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/sprites.lua'); +include(root.BasePaths.RootProfilesDir .. '/common/animation.lua'); +include(root.BasePaths.RootProfilesDir .. '/common/achievementnotification.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/charset.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/font.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/dialogue.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/waveeffects.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/hud/saveicon.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/hud/loadingdisplay.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/hud/datedisplay.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/hud/titlemenu.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/hud/backlogmenu.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/hud/sysmesboxdisplay.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/hud/selectiondisplay.lua'); +include(root.BasePaths.RootProfilesDir .. '/sg0/hud/tipsnotification.lua'); diff --git a/profiles/sg0/hud/backlogmenu.lua b/profiles/sg0/hud/backlogmenu.lua new file mode 100644 index 000000000..909546503 --- /dev/null +++ b/profiles/sg0/hud/backlogmenu.lua @@ -0,0 +1,42 @@ +local sheet = "Backlog"; + +local function sprite(name, x, y, w, h) + root.Sprites[name] = { Sheet = sheet, Bounds = { X = x, Y = y, Width = w, Height = h } }; + return name; +end + +root.BacklogMenu = { + Type = BacklogMenuType.SG0, + DrawType = DrawComponentType.SystemMenu, + + BacklogBackgroundSprite = sprite("BacklogPanel", 160, 0, 1668, 1080), + PanelPos = { X = 126, Y = 0 }, + ShadeOpacity = 0.6, + + EntryHighlightLocation = EntryHighlightLocationType.None, + EntryHighlightSprite = "BacklogPanel", + EntryHighlightOffset = { X = 0, Y = 0 }, + EntryHighlightPadding = 8.0, + HighlightBounds = { X = 176, Y = 0, Width = 1568, Height = 0 }, + HighlightColor = 0xFFA040, + HighlightOpacity = 0.16, + + VoiceIconSprite = sprite("BacklogVoiceIcon", 1928, 116, 60, 48), + VoiceIconOffset = { X = -14, Y = 2 }, + + ScrollbarTrackSprite = sprite("BacklogScrollbarTrack", 1924, 1084, 28, 1084), + ScrollbarThumbSprite = sprite("BacklogScrollbarThumb", 1932, 8, 28, 92), + ScrollbarPosition = { X = 1808, Y = -2 }, + ScrollbarThumbLength = 92, + + -- Offset by text mode 9's window position (243 px). + EntriesStart = { X = 57, Y = 60 }, + RenderingBounds = { X = 126, Y = 40, Width = 1668, Height = 1000 }, + HoverBounds = { X = 230, Y = 40, Width = 1500, Height = 1000 }, + EntryYPadding = 24, + + FadeInDuration = 16 / 60, + FadeOutDuration = 16 / 60, + ScrollingSpeed = 900, + PageUpDownHeight = 900 +}; diff --git a/profiles/sg0/hud/datedisplay.lua b/profiles/sg0/hud/datedisplay.lua new file mode 100644 index 000000000..940299136 --- /dev/null +++ b/profiles/sg0/hud/datedisplay.lua @@ -0,0 +1,178 @@ +local sheet = "Data"; +local name = "Date"; + +local yearNumFirstX = 2287.5; +local yearNumFirstY = 94.5; +local yearNumWidth = 37.5; +local yearNum1Width = 12; +local yearNumHeight = 30; + +local numFirstX = 2286; +local numFirstY = 49.5; +local numWidth = 60; +local num1Width = 18; +local numHeight = 42; + +local weekFirstX = 2677.5; +local weekFirstY = 94.5; +local weekSecondX = 2287.5; +local weekSecondY = 127.5; +local weekWidth = 109.5; +local weekFriWidth = 84; +local weekHeight = 30; + +root.DateDisplay = { + Type = DateDisplayType.RNE, + YearNumSprites = {}, + MonthNumSprites = {}, + DayNumSprites = {}, + WeekSprites = {}, + BackgroundStartPos = { X = 1632, Y = 109.5 }, + BackgroundEndPos = { X = 1632 - 384, Y = 109.5 }, + DateStartX = 1750.5, + YearWeekY = 90, + MonthDayY = 78, + Spacing = 1.5, + FadeInDuration = 0.5, + FadeOutDuration = 0.5 +}; + +for i = 0, 9 do + local yearW; + if i == 1 then + yearW = yearNum1Width; + else + yearW = yearNumWidth; + end + + root.Sprites[name .. "YearNum" .. i] = { + Sheet = sheet, + Bounds = { + X = yearNumFirstX, + Y = yearNumFirstY, + Width = yearW, + Height = yearNumHeight + } + }; + root.DateDisplay.YearNumSprites[#root.DateDisplay.YearNumSprites + 1] = name .. "YearNum" .. i; + + local numW + if i == 1 then + numW = num1Width; + else + numW = numWidth; + end + + root.Sprites[name .. "Num" .. i] = { + Sheet = sheet, + Bounds = { + X = numFirstX, + Y = numFirstY, + Width = numW, + Height = numHeight + } + }; + root.DateDisplay.MonthNumSprites[#root.DateDisplay.MonthNumSprites + 1] = name .. "Num" .. i; + root.DateDisplay.DayNumSprites[#root.DateDisplay.DayNumSprites + 1] = name .. "Num" .. i; + + if i == 1 then + yearNumFirstX = yearNumFirstX + yearNum1Width; + numFirstX = numFirstX + num1Width; + else + yearNumFirstX = yearNumFirstX + yearNumWidth; + numFirstX = numFirstX + numWidth; + end +end + +for i = 0, 6 do + if i > 1 then + local weekW; + if i == 5 then + weekW = weekFriWidth; + else + weekW = weekWidth; + end + + root.Sprites[name .. "Week" .. i] = { + Sheet = sheet, + Bounds = { + X = weekSecondX, + Y = weekSecondY, + Width = weekW, + Height = weekHeight + } + }; + if i == 5 then + weekSecondX = weekSecondX + weekFriWidth; + else + weekSecondX = weekSecondX + weekWidth; + end + else + root.Sprites[name .. "Week" .. i] = { + Sheet = sheet, + Bounds = { + X = weekFirstX, + Y = weekFirstY, + Width = weekWidth, + Height = weekHeight + } + }; + weekFirstX = weekFirstX + weekWidth; + end + root.DateDisplay.WeekSprites[#root.DateDisplay.WeekSprites + 1] = name .. "Week" .. i; +end + +root.Sprites[name .. "MonthDaySeparator"] = { + Sheet = sheet, + Bounds = { + X = 2845.5, + Y = 49.5, + Width = 15, + Height = 42 + } +}; +root.DateDisplay.MDSeparatorSprite = name .. "MonthDaySeparator"; + +root.Sprites[name .. "DayYearSeparator"] = { + Sheet = sheet, + Bounds = { + X = 2637, + Y = 94.5, + Width = 12, + Height = 30 + } +}; +root.DateDisplay.DYSeparatorSprite = name .. "DayYearSeparator"; + +root.Sprites[name .. "OpenBracket"] = { + Sheet = sheet, + Bounds = { + X = 2649, + Y = 94.5, + Width = 12, + Height = 30 + } +}; +root.DateDisplay.OpenBracketSprite = name .. "OpenBracket"; + +root.Sprites[name .. "CloseBracket"] = { + Sheet = sheet, + Bounds = { + X = 2664, + Y = 94.5, + Width = 12, + Height = 30 + } +}; +root.DateDisplay.CloseBracketSprite = name .. "CloseBracket"; + +root.Sprites[name .. "Background"] = { + Sheet = sheet, + Bounds = { + X = 2287.5, + Y = 2, + Width = 675, + Height = 42 + } +}; +root.DateDisplay.BackgroundSprite = name .. "Background"; \ No newline at end of file diff --git a/profiles/sg0/hud/loadingdisplay.lua b/profiles/sg0/hud/loadingdisplay.lua new file mode 100644 index 000000000..f86c4eb55 --- /dev/null +++ b/profiles/sg0/hud/loadingdisplay.lua @@ -0,0 +1,78 @@ +root.LoadingDisplay = { + ResourceLoadBgAnim = "ResourceLoadingBg", + SaveLoadBgAnim = "SaveLoadingBg", + LoadingIconAnim = "LoadingDisc", + LoadingTextAnim = "LoadingText", + ResourceBgPos = { X = 1074, Y = 611 }, + SaveBgPos = { X = 1019, Y = 598 }, + IconPos = { X = 986, Y = 608 }, + TextPos = { X = 1025, Y = 628 }, + FadeInDuration = 0.66, + FadeOutDuration = 0.33 +}; + +MakeAnimation({ + Name = "ResourceLoadingBg", + Sheet = "Data", + FirstFrameX = 555, + FirstFrameY = 544, + FrameWidth = 206, + ColWidth = 206, + FrameHeight = 58, + RowHeight = 60, + Frames = 8, + Duration = 0.8, + Rows = 8, + Columns = 1, + PrimaryDirection = AnimationDirections.Down +}); + +MakeAnimation({ + Name = "SaveLoadingBg", + Sheet = "Data", + FirstFrameX = 388, + FirstFrameY = 0, + FrameWidth = 277, + ColWidth = 279, + FrameHeight = 81, + RowHeight = 83, + Frames = 4, + Duration = 0.8, + Rows = 2, + Columns = 2, + PrimaryDirection = AnimationDirections.Down, + SecondaryDirection = AnimationDirections.Right +}); + +MakeAnimation({ + Name = "LoadingDisc", + Sheet = "Data", + FirstFrameX = 172, + FirstFrameY = 1, + FrameWidth = 60, + ColWidth = 62, + FrameHeight = 60, + RowHeight = 62, + Frames = 3, + Duration = 0.8, + Rows = 1, + Columns = 3, + PrimaryDirection = AnimationDirections.Right +}); +root.Animations["LoadingDisc"].Frames[#root.Animations["LoadingDisc"].Frames + 1] = "LoadingDisc1"; + +MakeAnimation({ + Name = "LoadingText", + Sheet = "Data", + FirstFrameX = 173, + FirstFrameY = 91, + FrameWidth = 214, + ColWidth = 214, + FrameHeight = 21, + RowHeight = 23, + Frames = 5, + Duration = 0.8, + Rows = 5, + Columns = 1, + PrimaryDirection = AnimationDirections.Down +}); \ No newline at end of file diff --git a/profiles/sg0/hud/saveicon.lua b/profiles/sg0/hud/saveicon.lua new file mode 100644 index 000000000..789d4cfc5 --- /dev/null +++ b/profiles/sg0/hud/saveicon.lua @@ -0,0 +1,30 @@ +root.SaveIcon = { + ForegroundAnimation = "SaveIcon", + DefaultPosition = { X = 92, Y = 713 }, + BackgroundSprite = "SaveIconBg", + BackgroundOffset = { X = 0, Y = 0 }, + BackgroundMaxAlpha = 0.0, + FadeInDuration = 0.5, + FadeOutDuration = 0.25 +}; + +MakeAnimation({ + Name = "SaveIcon", + Sheet = "Data", + FirstFrameX = 115, + FirstFrameY = 456, + FrameWidth = 258, + ColWidth = 258, + FrameHeight = 178, + RowHeight = 178, + Frames = 2, + Duration = 0.4, + Rows = 2, + Columns = 1, + PrimaryDirection = AnimationDirections.Down +}); + +root.Sprites["SaveIconBg"] = { + Sheet = "Data", + Bounds = { X = 630, Y = 479, Width = 179, Height = 62 } +}; \ No newline at end of file diff --git a/profiles/sg0/hud/selectiondisplay.lua b/profiles/sg0/hud/selectiondisplay.lua new file mode 100644 index 000000000..33a038e05 --- /dev/null +++ b/profiles/sg0/hud/selectiondisplay.lua @@ -0,0 +1,75 @@ +root.SelectionDisplay = { + DrawType = DrawComponentType.Text, + SelectionBackgroundSprite = "SelectionBackground", + PlainSelectionFrameTopLeftSprite = "PlainSelectionFrameTopLeft", + PlainSelectionFrameTopSideSprite = "PlainSelectionFrameTopSide", + PlainSelectionFrameTopRightSprite = "PlainSelectionFrameTopRight", + PlainSelectionFrameLeftSideSprite = "PlainSelectionFrameLeftSide", + PlainSelectionFrameBottomLeftSprite = "PlainSelectionFrameBottomLeft", + PlainSelectionFrameRightSideSprite = "PlainSelectionFrameRightSide", + PlainSelectionFrameBottomRightSprite = "PlainSelectionFrameBottomRight", + PlainSelectionFrameBottomSideSprite = "PlainSelectionFrameBottomSide", + PlainSelectionFrameMiddleSprite = "PlainSelectionFrameMiddle", + SelectionHighlightSprite = "SelectionHighlight", + SelectionMaxCount = 5, + SelectionBackgroundX = 228, + SelectionBackgroundY = {277, 277, 196, 129, 95}, + SelectionYSpacing = 81, + PlainSelectionYSpacing = 10, + FadeAnimationDurationInOut = 0.2 +}; + +root.Sprites["SelectionBackground"] = { + Sheet = "Data", + Bounds = { X = 1, Y = 535, Width = 829, Height = 69 } +}; + +root.Sprites["PlainSelectionFrameTopLeft"] = { + Sheet = "Data", + Bounds = { X = 0, Y = 0, Width = 16, Height = 16 } +}; + +root.Sprites["PlainSelectionFrameTopSide"] = { + Sheet = "Data", + Bounds = { X = 16, Y = 0, Width = 16, Height = 16 } +}; + +root.Sprites["PlainSelectionFrameTopRight"] = { + Sheet = "Data", + Bounds = { X = 32, Y = 0, Width = 16, Height = 16 } +}; + +root.Sprites["PlainSelectionFrameLeftSide"] = { + Sheet = "Data", + Bounds = { X = 0, Y = 16, Width = 16, Height = 16 } +}; + +root.Sprites["PlainSelectionFrameBottomLeft"] = { + Sheet = "Data", + Bounds = { X = 0, Y = 32, Width = 16, Height = 16 } +}; + +root.Sprites["PlainSelectionFrameRightSide"] = { + Sheet = "Data", + Bounds = { X = 32, Y = 16, Width = 16, Height = 16 } +}; + +root.Sprites["PlainSelectionFrameBottomRight"] = { + Sheet = "Data", + Bounds = { X = 32, Y = 32, Width = 16, Height = 16 } +}; + +root.Sprites["PlainSelectionFrameBottomSide"] = { + Sheet = "Data", + Bounds = { X = 16, Y = 32, Width = 16, Height = 16 } +}; + +root.Sprites["PlainSelectionFrameMiddle"] = { + Sheet = "Data", + Bounds = { X = 16, Y = 16, Width = 16, Height = 16 } +}; + +root.Sprites["SelectionHighlight"] = { + Sheet = "Data", + Bounds = { X = 65, Y = 33, Width = 94, Height = 30 } +}; diff --git a/profiles/sg0/hud/sysmesboxdisplay.lua b/profiles/sg0/hud/sysmesboxdisplay.lua new file mode 100644 index 000000000..435a5eec6 --- /dev/null +++ b/profiles/sg0/hud/sysmesboxdisplay.lua @@ -0,0 +1,25 @@ +root.SysMesBoxDisplay = { + Type = SysMesBoxType.SG0, + DrawType = DrawComponentType.SystemMessage, + BackgroundSprite = "SysMesBoxBackground", + BackgroundOpacity = 1.0, + MessageColor = 0xFFFFFF, + ChoiceColor = 0x9A9A9A, + ChoiceHighlightColor = 0xFFB040, + OutlineColor = 0x000000, + ChoiceSpacing = 160, + ChoicePadding = { X = 48, Y = 12 }, + TextFontSize = 40, + TextMiddleY = 470, + TextX = 960, + TextLineHeight = 56, + TextMarginY = 56, + AnimationSpeed = 25, + FadeInDuration = 0.25, + FadeOutDuration = 0.25 +}; + +root.Sprites["SysMesBoxBackground"] = { + Sheet = "SysMesBox", + Bounds = { X = 0, Y = 0, Width = 1920, Height = 1080 } +}; diff --git a/profiles/sg0/hud/tipsnotification.lua b/profiles/sg0/hud/tipsnotification.lua new file mode 100644 index 000000000..4d80584c8 --- /dev/null +++ b/profiles/sg0/hud/tipsnotification.lua @@ -0,0 +1,3 @@ +root.TipsNotification = { + Type = TipsNotificationType.None, +}; diff --git a/profiles/sg0/hud/titlemenu.lua b/profiles/sg0/hud/titlemenu.lua new file mode 100644 index 000000000..66d8feec3 --- /dev/null +++ b/profiles/sg0/hud/titlemenu.lua @@ -0,0 +1,56 @@ +root.TitleMenu = { + Type = TitleMenuType.SG0, + DrawType = DrawComponentType.SystemMenu, + PressToStartPos = { X = 728, Y = 880 }, + PressToStartAnimDurationIn = 0.7, + PressToStartAnimDurationOut = 0.7, + PressToStartAnimFastDurationIn = 0.1, + PressToStartAnimFastDurationOut = 0.1, + PressToStartSprite = "TitleMenuPressToStart", + LogoSprite = "TitleMenuLogo", + LogoPos = { X = 432, Y = 150 }, + ItemPos = { X = 120, Y = 640 }, + ItemSpacing = 52, + SubItemOffsetX = 300, + SubItemSpacing = 48, + MenuEntriesNum = 5, + MenuEntriesSprites = {}, + MenuEntriesHighlightedSprites = {}, + SubItemSprites = {}, + SubItemHighlightedSprites = {}, +}; + +root.Sprites["TitleMenuPressToStart"] = { + Sheet = "TitleChip", + Bounds = { X = 8, Y = 1428, Width = 464, Height = 40 }, +}; +root.Sprites["TitleMenuLogo"] = { + Sheet = "TitleLogo", + Bounds = { X = 48, Y = 1788, Width = 1056, Height = 284 }, +}; + +for i = 0, 4 do + root.Sprites["TitleMenuEntry" .. i] = { + Sheet = "TitleChip", + Bounds = { X = 648, Y = 1088 + i * 42, Width = 268, Height = 40 }, + }; + root.Sprites["TitleMenuEntryHighlight" .. i] = { + Sheet = "TitleChip", + Bounds = { X = 920, Y = 1088 + i * 42, Width = 268, Height = 40 }, + }; + root.TitleMenu.MenuEntriesSprites[i + 1] = "TitleMenuEntry" .. i; + root.TitleMenu.MenuEntriesHighlightedSprites[i + 1] = "TitleMenuEntryHighlight" .. i; +end + +for i = 0, 6 do + root.Sprites["TitleMenuSubEntry" .. i] = { + Sheet = "TitleChip", + Bounds = { X = 4, Y = 1088 + i * 48, Width = 312, Height = 40 }, + }; + root.Sprites["TitleMenuSubEntryHighlight" .. i] = { + Sheet = "TitleChip", + Bounds = { X = 328, Y = 1088 + i * 48, Width = 312, Height = 40 }, + }; + root.TitleMenu.SubItemSprites[i + 1] = "TitleMenuSubEntry" .. i; + root.TitleMenu.SubItemHighlightedSprites[i + 1] = "TitleMenuSubEntryHighlight" .. i; +end diff --git a/profiles/sg0/movie.cls b/profiles/sg0/movie.cls new file mode 100644 index 000000000..9501a7934 --- /dev/null +++ b/profiles/sg0/movie.cls @@ -0,0 +1,33 @@ +END01 +END02 +END03 +END04 +IMV001 +IMV002 +IMV003 +IMV004 +IMV005 +IMV006 +IMV007 +IMV008 +IMV009 +IMV010 +IMV011 +IMV012 +OP +TIT_000 +TIT_001 +TIT_A01 +TIT_A02 +TIT_A03 +TIT_A04 +TIT_B01 +TIT_B02 +TIT_B03A +TIT_B03B +TIT_B04 +TIT_K01 +TIT_M01 +TIT_T01 +anisama +intro diff --git a/profiles/sg0/savedata.lua b/profiles/sg0/savedata.lua new file mode 100644 index 000000000..0c2457f93 --- /dev/null +++ b/profiles/sg0/savedata.lua @@ -0,0 +1,37 @@ +root.SaveData = { + Type = SaveDataType.CCLCC_PS4, + SaveFilePath = root.BasePaths.RootSavesDir .. "/sg0/SAVEDATA.DAT", + -- Per script: line count and offset into the read-text bit array. + ScriptMessageData = { + {0x3d2, 0x0}, {0x0, 0x3d2}, {0x6e, 0x3d2}, {0x6e, 0x440}, {0x5d, 0x4ae}, {0x78, 0x50b}, + {0x67, 0x583}, {0xdc, 0x5ea}, {0x40c, 0x6c6}, {0x0, 0xad2}, {0x23, 0xad2}, {0x0, 0xaf5}, + {0x24, 0xaf5}, {0x1, 0xb19}, {0x1, 0xb1a}, {0x0, 0xb1b}, {0x60, 0xb1b}, {0x1ec, 0xb7b}, + {0xc1, 0xd67}, {0x9a, 0xe28}, {0x26e, 0xec2}, {0xcb, 0x1130}, {0x129, 0x11fb}, {0x16e, 0x1324}, + {0x1a0, 0x1492}, {0xd7, 0x1632}, {0x4e, 0x1709}, {0xff, 0x1757}, {0x1a, 0x1856}, {0xf2, 0x1870}, + {0x14f, 0x1962}, {0xbe, 0x1ab1}, {0x1a, 0x1b6f}, {0x12c, 0x1b89}, {0x65, 0x1cb5}, {0xdb, 0x1d1a}, + {0x100, 0x1df5}, {0xb0, 0x1ef5}, {0xe7, 0x1fa5}, {0x14d, 0x208c}, {0x118, 0x21d9}, {0x6d, 0x22f1}, + {0x56, 0x235e}, {0xdb, 0x23b4}, {0x111, 0x248f}, {0x1c6, 0x25a0}, {0xfd, 0x2766}, {0x86, 0x2863}, + {0x18b, 0x28e9}, {0x56, 0x2a74}, {0x7d, 0x2aca}, {0x18a, 0x2b47}, {0x100, 0x2cd1}, {0x50, 0x2dd1}, + {0x19f, 0x2e21}, {0x2b, 0x2fc0}, {0x139, 0x2feb}, {0x49, 0x3124}, {0x111, 0x316d}, {0x1a9, 0x327e}, + {0x183, 0x3427}, {0xe9, 0x35aa}, {0x189, 0x3693}, {0x1db, 0x381c}, {0x72, 0x39f7}, {0x7f, 0x3a69}, + {0x1a3, 0x3ae8}, {0x187, 0x3c8b}, {0xef, 0x3e12}, {0xd8, 0x3f01}, {0x66, 0x3fd9}, {0x216, 0x403f}, + {0x245, 0x4255}, {0x1c5, 0x449a}, {0x5a, 0x465f}, {0x18c, 0x46b9}, {0x274, 0x4845}, {0x108, 0x4ab9}, + {0x57, 0x4bc1}, {0x95, 0x4c18}, {0x107, 0x4cad}, {0xda, 0x4db4}, {0x2a3, 0x4e8e}, {0xa2, 0x5131}, + {0xf2, 0x51d3}, {0x5e, 0x52c5}, {0x1b7, 0x5323}, {0xa5, 0x54da}, {0x81, 0x557f}, {0x110, 0x5600}, + {0x363, 0x5710}, {0x1a, 0x5a73}, {0xa2, 0x5a8d}, {0x119, 0x5b2f}, {0x1af, 0x5c48}, {0x202, 0x5df7}, + {0x80, 0x5ff9}, {0xe4, 0x6079}, {0xee, 0x615d}, {0xd3, 0x624b}, {0x199, 0x631e}, {0x79, 0x64b7}, + {0xcf, 0x6530}, {0x24, 0x65ff}, {0x215, 0x6623}, {0x64, 0x6838}, {0x66, 0x689c}, {0x50, 0x6902}, + {0x3d, 0x6952}, {0xba, 0x698f}, {0x2d, 0x6a49}, {0x10e, 0x6a76}, {0x1f7, 0x6b84}, {0x1f4, 0x6d7b}, + {0x19c, 0x6f6f}, {0x7d, 0x710b}, {0x1d5, 0x7188}, {0x17e, 0x735d}, {0x56, 0x74db}, {0xbc, 0x7531}, + {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, + {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, + {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, + {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, + {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, + {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, + {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, + {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, + {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, {0x0, 0x75ed}, + {0x0, 0x75ed}, {0x0, 0x75ed}, {0x17a, 0x75ed}, {0x0, 0x7767}, + }, +}; diff --git a/profiles/sg0/scriptvars.lua b/profiles/sg0/scriptvars.lua new file mode 100644 index 000000000..cb5aaa91d --- /dev/null +++ b/profiles/sg0/scriptvars.lua @@ -0,0 +1,25 @@ +local sv = root.ScriptVars; + +sv.SW_TITLECUR1 = 2139; +sv.SW_TITLECUR2 = 2140; --Actual guess +sv.SW_BG1POSX_OFS = 2400; +sv.SW_BG1POSY_OFS = 2401; +sv.SW_BG1SX_OFS = 2402; +sv.SW_BG1SY_OFS = 2403; +sv.SW_BG1SIZE_OFS = 2404; +sv.SW_BG1LX_OFS = 2405; +sv.SW_BG1LY_OFS = 2406; +sv.SW_BG1ROTZ_OFS = 2407; +sv.SW_BG1ALPHA_OFS = 2408; +sv.SW_MASK1COLOR = 4400; +sv.SW_MASK1ALPHA = 4401; +sv.SW_MASK1PRI = 4402; +sv.SW_MASK1POSX = 4403; +sv.SW_MASK1POSY = 4404; +sv.SW_MASK1SIZEX = 4405; +sv.SW_MASK1SIZEY = 4406; +sv.SW_MESMODE0 = 4363; + +-- SG0 uses 4422 for an effect state. 4430 is never written, so the window +-- type reads 0. +sv.SW_MESWIN0TYPE = 4430; diff --git a/profiles/sg0/sprites.lua b/profiles/sg0/sprites.lua new file mode 100644 index 000000000..750b58b19 --- /dev/null +++ b/profiles/sg0/sprites.lua @@ -0,0 +1,47 @@ +root.SpriteSheets = { + ["Data"] = { + Path = { Mount = "system", Id = 4 }, + DesignWidth = 3200, + DesignHeight = 1536 + }, + ["MesBox"] = { + Path = { Mount = "system", Id = 16 }, + DesignWidth = 3072, + DesignHeight = 1728 + }, + ["TitleLogo"] = { + Path = { Mount = "system", Id = 28 }, + DesignWidth = 3840, + DesignHeight = 2304 + }, + ["Font"] = { + -- font_a.dds rows 0-84, font_b.dds rows 85-124. + Path = { Mount = "system", Id = 9 }, + ContinuationPath = { Mount = "system", Id = 10 }, + FirstPageHeight = 4080, + DesignWidth = 3072, + DesignHeight = 6000 + }, + ["TitleChip"] = { + Path = { Mount = "system", Id = 25 }, + DesignWidth = 3072, + DesignHeight = 1536 + }, + ["SysMesBox"] = { + Path = { Mount = "system", Id = 13 }, + DesignWidth = 2048, + DesignHeight = 1440 + }, + ["Backlog"] = { + Path = { Mount = "system", Id = 1 }, + DesignWidth = 2048, + DesignHeight = 2208 + }, + ["NamePlate"] = { + Path = { Mount = "system", Id = 16 }, + DesignWidth = 3072, + DesignHeight = 1728 + } +}; + +root.Sprites = {}; \ No newline at end of file diff --git a/profiles/sg0/tipssystem.lua b/profiles/sg0/tipssystem.lua new file mode 100644 index 000000000..19b0f38dc --- /dev/null +++ b/profiles/sg0/tipssystem.lua @@ -0,0 +1,7 @@ +-- _tips.scx uses the CHAOS;CHILD Love Chu Chu tips table. +root.TipsSystem = { + Type = TipsSystemType.CCLCC, + MaxTipsCount = 300, + TipsTextTableId = 2, + TipsTextSortStrIndex = 10, +}; diff --git a/profiles/sg0/vfs.lua b/profiles/sg0/vfs.lua new file mode 100644 index 000000000..7b4aa1b81 --- /dev/null +++ b/profiles/sg0/vfs.lua @@ -0,0 +1,21 @@ +root.Vfs = { + Mounts = { + ["script"] = {root.BasePaths.RootGamedataDir .. "/sg0/script.mpk"}, + ["system"] = {root.BasePaths.RootGamedataDir .. "/sg0/system.mpk"}, + ["bgm"] = {root.BasePaths.RootGamedataDir .. "/sg0/bgm.mpk"}, + ["se"] = {root.BasePaths.RootGamedataDir .. "/sg0/se.mpk"}, + ["voice"] = {root.BasePaths.RootGamedataDir .. "/sg0/voice.mpk"}, + ["bg"] = {root.BasePaths.RootGamedataDir .. "/sg0/bg.mpk"}, + ["chara"] = {root.BasePaths.RootGamedataDir .. "/sg0/chara.mpk"}, + ["mask"] = {root.BasePaths.RootGamedataDir .. "/sg0/mask.mpk"}, + ["manual"] = {root.BasePaths.RootGamedataDir .. "/sg0/manual.mpk"}, + ["movie"] = { + { + Path = root.BasePaths.RootGamedataDir .. "/sg0/movie/1920x1080", + Whitelist = ".*\\.bk2", + -- Movie ids follow the ASCII order of the file names. + Order = root.BasePaths.RootProfilesDir .. "/sg0/movie.cls", + }, + } + } +}; diff --git a/profiles/sg0/waveeffects.lua b/profiles/sg0/waveeffects.lua new file mode 100644 index 000000000..9bfa70ee0 --- /dev/null +++ b/profiles/sg0/waveeffects.lua @@ -0,0 +1,4 @@ +root.WaveEffects = { + WaveMaxCount = 20; + BGWaveGridSize = { X = 160, Y = 90 } +}; diff --git a/src/background2d.cpp b/src/background2d.cpp index f48d8dfc5..56be0ff20 100644 --- a/src/background2d.cpp +++ b/src/background2d.cpp @@ -466,6 +466,7 @@ void Background2D::UpdateState(const int bgId) { switch (GameInstructionSet) { case Vm::InstructionSet::CC: + case Vm::InstructionSet::SG0: case Vm::InstructionSet::LCCSwitch: Tint = ScrWorkGetColor(SW_BG1FILTER + structOffset); break; @@ -633,6 +634,7 @@ void Capture2D::UpdateState(const int capId) { switch (GameInstructionSet) { case Vm::InstructionSet::CC: + case Vm::InstructionSet::SG0: case Vm::InstructionSet::LCCSwitch: Tint = ScrWorkGetColor(SW_CAP1FILTER + structOffset); break; @@ -733,6 +735,7 @@ void BackgroundEffect2D::UpdateState(const int bgId) { // Set tint switch (GameInstructionSet) { case Vm::InstructionSet::CC: + case Vm::InstructionSet::SG0: case Vm::InstructionSet::LCCSwitch: Tint = ScrWorkGetColor(SW_BGEFF1_FILTER + structOffset); break; diff --git a/src/data/savesystem.cpp b/src/data/savesystem.cpp index 7aedf9caf..e89f3f973 100644 --- a/src/data/savesystem.cpp +++ b/src/data/savesystem.cpp @@ -61,7 +61,8 @@ class SaveFileChecker : public Loadable { void MainThreadOnLoad(SaveError result) { // Let's not report errors until we finalize the implementation if (Profile::Vm::GameInstructionSet != Vm::InstructionSet::CC && - Profile::Vm::GameInstructionSet != Vm::InstructionSet::CHLCC) { + Profile::Vm::GameInstructionSet != Vm::InstructionSet::CHLCC && + Profile::Vm::GameInstructionSet != Vm::InstructionSet::SG0) { result = SaveError::OK; } diff --git a/src/game.cpp b/src/game.cpp index 27603c199..895835d97 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -372,6 +372,7 @@ void UpdateSystem(float dt) { } const bool isCC = Profile::Vm::GameInstructionSet == Vm::InstructionSet::CC || + Profile::Vm::GameInstructionSet == Vm::InstructionSet::SG0 || Profile::Vm::GameInstructionSet == Vm::InstructionSet::LCCSwitch; if (GetFlag(SF_BGEFF1DISP) && (!isCC || ScrWork[SW_EFF_WAVE_ALPHA])) { Effects::WaveEFF.Update(updateInterval); @@ -443,6 +444,7 @@ static void RenderMain() { for (uint32_t layer = 0; layer <= Profile::Game::LayerCount; layer++) { if (Profile::Vm::GameInstructionSet == Vm::InstructionSet::CC || + Profile::Vm::GameInstructionSet == Vm::InstructionSet::SG0 || Profile::Vm::GameInstructionSet == Vm::InstructionSet::LCCSwitch) { const int renderTarget = ScrWork[SW_RENDERTARGET + layer]; if (0 <= renderTarget && renderTarget <= MaxFramebuffers) { @@ -555,6 +557,7 @@ static void RenderMain() { if (Profile::Game::UseWaveEffects) { const bool isCC = Profile::Vm::GameInstructionSet == Vm::InstructionSet::CC || + Profile::Vm::GameInstructionSet == Vm::InstructionSet::SG0 || Profile::Vm::GameInstructionSet == Vm::InstructionSet::LCCSwitch; if (GetFlag(SF_BGEFF1DISP) && (!isCC || ScrWork[SW_EFF_WAVE_ALPHA])) { if (ScrWork[SW_EFF_WAVE_PRI] == static_cast(layer)) { @@ -677,6 +680,7 @@ void Render() { } case DrawComponentType::Main: { if ((Profile::Vm::GameInstructionSet == Vm::InstructionSet::CC || + Profile::Vm::GameInstructionSet == Vm::InstructionSet::SG0 || Profile::Vm::GameInstructionSet == Vm::InstructionSet::LCCSwitch) && !(!GetFlag(SF_SELECTMODE) || @@ -702,6 +706,7 @@ void Render() { } case DrawComponentType::SystemIcons: { if (Profile::Vm::GameInstructionSet == Vm::InstructionSet::CC || + Profile::Vm::GameInstructionSet == Vm::InstructionSet::SG0 || Profile::Vm::GameInstructionSet == Vm::InstructionSet::LCCSwitch) { UI::GameSpecific::RenderCCButtonGuide(); diff --git a/src/games/sg0/backlogmenu.cpp b/src/games/sg0/backlogmenu.cpp new file mode 100644 index 000000000..0cdc9167a --- /dev/null +++ b/src/games/sg0/backlogmenu.cpp @@ -0,0 +1,91 @@ +#include "backlogmenu.h" + +#include + +#include "../../profile/games/sg0/backlogmenu.h" +#include "../../profile/ui/backlogmenu.h" +#include "../../profile/game.h" +#include "../../profile/scriptvars.h" +#include "../../renderer/renderer.h" +#include "../../ui/ui.h" +#include "../../mem.h" +#include "../../audio/audiosystem.h" + +namespace Impacto { +namespace UI { +namespace SG0 { + +using namespace Impacto::Profile::BacklogMenu; +using namespace Impacto::Profile::SG0::BacklogMenu; +using namespace Impacto::Profile::ScriptVars; + +namespace { +constexpr int SubMenuNo = 1; +constexpr int AlphaMax = 256; +} // namespace + +void BacklogMenu::Hide() { + Audio::Channels[Audio::AC_REV]->Stop(0.0f); + UI::BacklogMenu::Hide(); +} + +void BacklogMenu::UpdateVisibility() { + const int alpha = + ScrWork[SW_SYSSUBMENUNO] == SubMenuNo ? ScrWork[SW_SYSSUBMENUALPHA] : 0; + + if (alpha > LastAlpha && State != Shown && State != Showing) { + Show(); + } else if (alpha < LastAlpha && State != Hidden && State != Hiding) { + Hide(); + } + LastAlpha = alpha; + + // Follow the script's fade. + FadeAnimation.Progress = std::clamp(alpha / float(AlphaMax), 0.0f, 1.0f); + + if (State == Showing && alpha >= AlphaMax) { + State = Shown; + IsFocused = UI::FocusedMenu == this; + } else if (State == Hiding && alpha <= 0) { + State = Hidden; + IsFocused = false; + for (auto& entry : Entries) entry.Hide(); + } +} + +void BacklogMenu::Render() { + if (State == Hidden) return; + + const float opacity = FadeAnimation.Progress; + const glm::vec4 tint(1.0f, 1.0f, 1.0f, opacity); + + Renderer->DrawQuad(RectF(0.0f, 0.0f, Profile::Game::DesignWidth, + Profile::Game::DesignHeight), + glm::vec4(0.0f, 0.0f, 0.0f, ShadeOpacity * opacity)); + Renderer->DrawSprite(BacklogBackground, PanelPos, tint); + + if (CurrentlyFocusedElement && + RenderingBounds.Intersects(CurrentlyFocusedElement->Bounds)) { + const RectF& b = CurrentlyFocusedElement->Bounds; + Renderer->DrawQuad( + RectF(HighlightBounds.X, b.Y - EntryHighlightPadding, + HighlightBounds.Width, b.Height + 2 * EntryHighlightPadding), + glm::vec4(HighlightColor, HighlightOpacity * opacity)); + } + + Renderer->EnableScissor(); + Renderer->SetScissorRect(RenderingBounds); + for (auto& entry : Entries) { + if (!entry.Bounds.Intersects(RenderingBounds)) continue; + entry.Tint = tint; + entry.Render(); + } + Renderer->DisableScissor(); + + MainScrollbar.Tint = tint; + MainScrollbar.Render(); +} + +} // namespace SG0 +} // namespace UI +} // namespace Impacto diff --git a/src/games/sg0/backlogmenu.h b/src/games/sg0/backlogmenu.h new file mode 100644 index 000000000..0ea73a9ee --- /dev/null +++ b/src/games/sg0/backlogmenu.h @@ -0,0 +1,23 @@ +#pragma once + +#include "../../ui/backlogmenu.h" + +namespace Impacto { +namespace UI { +namespace SG0 { + +class BacklogMenu : public UI::BacklogMenu { + public: + void Hide() override; + void Render() override; + + protected: + void UpdateVisibility() override; + + private: + int LastAlpha = 0; +}; + +} // namespace SG0 +} // namespace UI +} // namespace Impacto diff --git a/src/games/sg0/sysmesbox.cpp b/src/games/sg0/sysmesbox.cpp new file mode 100644 index 000000000..5af7891bc --- /dev/null +++ b/src/games/sg0/sysmesbox.cpp @@ -0,0 +1,180 @@ +#include "sysmesbox.h" + +#include "../../profile/games/sg0/sysmesbox.h" +#include "../../profile/ui/sysmesbox.h" +#include "../../profile/dialogue.h" +#include "../../profile/vm.h" +#include "../../profile/scriptvars.h" +#include "../../renderer/renderer.h" +#include "../../ui/ui.h" +#include "../../mem.h" +#include "../../inputsystem.h" +#include "../../vm/interface/input.h" +#include "../../audio/audiosystem.h" + +namespace Impacto { +namespace UI { +namespace SG0 { + +using namespace Impacto::Profile::SysMesBox; +using namespace Impacto::Profile::SG0::SysMesBox; +using namespace Impacto::Profile::ScriptVars; +using namespace Impacto::Vm::Interface; + +void SysMesBox::Init() { + ChoiceMade = false; + MessageCount = 0; + ChoiceCount = 0; + Cursor = 0; + + FadeAnimation.DurationIn = FadeInDuration; + FadeAnimation.DurationOut = FadeOutDuration; + FadeAnimation.Direction = AnimationDirection::In; + FadeAnimation.LoopMode = AnimationLoopMode::Stop; +} + +void SysMesBox::AddMessage(Vm::BufferOffsetContext ctx) { + if (MessageCount >= static_cast(Messages.size())) return; + Vm::Sc3VmThread dummy; + dummy.IpOffset = ctx.IpOffset; + dummy.ScriptBufferId = ctx.BufferId; + dummy.UseMSBBuffers = Profile::Vm::UseMsbStrings; + Messages[MessageCount] = TextLayoutPlainLine( + &dummy, 255, *Profile::Dialogue::DialogueFont, TextFontSize, + {MessageColor, OutlineColor}, 1.0f, glm::vec2(0.0f), TextAlignment::Left); + MessageWidths[MessageCount] = GetTextWidth(Messages[MessageCount]); + MessageCount++; +} + +void SysMesBox::AddChoice(Vm::BufferOffsetContext ctx) { + if (ChoiceCount >= static_cast(Choices.size())) return; + Vm::Sc3VmThread dummy; + dummy.IpOffset = ctx.IpOffset; + dummy.ScriptBufferId = ctx.BufferId; + dummy.UseMSBBuffers = Profile::Vm::UseMsbStrings; + Choices[ChoiceCount] = TextLayoutPlainLine( + &dummy, 255, *Profile::Dialogue::DialogueFont, TextFontSize, + {ChoiceColor, OutlineColor}, 1.0f, glm::vec2(0.0f), TextAlignment::Left); + if (Choices[ChoiceCount].empty()) return; + ChoiceWidths[ChoiceCount] = GetTextWidth(Choices[ChoiceCount]); + ChoiceCount++; +} + +void SysMesBox::Show() { + const float blockHeight = MessageCount * TextLineHeight; + const float firstLineY = TextMiddleY - blockHeight / 2.0f; + for (int i = 0; i < MessageCount; i++) { + if (Messages[i].empty()) continue; + const glm::vec2 target(TextX - MessageWidths[i] / 2.0f, + firstLineY + i * TextLineHeight); + const glm::vec2 offset = target - Messages[i][0].Position; + for (ProcessedTextGlyph& glyph : Messages[i]) glyph.Move(offset); + } + + float rowWidth = ChoiceSpacing * std::max(ChoiceCount - 1, 0); + for (int i = 0; i < ChoiceCount; i++) rowWidth += ChoiceWidths[i]; + float x = TextX - rowWidth / 2.0f; + const float choiceY = firstLineY + blockHeight + TextMarginY; + for (int i = 0; i < ChoiceCount; i++) { + const glm::vec2 offset = glm::vec2(x, choiceY) - Choices[i][0].Position; + for (ProcessedTextGlyph& glyph : Choices[i]) glyph.Move(offset); + ChoiceBounds[i] = RectF(x - ChoicePadding.x, choiceY - ChoicePadding.y, + ChoiceWidths[i] + 2 * ChoicePadding.x, + TextFontSize + 2 * ChoicePadding.y); + x += ChoiceWidths[i] + ChoiceSpacing; + } + SetCursor(0); + + FadeAnimation.StartIn(); + State = Showing; + if (UI::FocusedMenu != nullptr) { + LastFocusedMenu = UI::FocusedMenu; + LastFocusedMenu->IsFocused = false; + } + IsFocused = true; + UI::FocusedMenu = this; +} + +void SysMesBox::Hide() { + FadeAnimation.StartOut(); + State = Hiding; + if (LastFocusedMenu != nullptr) { + UI::FocusedMenu = LastFocusedMenu; + LastFocusedMenu->IsFocused = true; + } else { + UI::FocusedMenu = nullptr; + } + IsFocused = false; +} + +void SysMesBox::SetCursor(int choice) { + Cursor = choice; + for (int i = 0; i < ChoiceCount; i++) { + const uint32_t color = i == Cursor ? ChoiceHighlightColor : ChoiceColor; + for (ProcessedTextGlyph& glyph : Choices[i]) glyph.Colors.TextColor = color; + } +} + +void SysMesBox::Choose(int choice) { + ScrWork[SW_SYSSEL] = choice; + ChoiceMade = true; +} + +void SysMesBox::UpdateInput(float dt) { + if (ChoiceCount == 0 || ChoiceMade) return; + + int next = Cursor; + if (PADinputButtonWentDown & (PAD1LEFT | PAD1UP)) { + next = (Cursor + ChoiceCount - 1) % ChoiceCount; + } else if (PADinputButtonWentDown & (PAD1RIGHT | PAD1DOWN)) { + next = (Cursor + 1) % ChoiceCount; + } + for (int i = 0; i < ChoiceCount; i++) { + if (!ChoiceBounds[i].ContainsPoint(Input::CurMousePos)) continue; + if (Input::PrevMousePos != Input::CurMousePos) next = i; + if (Input::MouseButtonWentDown[SDL_BUTTON_LEFT]) { + SetCursor(i); + Choose(i); + return; + } + } + if (next != Cursor) { + SetCursor(next); + Audio::PlayInGroup(Audio::ACG_SE, "sysse", 1, false, 0); + } + + if (PADinputButtonWentDown & PAD1A) { + Choose(Cursor); + } else if (PADinputButtonWentDown & PAD1B) { + // Cancel picks the last choice ("No"). + SetCursor(ChoiceCount - 1); + Choose(ChoiceCount - 1); + } +} + +void SysMesBox::Update(float dt) { + FadeAnimation.Update(dt); + if (State == Showing && FadeAnimation.IsIn()) State = Shown; + if (State == Hiding && FadeAnimation.IsOut()) State = Hidden; + if (State == Shown && IsFocused) UpdateInput(dt); +} + +void SysMesBox::Render() { + if (State == Hidden) return; + const float alpha = FadeAnimation.Progress; + + Renderer->DrawSprite(BackgroundSprite, glm::vec2(0.0f), + glm::vec4(1.0f, 1.0f, 1.0f, alpha * BackgroundOpacity)); + for (int i = 0; i < MessageCount; i++) { + Profile::Dialogue::DialogueFont->DrawProcessedText( + Messages[i], alpha, RendererOutlineMode::Full); + } + for (int i = 0; i < ChoiceCount; i++) { + Profile::Dialogue::DialogueFont->DrawProcessedText( + Choices[i], alpha, RendererOutlineMode::Full); + } +} + +} // namespace SG0 +} // namespace UI +} // namespace Impacto diff --git a/src/games/sg0/sysmesbox.h b/src/games/sg0/sysmesbox.h new file mode 100644 index 000000000..1fe6c4a4a --- /dev/null +++ b/src/games/sg0/sysmesbox.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include "../../ui/sysmesbox.h" + +namespace Impacto { +namespace UI { +namespace SG0 { + +class SysMesBox : public UI::SysMesBox { + public: + void Show() override; + void Hide() override; + void Update(float dt) override; + void UpdateInput(float dt) override; + void Render() override; + + void Init() override; + void AddMessage(Vm::BufferOffsetContext ctx) override; + void AddChoice(Vm::BufferOffsetContext ctx) override; + + private: + void SetCursor(int choice); + void Choose(int choice); + + int Cursor = 0; + std::array ChoiceBounds; +}; + +} // namespace SG0 +} // namespace UI +} // namespace Impacto diff --git a/src/games/sg0/titlemenu.cpp b/src/games/sg0/titlemenu.cpp new file mode 100644 index 000000000..cd27a493c --- /dev/null +++ b/src/games/sg0/titlemenu.cpp @@ -0,0 +1,202 @@ +#include "titlemenu.h" + +#include "../../profile/ui/titlemenu.h" +#include "../../profile/games/sg0/titlemenu.h" +#include "../../profile/scriptvars.h" +#include "../../renderer/renderer.h" +#include "../../mem.h" +#include "../../inputsystem.h" +#include "../../vm/interface/input.h" +#include "../../games/cc/titlemenu.h" // TitleMenuMode::PS4 + +namespace Impacto { +namespace UI { +namespace SG0 { + +using namespace Impacto::Profile::TitleMenu; +using namespace Impacto::Profile::SG0::TitleMenu; +using namespace Impacto::Profile::ScriptVars; +using namespace Impacto::Vm::Interface; + +// SW_TITLECUR1 values the SG0 title script dispatches on. +constexpr int MainItemIds[] = {0, -1, -1, 30, 40}; +constexpr int SubItemIds[SubItemsNum] = {10, 11, 20, 21, 22, 23, 24}; + +void TitleMenu::MenuButtonOnClick(Widgets::Button* target) { + target->Hovered = false; + ScrWork[SW_TITLECUR1] = target->Id; + SetFlag(SF_TITLEEND, 1); + AllowsScriptInput = true; + if (CurrentSubMenu) { + CurrentSubMenu->Hide(); + CurrentSubMenu = nullptr; + } +} + +void TitleMenu::OpenSubMenu(Widgets::Group* subMenu, Widgets::Button* parent) { + parent->Hovered = false; + CurrentSubMenu = subMenu; + subMenu->Show(); + CurrentlyFocusedElement = subMenu->GetFirstFocusableChild(); + if (CurrentlyFocusedElement) CurrentlyFocusedElement->HasFocus = true; + AllowsScriptInput = false; +} + +TitleMenu::TitleMenu() { + MainItems = new Widgets::Group(this); + ContinueItems = new Widgets::Group(this); + ContinueItems->WrapFocus = false; + ExtraItems = new Widgets::Group(this); + ExtraItems->WrapFocus = false; + + auto onClick = [this](Widgets::Button* btn) { MenuButtonOnClick(btn); }; + const Sprite nullSprite{}; + + Widgets::Button* mainButtons[5]; + for (int i = 0; i < 5; i++) { + const glm::vec2 pos = ItemPos + glm::vec2(0.0f, i * ItemSpacing); + mainButtons[i] = + new Widgets::Button(MainItemIds[i], MenuEntriesSprites[i], + MenuEntriesHSprites[i], nullSprite, pos); + mainButtons[i]->OnClickHandler = onClick; + MainItems->Add(mainButtons[i], FDIR_DOWN); + } + NewGame = mainButtons[0]; + mainButtons[1]->OnClickHandler = [this](Widgets::Button* btn) { + OpenSubMenu(ContinueItems, btn); + }; + mainButtons[2]->OnClickHandler = [this](Widgets::Button* btn) { + OpenSubMenu(ExtraItems, btn); + }; + + for (int i = 0; i < SubItemsNum; i++) { + const bool isContinue = i < 2; + const int parentIndex = isContinue ? 1 : 2; + const int row = isContinue ? i : i - 2; + const glm::vec2 pos = + ItemPos + glm::vec2(SubItemOffsetX, + parentIndex * ItemSpacing + row * SubItemSpacing); + auto* button = new Widgets::Button(SubItemIds[i], SubItemSprites[i], + SubItemHSprites[i], nullSprite, pos); + button->OnClickHandler = onClick; + (isContinue ? ContinueItems : ExtraItems)->Add(button, FDIR_DOWN); + } +} + +void TitleMenu::Show() { + if (State == Shown) return; + State = Shown; + if (UI::FocusedMenu != nullptr) { + LastFocusedMenu = UI::FocusedMenu; + LastFocusedMenu->IsFocused = false; + } + IsFocused = true; + UI::FocusedMenu = this; + AllowsScriptInput = true; + if (PressToStartAnimation.State == AnimationState::Stopped) { + PressToStartAnimation.StartIn(); + } +} + +void TitleMenu::Hide() { + if (State == Hidden) return; + State = Hidden; + MainItems->Hide(); + ContinueItems->Hide(); + ExtraItems->Hide(); + CurrentSubMenu = nullptr; + if (LastFocusedMenu != nullptr) { + UI::FocusedMenu = LastFocusedMenu; + LastFocusedMenu->IsFocused = true; + } else { + UI::FocusedMenu = nullptr; + } + IsFocused = false; + AllowsScriptInput = true; +} + +void TitleMenu::UpdateInput(float dt) { + // Screens opened from the title hold focus; ignore their key presses. + if (!IsFocused) return; + Menu::UpdateInput(dt); + if (CurrentSubMenu) { + CurrentSubMenu->UpdateInput(dt); + if (PADinputButtonWentDown & PAD1B || PADinputMouseWentDown & PAD1B) { + CurrentSubMenu->Hide(); + CurrentSubMenu = nullptr; + AllowsScriptInput = true; + } + } else { + MainItems->UpdateInput(dt); + } +} + +void TitleMenu::Update(float dt) { + UpdateInput(dt); + PressToStartAnimation.Update(dt); + + if (GetFlag(SF_TITLEMODE)) { + Show(); + } else { + Hide(); + } + if (State == Hidden) return; + + using namespace CC::TitleMenuMode::PS4; + switch (ScrWork[SW_TITLEMODE]) { + case PressToStart: + PressToStartAnimation.DurationIn = PressToStartAnimDurationIn; + PressToStartAnimation.DurationOut = PressToStartAnimDurationOut; + break; + case StartTransition: + PressToStartAnimation.DurationIn = PressToStartAnimFastDurationIn; + PressToStartAnimation.DurationOut = PressToStartAnimFastDurationOut; + break; + case Main: + MainItems->Update(dt); + if (CurrentSubMenu) CurrentSubMenu->Update(dt); + if (MainItems->VisibilityState == Hidden) { + MainItems->Show(); + CurrentlyFocusedElement = NewGame; + NewGame->HasFocus = true; + } + break; + } +} + +void TitleMenu::Render() { + if (State == Hidden || !GetFlag(SF_TITLEMODE)) return; + + using namespace CC::TitleMenuMode::PS4; + switch (ScrWork[SW_TITLEMODE]) { + case PressToStart: + case StartTransition: + DrawLogo(1.0f); + DrawStartButton(); + break; + case Main: + DrawLogo(1.0f); + MainItems->Render(); + if (CurrentSubMenu) CurrentSubMenu->Render(); + break; + case InitialFade: + DrawLogo(ScrWork[SW_TITLEDISPCT] / 32.0f); + break; + } +} + +void TitleMenu::DrawLogo(float opacity) { + Renderer->DrawSprite( + LogoSprite, LogoPos, + glm::vec4(1.0f, 1.0f, 1.0f, std::clamp(opacity, 0.0f, 1.0f))); +} + +void TitleMenu::DrawStartButton() { + glm::vec4 col(1.0f); + col.a = glm::smoothstep(0.0f, 1.0f, PressToStartAnimation.Progress); + Renderer->DrawSprite(PressToStartSprite, PressToStartPos, col); +} + +} // namespace SG0 +} // namespace UI +} // namespace Impacto diff --git a/src/games/sg0/titlemenu.h b/src/games/sg0/titlemenu.h new file mode 100644 index 000000000..cb2617956 --- /dev/null +++ b/src/games/sg0/titlemenu.h @@ -0,0 +1,38 @@ +#pragma once + +#include "../../animation.h" +#include "../../ui/menu.h" +#include "../../ui/widgets/group.h" +#include "../../ui/widgets/button.h" + +namespace Impacto { +namespace UI { +namespace SG0 { + +class TitleMenu : public Menu { + public: + TitleMenu(); + void Show() override; + void Hide() override; + void UpdateInput(float dt) override; + void Update(float dt) override; + void Render() override; + + Animation PressToStartAnimation; + + private: + void MenuButtonOnClick(Widgets::Button* target); + void OpenSubMenu(Widgets::Group* subMenu, Widgets::Button* parent); + void DrawLogo(float opacity); + void DrawStartButton(); + + Widgets::Group* MainItems; + Widgets::Group* ContinueItems; + Widgets::Group* ExtraItems; + Widgets::Group* CurrentSubMenu = nullptr; + Widgets::Button* NewGame; +}; + +} // namespace SG0 +} // namespace UI +} // namespace Impacto diff --git a/src/profile/fonts.cpp b/src/profile/fonts.cpp index c47bb642b..45aa61e67 100644 --- a/src/profile/fonts.cpp +++ b/src/profile/fonts.cpp @@ -86,10 +86,15 @@ void LoadFonts() { } if (fontType == SingleSheet) { - Fonts[name] = new SingleSheetFont( + auto* font = new SingleSheetFont( *bitmapEmWidth, *bitmapEmHeight, foregroundOpacityCurve, outlineOpacityCurve, sheet, gridSize, EnsureGetAdvanceWidths(name, *bitmapEmWidth)); + std::vector leftBearings; + if (TryGetMember("LeftBearingsTable", leftBearings)) { + font->SetLeftBearings(std::move(leftBearings)); + } + Fonts[name] = font; } else { assert(fontType == EdgeDetectedSingleSheet); diff --git a/src/profile/games/sg0/backlogmenu.cpp b/src/profile/games/sg0/backlogmenu.cpp new file mode 100644 index 000000000..a0bf1b82c --- /dev/null +++ b/src/profile/games/sg0/backlogmenu.cpp @@ -0,0 +1,31 @@ +#include "backlogmenu.h" +#include "../../profile_internal.h" + +#include "../../../game.h" +#include "../../../ui/ui.h" +#include "../../../games/sg0/backlogmenu.h" + +namespace Impacto { +namespace Profile { +namespace SG0 { +namespace BacklogMenu { + +void Configure() { + PanelPos = EnsureGetMember("PanelPos"); + ShadeOpacity = EnsureGetMember("ShadeOpacity"); + HighlightBounds = EnsureGetMember("HighlightBounds"); + const uint32_t color = EnsureGetMember("HighlightColor"); + HighlightColor = + glm::vec3((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF) / + 255.0f; + HighlightOpacity = EnsureGetMember("HighlightOpacity"); + + auto drawType = EnsureGetMember("DrawType"); + UI::BacklogMenuPtr = new UI::SG0::BacklogMenu(); + UI::Menus[drawType].push_back(UI::BacklogMenuPtr); +} + +} // namespace BacklogMenu +} // namespace SG0 +} // namespace Profile +} // namespace Impacto diff --git a/src/profile/games/sg0/backlogmenu.h b/src/profile/games/sg0/backlogmenu.h new file mode 100644 index 000000000..8ad3b34dd --- /dev/null +++ b/src/profile/games/sg0/backlogmenu.h @@ -0,0 +1,21 @@ +#pragma once + +#include "../../../spritesheet.h" + +namespace Impacto { +namespace Profile { +namespace SG0 { +namespace BacklogMenu { + +void Configure(); + +inline glm::vec2 PanelPos; +inline float ShadeOpacity; // dims the scene around the panel +inline RectF HighlightBounds; // horizontal extent of the focus highlight +inline glm::vec3 HighlightColor; +inline float HighlightOpacity; + +} // namespace BacklogMenu +} // namespace SG0 +} // namespace Profile +} // namespace Impacto diff --git a/src/profile/games/sg0/sysmesbox.cpp b/src/profile/games/sg0/sysmesbox.cpp new file mode 100644 index 000000000..b0e26db5c --- /dev/null +++ b/src/profile/games/sg0/sysmesbox.cpp @@ -0,0 +1,33 @@ +#include "sysmesbox.h" +#include "../../profile_internal.h" + +#include "../../../game.h" +#include "../../../ui/ui.h" +#include "../../../games/sg0/sysmesbox.h" + +namespace Impacto { +namespace Profile { +namespace SG0 { +namespace SysMesBox { + +void Configure() { + BackgroundSprite = EnsureGetMember("BackgroundSprite"); + BackgroundOpacity = EnsureGetMember("BackgroundOpacity"); + MessageColor = EnsureGetMember("MessageColor"); + ChoiceColor = EnsureGetMember("ChoiceColor"); + ChoiceHighlightColor = EnsureGetMember("ChoiceHighlightColor"); + OutlineColor = EnsureGetMember("OutlineColor"); + ChoiceSpacing = EnsureGetMember("ChoiceSpacing"); + ChoicePadding = EnsureGetMember("ChoicePadding"); + + UI::SysMesBox::DrawType = + EnsureGetMember("DrawType"); + UI::SysMesBox::Factory = []() -> UI::SysMesBox* { + return new UI::SG0::SysMesBox(); + }; +} + +} // namespace SysMesBox +} // namespace SG0 +} // namespace Profile +} // namespace Impacto diff --git a/src/profile/games/sg0/sysmesbox.h b/src/profile/games/sg0/sysmesbox.h new file mode 100644 index 000000000..4af963299 --- /dev/null +++ b/src/profile/games/sg0/sysmesbox.h @@ -0,0 +1,25 @@ +#pragma once + +#include "../../../spritesheet.h" + +namespace Impacto { +namespace Profile { +namespace SG0 { +namespace SysMesBox { + +void Configure(); + +inline Sprite BackgroundSprite; +inline float BackgroundOpacity; + +inline uint32_t MessageColor; +inline uint32_t ChoiceColor; +inline uint32_t ChoiceHighlightColor; +inline uint32_t OutlineColor; +inline float ChoiceSpacing; +inline glm::vec2 ChoicePadding; + +} // namespace SysMesBox +} // namespace SG0 +} // namespace Profile +} // namespace Impacto diff --git a/src/profile/games/sg0/titlemenu.cpp b/src/profile/games/sg0/titlemenu.cpp new file mode 100644 index 000000000..ea915a0db --- /dev/null +++ b/src/profile/games/sg0/titlemenu.cpp @@ -0,0 +1,47 @@ +#include "titlemenu.h" +#include "../../profile_internal.h" + +#include "../../ui/titlemenu.h" +#include "../../../game.h" +#include "../../../ui/ui.h" +#include "../../../games/sg0/titlemenu.h" + +namespace Impacto { +namespace Profile { +namespace SG0 { +namespace TitleMenu { + +void Configure() { + LogoSprite = EnsureGetMember("LogoSprite"); + LogoPos = EnsureGetMember("LogoPos"); + + ItemPos = EnsureGetMember("ItemPos"); + ItemSpacing = EnsureGetMember("ItemSpacing"); + GetMemberArray(std::span(SubItemSprites, SubItemsNum), + "SubItemSprites"); + GetMemberArray(std::span(SubItemHSprites, SubItemsNum), + "SubItemHighlightedSprites"); + SubItemOffsetX = EnsureGetMember("SubItemOffsetX"); + SubItemSpacing = EnsureGetMember("SubItemSpacing"); + + PressToStartAnimFastDurationIn = + EnsureGetMember("PressToStartAnimFastDurationIn"); + PressToStartAnimFastDurationOut = + EnsureGetMember("PressToStartAnimFastDurationOut"); + + UI::SG0::TitleMenu* menu = new UI::SG0::TitleMenu(); + menu->PressToStartAnimation.DurationIn = + Profile::TitleMenu::PressToStartAnimDurationIn; + menu->PressToStartAnimation.DurationOut = + Profile::TitleMenu::PressToStartAnimDurationOut; + menu->PressToStartAnimation.LoopMode = AnimationLoopMode::ReverseDirection; + UI::TitleMenuPtr = menu; + + auto drawType = EnsureGetMember("DrawType"); + UI::Menus[drawType].push_back(UI::TitleMenuPtr); +} + +} // namespace TitleMenu +} // namespace SG0 +} // namespace Profile +} // namespace Impacto diff --git a/src/profile/games/sg0/titlemenu.h b/src/profile/games/sg0/titlemenu.h new file mode 100644 index 000000000..cf930bb5b --- /dev/null +++ b/src/profile/games/sg0/titlemenu.h @@ -0,0 +1,30 @@ +#pragma once + +#include "../../../spritesheet.h" + +namespace Impacto { +namespace Profile { +namespace SG0 { +namespace TitleMenu { + +void Configure(); + +int constexpr SubItemsNum = 7; + +inline Sprite LogoSprite; +inline glm::vec2 LogoPos; + +inline glm::vec2 ItemPos; +inline float ItemSpacing; +inline Sprite SubItemSprites[SubItemsNum]; +inline Sprite SubItemHSprites[SubItemsNum]; +inline float SubItemOffsetX; +inline float SubItemSpacing; + +inline float PressToStartAnimFastDurationIn; +inline float PressToStartAnimFastDurationOut; + +} // namespace TitleMenu +} // namespace SG0 +} // namespace Profile +} // namespace Impacto diff --git a/src/profile/sprites.cpp b/src/profile/sprites.cpp index 97315d2f3..65e385e08 100644 --- a/src/profile/sprites.cpp +++ b/src/profile/sprites.cpp @@ -4,6 +4,7 @@ #include "../log.h" #include "../renderer/renderer.h" #include "../texture/texture.h" +#include #include namespace Impacto { @@ -23,6 +24,39 @@ static Texture LoadTexture(Io::Stream* stream, std::string name) { return texture; } +// SG0 Steam splits its font atlas into two textures (font_a, font_b). +// Stack them back into one sheet. +static Texture LoadStackedTexture(Io::Stream* firstStream, + Io::Stream* continuationStream, + std::string name, int firstHeight, + int height) { + Texture first = LoadTexture(firstStream, name); + Texture continuation = LoadTexture(continuationStream, name + " (continued)"); + + if (firstHeight <= 0 || firstHeight > first.Height) + firstHeight = first.Height; + const size_t firstPixels = static_cast(first.Width) * first.Height; + if (first.Width != continuation.Width || + first.Format != continuation.Format || firstPixels == 0 || + height <= firstHeight || height > firstHeight + continuation.Height) { + ImpLog(LogLevel::Error, LogChannel::Profile, + "Spritesheet {:s} pages cannot be stacked to height {:d}, using " + "the first page only\n", + name, height); + return first; + } + + const size_t bytesPerPixel = first.Buffer.size() / firstPixels; + const size_t rowBytes = static_cast(first.Width) * bytesPerPixel; + Texture stacked{}; + stacked.Init(first.Format, first.Width, height); + std::copy_n(first.Buffer.begin(), firstHeight * rowBytes, + stacked.Buffer.begin()); + std::copy_n(continuation.Buffer.begin(), (height - firstHeight) * rowBytes, + stacked.Buffer.begin() + firstHeight * rowBytes); + return stacked; +} + void LoadSpritesheets() { EnsurePushMemberOfType("SpriteSheets", LUA_TTABLE); @@ -49,8 +83,23 @@ void LoadSpritesheets() { Window->Shutdown(); } - futures.emplace_back(std::tuple( - name, std::async(std::launch::async, LoadTexture, stream, name))); + if (auto continuationPath = + TryGetMember("ContinuationPath")) { + Io::Stream* continuationStream; + if (continuationPath->Open(&continuationStream) != IoError_OK) { + ImpLog(LogLevel::Fatal, LogChannel::Profile, + "Could not open spritesheet {:s} continuation page\n", name); + Window->Shutdown(); + } + futures.emplace_back(std::tuple( + name, std::async(std::launch::async, LoadStackedTexture, stream, + continuationStream, name, + TryGetMember("FirstPageHeight").value_or(0), + static_cast(sheet.DesignHeight)))); + } else { + futures.emplace_back(std::tuple( + name, std::async(std::launch::async, LoadTexture, stream, name))); + } } Pop(); } diff --git a/src/profile/ui/backlogmenu.cpp b/src/profile/ui/backlogmenu.cpp index ffeaf859c..b71b0e3c8 100644 --- a/src/profile/ui/backlogmenu.cpp +++ b/src/profile/ui/backlogmenu.cpp @@ -9,6 +9,7 @@ #include "../games/mo6tw/backlogmenu.h" #include "../games/chlcc/backlogmenu.h" #include "../games/cc/backlogmenu.h" +#include "../games/sg0/backlogmenu.h" namespace Impacto { namespace Profile { @@ -70,6 +71,10 @@ void Configure() { CC::BacklogMenu::Configure(); break; + case BacklogMenuType::SG0: + SG0::BacklogMenu::Configure(); + break; + case BacklogMenuType::None: break; } diff --git a/src/profile/ui/backlogmenu.h b/src/profile/ui/backlogmenu.h index 1eb0cfb36..3bd2ddfbc 100644 --- a/src/profile/ui/backlogmenu.h +++ b/src/profile/ui/backlogmenu.h @@ -13,6 +13,7 @@ enum class BacklogMenuType : int { MO6TW, CHLCC, CC, + SG0, }; enum class EntryHighlightLocationType : int { None, diff --git a/src/profile/ui/sysmesbox.cpp b/src/profile/ui/sysmesbox.cpp index 8463de3be..2dd769a9e 100644 --- a/src/profile/ui/sysmesbox.cpp +++ b/src/profile/ui/sysmesbox.cpp @@ -4,6 +4,7 @@ #include "../games/mo6tw/sysmesbox.h" #include "../games/darling/sysmesbox.h" #include "../games/cc/sysmesbox.h" +#include "../games/sg0/sysmesbox.h" #include "../profile_internal.h" @@ -29,6 +30,8 @@ void Configure() { Darling::SysMesBox::Configure(); } else if (Type == SysMesBoxType::CC) { CC::SysMesBox::Configure(); + } else if (Type == SysMesBoxType::SG0) { + SG0::SysMesBox::Configure(); } TextFontSize = EnsureGetMember("TextFontSize"); diff --git a/src/profile/ui/titlemenu.cpp b/src/profile/ui/titlemenu.cpp index 42881313b..3927d6ab0 100644 --- a/src/profile/ui/titlemenu.cpp +++ b/src/profile/ui/titlemenu.cpp @@ -8,6 +8,7 @@ #include "../games/mo8/titlemenu.h" #include "../games/cc/titlemenu.h" #include "../games/cclcc/titlemenu.h" +#include "../games/sg0/titlemenu.h" #include "../../log.h" namespace Impacto { @@ -53,6 +54,8 @@ void Configure() { CC::TitleMenu::Configure(); } else if (Type == TitleMenuType::CCLCC) { CCLCC::TitleMenu::Configure(); + } else if (Type == TitleMenuType::SG0) { + SG0::TitleMenu::Configure(); } // if (Implementation != 0) { diff --git a/src/text/fonts/font.h b/src/text/fonts/font.h index dfee74217..8910d0fc9 100644 --- a/src/text/fonts/font.h +++ b/src/text/fonts/font.h @@ -116,7 +116,15 @@ class SingleSheetFont : public Font { glm::vec2 CellSize; std::vector AdvanceWidths; + // Optional per-glyph offset of the ink within its cell. + std::vector LeftBearings; + public: + void SetLeftBearings(std::vector&& leftBearings) { + LeftBearings = std::move(leftBearings); + } + + protected: SingleSheetFont(FontType fontType, float bitmapEmWidth, float bitmapEmHeight, OpacityCurve foregroundOpacityCurve, OpacityCurve outlineOpacityCurve, SpriteSheet sheet, @@ -134,6 +142,10 @@ class SingleSheetFont : public Font { const uint16_t col = static_cast(id % GridSize.x); const float width = AdvanceWidths[id]; + if (id < LeftBearings.size()) { + return Sprite(Sheet, col * CellSize.x + LeftBearings[id], + row * CellSize.y + 1.0f, width, BitmapEmHeight - 2.0f); + } return Sprite(Sheet, col * CellSize.x + 1.0f, row * CellSize.y + 1.0f, width - 2.0f, BitmapEmHeight - 2.0f); } diff --git a/src/ui/ui.h b/src/ui/ui.h index 8f7e70edc..c45bbe25c 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -42,6 +42,7 @@ enum class SysMesBoxType : int { MO6TW, Darling, CC, + SG0, }; enum class TitleMenuType : int { None, @@ -52,6 +53,7 @@ enum class TitleMenuType : int { MO8, CC, CCLCC, + SG0, }; enum class OptionsMenuType : int { None, diff --git a/src/vm/inst_controlflow.cpp b/src/vm/inst_controlflow.cpp index 791ee75dd..3dbe2c419 100644 --- a/src/vm/inst_controlflow.cpp +++ b/src/vm/inst_controlflow.cpp @@ -99,6 +99,56 @@ VmInstruction(InstCallFar) { "CallFar error, call stack overflow.\n"); } } +// SG0: Call / CallFar taken when GetFlag(flagId) == value. The return id is +// read either way. +VmInstruction(InstCallIfFlag) { + StartInstruction; + PopUint8(value); + PopExpression(flagId); + PopLocalLabel(labelAdr); + PopUint16(retNum); + + if (GetFlag(flagId) != (bool)value) return; + + if (thread->CallStackDepth == MaxCallStackDepth) { + ImpLog(LogLevel::Error, LogChannel::VM, + "CallIfFlag error, call stack overflow.\n"); + return; + } + if (Profile::Vm::UseReturnIds) { + thread->ReturnIds[thread->CallStackDepth] = retNum; + } else { + thread->ReturnAddresses[thread->CallStackDepth] = thread->IpOffset; + } + thread->ReturnScriptBufferIds[thread->CallStackDepth++] = + thread->ScriptBufferId; + thread->IpOffset = labelAdr; +} +VmInstruction(InstCallFarIfFlag) { + StartInstruction; + PopUint8(value); + PopExpression(flagId); + PopExpression(scriptBufferId); + PopFarLabel(labelAdr, scriptBufferId); + PopUint16(retNum); + + if (GetFlag(flagId) != (bool)value) return; + + if (thread->CallStackDepth == MaxCallStackDepth) { + ImpLog(LogLevel::Error, LogChannel::VM, + "CallFarIfFlag error, call stack overflow.\n"); + return; + } + if (Profile::Vm::UseReturnIds) { + thread->ReturnIds[thread->CallStackDepth] = retNum; + } else { + thread->ReturnAddresses[thread->CallStackDepth] = thread->IpOffset; + } + thread->ReturnScriptBufferIds[thread->CallStackDepth++] = + thread->ScriptBufferId; + thread->IpOffset = labelAdr; + thread->ScriptBufferId = scriptBufferId; +} VmInstruction(InstReturn) { StartInstruction; if (thread->CallStackDepth) { @@ -254,6 +304,17 @@ VmInstruction(InstClickOnJump) { PopExpression(arg2); PopUint16(labelNum); uint32_t labelAdr = ScriptGetLabelAddress(thread->ScriptBufferId, labelNum); + if (Profile::Vm::GameInstructionSet == InstructionSet::SG0) { + // SG0 passes a mouse button mask (1 left, 2 right). 0x200000 also skips + // on a left click. + const bool left = Input::MouseButtonWentDown[SDL_BUTTON_LEFT]; + const bool right = Input::MouseButtonWentDown[SDL_BUTTON_RIGHT]; + if (((arg2 & 1) && left) || ((arg2 & 2) && right) || + ((arg2 & 0x200000) && left)) { + thread->IpOffset = labelAdr; + } + return; + } if (Input::KeyboardButtonWentDown[SDL_SCANCODE_D]) { thread->IpOffset = labelAdr; } diff --git a/src/vm/inst_controlflow.h b/src/vm/inst_controlflow.h index 06ff454f0..7aa5ca5d2 100644 --- a/src/vm/inst_controlflow.h +++ b/src/vm/inst_controlflow.h @@ -12,6 +12,8 @@ VmInstruction(InstIf); VmInstruction(InstCall); VmInstruction(InstJumpFar); VmInstruction(InstCallFar); +VmInstruction(InstCallIfFlag); +VmInstruction(InstCallFarIfFlag); VmInstruction(InstReturn); VmInstruction(InstReturnIfFlag); VmInstruction(InstLoop); diff --git a/src/vm/inst_dialogue.cpp b/src/vm/inst_dialogue.cpp index 8a167f5d0..6a9814374 100644 --- a/src/vm/inst_dialogue.cpp +++ b/src/vm/inst_dialogue.cpp @@ -950,7 +950,8 @@ VmInstruction(InstSel) { if (Profile::Vm::GameInstructionSet == InstructionSet::Dash || Profile::Vm::GameInstructionSet == InstructionSet::CC || Profile::Vm::GameInstructionSet == InstructionSet::LCCSwitch || - Profile::Vm::GameInstructionSet == InstructionSet::MO8) { + Profile::Vm::GameInstructionSet == InstructionSet::MO8 || + Profile::Vm::GameInstructionSet == InstructionSet::SG0) { PopUint16(savepointid); // SF_MESSAVEPOINT_SSP + dialog page's field 5 in decompile? // if (GetFlag(SF_MESSAVEPOINT_SSP + thread->DialoguePageId) == 0) { @@ -1134,7 +1135,8 @@ VmInstruction(InstNameID) { if (Profile::Vm::GameInstructionSet == InstructionSet::CC || Profile::Vm::GameInstructionSet == InstructionSet::LCCSwitch || Profile::Vm::GameInstructionSet == InstructionSet::MO8 || - Profile::Vm::GameInstructionSet == InstructionSet::CHN) { + Profile::Vm::GameInstructionSet == InstructionSet::CHN || + Profile::Vm::GameInstructionSet == InstructionSet::SG0) { PopLocalLabel(namePlateDataBlock); Sc3Stream namePlateData( &ScriptBuffers[thread->ScriptBufferId][namePlateDataBlock]); diff --git a/src/vm/inst_gamespecific.cpp b/src/vm/inst_gamespecific.cpp index d82e55bb0..c8aa217ad 100644 --- a/src/vm/inst_gamespecific.cpp +++ b/src/vm/inst_gamespecific.cpp @@ -763,6 +763,115 @@ VmInstruction(InstPhoneSG) { } } } +// SG0 operand layouts agree with sc3ntist's ZeroDisassembler.cpp. + +// 00 35: like InstSignIn, but SG0 encodes a one-byte argument. +VmInstruction(InstSignInSG0) { + StartInstruction; + PopUint8(arg1); + ImpLogSlow(LogLevel::Warning, LogChannel::VMStub, + "STUB instruction SignInSG0(arg1: {:d})\n", arg1); +} + +// 00 4C: u8 type, type 0 takes one expression. +VmInstruction(InstUnk004CSG0) { + StartInstruction; + PopUint8(type); + if (type == 0) { + PopExpression(arg1); + ImpLogSlow(LogLevel::Warning, LogChannel::VMStub, + "STUB instruction Unk004CSG0(type: {:d}, arg1: {:d})\n", type, + arg1); + } else { + ImpLogSlow(LogLevel::Warning, LogChannel::VMStub, + "STUB instruction Unk004CSG0(type: {:d})\n", type); + } +} + +// 00 50: u8 type; types 0 and 2 take two labels, type 3 takes three. +// Types 0 and 3 jump to their first label, like InstPressStartNew. +VmInstruction(InstPressStartSG0) { + StartInstruction; + PopUint8(type); + switch (type) { + case 0: + case 2: { + PopUint16(label1Num); + PopUint16(label2Num); + ImpLogSlow(LogLevel::Warning, LogChannel::VMStub, + "STUB instruction PressStartSG0(type: {:d}, label1: {:d}, " + "label2: {:d})\n", + type, label1Num, label2Num); + if (type == 0) { + thread->IpOffset = + ScriptGetLabelAddress(thread->ScriptBufferId, label1Num); + } + } break; + case 3: { + PopUint16(label1Num); + PopUint16(label2Num); + PopUint16(label3Num); + ImpLogSlow(LogLevel::Warning, LogChannel::VMStub, + "STUB instruction PressStartSG0(type: {:d}, label1: {:d}, " + "label2: {:d}, label3: {:d})\n", + type, label1Num, label2Num, label3Num); + thread->IpOffset = + ScriptGetLabelAddress(thread->ScriptBufferId, label1Num); + } break; + default: + ImpLogSlow(LogLevel::Warning, LogChannel::VMStub, + "STUB instruction PressStartSG0(type: {:d})\n", type); + break; + } +} + +// 10 37: SG0 phone. Type 0 names seven data blocks; 0xA and 0xD name code. +VmInstruction(InstPhoneSG0) { + StartInstruction; + PopUint8(type); + switch (type) { + case 0x00: + for (int i = 0; i < 7; i++) { + PopUint16(labelNum); + (void)labelNum; + } + break; + case 0x0A: + case 0x32: { + PopUint16(labelNum); + (void)labelNum; + } break; + case 0x0C: { + PopExpression(arg1); + PopExpression(arg2); + } break; + case 0x0D: { + PopExpression(arg1); + PopUint16(labelNum); + (void)labelNum; + } break; + case 0x0F: + case 0x2E: { + PopExpression(arg1); + PopExpression(arg2); + PopExpression(arg3); + } break; + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x30: { + PopExpression(arg1); + } break; + case 0x31: { + PopExpression(arg1); + PopExpression(arg2); + } break; + } + ImpLogSlow(LogLevel::Warning, LogChannel::VMStub, + "STUB instruction PhoneSG0(type: {:d})\n", type); +} + VmInstruction(InstMail) { StartInstruction; PopUint8(type); diff --git a/src/vm/inst_gamespecific.h b/src/vm/inst_gamespecific.h index d4a7146e4..ef2ee783f 100644 --- a/src/vm/inst_gamespecific.h +++ b/src/vm/inst_gamespecific.h @@ -26,6 +26,10 @@ VmInstruction(InstUnk1037Noah); VmInstruction(InstUnk1037MO7); VmInstruction(InstMapSystem); VmInstruction(InstPhoneSG); +VmInstruction(InstSignInSG0); +VmInstruction(InstUnk004CSG0); +VmInstruction(InstPressStartSG0); +VmInstruction(InstPhoneSG0); VmInstruction(InstMail); VmInstruction(InstMtrg); VmInstruction(InstUnk1038Darling); diff --git a/src/vm/inst_misc.cpp b/src/vm/inst_misc.cpp index c50faf69f..775f81396 100644 --- a/src/vm/inst_misc.cpp +++ b/src/vm/inst_misc.cpp @@ -23,6 +23,8 @@ #include "../games/cc/titlemenu.h" #include "../games/cclcc/systemmenu.h" #include "../games/cclcc/helpmenu.h" +#include "../video/videosystem.h" +#include "../io/vfs.h" namespace Impacto { namespace Vm { @@ -545,6 +547,7 @@ VmInstruction(InstTitleMenuNew) { break; case InstructionSet::LCCSwitch: case InstructionSet::CC: + case InstructionSet::SG0: case InstructionSet::CHN: { int mainState; int startTransitionState; @@ -562,6 +565,17 @@ VmInstruction(InstTitleMenuNew) { startTransitionState = StartTransition; } + if (Profile::Vm::GameInstructionSet == InstructionSet::SG0 && + +Profile::Game::GameFeatures & +GameFeature::Video && + !Video::Players[0]->IsPlaying) { + // Keep the title movie looping. + constexpr int TitleMovieId = 32; + Io::Stream* stream; + if (Io::VfsOpen("movie", TitleMovieId, &stream) == IoError_OK) { + ScrWork[SW_MOVIEPRI] = 1; + Video::Players[0]->Play(stream, true, false); + } + } if (ScrWork[SW_TITLEMODE] == mainState) { if (!UI::TitleMenuPtr->AllowsScriptInput) { ResetInstruction; diff --git a/src/vm/inst_system.cpp b/src/vm/inst_system.cpp index 48d2b3f24..ca5eb4392 100644 --- a/src/vm/inst_system.cpp +++ b/src/vm/inst_system.cpp @@ -706,6 +706,7 @@ VmInstruction(InstSystemMes) { case InstructionSet::Dash: case InstructionSet::CC: case InstructionSet::LCCSwitch: + case InstructionSet::SG0: PopUint8(id); sysMesId = id; break; @@ -1010,7 +1011,8 @@ VmInstruction(InstMSinit) { Profile::Vm::GameInstructionSet == InstructionSet::CHLCC) { memset(&FlagWork, 0, 500); memset(&ScrWork, 0, 24000); - } else if (Profile::Vm::GameInstructionSet == InstructionSet::CC) { + } else if (Profile::Vm::GameInstructionSet == InstructionSet::CC || + Profile::Vm::GameInstructionSet == InstructionSet::SG0) { memset(&FlagWork, 0, 1000); memset(&ScrWork, 0, 32000); } else if (Profile::Vm::GameInstructionSet == InstructionSet::LCCSwitch) { diff --git a/src/vm/opcodetables_sg0.h b/src/vm/opcodetables_sg0.h new file mode 100644 index 000000000..35ad1cc32 --- /dev/null +++ b/src/vm/opcodetables_sg0.h @@ -0,0 +1,799 @@ +// Based on opcodetables_cc.h, corrected against SG0's scripts. +#include "inst_system.h" +#include "inst_controlflow.h" +#include "inst_graphics2d.h" +#include "inst_graphics3d.h" +#include "inst_dialogue.h" +#include "inst_sound.h" +#include "inst_movie.h" +#include "inst_gamespecific.h" +#include "inst_misc.h" + +// clang-format off + +namespace Impacto { + +namespace Vm { + +InstructionProc inline constexpr OpcodeTableSystem_SG0[256] = { + InstEnd, // 00 00 + InstCreateThread, // 00 01 + InstKillThread, // 00 02 + InstReset, // 00 03 + InstScriptLoad, // 00 04 + InstWait, // 00 05 + InstHalt, // 00 06 + InstJump, // 00 07 + InstJumpTable, // 00 08 + InstGetLabelAdr, // 00 09 + InstIf, // 00 0A + InstCall, // 00 0B + InstJumpFar, // 00 0C + InstCallFar, // 00 0D + InstReturn, // 00 0E + InstLoop, // 00 0F + InstFlagOnJump, // 00 10 + InstFlagOnWait, // 00 11 + InstSetFlag, // 00 12 + InstResetFlag, // 00 13 + InstCopyFlag, // 00 14 + InstKeyOnJump, // 00 15 + InstKeyWait, // 00 16 + InstKeyWaitTimer, // 00 17 + InstMemberWrite, // 00 18 + InstThreadControl, // 00 19 + InstGetSelfPointer, // 00 1A + InstLoadJump, // 00 1B + InstVsync, // 00 1C + InstTest, // 00 1D + InstThreadControlStore, // 00 1E + InstSwitch, // 00 1F + InstCase, // 00 20 + InstBGMplay, // 00 21 + InstBGMstop, // 00 22 + InstSEplay, // 00 23 + InstSEstop, // 00 24 + InstPadAct, // 00 25 + InstSSEplay, // 00 26 + InstSSEstop, // 00 27 + InstCopyThreadWork, // 00 28 + InstUPLmenuUI, // 00 29 + InstSave, // 00 2A + InstSaveIconLoad, // 00 2B + InstBGMflag, // 00 2C + InstUPLxTitle, // 00 2D + InstPresence, // 00 2E + InstSetAchievement, // 00 2F + InstSetPlayer, // 00 30 + InstVoiceTableLoadMaybe, // 00 31 + InstSetPadCustom, // 00 32 + InstMwait, // 00 33 + InstTerminate, // 00 34 + InstSignInSG0, // 00 35 + InstAchievementIcon, // 00 36 + InstVoicePlay, // 00 37 + InstVoiceStopNew, // 00 38 + InstVoicePlayWait, // 00 39 + InstBGMduelPlay, // 00 3A + InstSNDpause, // 00 3B + InstSEplayWait, // 00 3C + InstDebugPrint, // 00 3D + InstResetSoundAll, // 00 3E + InstSNDloadStop, // 00 3F + InstBGMstopWait, // 00 40 + InstUnk0041, // 00 41 + InstSetX360SysMesPos, // 00 42 + InstSystemMes, // 00 43 + InstSystemMenu, // 00 44 + InstGetNowTime, // 00 45 + InstGetSystemStatus, // 00 46 + InstReboot, // 00 47 + InstReloadScript, // 00 48 + InstReloadScriptMenu, // 00 49 + InstDebugEditer, // 00 4A + InstSysSeload, // 00 4B + InstUnk004CSG0, // 00 4C + InstSysVoicePlay, // 00 4D + InstPadActEx, // 00 4E + InstDebugSetup, // 00 4F + InstPressStartSG0, // 00 50 + InstGlobalSystemMessage, // 00 51 + InstUnk0052, // 00 52 + InstControlOnJump, // 00 53 + InstCallIfFlag, // 00 54 + InstControlOnJump, // 00 55 + InstCallFarIfFlag, // 00 56 + InstReturnIfFlag, // 00 57 + InstClickOnJump, // 00 58 + InstKeyboardOnJump, // 00 59 + InstDummy, // 00 5A + InstDummy, // 00 5B + InstFlagOffReturn, // 00 5C + InstDummy, // 00 5D + InstDummy, // 00 5E + InstPackFileAddBind, // 00 5F + InstDummy, // 00 60 + InstDummy, // 00 61 + InstDummy, // 00 62 + InstDummy, // 00 63 + InstDummy, // 00 64 + InstDummy, // 00 65 + InstDummy, // 00 66 + InstDummy, // 00 67 + InstDummy, // 00 68 + InstDummy, // 00 69 + InstDummy, // 00 6A + InstDummy, // 00 6B + InstDummy, // 00 6C + InstDummy, // 00 6D + InstDummy, // 00 6E + InstDummy, // 00 6F + InstDummy, // 00 70 + InstDummy, // 00 71 + InstDummy, // 00 72 + InstDummy, // 00 73 + InstDummy, // 00 74 + InstDummy, // 00 75 + InstDummy, // 00 76 + InstDummy, // 00 77 + InstDummy, // 00 78 + InstDummy, // 00 79 + InstDummy, // 00 7A + InstDummy, // 00 7B + InstDummy, // 00 7C + InstDummy, // 00 7D + InstDummy, // 00 7E + InstDummy, // 00 7F + InstDummy, // 00 80 + InstDummy, // 00 81 + InstDummy, // 00 82 + InstDummy, // 00 83 + InstDummy, // 00 84 + InstDummy, // 00 85 + InstDummy, // 00 86 + InstDummy, // 00 87 + InstDummy, // 00 88 + InstDummy, // 00 89 + InstDummy, // 00 8A + InstDummy, // 00 8B + InstDummy, // 00 8C + InstDummy, // 00 8D + InstDummy, // 00 8E + InstDummy, // 00 8F + InstDummy, // 00 90 + InstDummy, // 00 91 + InstDummy, // 00 92 + InstDummy, // 00 93 + InstDummy, // 00 94 + InstDummy, // 00 95 + InstDummy, // 00 96 + InstDummy, // 00 97 + InstDummy, // 00 98 + InstDummy, // 00 99 + InstDummy, // 00 9A + InstDummy, // 00 9B + InstDummy, // 00 9C + InstDummy, // 00 9D + InstDummy, // 00 9E + InstDummy, // 00 9F + InstDummy, // 00 A0 + InstDummy, // 00 A1 + InstDummy, // 00 A2 + InstDummy, // 00 A3 + InstDummy, // 00 A4 + InstDummy, // 00 A5 + InstDummy, // 00 A6 + InstDummy, // 00 A7 + InstDummy, // 00 A8 + InstDummy, // 00 A9 + InstDummy, // 00 AA + InstDummy, // 00 AB + InstDummy, // 00 AC + InstDummy, // 00 AD + InstDummy, // 00 AE + InstDummy, // 00 AF + InstDummy, // 00 B0 + InstDummy, // 00 B1 + InstDummy, // 00 B2 + InstDummy, // 00 B3 + InstDummy, // 00 B4 + InstDummy, // 00 B5 + InstDummy, // 00 B6 + InstDummy, // 00 B7 + InstDummy, // 00 B8 + InstDummy, // 00 B9 + InstDummy, // 00 BA + InstDummy, // 00 BB + InstDummy, // 00 BC + InstDummy, // 00 BD + InstDummy, // 00 BE + InstDummy, // 00 BF + InstDummy, // 00 C0 + InstDummy, // 00 C1 + InstDummy, // 00 C2 + InstDummy, // 00 C3 + InstDummy, // 00 C4 + InstDummy, // 00 C5 + InstDummy, // 00 C6 + InstDummy, // 00 C7 + InstDummy, // 00 C8 + InstDummy, // 00 C9 + InstDummy, // 00 CA + InstDummy, // 00 CB + InstDummy, // 00 CC + InstDummy, // 00 CD + InstDummy, // 00 CE + InstDummy, // 00 CF + InstDummy, // 00 D0 + InstDummy, // 00 D1 + InstDummy, // 00 D2 + InstDummy, // 00 D3 + InstDummy, // 00 D4 + InstDummy, // 00 D5 + InstDummy, // 00 D6 + InstDummy, // 00 D7 + InstDummy, // 00 D8 + InstDummy, // 00 D9 + InstDummy, // 00 DA + InstDummy, // 00 DB + InstDummy, // 00 DC + InstDummy, // 00 DD + InstDummy, // 00 DE + InstDummy, // 00 DF + InstDummy, // 00 E0 + InstDummy, // 00 E1 + InstDummy, // 00 E2 + InstDummy, // 00 E3 + InstDummy, // 00 E4 + InstDummy, // 00 E5 + InstDummy, // 00 E6 + InstDummy, // 00 E7 + InstDummy, // 00 E8 + InstDummy, // 00 E9 + InstDummy, // 00 EA + InstDummy, // 00 EB + InstDummy, // 00 EC + InstDummy, // 00 ED + InstDummy, // 00 EE + InstDummy, // 00 EF + InstDummy, // 00 F0 + InstDummy, // 00 F1 + InstDummy, // 00 F2 + InstDummy, // 00 F3 + InstDummy, // 00 F4 + InstDummy, // 00 F5 + InstDummy, // 00 F6 + InstDummy, // 00 F7 + InstDummy, // 00 F8 + InstDummy, // 00 F9 + InstDummy, // 00 FA + InstDummy, // 00 FB + InstDummy, // 00 FC + InstDummy, // 00 FD + InstDummy, // 00 FE + InstDummy // 00 FF +}; + +InstructionProc inline constexpr OpcodeTableGraph_SG0[256] = { + InstCreateSurf, // 01 00 + InstReleaseSurf, // 01 01 + InstLoadPic, // 01 02 + InstReleaseSurf, // 01 03 + InstSurfFill, // 01 04 + InstCalc, // 01 05 + InstMesViewFlag, // 01 06 + InstSetMesWinPri, // 01 07 + InstMesSync, // 01 08 + InstMesSetID, // 01 09 + InstMesCls, // 01 0A + InstMesVoiceWait, // 01 0B + InstMes, // 01 0C + InstMesMain, // 01 0D + InstSetMesModeFormat, // 01 0E + InstSetNGmoji, // 01 0F + InstMesRev, // 01 10 + InstMessWindow, // 01 11 + InstSel, // 01 12 + InstSelect, // 01 13 + InstSysSel, // 01 14 + InstSysSelect, // 01 15 + InstDummy, // 01 16 + InstDummy, // 01 17 + InstDummy, // 01 18 + InstDummy, // 01 19 + InstDummy, // 01 1A + InstDummy, // 01 1B + InstDummy, // 01 1C + InstDummy, // 01 1D + InstDummy, // 01 1E + InstLoadFontWidths, // 01 1F + InstSCcapture, // 01 20 + InstSetTextTable, // 01 21 + InstPlayMovie, // 01 22 + InstMovieMain, // 01 23 + InstLoadMovie, // 01 24 + InstSetRevMes, // 01 25 + InstPlayMovieMemory, // 01 26 + InstPlayMovie, // 01 27 + InstMovieMain, // 01 28 + InstLoadMovie, // 01 29 + InstPlayMovieMemory, // 01 2A + InstSFDpause, // 01 2B + InstPlayMovie, // 01 2C + InstUnk012D, // 01 2D + InstDummy, // 01 2E + InstDummy, // 01 2F + InstDummy, // 01 30 + InstDummy, // 01 31 + InstDummy, // 01 32 + InstDummy, // 01 33 + InstDummy, // 01 34 + InstDummy, // 01 35 + InstDummy, // 01 36 + InstDummy, // 01 37 + InstDummy, // 01 38 + InstDummy, // 01 39 + InstDummy, // 01 3A + InstDummy, // 01 3B + InstDummy, // 01 3C + InstDummy, // 01 3D + InstDummy, // 01 3E + InstDummy, // 01 3F + InstDummy, // 01 40 + InstDummy, // 01 41 + InstDummy, // 01 42 + InstDummy, // 01 43 + InstDummy, // 01 44 + InstDummy, // 01 45 + InstDummy, // 01 46 + InstDummy, // 01 47 + InstDummy, // 01 48 + InstDummy, // 01 49 + InstDummy, // 01 4A + InstDummy, // 01 4B + InstDummy, // 01 4C + InstDummy, // 01 4D + InstDummy, // 01 4E + InstDummy, // 01 4F + InstDummy, // 01 50 + InstDummy, // 01 51 + InstDummy, // 01 52 + InstDummy, // 01 53 + InstDummy, // 01 54 + InstDummy, // 01 55 + InstDummy, // 01 56 + InstDummy, // 01 57 + InstDummy, // 01 58 + InstDummy, // 01 59 + InstDummy, // 01 5A + InstDummy, // 01 5B + InstDummy, // 01 5C + InstDummy, // 01 5D + InstDummy, // 01 5E + InstDummy, // 01 5F + InstDummy, // 01 60 + InstDummy, // 01 61 + InstDummy, // 01 62 + InstDummy, // 01 63 + InstDummy, // 01 64 + InstDummy, // 01 65 + InstDummy, // 01 66 + InstDummy, // 01 67 + InstDummy, // 01 68 + InstDummy, // 01 69 + InstDummy, // 01 6A + InstDummy, // 01 6B + InstDummy, // 01 6C + InstDummy, // 01 6D + InstDummy, // 01 6E + InstDummy, // 01 6F + InstDummy, // 01 70 + InstDummy, // 01 71 + InstDummy, // 01 72 + InstDummy, // 01 73 + InstDummy, // 01 74 + InstDummy, // 01 75 + InstDummy, // 01 76 + InstDummy, // 01 77 + InstDummy, // 01 78 + InstDummy, // 01 79 + InstDummy, // 01 7A + InstDummy, // 01 7B + InstDummy, // 01 7C + InstDummy, // 01 7D + InstDummy, // 01 7E + InstDummy, // 01 7F + InstDummy, // 01 80 + InstDummy, // 01 81 + InstDummy, // 01 82 + InstDummy, // 01 83 + InstDummy, // 01 84 + InstDummy, // 01 85 + InstDummy, // 01 86 + InstDummy, // 01 87 + InstDummy, // 01 88 + InstDummy, // 01 89 + InstDummy, // 01 8A + InstDummy, // 01 8B + InstDummy, // 01 8C + InstDummy, // 01 8D + InstDummy, // 01 8E + InstDummy, // 01 8F + InstDummy, // 01 90 + InstDummy, // 01 91 + InstDummy, // 01 92 + InstDummy, // 01 93 + InstDummy, // 01 94 + InstDummy, // 01 95 + InstDummy, // 01 96 + InstDummy, // 01 97 + InstDummy, // 01 98 + InstDummy, // 01 99 + InstDummy, // 01 9A + InstDummy, // 01 9B + InstDummy, // 01 9C + InstDummy, // 01 9D + InstDummy, // 01 9E + InstDummy, // 01 9F + InstDummy, // 01 A0 + InstDummy, // 01 A1 + InstDummy, // 01 A2 + InstDummy, // 01 A3 + InstDummy, // 01 A4 + InstDummy, // 01 A5 + InstDummy, // 01 A6 + InstDummy, // 01 A7 + InstDummy, // 01 A8 + InstDummy, // 01 A9 + InstDummy, // 01 AA + InstDummy, // 01 AB + InstDummy, // 01 AC + InstDummy, // 01 AD + InstDummy, // 01 AE + InstDummy, // 01 AF + InstDummy, // 01 B0 + InstDummy, // 01 B1 + InstDummy, // 01 B2 + InstDummy, // 01 B3 + InstDummy, // 01 B4 + InstDummy, // 01 B5 + InstDummy, // 01 B6 + InstDummy, // 01 B7 + InstDummy, // 01 B8 + InstDummy, // 01 B9 + InstDummy, // 01 BA + InstDummy, // 01 BB + InstDummy, // 01 BC + InstDummy, // 01 BD + InstDummy, // 01 BE + InstDummy, // 01 BF + InstDummy, // 01 C0 + InstDummy, // 01 C1 + InstDummy, // 01 C2 + InstDummy, // 01 C3 + InstDummy, // 01 C4 + InstDummy, // 01 C5 + InstDummy, // 01 C6 + InstDummy, // 01 C7 + InstDummy, // 01 C8 + InstDummy, // 01 C9 + InstDummy, // 01 CA + InstDummy, // 01 CB + InstDummy, // 01 CC + InstDummy, // 01 CD + InstDummy, // 01 CE + InstDummy, // 01 CF + InstDummy, // 01 D0 + InstDummy, // 01 D1 + InstDummy, // 01 D2 + InstDummy, // 01 D3 + InstDummy, // 01 D4 + InstDummy, // 01 D5 + InstDummy, // 01 D6 + InstDummy, // 01 D7 + InstDummy, // 01 D8 + InstDummy, // 01 D9 + InstDummy, // 01 DA + InstDummy, // 01 DB + InstDummy, // 01 DC + InstDummy, // 01 DD + InstDummy, // 01 DE + InstDummy, // 01 DF + InstDummy, // 01 E0 + InstDummy, // 01 E1 + InstDummy, // 01 E2 + InstDummy, // 01 E3 + InstDummy, // 01 E4 + InstDummy, // 01 E5 + InstDummy, // 01 E6 + InstDummy, // 01 E7 + InstDummy, // 01 E8 + InstDummy, // 01 E9 + InstDummy, // 01 EA + InstDummy, // 01 EB + InstDummy, // 01 EC + InstDummy, // 01 ED + InstDummy, // 01 EE + InstDummy, // 01 EF + InstDummy, // 01 F0 + InstDummy, // 01 F1 + InstDummy, // 01 F2 + InstDummy, // 01 F3 + InstDummy, // 01 F4 + InstDummy, // 01 F5 + InstDummy, // 01 F6 + InstDummy, // 01 F7 + InstDummy, // 01 F8 + InstDummy, // 01 F9 + InstDummy, // 01 FA + InstDummy, // 01 FB + InstDummy, // 01 FC + InstDummy, // 01 FD + InstDummy, // 01 FE + InstDummy // 01 FF +}; + +InstructionProc inline constexpr OpcodeTableUser1_SG0[256] = { + InstMSinit, // 10 00 + InstBGload, // 10 01 + InstBGswap, // 10 02 + InstBGsetColor, // 10 03 + InstBGsetLink, // 10 04 + InstCHAload, // 10 05 + InstCHAswap, // 10 06 + InstBGcopy, // 10 07 + InstCHAcopy, // 10 08 + InstSaveSlot, // 10 09 + InstSystemMain, // 10 0A + InstCharaLayerLoad, // 10 0B + InstGameInfoInit, // 10 0C + InstCHAmove, // 10 0D + InstBGloadEx, // 10 0E + InstDummy, // 10 0F + InstBGrelease, // 10 10 + InstCHArelease, // 10 11 + InstClearFlagChk, // 10 12 + InstOption, // 10 13 + InstSystemDataReset, // 10 14 + InstDebugData, // 10 15 + InstGetCharaPause, // 10 16 + InstBGfadeExpInit, // 10 17 + InstDummy, // 10 18 + InstDummy, // 10 19 + InstHelp, // 10 1A + InstHelp, // 10 1B + InstAchievementMenu, // 10 1C + InstSoundMenu, // 10 1D + InstAllClear, // 10 1E + InstAlbum, // 10 1F + InstMovieMode, // 10 20 + InstClistInit, // 10 21 + InstAutoSave, // 10 22 + InstSaveMenu, // 10 23 + InstLoadData, // 10 24 + InstDummy, // 10 25 + InstDummy, // 10 26 + InstSetDic, // 10 27 + InstSetPlayMode, // 10 28 + InstSetEVflag, // 10 29 + InstSetCutin, // 10 2A + InstDummy, // 10 2B + InstDummy, // 10 2C + InstAchChkTitle, // 10 2D + InstSetSceneViewFlag, // 10 2E + InstChkClearFlag, // 10 2F + InstBGeffectWave, // 10 30 + InstGeotag, // 10 31 + InstNameID, // 10 32 + InstTips, // 10 33 + InstTitleMenuNew, // 10 34 + InstDummy, // 10 35 + InstBGeffect, // 10 36 + InstPhoneSG0, // 10 37 + InstMtrg, // 10 38 + InstTwipo_Dash, // 10 39 + InstYesNoTriggerCCLCC, // 10 3A + InstDummy, // 10 3B + InstDummy, // 10 3C + InstDummy, // 10 3D + InstDummy, // 10 3E + InstDummy, // 10 3F + InstScreenChange, // 10 40 + InstExitGame, // 10 41 + InstDummy, // 10 42 + InstDummy, // 10 43 + InstDummy, // 10 44 + InstDummy, // 10 45 + InstDummy, // 10 46 + InstDummy, // 10 47 + InstDummy, // 10 48 + InstDummy, // 10 49 + InstDummy, // 10 4A + InstDummy, // 10 4B + InstDummy, // 10 4C + InstDummy, // 10 4D + InstDummy, // 10 4E + InstDummy, // 10 4F + InstDummy, // 10 50 + InstDummy, // 10 51 + InstDummy, // 10 52 + InstDummy, // 10 53 + InstDummy, // 10 54 + InstDummy, // 10 55 + InstDummy, // 10 56 + InstDummy, // 10 57 + InstDummy, // 10 58 + InstDummy, // 10 59 + InstDummy, // 10 5A + InstDummy, // 10 5B + InstDummy, // 10 5C + InstDummy, // 10 5D + InstDummy, // 10 5E + InstDummy, // 10 5F + InstDummy, // 10 60 + InstDummy, // 10 61 + InstDummy, // 10 62 + InstDummy, // 10 63 + InstDummy, // 10 64 + InstDummy, // 10 65 + InstDummy, // 10 66 + InstDummy, // 10 67 + InstDummy, // 10 68 + InstDummy, // 10 69 + InstDummy, // 10 6A + InstDummy, // 10 6B + InstDummy, // 10 6C + InstDummy, // 10 6D + InstDummy, // 10 6E + InstDummy, // 10 6F + InstDummy, // 10 70 + InstDummy, // 10 71 + InstDummy, // 10 72 + InstDummy, // 10 73 + InstDummy, // 10 74 + InstDummy, // 10 75 + InstDummy, // 10 76 + InstDummy, // 10 77 + InstDummy, // 10 78 + InstDummy, // 10 79 + InstDummy, // 10 7A + InstDummy, // 10 7B + InstDummy, // 10 7C + InstDummy, // 10 7D + InstDummy, // 10 7E + InstDummy, // 10 7F + InstDummy, // 10 80 + InstDummy, // 10 81 + InstDummy, // 10 82 + InstDummy, // 10 83 + InstDummy, // 10 84 + InstDummy, // 10 85 + InstDummy, // 10 86 + InstDummy, // 10 87 + InstDummy, // 10 88 + InstDummy, // 10 89 + InstDummy, // 10 8A + InstDummy, // 10 8B + InstDummy, // 10 8C + InstDummy, // 10 8D + InstDummy, // 10 8E + InstDummy, // 10 8F + InstDummy, // 10 90 + InstDummy, // 10 91 + InstDummy, // 10 92 + InstDummy, // 10 93 + InstDummy, // 10 94 + InstDummy, // 10 95 + InstDummy, // 10 96 + InstDummy, // 10 97 + InstDummy, // 10 98 + InstDummy, // 10 99 + InstDummy, // 10 9A + InstDummy, // 10 9B + InstDummy, // 10 9C + InstDummy, // 10 9D + InstDummy, // 10 9E + InstDummy, // 10 9F + InstDummy, // 10 A0 + InstDummy, // 10 A1 + InstDummy, // 10 A2 + InstDummy, // 10 A3 + InstDummy, // 10 A4 + InstDummy, // 10 A5 + InstDummy, // 10 A6 + InstDummy, // 10 A7 + InstDummy, // 10 A8 + InstDummy, // 10 A9 + InstDummy, // 10 AA + InstDummy, // 10 AB + InstDummy, // 10 AC + InstDummy, // 10 AD + InstDummy, // 10 AE + InstDummy, // 10 AF + InstDummy, // 10 B0 + InstDummy, // 10 B1 + InstDummy, // 10 B2 + InstDummy, // 10 B3 + InstDummy, // 10 B4 + InstDummy, // 10 B5 + InstDummy, // 10 B6 + InstDummy, // 10 B7 + InstDummy, // 10 B8 + InstDummy, // 10 B9 + InstDummy, // 10 BA + InstDummy, // 10 BB + InstDummy, // 10 BC + InstDummy, // 10 BD + InstDummy, // 10 BE + InstDummy, // 10 BF + InstDummy, // 10 C0 + InstDummy, // 10 C1 + InstDummy, // 10 C2 + InstDummy, // 10 C3 + InstDummy, // 10 C4 + InstDummy, // 10 C5 + InstDummy, // 10 C6 + InstDummy, // 10 C7 + InstDummy, // 10 C8 + InstDummy, // 10 C9 + InstDummy, // 10 CA + InstDummy, // 10 CB + InstDummy, // 10 CC + InstDummy, // 10 CD + InstDummy, // 10 CE + InstDummy, // 10 CF + InstDummy, // 10 D0 + InstDummy, // 10 D1 + InstDummy, // 10 D2 + InstDummy, // 10 D3 + InstDummy, // 10 D4 + InstDummy, // 10 D5 + InstDummy, // 10 D6 + InstDummy, // 10 D7 + InstDummy, // 10 D8 + InstDummy, // 10 D9 + InstDummy, // 10 DA + InstDummy, // 10 DB + InstDummy, // 10 DC + InstDummy, // 10 DD + InstDummy, // 10 DE + InstDummy, // 10 DF + InstDummy, // 10 E0 + InstDummy, // 10 E1 + InstDummy, // 10 E2 + InstDummy, // 10 E3 + InstDummy, // 10 E4 + InstDummy, // 10 E5 + InstDummy, // 10 E6 + InstDummy, // 10 E7 + InstDummy, // 10 E8 + InstDummy, // 10 E9 + InstDummy, // 10 EA + InstDummy, // 10 EB + InstDummy, // 10 EC + InstDummy, // 10 ED + InstDummy, // 10 EE + InstDummy, // 10 EF + InstDummy, // 10 F0 + InstDummy, // 10 F1 + InstDummy, // 10 F2 + InstDummy, // 10 F3 + InstDummy, // 10 F4 + InstDummy, // 10 F5 + InstDummy, // 10 F6 + InstDummy, // 10 F7 + InstDummy, // 10 F8 + InstDummy, // 10 F9 + InstDummy, // 10 FA + InstDummy, // 10 FB + InstDummy, // 10 FC + InstDummy, // 10 FD + InstDummy, // 10 FE + InstDummy // 10 FF +}; + +} + +} + +// clang-format on \ No newline at end of file diff --git a/src/vm/vm.cpp b/src/vm/vm.cpp index e0ec54450..a14c3f5c9 100644 --- a/src/vm/vm.cpp +++ b/src/vm/vm.cpp @@ -19,6 +19,7 @@ #include "opcodetables_sgps3.h" #include "opcodetables_chn.h" #include "opcodetables_lccswitch.h" +#include "opcodetables_sg0.h" #include "../profile/game.h" #include "../profile/vm.h" #include "../profile/scriptinput.h" @@ -143,6 +144,12 @@ void Init() { break; } + case InstructionSet::SG0: { + OpcodeTableSystem = OpcodeTableSystem_SG0; + OpcodeTableGraph = OpcodeTableGraph_SG0; + OpcodeTableUser1 = OpcodeTableUser1_SG0; + break; + } default: { ImpLog(LogLevel::Fatal, LogChannel::VM, "Unsupported instruction set\n"); Window->Shutdown(); diff --git a/src/vm/vm.h b/src/vm/vm.h index 14010451f..3b578578b 100644 --- a/src/vm/vm.h +++ b/src/vm/vm.h @@ -22,6 +22,7 @@ enum class InstructionSet : int { MO8, CHN, LCCSwitch, + SG0, }; using InstructionProc = auto (*)(Sc3VmThread* thread, float dt) -> void;