From fe2ab3a21b6c0f3fe3932b3bd502ebcd52f2bae3 Mon Sep 17 00:00:00 2001 From: ALipAkrohk Date: Sat, 29 Oct 2022 07:32:00 +0330 Subject: [PATCH] First commit --- .gitignore | 1 + fonts/Material-Design-Iconic-Font.ttf | Bin 0 -> 99212 bytes input.conf | 45 + mpv.conf | 273 ++++ scripts/modern.lua | 2125 +++++++++++++++++++++++++ shaders/FSRCNNX_x2_8-0-4-1.glsl | 431 +++++ shaders/KrigBilateral.glsl | 217 +++ shaders/SSimDownscaler.glsl | 219 +++ shaders/SSimSuperRes.glsl | 206 +++ shaders/adaptive-sharpen.glsl | 233 +++ shaders/filmgrain.glsl | 45 + 11 files changed, 3795 insertions(+) create mode 100644 .gitignore create mode 100644 fonts/Material-Design-Iconic-Font.ttf create mode 100644 input.conf create mode 100644 mpv.conf create mode 100644 scripts/modern.lua create mode 100644 shaders/FSRCNNX_x2_8-0-4-1.glsl create mode 100755 shaders/KrigBilateral.glsl create mode 100755 shaders/SSimDownscaler.glsl create mode 100755 shaders/SSimSuperRes.glsl create mode 100755 shaders/adaptive-sharpen.glsl create mode 100755 shaders/filmgrain.glsl diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..663886c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +watch_later/ diff --git a/fonts/Material-Design-Iconic-Font.ttf b/fonts/Material-Design-Iconic-Font.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5d489fdd1a04cf2169af5e4d29d2929432a73f04 GIT binary patch literal 99212 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 Bf0O_K literal 0 HcmV?d00001 diff --git a/input.conf b/input.conf new file mode 100644 index 0000000..dd97a00 --- /dev/null +++ b/input.conf @@ -0,0 +1,45 @@ +ض quit + +Enter cycle fullscreen +a cycle audio +l cycle sub + +LEFT seek -2 +RIGHT seek +1 +Ctrl+LEFT seek -6 +Ctrl+RIGHT seek +5 +Shift+LEFT seek -11 +Shift+RIGHT seek +10 + +UP add volume 5 +Down add volume -5 +Ctrl+UP add volume 1 +Ctrl+DOWN add volume -1 +Shift+UP add volume 10 +Shift+DOWN add volume -10 + +WHEEL_UP add volume 5 +WHEEL_DOWN add volume -5 + +r cycle-values video-rotate 90 180 270 0 +- add video-zoom -0.05 ++ add video-zoom 0.05 +* set video-zoom 0 ; set video-pan-x 0 ; set video-pan-y 0 ; show-text "Reset zoom/pan" +Alt+Left add video-pan-x -0.01 +Alt+Right add video-pan-x 0.01 +Alt+Up add video-pan-y -0.01 +Alt+Down add video-pan-y 0.01 + +c add speed 0.2 ; show-text "Increaced Playback Speed: ${speed}" +C add speed 0.1 ; show-text "Increaced Playback Speed: ${speed}" +x add speed -0.2 ; show-text "Decreaced Playback Speed: ${speed}" +X add speed -0.1 ; show-text "Decreaced Playback Speed: ${speed}" +z set speed 1.0 ; show-text "Reset Playback Speed: ${speed}" +Z set speed 2.0 ; show-text "Playback Speed: ${speed}" + +. add sub-delay -0.1 ; show-text "Decreaced Subtitle Delay: ${sub-delay}" +, add sub-delay 0.1 ; show-text "Increaced Subtitle Delay: ${sub-delay}" +/ set sub-delay 0.0 ; show-text "Reset Subtile Delay: ${sub-delay}" + +] frame-step ; show-text "Frame: ${estimated-frame-number} / ${estimated-frame-count}" +[ frame-back-step ; show-text "Frame: ${estimated-frame-number} / ${estimated-frame-count}" diff --git a/mpv.conf b/mpv.conf new file mode 100644 index 0000000..de13e29 --- /dev/null +++ b/mpv.conf @@ -0,0 +1,273 @@ + +###### +# UI # +###### + +no-border # hide the window title bar +msg-color=yes # color log messages on terminal +term-osd-bar=yes # display a progress bar on the terminal +no-hidpi-window-scale # used on 5K iMac to prevent scaling by OSX +force-window=immediate # Do not wait with showing the video window until it has loaded. (This will +# resize the window once video is loaded. Also always shows a window with +# audio.) + +# fs=yes # Start in fullscreen mode by default. +# force starting with centered window +geometry=40%:60% + +# don't allow a new window to have a size larger than 90% of the screen size +autofit-larger=60%x60% + +# Do not close the window on exit. +#keep-open=yes + + +# Disable the On Screen Controller (OSC). +osc=no + +# Keep the player window on top of all other windows. +ontop=no + + +########### +# General # +########### + +# Main reference: +# https://mpv.io/manual/master/ + +--keep-open # Don't terminate if the current file is the last playlist entry. +--save-position-on-quit # Always save the current playback position on quit. + +#showFileNameInTitle +script-opts='osc-title=${filename}' + +#ScreenShot +screenshot-format=jpg +screenshot-jpeg-quality=100 +screenshot-high-bit-depth=yes +screenshot-directory="~/Pictures/ScreenShot/mpv" + +# OpenGL settings +gpu-api=opengl + +# Vulkan settings +# gpu-api=vulkan +# vulkan-async-compute=yes +# vulkan-async-transfer=yes +# vulkan-queue-count=1 +# vd-lavc-dr=yes + +# Enable hardware decoding if available. +hwdec=auto +reset-on-next-file=audio-delay,mute,pause,speed,sub-delay,video-aspect-override,video-pan-x,video-pan-y,video-rotate,video-zoom,volume + +############## +# Colorspace # +############## + +# see https://github.com/mpv-player/mpv/wiki/Video-output---shader-stage-diagram +target-prim=auto +# target-prim=bt.709 # target Rec.709 for SDR TVs +# target-prim=bt.2020 # target Rec.2020 (wide color gamut) for HDR TVs +target-trc=auto +gamma-auto +vf=format=colorlevels=full:colormatrix=auto +video-output-levels=full + +######################### +# Motion Interpolation # +######################### + +override-display-fps=60 +video-sync=display-resample +interpolation=yes +tscale=oversample # smoothmotion + +################ +# Anti-Ringing # +################ + +scale-antiring=0.7 # luma upscale deringing +dscale-antiring=0.7 # luma downscale deringing +cscale-antiring=0.7 # chroma upscale deringing + +# Enable fuzzy searching for subtitles. +sub-auto=fuzzy + +# Display English subtitles if available. +slang=en,eng,english + +# Play Farsi audio if available, fall back to English otherwise. +alang=fa,en + +# Set max volume to 100% +volume-max=150 +volume=75 + +# Change title to filename instead of media-title +title='${filename} - mpv' +script-opts='osc-title=${filename}' + +# Save video's volume amount and position +# It's when you quit mpv without killing the instance (not working with Shift+Q) +save-position-on-quit + +# Adjusting the window size for music. +[extension.mp3] +geometry=250x250 + +# If webm file is selected, playback forever. +[extension.webm] +loop-file=inf + +# If gif file is selected, playback forever. +[extension.gif] +loop-file=inf + +# If image is selected, keep it forever. +image-display-duration=inf + + +################################### +# Protocol Specific Configuration # +################################### + +# Pretend to be a web browser. Might fix playback with some streaming sites, +# but also will break with shoutcast streams. +user-agent="Mozilla/5.0" + +[protocol.http] +hls-bitrate=max # use max quality for HLS streams +cache=yes +no-cache-pause # don't pause when the cache runs low + +[protocol.https] +profile=protocol.http + +[protocol.ytdl] +profile=protocol.http + +# youtube-dl video quality configuration +# ytdl-format=bestvideo[height<=480]+bestaudio/best[height<=480] +# ytdl-format=bestvideo[height<=720]+bestaudio/best[height<=720] +# ytdl-format=bestvideo[height<=1080]+bestaudio/best[height<=1080] +# ytdl-format=bestvideo[height<=2160]+bestaudio/best[height<=2160] +ytdl-format=auto + + +# Misc +## youtube-dl subtitle configuration (non-auto-generated subtitles) +## Swith to yt-dlp +script-opts=ytdl-all-subs,ytdl_hook-ytdl_path=yt-dlp + + +########################################################################## FOR SCRIPTS ########################################################################### + +[Idle] +profile-cond=p["idle-active"] +profile-restore=copy-equal +keepaspect=no +background=1 +cursor-autohide=1000 # autohide the curser after 1s + + +############################################################# +# Upscaling & Processing Based on Source Video's Resolution # +############################################################# + +# Chroma subsampling means that chroma information is encoded at lower resolution than luma +# In MPV, chroma is upscaled to luma resolution (video size) and then the converted RGB is upscaled to target resolution (screen size) +# For detailed analysis of upscaler/downscaler quality, see https://artoriuz.github.io/blog/mpv_upscaling.html + +fbo-format=rgba16f # use with gpu-api=opengl +# fbo-format=rgba16hf # use with gpu-api=vulkan +# fbo-format is not not supported in gpu-next profile +glsl-shaders-clr +# luma upscaling +# note: any FSRCNNX above FSRCNNX_x2_8-0-4-1 is not worth the additional computional overhead +glsl-shaders="~/.config/mpv/shaders/FSRCNNX_x2_8-0-4-1.glsl" +scale=ewa_lanczos +# luma downscaling +# note: ssimdownscaler is tuned for mitchell and downscaling=no +glsl-shaders-append="~/.config/mpv/shaders/SSimDownscaler.glsl" +dscale=mitchell +linear-downscaling=no +# chroma upscaling and downscaling +glsl-shaders-append="~/.config/mpv/shaders/KrigBilateral.glsl" +cscale=mitchell # ignored with gpu-next +sigmoid-upscaling=yes + +############ +# Profiles # +############ + +[4k60] # 2160p @ 60fps (3840x2160 UHDTV) +profile-desc=4k60 +profile-cond=((width ==3840 and height ==2160) and p["estimated-vf-fps"]>=31) +# deband=yes # necessary to avoid blue screen with KrigBilateral.glsl +deband=no # turn off debanding because presume wide color gamut +interpolation=no # turn off interpolation because presume 60fps +# UHD videos are already 4K so no luma upscaling is needed +# UHD videos are YUV420 so chroma upscaling is still needed +glsl-shaders-clr +# glsl-shaders="~/.config/mpv/shaders/KrigBilateral.glsl" # enable if your hardware can support it +interpolation=no # no motion interpolation required because 60fps is hardware ceiling +# no deinterlacer required because progressive + +[4k30] # 2160p @ 24-30fps (3840x2160 UHDTV) +profile-cond=((width ==3840 and height ==2160) and p["estimated-vf-fps"]<31) +# deband=yes # necessary to avoid blue screen with KrigBilateral.glsl +deband=no # turn off debanding because presume wide color gamut +# UHD videos are already 4K so no luma upscaling is needed +# UHD videos are YUV420 so chroma upscaling is still needed +glsl-shaders-clr +# glsl-shaders="~/.config/mpv/shaders/KrigBilateral.glsl" # enable if your hardware can support it +# apply motion interpolation +# no deinterlacer required because progressive + +[full-hd60] # 1080p @ 60fps (progressive ATSC) +profile-desc=full-hd60 +profile-cond=((width ==1920 and height ==1080) and not p["video-frame-info/interlaced"] and p["estimated-vf-fps"]>=31) +# apply all luma and chroma upscaling and downscaling settings +interpolation=no # no motion interpolation required because 60fps is hardware ceiling +# no deinterlacer required because progressive + +[full-hd30] # 1080p @ 24-30fps (NextGen TV/ATSC 3.0, progressive Blu-ray) +profile-desc=full-hd30 +profile-cond=((width ==1920 and height ==1080) and not p["video-frame-info/interlaced"] and p["estimated-vf-fps"]<31) +# apply all luma and chroma upscaling and downscaling settings +# apply motion interpolation +# no deinterlacer required because progressive + +[full-hd-interlaced] # 1080i @ 24-30fps (HDTV, interlaced Blu-rays) +profile-desc=full-hd-interlaced +profile-cond=((width ==1920 and height ==1080) and p["video-frame-info/interlaced"] and p["estimated-vf-fps"]<31) +# apply all luma and chroma upscaling and downscaling settings +# apply motion interpolation +vf=bwdif # apply FFMPEG's bwdif deinterlacer + +[hd] # 720p @ 60 fps (HDTV, Blu-ray - progressive) +profile-desc=hd +profile-cond=(width ==1280 and height ==720) +# apply all luma and chroma upscaling and downscaling settings +interpolation=no # no motion interpolation required because 60fps is hardware ceiling +# no deinterlacer required because progressive + +[sdtv-ntsc] # 640x480, 704x480, 720x480 @ 30fps (NTSC DVD - interlaced) +profile-desc=sdtv-ntsc +profile-cond=((width ==640 and height ==480) or (width ==704 and height ==480) or (width ==720 and height ==480)) +# apply all luma and chroma upscaling and downscaling settings +# apply motion interpolation +vf=bwdif # apply FFMPEG's bwdif deinterlacer + +[sdtv-pal] # 352x576, 480x576, 544x576, 720x576 @ 30fps (PAL broadcast or DVD - interlaced) +profile-desc=sdtv-pal +profile-cond=((width ==352 and height ==576) or (width ==480 and height ==576) or (width ==544 and height ==576) or (width ==720 and height ==576)) +# apply all luma and chroma upscaling and downscaling settings +# apply motion interpolation +vf=bwdif # apply FFMPEG's bwdif deinterlacer + +[default] + +########################################################################## FOR SCRIPTS ########################################################################### diff --git a/scripts/modern.lua b/scripts/modern.lua new file mode 100644 index 0000000..41db0f8 --- /dev/null +++ b/scripts/modern.lua @@ -0,0 +1,2125 @@ +-- by maoiscat +-- email:valarmor@163.com +-- https://github.com/maoiscat/mpv-osc-morden + +local assdraw = require 'mp.assdraw' +local msg = require 'mp.msg' +local opt = require 'mp.options' +local utils = require 'mp.utils' + +-- +-- Parameters +-- +-- default user option values +-- may change them in osc.conf +local user_opts = { + showwindowed = true, -- show OSC when windowed? + showfullscreen = true, -- show OSC when fullscreen? + scalewindowed = 1, -- scaling of the controller when windowed + scalefullscreen = 1, -- scaling of the controller when fullscreen + scaleforcedwindow = 2, -- scaling when rendered on a forced window + vidscale = false, -- scale the controller with the video? + hidetimeout = 1000, -- duration in ms until the OSC hides if no + -- mouse movement. enforced non-negative for the + -- user, but internally negative is 'always-on'. + fadeduration = 500, -- duration of fade out in ms, 0 = no fade + minmousemove = 3, -- minimum amount of pixels the mouse has to + -- move between ticks to make the OSC show up + iamaprogrammer = false, -- use native mpv values and disable OSC + -- internal track list management (and some + -- functions that depend on it) + font = 'mpv-osd-symbols', -- default osc font + seekbarhandlesize = 1.0, -- size ratio of the slider handle, range 0 ~ 1 + seekrange = true, -- show seekrange overlay + seekrangealpha = 128, -- transparency of seekranges + seekbarkeyframes = true, -- use keyframes when dragging the seekbar + title = '${media-title}', -- string compatible with property-expansion + -- to be shown as OSC title + showtitle = true, -- show title and no hide timeout on pause + timetotal = true, -- display total time instead of remaining time? + visibility = 'auto', -- only used at init to set visibility_mode(...) + windowcontrols = 'auto', -- whether to show window controls + volumecontrol = true, -- whether to show mute button and volumne slider + language = 'eng', -- eng=English, chs=Chinese +} + +-- Localization +local language = { + ['eng'] = { + welcome = '{\\fs24\\1c&H0&\\3c&HFFFFFF&}Drop files or URLs to play here.', -- this text appears when mpv starts + off = 'OFF', + na = 'n/a', + none = 'none', + video = 'Video', + audio = 'Audio', + subtitle = 'Subtitle', + available = 'Available ', + track = ' Tracks:', + playlist = 'Playlist', + nolist = 'Empty playlist.', + chapter = 'Chapter', + nochapter = 'No chapters.', + }, + ['chs'] = { + welcome = '{\\1c&H00\\bord0\\fs30\\fn微软雅黑 light\\fscx125}MPV{\\fscx100} 播放器', -- this text appears when mpv starts + off = '关闭', + na = 'n/a', + none = '无', + video = '视频', + audio = '音频', + subtitle = '字幕', + available = '可选', + track = ':', + playlist = '播放列表', + nolist = '无列表信息', + chapter = '章节', + nochapter = '无章节信息', + } +} +-- read options from config and command-line +opt.read_options(user_opts, 'osc', function(list) update_options(list) end) +-- apply lang opts +local texts = language[user_opts.language] +local osc_param = { -- calculated by osc_init() + playresy = 0, -- canvas size Y + playresx = 0, -- canvas size X + display_aspect = 1, + unscaled_y = 0, + areas = {}, +} + +local osc_styles = { + TransBg = '{\\blur100\\bord140\\1c&H000000&\\3c&H000000&}', + SeekbarBg = '{\\blur0\\bord0\\1c&HFFFFFF&}', + SeekbarFg = '{\\blur1\\bord1\\1c&HE39C42&}', + VolumebarBg = '{\\blur0\\bord0\\1c&H999999&}', + VolumebarFg = '{\\blur1\\bord1\\1c&HFFFFFF&}', + Ctrl1 = '{\\blur0\\bord0\\1c&HFFFFFF&\\3c&HFFFFFF&\\fs36\\fnmaterial-design-iconic-font}', + Ctrl2 = '{\\blur0\\bord0\\1c&HFFFFFF&\\3c&HFFFFFF&\\fs24\\fnmaterial-design-iconic-font}', + Ctrl3 = '{\\blur0\\bord0\\1c&HFFFFFF&\\3c&HFFFFFF&\\fs24\\fnmaterial-design-iconic-font}', + Time = '{\\blur0\\bord0\\1c&HFFFFFF&\\3c&H000000&\\fs17\\fn' .. user_opts.font .. '}', + Tooltip = '{\\blur1\\bord0.5\\1c&HFFFFFF&\\3c&H000000&\\fs18\\fn' .. user_opts.font .. '}', + Title = '{\\blur1\\bord0.5\\1c&HFFFFFF&\\3c&H0\\fs48\\q2\\fn' .. user_opts.font .. '}', + WinCtrl = '{\\blur1\\bord0.5\\1c&HFFFFFF&\\3c&H0\\fs20\\fnmpv-osd-symbols}', + elementDown = '{\\1c&H999999&}', +} + +-- internal states, do not touch +local state = { + showtime, -- time of last invocation (last mouse move) + osc_visible = false, + anistart, -- time when the animation started + anitype, -- current type of animation + animation, -- current animation alpha + mouse_down_counter = 0, -- used for softrepeat + active_element = nil, -- nil = none, 0 = background, 1+ = see elements[] + active_event_source = nil, -- the 'button' that issued the current event + rightTC_trem = not user_opts.timetotal, -- if the right timecode should display total or remaining time + mp_screen_sizeX, mp_screen_sizeY, -- last screen-resolution, to detect resolution changes to issue reINITs + initREQ = false, -- is a re-init request pending? + last_mouseX, last_mouseY, -- last mouse position, to detect significant mouse movement + mouse_in_window = false, + message_text, + message_hide_timer, + fullscreen = false, + tick_timer = nil, + tick_last_time = 0, -- when the last tick() was run + hide_timer = nil, + cache_state = nil, + idle = false, + enabled = true, + input_enabled = true, + showhide_enabled = false, + dmx_cache = 0, + border = true, + maximized = false, + osd = mp.create_osd_overlay('ass-events'), + mute = false, + lastvisibility = user_opts.visibility, -- save last visibility on pause if showtitle +} + +local window_control_box_width = 138 +local tick_delay = 0.03 + +-- +-- Helperfunctions +-- + +function set_osd(res_x, res_y, text) + if state.osd.res_x == res_x and + state.osd.res_y == res_y and + state.osd.data == text then + return + end + state.osd.res_x = res_x + state.osd.res_y = res_y + state.osd.data = text + state.osd.z = 1000 + state.osd:update() +end + +-- scale factor for translating between real and virtual ASS coordinates +function get_virt_scale_factor() + local w, h = mp.get_osd_size() + if w <= 0 or h <= 0 then + return 0, 0 + end + return osc_param.playresx / w, osc_param.playresy / h +end + +-- return mouse position in virtual ASS coordinates (playresx/y) +function get_virt_mouse_pos() + if state.mouse_in_window then + local sx, sy = get_virt_scale_factor() + local x, y = mp.get_mouse_pos() + return x * sx, y * sy + else + return -1, -1 + end +end + +function set_virt_mouse_area(x0, y0, x1, y1, name) + local sx, sy = get_virt_scale_factor() + mp.set_mouse_area(x0 / sx, y0 / sy, x1 / sx, y1 / sy, name) +end + +function scale_value(x0, x1, y0, y1, val) + local m = (y1 - y0) / (x1 - x0) + local b = y0 - (m * x0) + return (m * val) + b +end + +-- returns hitbox spanning coordinates (top left, bottom right corner) +-- according to alignment +function get_hitbox_coords(x, y, an, w, h) + + local alignments = { + [1] = function () return x, y-h, x+w, y end, + [2] = function () return x-(w/2), y-h, x+(w/2), y end, + [3] = function () return x-w, y-h, x, y end, + + [4] = function () return x, y-(h/2), x+w, y+(h/2) end, + [5] = function () return x-(w/2), y-(h/2), x+(w/2), y+(h/2) end, + [6] = function () return x-w, y-(h/2), x, y+(h/2) end, + + [7] = function () return x, y, x+w, y+h end, + [8] = function () return x-(w/2), y, x+(w/2), y+h end, + [9] = function () return x-w, y, x, y+h end, + } + + return alignments[an]() +end + +function get_hitbox_coords_geo(geometry) + return get_hitbox_coords(geometry.x, geometry.y, geometry.an, + geometry.w, geometry.h) +end + +function get_element_hitbox(element) + return element.hitbox.x1, element.hitbox.y1, + element.hitbox.x2, element.hitbox.y2 +end + +function mouse_hit(element) + return mouse_hit_coords(get_element_hitbox(element)) +end + +function mouse_hit_coords(bX1, bY1, bX2, bY2) + local mX, mY = get_virt_mouse_pos() + return (mX >= bX1 and mX <= bX2 and mY >= bY1 and mY <= bY2) +end + +function limit_range(min, max, val) + if val > max then + val = max + elseif val < min then + val = min + end + return val +end + +-- translate value into element coordinates +function get_slider_ele_pos_for(element, val) + + local ele_pos = scale_value( + element.slider.min.value, element.slider.max.value, + element.slider.min.ele_pos, element.slider.max.ele_pos, + val) + + return limit_range( + element.slider.min.ele_pos, element.slider.max.ele_pos, + ele_pos) +end + +-- translates global (mouse) coordinates to value +function get_slider_value_at(element, glob_pos) + + local val = scale_value( + element.slider.min.glob_pos, element.slider.max.glob_pos, + element.slider.min.value, element.slider.max.value, + glob_pos) + + return limit_range( + element.slider.min.value, element.slider.max.value, + val) +end + +-- get value at current mouse position +function get_slider_value(element) + return get_slider_value_at(element, get_virt_mouse_pos()) +end + +function countone(val) + if not (user_opts.iamaprogrammer) then + val = val + 1 + end + return val +end + +-- multiplies two alpha values, formular can probably be improved +function mult_alpha(alphaA, alphaB) + return 255 - (((1-(alphaA/255)) * (1-(alphaB/255))) * 255) +end + +function add_area(name, x1, y1, x2, y2) + -- create area if needed + if (osc_param.areas[name] == nil) then + osc_param.areas[name] = {} + end + table.insert(osc_param.areas[name], {x1=x1, y1=y1, x2=x2, y2=y2}) +end + +function ass_append_alpha(ass, alpha, modifier) + local ar = {} + + for ai, av in pairs(alpha) do + av = mult_alpha(av, modifier) + if state.animation then + av = mult_alpha(av, state.animation) + end + ar[ai] = av + end + + ass:append(string.format('{\\1a&H%X&\\2a&H%X&\\3a&H%X&\\4a&H%X&}', + ar[1], ar[2], ar[3], ar[4])) +end + +function ass_draw_cir_cw(ass, x, y, r) + ass:round_rect_cw(x-r, y-r, x+r, y+r, r) +end + +function ass_draw_rr_h_cw(ass, x0, y0, x1, y1, r1, hexagon, r2) + if hexagon then + ass:hexagon_cw(x0, y0, x1, y1, r1, r2) + else + ass:round_rect_cw(x0, y0, x1, y1, r1, r2) + end +end + +function ass_draw_rr_h_ccw(ass, x0, y0, x1, y1, r1, hexagon, r2) + if hexagon then + ass:hexagon_ccw(x0, y0, x1, y1, r1, r2) + else + ass:round_rect_ccw(x0, y0, x1, y1, r1, r2) + end +end + + +-- +-- Tracklist Management +-- + +local nicetypes = {video = texts.video, audio = texts.audio, sub = texts.subtitle} + +-- updates the OSC internal playlists, should be run each time the track-layout changes +function update_tracklist() + local tracktable = mp.get_property_native('track-list', {}) + + -- by osc_id + tracks_osc = {} + tracks_osc.video, tracks_osc.audio, tracks_osc.sub = {}, {}, {} + -- by mpv_id + tracks_mpv = {} + tracks_mpv.video, tracks_mpv.audio, tracks_mpv.sub = {}, {}, {} + for n = 1, #tracktable do + if not (tracktable[n].type == 'unknown') then + local type = tracktable[n].type + local mpv_id = tonumber(tracktable[n].id) + + -- by osc_id + table.insert(tracks_osc[type], tracktable[n]) + + -- by mpv_id + tracks_mpv[type][mpv_id] = tracktable[n] + tracks_mpv[type][mpv_id].osc_id = #tracks_osc[type] + end + end +end + +-- return a nice list of tracks of the given type (video, audio, sub) +function get_tracklist(type) + local msg = texts.available .. nicetypes[type] .. texts.track + if #tracks_osc[type] == 0 then + msg = msg .. texts.none + else + for n = 1, #tracks_osc[type] do + local track = tracks_osc[type][n] + local lang, title, selected = 'unknown', '', '○' + if not(track.lang == nil) then lang = track.lang end + if not(track.title == nil) then title = track.title end + if (track.id == tonumber(mp.get_property(type))) then + selected = '●' + end + msg = msg..'\n'..selected..' '..n..': ['..lang..'] '..title + end + end + return msg +end + +-- relatively change the track of given by tracks + --(+1 -> next, -1 -> previous) +function set_track(type, next) + local current_track_mpv, current_track_osc + if (mp.get_property(type) == 'no') then + current_track_osc = 0 + else + current_track_mpv = tonumber(mp.get_property(type)) + current_track_osc = tracks_mpv[type][current_track_mpv].osc_id + end + local new_track_osc = (current_track_osc + next) % (#tracks_osc[type] + 1) + local new_track_mpv + if new_track_osc == 0 then + new_track_mpv = 'no' + else + new_track_mpv = tracks_osc[type][new_track_osc].id + end + + mp.commandv('set', type, new_track_mpv) + +-- if (new_track_osc == 0) then +-- show_message(nicetypes[type] .. ' Track: none') +-- else +-- show_message(nicetypes[type] .. ' Track: ' +-- .. new_track_osc .. '/' .. #tracks_osc[type] +-- .. ' ['.. (tracks_osc[type][new_track_osc].lang or 'unknown') ..'] ' +-- .. (tracks_osc[type][new_track_osc].title or '')) +-- end +end + +-- get the currently selected track of , OSC-style counted +function get_track(type) + local track = mp.get_property(type) + if track ~= 'no' and track ~= nil then + local tr = tracks_mpv[type][tonumber(track)] + if tr then + return tr.osc_id + end + end + return 0 +end + +-- WindowControl helpers +function window_controls_enabled() + val = user_opts.windowcontrols + if val == 'auto' then + return (not state.border) or state.fullscreen + else + return val ~= 'no' + end +end + +-- +-- Element Management +-- + +local elements = {} + +function prepare_elements() + + -- remove elements without layout or invisble + local elements2 = {} + for n, element in pairs(elements) do + if not (element.layout == nil) and (element.visible) then + table.insert(elements2, element) + end + end + elements = elements2 + + function elem_compare (a, b) + return a.layout.layer < b.layout.layer + end + + table.sort(elements, elem_compare) + + + for _,element in pairs(elements) do + + local elem_geo = element.layout.geometry + + -- Calculate the hitbox + local bX1, bY1, bX2, bY2 = get_hitbox_coords_geo(elem_geo) + element.hitbox = {x1 = bX1, y1 = bY1, x2 = bX2, y2 = bY2} + + local style_ass = assdraw.ass_new() + + -- prepare static elements + style_ass:append('{}') -- hack to troll new_event into inserting a \n + style_ass:new_event() + style_ass:pos(elem_geo.x, elem_geo.y) + style_ass:an(elem_geo.an) + style_ass:append(element.layout.style) + + element.style_ass = style_ass + + local static_ass = assdraw.ass_new() + + + if (element.type == 'box') then + --draw box + static_ass:draw_start() + ass_draw_rr_h_cw(static_ass, 0, 0, elem_geo.w, elem_geo.h, + element.layout.box.radius, element.layout.box.hexagon) + static_ass:draw_stop() + + elseif (element.type == 'slider') then + --draw static slider parts + local slider_lo = element.layout.slider + -- calculate positions of min and max points + element.slider.min.ele_pos = user_opts.seekbarhandlesize * elem_geo.h / 2 + element.slider.max.ele_pos = elem_geo.w - element.slider.min.ele_pos + element.slider.min.glob_pos = element.hitbox.x1 + element.slider.min.ele_pos + element.slider.max.glob_pos = element.hitbox.x1 + element.slider.max.ele_pos + + static_ass:draw_start() + -- a hack which prepares the whole slider area to allow center placements such like an=5 + static_ass:rect_cw(0, 0, elem_geo.w, elem_geo.h) + static_ass:rect_ccw(0, 0, elem_geo.w, elem_geo.h) + -- marker nibbles + if not (element.slider.markerF == nil) and (slider_lo.gap > 0) then + local markers = element.slider.markerF() + for _,marker in pairs(markers) do + if (marker >= element.slider.min.value) and (marker <= element.slider.max.value) then + local s = get_slider_ele_pos_for(element, marker) + if (slider_lo.gap > 5) then -- draw triangles + --top + if (slider_lo.nibbles_top) then + static_ass:move_to(s - 3, slider_lo.gap - 5) + static_ass:line_to(s + 3, slider_lo.gap - 5) + static_ass:line_to(s, slider_lo.gap - 1) + end + --bottom + if (slider_lo.nibbles_bottom) then + static_ass:move_to(s - 3, elem_geo.h - slider_lo.gap + 5) + static_ass:line_to(s, elem_geo.h - slider_lo.gap + 1) + static_ass:line_to(s + 3, elem_geo.h - slider_lo.gap + 5) + end + else -- draw 2x1px nibbles + --top + if (slider_lo.nibbles_top) then + static_ass:rect_cw(s - 1, 0, s + 1, slider_lo.gap); + end + --bottom + if (slider_lo.nibbles_bottom) then + static_ass:rect_cw(s - 1, elem_geo.h-slider_lo.gap, s + 1, elem_geo.h); + end + end + end + end + end + end + + element.static_ass = static_ass + + -- if the element is supposed to be disabled, + -- style it accordingly and kill the eventresponders + if not (element.enabled) then + element.layout.alpha[1] = 136 + element.eventresponder = nil + end + end +end + +-- +-- Element Rendering +-- +function render_elements(master_ass) + + for n=1, #elements do + local element = elements[n] + local style_ass = assdraw.ass_new() + style_ass:merge(element.style_ass) + ass_append_alpha(style_ass, element.layout.alpha, 0) + + if element.eventresponder and (state.active_element == n) then + -- run render event functions + if not (element.eventresponder.render == nil) then + element.eventresponder.render(element) + end + if mouse_hit(element) then + -- mouse down styling + if (element.styledown) then + style_ass:append(osc_styles.elementDown) + end + if (element.softrepeat) and (state.mouse_down_counter >= 15 + and state.mouse_down_counter % 5 == 0) then + + element.eventresponder[state.active_event_source..'_down'](element) + end + state.mouse_down_counter = state.mouse_down_counter + 1 + end + end + + local elem_ass = assdraw.ass_new() + elem_ass:merge(style_ass) + + if not (element.type == 'button') then + elem_ass:merge(element.static_ass) + end + + if (element.type == 'slider') then + + local slider_lo = element.layout.slider + local elem_geo = element.layout.geometry + local s_min = element.slider.min.value + local s_max = element.slider.max.value + -- draw pos marker + local pos = element.slider.posF() + local seekRanges = element.slider.seekRangesF() + local rh = user_opts.seekbarhandlesize * elem_geo.h / 2 -- Handle radius + local xp + + if pos then + xp = get_slider_ele_pos_for(element, pos) + ass_draw_cir_cw(elem_ass, xp, elem_geo.h/2, rh) + elem_ass:rect_cw(0, slider_lo.gap, xp, elem_geo.h - slider_lo.gap) + end + + if seekRanges then + elem_ass:draw_stop() + elem_ass:merge(element.style_ass) + ass_append_alpha(elem_ass, element.layout.alpha, user_opts.seekrangealpha) + elem_ass:merge(element.static_ass) + + for _,range in pairs(seekRanges) do + local pstart = get_slider_ele_pos_for(element, range['start']) + local pend = get_slider_ele_pos_for(element, range['end']) + elem_ass:rect_cw(pstart - rh, slider_lo.gap, pend + rh, elem_geo.h - slider_lo.gap) + end + end + + elem_ass:draw_stop() + + -- add tooltip + if not (element.slider.tooltipF == nil) then + if mouse_hit(element) then + local sliderpos = get_slider_value(element) + local tooltiplabel = element.slider.tooltipF(sliderpos) + local an = slider_lo.tooltip_an + local ty + if (an == 2) then + ty = element.hitbox.y1 + else + ty = element.hitbox.y1 + elem_geo.h/2 + end + + local tx = get_virt_mouse_pos() + if (slider_lo.adjust_tooltip) then + if (an == 2) then + if (sliderpos < (s_min + 3)) then + an = an - 1 + elseif (sliderpos > (s_max - 3)) then + an = an + 1 + end + elseif (sliderpos > (s_max-s_min)/2) then + an = an + 1 + tx = tx - 5 + else + an = an - 1 + tx = tx + 10 + end + end + + -- tooltip label + elem_ass:new_event() + elem_ass:pos(tx, ty) + elem_ass:an(an) + elem_ass:append(slider_lo.tooltip_style) + ass_append_alpha(elem_ass, slider_lo.alpha, 0) + elem_ass:append(tooltiplabel) + end + end + + elseif (element.type == 'button') then + + local buttontext + if type(element.content) == 'function' then + buttontext = element.content() -- function objects + elseif not (element.content == nil) then + buttontext = element.content -- text objects + end + + buttontext = buttontext:gsub(':%((.?.?.?)%) unknown ', ':%(%1%)') --gsub('%) unknown %(\'', '') + + local maxchars = element.layout.button.maxchars + -- 认为1个中文字符约等于1.5个英文字符 + local charcount = (buttontext:len() + select(2, buttontext:gsub('[^\128-\193]', ''))*2) / 3 + if not (maxchars == nil) and (charcount > maxchars) then + local limit = math.max(0, maxchars - 3) + if (charcount > limit) then + while (charcount > limit) do + buttontext = buttontext:gsub('.[\128-\191]*$', '') + charcount = (buttontext:len() + select(2, buttontext:gsub('[^\128-\193]', ''))*2) / 3 + end + buttontext = buttontext .. '...' + end + end + + elem_ass:append(buttontext) + + -- add tooltip + if not (element.tooltipF == nil) and element.enabled then + if mouse_hit(element) then + local tooltiplabel = element.tooltipF + local an = 1 + local ty = element.hitbox.y1 + local tx = get_virt_mouse_pos() + + if ty < osc_param.playresy / 2 then + ty = element.hitbox.y2 + an = 7 + end + + -- tooltip label + if type(element.tooltipF) == 'function' then + tooltiplabel = element.tooltipF() + else + tooltiplabel = element.tooltipF + end + elem_ass:new_event() + elem_ass:pos(tx, ty) + elem_ass:an(an) + elem_ass:append(element.tooltip_style) + elem_ass:append(tooltiplabel) + end + end + end + + master_ass:merge(elem_ass) + end +end + +-- +-- Message display +-- + +-- pos is 1 based +function limited_list(prop, pos) + local proplist = mp.get_property_native(prop, {}) + local count = #proplist + if count == 0 then + return count, proplist + end + + local fs = tonumber(mp.get_property('options/osd-font-size')) + local max = math.ceil(osc_param.unscaled_y*0.75 / fs) + if max % 2 == 0 then + max = max - 1 + end + local delta = math.ceil(max / 2) - 1 + local begi = math.max(math.min(pos - delta, count - max + 1), 1) + local endi = math.min(begi + max - 1, count) + + local reslist = {} + for i=begi, endi do + local item = proplist[i] + item.current = (i == pos) and true or nil + table.insert(reslist, item) + end + return count, reslist +end + +function get_playlist() + local pos = mp.get_property_number('playlist-pos', 0) + 1 + local count, limlist = limited_list('playlist', pos) + if count == 0 then + return texts.nolist + end + + local message = string.format(texts.playlist .. ' [%d/%d]:\n', pos, count) + for i, v in ipairs(limlist) do + local title = v.title + local _, filename = utils.split_path(v.filename) + if title == nil then + title = filename + end + message = string.format('%s %s %s\n', message, + (v.current and '●' or '○'), title) + end + return message +end + +function get_chapterlist() + local pos = mp.get_property_number('chapter', 0) + 1 + local count, limlist = limited_list('chapter-list', pos) + if count == 0 then + return texts.nochapter + end + + local message = string.format(texts.chapter.. ' [%d/%d]:\n', pos, count) + for i, v in ipairs(limlist) do + local time = mp.format_time(v.time) + local title = v.title + if title == nil then + title = string.format(texts.chapter .. ' %02d', i) + end + message = string.format('%s[%s] %s %s\n', message, time, + (v.current and '●' or '○'), title) + end + return message +end + +function show_message(text, duration) + + --print('text: '..text..' duration: ' .. duration) + if duration == nil then + duration = tonumber(mp.get_property('options/osd-duration')) / 1000 + elseif not type(duration) == 'number' then + print('duration: ' .. duration) + end + + -- cut the text short, otherwise the following functions + -- may slow down massively on huge input + text = string.sub(text, 0, 4000) + + -- replace actual linebreaks with ASS linebreaks + text = string.gsub(text, '\n', '\\N') + + state.message_text = text + + if not state.message_hide_timer then + state.message_hide_timer = mp.add_timeout(0, request_tick) + end + state.message_hide_timer:kill() + state.message_hide_timer.timeout = duration + state.message_hide_timer:resume() + request_tick() +end + +function render_message(ass) + if state.message_hide_timer and state.message_hide_timer:is_enabled() and + state.message_text + then + local _, lines = string.gsub(state.message_text, '\\N', '') + + local fontsize = tonumber(mp.get_property('options/osd-font-size')) + local outline = tonumber(mp.get_property('options/osd-border-size')) + local maxlines = math.ceil(osc_param.unscaled_y*0.75 / fontsize) + local counterscale = osc_param.playresy / osc_param.unscaled_y + + fontsize = fontsize * counterscale / math.max(0.65 + math.min(lines/maxlines, 1), 1) + outline = outline * counterscale / math.max(0.75 + math.min(lines/maxlines, 1)/2, 1) + + local style = '{\\bord' .. outline .. '\\fs' .. fontsize .. '}' + + + ass:new_event() + ass:append(style .. state.message_text) + else + state.message_text = nil + end +end + +-- +-- Initialisation and Layout +-- + +function new_element(name, type) + elements[name] = {} + elements[name].type = type + + -- add default stuff + elements[name].eventresponder = {} + elements[name].visible = true + elements[name].enabled = true + elements[name].softrepeat = false + elements[name].styledown = (type == 'button') + elements[name].state = {} + + if (type == 'slider') then + elements[name].slider = {min = {value = 0}, max = {value = 100}} + end + + + return elements[name] +end + +function add_layout(name) + if not (elements[name] == nil) then + -- new layout + elements[name].layout = {} + + -- set layout defaults + elements[name].layout.layer = 50 + elements[name].layout.alpha = {[1] = 0, [2] = 255, [3] = 255, [4] = 255} + + if (elements[name].type == 'button') then + elements[name].layout.button = { + maxchars = nil, + } + elseif (elements[name].type == 'slider') then + -- slider defaults + elements[name].layout.slider = { + border = 1, + gap = 1, + nibbles_top = true, + nibbles_bottom = true, + adjust_tooltip = true, + tooltip_style = '', + tooltip_an = 2, + alpha = {[1] = 0, [2] = 255, [3] = 88, [4] = 255}, + } + elseif (elements[name].type == 'box') then + elements[name].layout.box = {radius = 0, hexagon = false} + end + + return elements[name].layout + else + msg.error('Can\'t add_layout to element \''..name..'\', doesn\'t exist.') + end +end + +-- Window Controls +function window_controls() + local wc_geo = { + x = 0, + y = 32, + an = 1, + w = osc_param.playresx, + h = 32, + } + + local controlbox_w = window_control_box_width + local titlebox_w = wc_geo.w - controlbox_w + + -- Default alignment is 'right' + local controlbox_left = wc_geo.w - controlbox_w + local titlebox_left = wc_geo.x + local titlebox_right = wc_geo.w - controlbox_w + + add_area('window-controls', + get_hitbox_coords(controlbox_left, wc_geo.y, wc_geo.an, + controlbox_w, wc_geo.h)) + + local lo + + local button_y = wc_geo.y - (wc_geo.h / 2) + local first_geo = + {x = controlbox_left + 27, y = button_y, an = 5, w = 40, h = wc_geo.h} + local second_geo = + {x = controlbox_left + 69, y = button_y, an = 5, w = 40, h = wc_geo.h} + local third_geo = + {x = controlbox_left + 115, y = button_y, an = 5, w = 40, h = wc_geo.h} + + -- Window control buttons use symbols in the custom mpv osd font + -- because the official unicode codepoints are sufficiently + -- exotic that a system might lack an installed font with them, + -- and libass will complain that they are not present in the + -- default font, even if another font with them is available. + + -- Close: ?? + ne = new_element('close', 'button') + ne.content = '\238\132\149' + ne.eventresponder['mbtn_left_up'] = + function () mp.commandv('quit') end + lo = add_layout('close') + lo.geometry = third_geo + lo.style = osc_styles.WinCtrl + lo.alpha[3] = 0 + + -- Minimize: ?? + ne = new_element('minimize', 'button') + ne.content = '\\n\238\132\146' + ne.eventresponder['mbtn_left_up'] = + function () mp.commandv('cycle', 'window-minimized') end + lo = add_layout('minimize') + lo.geometry = first_geo + lo.style = osc_styles.WinCtrl + lo.alpha[3] = 0 + + -- Maximize: ?? /?? + ne = new_element('maximize', 'button') + if state.maximized or state.fullscreen then + ne.content = '\238\132\148' + else + ne.content = '\238\132\147' + end + ne.eventresponder['mbtn_left_up'] = + function () + if state.fullscreen then + mp.commandv('cycle', 'fullscreen') + else + mp.commandv('cycle', 'window-maximized') + end + end + lo = add_layout('maximize') + lo.geometry = second_geo + lo.style = osc_styles.WinCtrl + lo.alpha[3] = 0 +end + +-- +-- Layouts +-- + +local layouts = {} + +-- Default layout +layouts = function () + + local osc_geo = {w, h} + + osc_geo.w = osc_param.playresx + osc_geo.h = 180 + + -- origin of the controllers, left/bottom corner + local posX = 0 + local posY = osc_param.playresy + + osc_param.areas = {} -- delete areas + + -- area for active mouse input + add_area('input', get_hitbox_coords(posX, posY, 1, osc_geo.w, 104)) + + -- area for show/hide + add_area('showhide', 0, 0, osc_param.playresx, osc_param.playresy) + + -- fetch values + local osc_w, osc_h= + osc_geo.w, osc_geo.h + + -- + -- Controller Background + -- + local lo + + new_element('TransBg', 'box') + lo = add_layout('TransBg') + lo.geometry = {x = posX, y = posY, an = 7, w = osc_w, h = 1} + lo.style = osc_styles.TransBg + lo.layer = 10 + lo.alpha[3] = 0 + + -- + -- Alignment + -- + local refX = osc_w / 2 + local refY = posY + local geo + + -- + -- Seekbar + -- + new_element('seekbarbg', 'box') + lo = add_layout('seekbarbg') + lo.geometry = {x = refX , y = refY - 96 , an = 5, w = osc_geo.w - 50, h = 2} + lo.layer = 13 + lo.style = osc_styles.SeekbarBg + lo.alpha[1] = 128 + lo.alpha[3] = 128 + + lo = add_layout('seekbar') + lo.geometry = {x = refX, y = refY - 96 , an = 5, w = osc_geo.w - 50, h = 16} + lo.style = osc_styles.SeekbarFg + lo.slider.gap = 7 + lo.slider.tooltip_style = osc_styles.Tooltip + lo.slider.tooltip_an = 2 + -- + -- Volumebar + -- + lo = new_element('volumebarbg', 'box') + lo.visible = (osc_param.playresx >= 750) and user_opts.volumecontrol + lo = add_layout('volumebarbg') + lo.geometry = {x = 155, y = refY - 40, an = 4, w = 80, h = 2} + lo.layer = 13 + lo.style = osc_styles.VolumebarBg + + + lo = add_layout('volumebar') + lo.geometry = {x = 155, y = refY - 40, an = 4, w = 80, h = 8} + lo.style = osc_styles.VolumebarFg + lo.slider.gap = 3 + lo.slider.tooltip_style = osc_styles.Tooltip + lo.slider.tooltip_an = 2 + + -- buttons + lo = add_layout('pl_prev') + lo.geometry = {x = refX - 120, y = refY - 40 , an = 5, w = 30, h = 24} + lo.style = osc_styles.Ctrl2 + + lo = add_layout('skipback') + lo.geometry = {x = refX - 60, y = refY - 40 , an = 5, w = 30, h = 24} + lo.style = osc_styles.Ctrl2 + + + lo = add_layout('playpause') + lo.geometry = {x = refX, y = refY - 40 , an = 5, w = 45, h = 45} + lo.style = osc_styles.Ctrl1 + + lo = add_layout('skipfrwd') + lo.geometry = {x = refX + 60, y = refY - 40 , an = 5, w = 30, h = 24} + lo.style = osc_styles.Ctrl2 + + lo = add_layout('pl_next') + lo.geometry = {x = refX + 120, y = refY - 40 , an = 5, w = 30, h = 24} + lo.style = osc_styles.Ctrl2 + + + -- Time + lo = add_layout('tc_left') + lo.geometry = {x = 25, y = refY - 84, an = 7, w = 64, h = 20} + lo.style = osc_styles.Time + + + lo = add_layout('tc_right') + lo.geometry = {x = osc_geo.w - 25 , y = refY -84, an = 9, w = 64, h = 20} + lo.style = osc_styles.Time + + lo = add_layout('cy_audio') + lo.geometry = {x = 37, y = refY - 40, an = 5, w = 24, h = 24} + lo.style = osc_styles.Ctrl3 + lo.visible = (osc_param.playresx >= 540) + + lo = add_layout('cy_sub') + lo.geometry = {x = 87, y = refY - 40, an = 5, w = 24, h = 24} + lo.style = osc_styles.Ctrl3 + lo.visible = (osc_param.playresx >= 600) + + lo = add_layout('vol_ctrl') + lo.geometry = {x = 137, y = refY - 40, an = 5, w = 24, h = 24} + lo.style = osc_styles.Ctrl3 + lo.visible = (osc_param.playresx >= 650) + + lo = add_layout('tog_fs') + lo.geometry = {x = osc_geo.w - 37, y = refY - 40, an = 5, w = 24, h = 24} + lo.style = osc_styles.Ctrl3 + lo.visible = (osc_param.playresx >= 540) + + lo = add_layout('tog_info') + lo.geometry = {x = osc_geo.w - 87, y = refY - 40, an = 5, w = 24, h = 24} + lo.style = osc_styles.Ctrl3 + lo.visible = (osc_param.playresx >= 600) + + geo = { x = 25, y = refY - 132, an = 1, w = osc_geo.w - 50, h = 48 } + lo = add_layout('title') + lo.geometry = geo + lo.style = string.format('%s{\\clip(%f,%f,%f,%f)}', osc_styles.Title, + geo.x, geo.y - geo.h, geo.x + geo.w , geo.y) + lo.alpha[3] = 0 + lo.button.maxchars = geo.w / 23 +end + +-- Validate string type user options +function validate_user_opts() + if user_opts.windowcontrols ~= 'auto' and + user_opts.windowcontrols ~= 'yes' and + user_opts.windowcontrols ~= 'no' then + msg.warn('windowcontrols cannot be \'' .. + user_opts.windowcontrols .. '\'. Ignoring.') + user_opts.windowcontrols = 'auto' + end +end + +function update_options(list) + validate_user_opts() + request_tick() + visibility_mode(user_opts.visibility, true) + request_init() +end + +-- OSC INIT +function osc_init() + msg.debug('osc_init') + + -- set canvas resolution according to display aspect and scaling setting + local baseResY = 720 + local display_w, display_h, display_aspect = mp.get_osd_size() + local scale = 1 + + if (mp.get_property('video') == 'no') then -- dummy/forced window + scale = user_opts.scaleforcedwindow + elseif state.fullscreen then + scale = user_opts.scalefullscreen + else + scale = user_opts.scalewindowed + end + + if user_opts.vidscale then + osc_param.unscaled_y = baseResY + else + osc_param.unscaled_y = display_h + end + osc_param.playresy = osc_param.unscaled_y / scale + if (display_aspect > 0) then + osc_param.display_aspect = display_aspect + end + osc_param.playresx = osc_param.playresy * osc_param.display_aspect + + -- stop seeking with the slider to prevent skipping files + state.active_element = nil + + elements = {} + + -- some often needed stuff + local pl_count = mp.get_property_number('playlist-count', 0) + local have_pl = (pl_count > 1) + local pl_pos = mp.get_property_number('playlist-pos', 0) + 1 + local have_ch = (mp.get_property_number('chapters', 0) > 0) + local loop = mp.get_property('loop-playlist', 'no') + + local ne + + -- playlist buttons + -- prev + ne = new_element('pl_prev', 'button') + + ne.content = '\xEF\x8E\xB5' + ne.enabled = (pl_pos > 1) or (loop ~= 'no') + ne.eventresponder['mbtn_left_up'] = + function () + mp.commandv('playlist-prev', 'weak') + end + ne.eventresponder['mbtn_right_up'] = + function () show_message(get_playlist()) end + + --next + ne = new_element('pl_next', 'button') + + ne.content = '\xEF\x8E\xB4' + ne.enabled = (have_pl and (pl_pos < pl_count)) or (loop ~= 'no') + ne.eventresponder['mbtn_left_up'] = + function () + mp.commandv('playlist-next', 'weak') + end + ne.eventresponder['mbtn_right_up'] = + function () show_message(get_playlist()) end + + + --play control buttons + --playpause + ne = new_element('playpause', 'button') + + ne.content = function () + if mp.get_property('pause') == 'no' then + return ('\xEF\x8E\xA7') + else + return ('\xEF\x8E\xAA') + end + end + ne.eventresponder['mbtn_left_up'] = + function () mp.commandv('cycle', 'pause') end + --ne.eventresponder['mbtn_right_up'] = + -- function () mp.commandv('script-binding', 'open-file-dialog') end + + --skipback + ne = new_element('skipback', 'button') + + ne.softrepeat = true + ne.content = '\xEF\x8E\xA0' + ne.eventresponder['mbtn_left_down'] = + --function () mp.command('seek -5') end + function () mp.commandv('seek', -5, 'relative', 'keyframes') end + ne.eventresponder['shift+mbtn_left_down'] = + function () mp.commandv('frame-back-step') end + ne.eventresponder['mbtn_right_down'] = + --function () mp.command('seek -60') end + function () mp.commandv('seek', -60, 'relative', 'keyframes') end + + --skipfrwd + ne = new_element('skipfrwd', 'button') + + ne.softrepeat = true + ne.content = '\xEF\x8E\x9F' + ne.eventresponder['mbtn_left_down'] = + --function () mp.command('seek +5') end + function () mp.commandv('seek', 5, 'relative', 'keyframes') end + ne.eventresponder['shift+mbtn_left_down'] = + function () mp.commandv('frame-step') end + ne.eventresponder['mbtn_right_down'] = + --function () mp.command('seek +60') end + function () mp.commandv('seek', 60, 'relative', 'keyframes') end + + -- + update_tracklist() + + --cy_audio + ne = new_element('cy_audio', 'button') + ne.enabled = (#tracks_osc.audio > 0) + ne.visible = (osc_param.playresx >= 540) + ne.content = '\xEF\x8E\xB7' + ne.tooltip_style = osc_styles.Tooltip + ne.tooltipF = function () + local msg = texts.off + if not (get_track('audio') == 0) then + msg = (texts.audio .. ' [' .. get_track('audio') .. ' ∕ ' .. #tracks_osc.audio .. '] ') + local prop = mp.get_property('current-tracks/audio/lang') + if not prop then + prop = texts.na + end + msg = msg .. '[' .. prop .. ']' + prop = mp.get_property('current-tracks/audio/title') + if prop then + msg = msg .. ' ' .. prop + end + return msg + end + return msg + end + ne.eventresponder['mbtn_left_up'] = + function () set_track('audio', 1) end + ne.eventresponder['mbtn_right_up'] = + function () set_track('audio', -1) end + ne.eventresponder['mbtn_mid_up'] = + function () show_message(get_tracklist('audio')) end + + --cy_sub + ne = new_element('cy_sub', 'button') + ne.enabled = (#tracks_osc.sub > 0) + ne.visible = (osc_param.playresx >= 600) + ne.content = '\xEF\x8F\x93' + ne.tooltip_style = osc_styles.Tooltip + ne.tooltipF = function () + local msg = texts.off + if not (get_track('sub') == 0) then + msg = (texts.subtitle .. ' [' .. get_track('sub') .. ' ∕ ' .. #tracks_osc.sub .. '] ') + local prop = mp.get_property('current-tracks/sub/lang') + if not prop then + prop = texts.na + end + msg = msg .. '[' .. prop .. ']' + prop = mp.get_property('current-tracks/sub/title') + if prop then + msg = msg .. ' ' .. prop + end + return msg + end + return msg + end + ne.eventresponder['mbtn_left_up'] = + function () set_track('sub', 1) end + ne.eventresponder['mbtn_right_up'] = + function () set_track('sub', -1) end + ne.eventresponder['mbtn_mid_up'] = + function () show_message(get_tracklist('sub')) end + + -- vol_ctrl + ne = new_element('vol_ctrl', 'button') + ne.enabled = (get_track('audio')>0) + ne.visible = (osc_param.playresx >= 650) and user_opts.volumecontrol + ne.content = function () + if (state.mute) then + return ('\xEF\x8E\xBB') + else + return ('\xEF\x8E\xBC') + end + end + ne.eventresponder['mbtn_left_up'] = + function () mp.commandv('cycle', 'mute') end + + --tog_fs + ne = new_element('tog_fs', 'button') + ne.content = function () + if (state.fullscreen) then + return ('\xEF\x85\xAC') + else + return ('\xEF\x85\xAD') + end + end + ne.visible = (osc_param.playresx >= 540) + ne.eventresponder['mbtn_left_up'] = + function () mp.commandv('cycle', 'fullscreen') end + + --tog_info + ne = new_element('tog_info', 'button') + ne.content = '' + ne.visible = (osc_param.playresx >= 600) + ne.eventresponder['mbtn_left_up'] = + function () mp.commandv('script-binding', 'stats/display-stats-toggle') end + + -- title + ne = new_element('title', 'button') + ne.content = function () + local title = mp.command_native({'expand-text', user_opts.title}) + if state.paused then + title = title:gsub('\\n', ' '):gsub('\\$', ''):gsub('{','\\{') + else + title = ' ' + end + return not (title == '') and title or ' ' + end + ne.visible = osc_param.playresy >= 320 and user_opts.showtitle + + --seekbar + ne = new_element('seekbar', 'slider') + + ne.enabled = not (mp.get_property('percent-pos') == nil) + ne.slider.markerF = function () + local duration = mp.get_property_number('duration', nil) + if not (duration == nil) then + local chapters = mp.get_property_native('chapter-list', {}) + local markers = {} + for n = 1, #chapters do + markers[n] = (chapters[n].time / duration * 100) + end + return markers + else + return {} + end + end + ne.slider.posF = + function () return mp.get_property_number('percent-pos', nil) end + ne.slider.tooltipF = function (pos) + local duration = mp.get_property_number('duration', nil) + if not ((duration == nil) or (pos == nil)) then + possec = duration * (pos / 100) + return mp.format_time(possec) + else + return '' + end + end + ne.slider.seekRangesF = function() + if not user_opts.seekrange then + return nil + end + local cache_state = state.cache_state + if not cache_state then + return nil + end + local duration = mp.get_property_number('duration', nil) + if (duration == nil) or duration <= 0 then + return nil + end + local ranges = cache_state['seekable-ranges'] + if #ranges == 0 then + return nil + end + local nranges = {} + for _, range in pairs(ranges) do + nranges[#nranges + 1] = { + ['start'] = 100 * range['start'] / duration, + ['end'] = 100 * range['end'] / duration, + } + end + return nranges + end + ne.eventresponder['mouse_move'] = --keyframe seeking when mouse is dragged + function (element) + if not element.state.mbtnleft then return end -- allow drag for mbtnleft only! + -- mouse move events may pile up during seeking and may still get + -- sent when the user is done seeking, so we need to throw away + -- identical seeks + local seekto = get_slider_value(element) + if (element.state.lastseek == nil) or + (not (element.state.lastseek == seekto)) then + local flags = 'absolute-percent' + if not user_opts.seekbarkeyframes then + flags = flags .. '+exact' + end + mp.commandv('seek', seekto, flags) + element.state.lastseek = seekto + end + + end + ne.eventresponder['mbtn_left_down'] = --exact seeks on single clicks + function (element) + mp.commandv('seek', get_slider_value(element), 'absolute-percent', 'exact') + element.state.mbtnleft = true + end + ne.eventresponder['mbtn_left_up'] = + function (element) element.state.mbtnleft = false end + ne.eventresponder['mbtn_right_down'] = --seeks to chapter start + function (element) + local duration = mp.get_property_number('duration', nil) + if not (duration == nil) then + local chapters = mp.get_property_native('chapter-list', {}) + if #chapters > 0 then + local pos = get_slider_value(element) + local ch = #chapters + for n = 1, ch do + if chapters[n].time / duration * 100 >= pos then + ch = n - 1 + break + end + end + mp.commandv('set', 'chapter', ch - 1) + --if chapters[ch].title then show_message(chapters[ch].time) end + end + end + end + ne.eventresponder['reset'] = + function (element) element.state.lastseek = nil end + + --volumebar + ne = new_element('volumebar', 'slider') + ne.visible = (osc_param.playresx >= 700) and user_opts.volumecontrol + ne.enabled = (get_track('audio')>0) + ne.slider.markerF = function () + return {} + end + ne.slider.seekRangesF = function() + return nil + end + ne.slider.posF = + function () + local val = mp.get_property_number('volume', nil) + return val*val/100 + end + ne.eventresponder['mouse_move'] = + function (element) + if not element.state.mbtnleft then return end -- allow drag for mbtnleft only! + local seekto = get_slider_value(element) + if (element.state.lastseek == nil) or + (not (element.state.lastseek == seekto)) then + mp.commandv('set', 'volume', 10*math.sqrt(seekto)) + element.state.lastseek = seekto + end + end + ne.eventresponder['mbtn_left_down'] = --exact seeks on single clicks + function (element) + local seekto = get_slider_value(element) + mp.commandv('set', 'volume', 10*math.sqrt(seekto)) + element.state.mbtnleft = true + end + ne.eventresponder['mbtn_left_up'] = + function (element) element.state.mbtnleft = false end + ne.eventresponder['reset'] = + function (element) element.state.lastseek = nil end + + -- tc_left (current pos) + ne = new_element('tc_left', 'button') + ne.content = function () return (mp.get_property_osd('playback-time')) end + + -- tc_right (total/remaining time) + ne = new_element('tc_right', 'button') + ne.content = function () + if (mp.get_property_number('duration', 0) <= 0) then return '--:--:--' end + if (state.rightTC_trem) then + return ('-'..mp.get_property_osd('playtime-remaining')) + else + return (mp.get_property_osd('duration')) + end + end + ne.eventresponder['mbtn_left_up'] = + function () state.rightTC_trem = not state.rightTC_trem end + + -- load layout + layouts() + + -- load window controls + if window_controls_enabled() then + window_controls() + end + + --do something with the elements + prepare_elements() +end + +function shutdown() + +end + +-- +-- Other important stuff +-- + + +function show_osc() + -- show when disabled can happen (e.g. mouse_move) due to async/delayed unbinding + if not state.enabled then return end + + msg.trace('show_osc') + --remember last time of invocation (mouse move) + state.showtime = mp.get_time() + + osc_visible(true) + + if (user_opts.fadeduration > 0) then + state.anitype = nil + end +end + +function hide_osc() + msg.trace('hide_osc') + if not state.enabled then + -- typically hide happens at render() from tick(), but now tick() is + -- no-op and won't render again to remove the osc, so do that manually. + state.osc_visible = false + render_wipe() + elseif (user_opts.fadeduration > 0) then + if not(state.osc_visible == false) then + state.anitype = 'out' + request_tick() + end + else + osc_visible(false) + end +end + +function osc_visible(visible) + if state.osc_visible ~= visible then + state.osc_visible = visible + end + request_tick() +end + +function pause_state(name, enabled) + state.paused = enabled + if user_opts.showtitle then + if enabled then + state.lastvisibility = user_opts.visibility + visibility_mode("always", true) + show_osc() + else + visibility_mode(state.lastvisibility, true) + end + end + request_tick() +end + +function cache_state(name, st) + state.cache_state = st + request_tick() +end + +-- Request that tick() is called (which typically re-renders the OSC). +-- The tick is then either executed immediately, or rate-limited if it was +-- called a small time ago. +function request_tick() + if state.tick_timer == nil then + state.tick_timer = mp.add_timeout(0, tick) + end + + if not state.tick_timer:is_enabled() then + local now = mp.get_time() + local timeout = tick_delay - (now - state.tick_last_time) + if timeout < 0 then + timeout = 0 + end + state.tick_timer.timeout = timeout + state.tick_timer:resume() + end +end + +function mouse_leave() + if get_hidetimeout() >= 0 then + hide_osc() + end + -- reset mouse position + state.last_mouseX, state.last_mouseY = nil, nil + state.mouse_in_window = false +end + +function request_init() + state.initREQ = true + request_tick() +end + +-- Like request_init(), but also request an immediate update +function request_init_resize() + request_init() + -- ensure immediate update + state.tick_timer:kill() + state.tick_timer.timeout = 0 + state.tick_timer:resume() +end + +function render_wipe() + msg.trace('render_wipe()') + state.osd:remove() +end + +function render() + msg.trace('rendering') + local current_screen_sizeX, current_screen_sizeY, aspect = mp.get_osd_size() + local mouseX, mouseY = get_virt_mouse_pos() + local now = mp.get_time() + + -- check if display changed, if so request reinit + if not (state.mp_screen_sizeX == current_screen_sizeX + and state.mp_screen_sizeY == current_screen_sizeY) then + + request_init_resize() + + state.mp_screen_sizeX = current_screen_sizeX + state.mp_screen_sizeY = current_screen_sizeY + end + + -- init management + if state.initREQ then + osc_init() + state.initREQ = false + + -- store initial mouse position + if (state.last_mouseX == nil or state.last_mouseY == nil) + and not (mouseX == nil or mouseY == nil) then + + state.last_mouseX, state.last_mouseY = mouseX, mouseY + end + end + + + -- fade animation + if not(state.anitype == nil) then + + if (state.anistart == nil) then + state.anistart = now + end + + if (now < state.anistart + (user_opts.fadeduration/1000)) then + + if (state.anitype == 'in') then --fade in + osc_visible(true) + state.animation = scale_value(state.anistart, + (state.anistart + (user_opts.fadeduration/1000)), + 255, 0, now) + elseif (state.anitype == 'out') then --fade out + state.animation = scale_value(state.anistart, + (state.anistart + (user_opts.fadeduration/1000)), + 0, 255, now) + end + + else + if (state.anitype == 'out') then + osc_visible(false) + end + state.anistart = nil + state.animation = nil + state.anitype = nil + end + else + state.anistart = nil + state.animation = nil + state.anitype = nil + end + + --mouse show/hide area + for k,cords in pairs(osc_param.areas['showhide']) do + set_virt_mouse_area(cords.x1, cords.y1, cords.x2, cords.y2, 'showhide') + end + if osc_param.areas['showhide_wc'] then + for k,cords in pairs(osc_param.areas['showhide_wc']) do + set_virt_mouse_area(cords.x1, cords.y1, cords.x2, cords.y2, 'showhide_wc') + end + else + set_virt_mouse_area(0, 0, 0, 0, 'showhide_wc') + end + do_enable_keybindings() + + --mouse input area + local mouse_over_osc = false + + for _,cords in ipairs(osc_param.areas['input']) do + if state.osc_visible then -- activate only when OSC is actually visible + set_virt_mouse_area(cords.x1, cords.y1, cords.x2, cords.y2, 'input') + end + if state.osc_visible ~= state.input_enabled then + if state.osc_visible then + mp.enable_key_bindings('input') + else + mp.disable_key_bindings('input') + end + state.input_enabled = state.osc_visible + end + + if (mouse_hit_coords(cords.x1, cords.y1, cords.x2, cords.y2)) then + mouse_over_osc = true + end + end + + if osc_param.areas['window-controls'] then + for _,cords in ipairs(osc_param.areas['window-controls']) do + if state.osc_visible then -- activate only when OSC is actually visible + set_virt_mouse_area(cords.x1, cords.y1, cords.x2, cords.y2, 'window-controls') + mp.enable_key_bindings('window-controls') + else + mp.disable_key_bindings('window-controls') + end + + if (mouse_hit_coords(cords.x1, cords.y1, cords.x2, cords.y2)) then + mouse_over_osc = true + end + end + end + + if osc_param.areas['window-controls-title'] then + for _,cords in ipairs(osc_param.areas['window-controls-title']) do + if (mouse_hit_coords(cords.x1, cords.y1, cords.x2, cords.y2)) then + mouse_over_osc = true + end + end + end + + -- autohide + if not (state.showtime == nil) and (get_hidetimeout() >= 0) then + local timeout = state.showtime + (get_hidetimeout()/1000) - now + if timeout <= 0 then + if (state.active_element == nil) and not (mouse_over_osc) then + hide_osc() + end + else + -- the timer is only used to recheck the state and to possibly run + -- the code above again + if not state.hide_timer then + state.hide_timer = mp.add_timeout(0, tick) + end + state.hide_timer.timeout = timeout + -- re-arm + state.hide_timer:kill() + state.hide_timer:resume() + end + end + + + -- actual rendering + local ass = assdraw.ass_new() + + -- Messages + render_message(ass) + + -- actual OSC + if state.osc_visible then + render_elements(ass) + end + + -- submit + set_osd(osc_param.playresy * osc_param.display_aspect, + osc_param.playresy, ass.text) +end + +-- +-- Eventhandling +-- + +local function element_has_action(element, action) + return element and element.eventresponder and + element.eventresponder[action] +end + +function process_event(source, what) + local action = string.format('%s%s', source, + what and ('_' .. what) or '') + + if what == 'down' or what == 'press' then + + for n = 1, #elements do + + if mouse_hit(elements[n]) and + elements[n].eventresponder and + (elements[n].eventresponder[source .. '_up'] or + elements[n].eventresponder[action]) then + + if what == 'down' then + state.active_element = n + state.active_event_source = source + end + -- fire the down or press event if the element has one + if element_has_action(elements[n], action) then + elements[n].eventresponder[action](elements[n]) + end + + end + end + + elseif what == 'up' then + + if elements[state.active_element] then + local n = state.active_element + + if n == 0 then + --click on background (does not work) + elseif element_has_action(elements[n], action) and + mouse_hit(elements[n]) then + + elements[n].eventresponder[action](elements[n]) + end + + --reset active element + if element_has_action(elements[n], 'reset') then + elements[n].eventresponder['reset'](elements[n]) + end + + end + state.active_element = nil + state.mouse_down_counter = 0 + + elseif source == 'mouse_move' then + + state.mouse_in_window = true + + local mouseX, mouseY = get_virt_mouse_pos() + if (user_opts.minmousemove == 0) or + (not ((state.last_mouseX == nil) or (state.last_mouseY == nil)) and + ((math.abs(mouseX - state.last_mouseX) >= user_opts.minmousemove) + or (math.abs(mouseY - state.last_mouseY) >= user_opts.minmousemove) + ) + ) then + show_osc() + end + state.last_mouseX, state.last_mouseY = mouseX, mouseY + + local n = state.active_element + if element_has_action(elements[n], action) then + elements[n].eventresponder[action](elements[n]) + end + request_tick() + end +end + +function show_logo() + local osd_w, osd_h = 640, 360 + local logo_x, logo_y = osd_w/2, osd_h/2-20 + local ass = assdraw.ass_new() + ass:new_event() + ass:pos(logo_x, logo_y) + ass:append('{\\1c&H8E348D&\\3c&H0&\\3a&H60&\\blur1\\bord0.5}') + ass:draw_start() + ass_draw_cir_cw(ass, 0, 0, 100) + ass:draw_stop() + + ass:new_event() + ass:pos(logo_x, logo_y) + ass:append('{\\1c&H632462&\\bord0}') + ass:draw_start() + ass_draw_cir_cw(ass, 6, -6, 75) + ass:draw_stop() + + ass:new_event() + ass:pos(logo_x, logo_y) + ass:append('{\\1c&HFFFFFF&\\bord0}') + ass:draw_start() + ass_draw_cir_cw(ass, -4, 4, 50) + ass:draw_stop() + + ass:new_event() + ass:pos(logo_x, logo_y) + ass:append('{\\1c&H632462&\\bord&}') + ass:draw_start() + ass:move_to(-20, -20) + ass:line_to(23.3, 5) + ass:line_to(-20, 30) + ass:draw_stop() + + ass:new_event() + ass:pos(logo_x, logo_y+110) + ass:an(8) + ass:append(texts.welcome) + set_osd(osd_w, osd_h, ass.text) +end + +-- called by mpv on every frame +function tick() + if (not state.enabled) then return end + + if (state.idle) then + show_logo() + -- render idle message + msg.trace('idle message') + + if state.showhide_enabled then + mp.disable_key_bindings('showhide') + mp.disable_key_bindings('showhide_wc') + state.showhide_enabled = false + end + + + elseif (state.fullscreen and user_opts.showfullscreen) + or (not state.fullscreen and user_opts.showwindowed) then + + -- render the OSC + render() + else + -- Flush OSD + set_osd(osc_param.playresy, osc_param.playresy, '') + end + + state.tick_last_time = mp.get_time() + + if state.anitype ~= nil then + request_tick() + end +end + +function do_enable_keybindings() + if state.enabled then + if not state.showhide_enabled then + mp.enable_key_bindings('showhide', 'allow-vo-dragging+allow-hide-cursor') + mp.enable_key_bindings('showhide_wc', 'allow-vo-dragging+allow-hide-cursor') + end + state.showhide_enabled = true + end +end + +function enable_osc(enable) + state.enabled = enable + if enable then + do_enable_keybindings() + else + hide_osc() -- acts immediately when state.enabled == false + if state.showhide_enabled then + mp.disable_key_bindings('showhide') + mp.disable_key_bindings('showhide_wc') + end + state.showhide_enabled = false + end +end + +validate_user_opts() + +mp.register_event('shutdown', shutdown) +mp.register_event('start-file', request_init) +mp.observe_property('track-list', nil, request_init) +mp.observe_property('playlist', nil, request_init) + +mp.register_script_message('osc-message', show_message) +mp.register_script_message('osc-chapterlist', function(dur) + show_message(get_chapterlist(), dur) +end) +mp.register_script_message('osc-playlist', function(dur) + show_message(get_playlist(), dur) +end) +mp.register_script_message('osc-tracklist', function(dur) + local msg = {} + for k,v in pairs(nicetypes) do + table.insert(msg, get_tracklist(k)) + end + show_message(table.concat(msg, '\n\n'), dur) +end) + +mp.observe_property('fullscreen', 'bool', + function(name, val) + state.fullscreen = val + request_init_resize() + end +) +mp.observe_property('mute', 'bool', + function(name, val) + state.mute = val + end +) +mp.observe_property('border', 'bool', + function(name, val) + state.border = val + request_init_resize() + end +) +mp.observe_property('window-maximized', 'bool', + function(name, val) + state.maximized = val + request_init_resize() + end +) +mp.observe_property('idle-active', 'bool', + function(name, val) + state.idle = val + request_tick() + end +) +mp.observe_property('pause', 'bool', pause_state) +mp.observe_property('demuxer-cache-state', 'native', cache_state) +mp.observe_property('vo-configured', 'bool', function(name, val) + request_tick() +end) +mp.observe_property('playback-time', 'number', function(name, val) + request_tick() +end) +mp.observe_property('osd-dimensions', 'native', function(name, val) + -- (we could use the value instead of re-querying it all the time, but then + -- we might have to worry about property update ordering) + request_init_resize() +end) + +-- mouse show/hide bindings +mp.set_key_bindings({ + {'mouse_move', function(e) process_event('mouse_move', nil) end}, + {'mouse_leave', mouse_leave}, +}, 'showhide', 'force') +mp.set_key_bindings({ + {'mouse_move', function(e) process_event('mouse_move', nil) end}, + {'mouse_leave', mouse_leave}, +}, 'showhide_wc', 'force') +do_enable_keybindings() + +--mouse input bindings +mp.set_key_bindings({ + {'mbtn_left', function(e) process_event('mbtn_left', 'up') end, + function(e) process_event('mbtn_left', 'down') end}, + {'mbtn_right', function(e) process_event('mbtn_right', 'up') end, + function(e) process_event('mbtn_right', 'down') end}, + {'mbtn_mid', function(e) process_event('mbtn_mid', 'up') end, + function(e) process_event('mbtn_mid', 'down') end}, + {'wheel_up', function(e) process_event('wheel_up', 'press') end}, + {'wheel_down', function(e) process_event('wheel_down', 'press') end}, + {'mbtn_left_dbl', 'ignore'}, + {'mbtn_right_dbl', 'ignore'}, +}, 'input', 'force') +mp.enable_key_bindings('input') + +mp.set_key_bindings({ + {'mbtn_left', function(e) process_event('mbtn_left', 'up') end, + function(e) process_event('mbtn_left', 'down') end}, +}, 'window-controls', 'force') +mp.enable_key_bindings('window-controls') + +function get_hidetimeout() + if user_opts.visibility == 'always' then + return -1 -- disable autohide + end + return user_opts.hidetimeout +end + +function always_on(val) + if state.enabled then + if val then + show_osc() + else + hide_osc() + end + end +end + +-- mode can be auto/always/never/cycle +-- the modes only affect internal variables and not stored on its own. +function visibility_mode(mode, no_osd) + if mode == 'auto' then + always_on(false) + enable_osc(true) + elseif mode == 'always' then + enable_osc(true) + always_on(true) + elseif mode == 'never' then + enable_osc(false) + else + msg.warn('Ignoring unknown visibility mode \"' .. mode .. '\"') + return + end + + user_opts.visibility = mode + + if not no_osd and tonumber(mp.get_property('osd-level')) >= 1 then + mp.osd_message('OSC visibility: ' .. mode) + end + + -- Reset the input state on a mode change. The input state will be + -- recalcuated on the next render cycle, except in 'never' mode where it + -- will just stay disabled. + mp.disable_key_bindings('input') + mp.disable_key_bindings('window-controls') + state.input_enabled = false + request_tick() +end + +visibility_mode(user_opts.visibility, true) +mp.register_script_message('osc-visibility', visibility_mode) +mp.add_key_binding(nil, 'visibility', function() visibility_mode('cycle') end) + +set_virt_mouse_area(0, 0, 0, 0, 'input') +set_virt_mouse_area(0, 0, 0, 0, 'window-controls') diff --git a/shaders/FSRCNNX_x2_8-0-4-1.glsl b/shaders/FSRCNNX_x2_8-0-4-1.glsl new file mode 100644 index 0000000..24da70c --- /dev/null +++ b/shaders/FSRCNNX_x2_8-0-4-1.glsl @@ -0,0 +1,431 @@ +// Revised 03/05/21 +// https://github.com/deus0ww/mpv-conf/tree/master/shaders/igv +// +// FSRCNNX by igv +// +// Copyright (C) 2017-2021 igv +// +// This program 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 3.0 of the License, or (at your option) any later version. +// +// This program 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 this program. If not, see . + +//!HOOK LUMA +//!WHEN OUTPUT.w LUMA.w / 1.300 > OUTPUT.h LUMA.h / 1.300 > * +//!DESC feature map 1 +//!BIND LUMA +//!SAVE FEATURE1 +//!COMPONENTS 4 +vec4 hook() +{ +vec4 res = vec4(-0.1572492271661758,-0.0120896836742759,0.0061487639322877,-0.2852848768234253); +res += vec4(-0.0047900392673910,0.0537447109818459,-0.0000247144635068,0.0066653941757977) * float(LUMA_texOff(vec2(-2,-2))); +res += vec4(0.0073144687339664,-0.0309004038572311,-0.0109181385487318,-0.0092840325087309) * float(LUMA_texOff(vec2(-2,-1))); +res += vec4(0.0591700896620750,0.1974907070398331,-0.0197357516735792,-0.0546554848551750) * float(LUMA_texOff(vec2(-2,0))); +res += vec4(-0.0011764382943511,-0.0299451071768999,0.0229587312787771,0.0021908886265010) * float(LUMA_texOff(vec2(-2,1))); +res += vec4(0.0098101310431957,0.0080995410680771,-0.0030452020000666,-0.0132035519927740) * float(LUMA_texOff(vec2(-2,2))); +res += vec4(-0.0168330334126949,-0.0743711441755295,-0.0259261634200811,0.0234480481594801) * float(LUMA_texOff(vec2(-1,-2))); +res += vec4(0.0239933785051107,0.1896541714668274,0.0207756329327822,-0.0370332375168800) * float(LUMA_texOff(vec2(-1,-1))); +res += vec4(0.0094799501821399,-0.0652511194348335,-0.0004292793164495,-0.0726212188601494) * float(LUMA_texOff(vec2(-1,0))); +res += vec4(0.0297284796833992,-0.1210186630487442,-0.0202929321676493,-0.0574462898075581) * float(LUMA_texOff(vec2(-1,1))); +res += vec4(-0.0318185277283192,0.0840775370597839,0.0110451309010386,0.0415569432079792) * float(LUMA_texOff(vec2(-1,2))); +res += vec4(-0.0253141783177853,0.1168256178498268,0.1159729585051537,0.0963164269924164) * float(LUMA_texOff(vec2(0,-2))); +res += vec4(-0.1103615835309029,-0.0276833958923817,-0.4999594092369080,0.1053867191076279) * float(LUMA_texOff(vec2(0,-1))); +res += vec4(1.1100435256958008,0.0646764487028122,0.0154005717486143,0.8891586661338806) * float(LUMA_texOff(vec2(0,0))); +res += vec4(0.1229330673813820,0.1719468832015991,0.5730338096618652,-0.1645544171333313) * float(LUMA_texOff(vec2(0,1))); +res += vec4(-0.0090442728251219,-0.3023961782455444,-0.1589493155479431,0.0418574027717113) * float(LUMA_texOff(vec2(0,2))); +res += vec4(0.0031942036002874,-0.1310926079750061,0.0075543406419456,-0.0016449346439913) * float(LUMA_texOff(vec2(1,-2))); +res += vec4(-0.0995150282979012,-0.0701921209692955,-0.0130895879119635,0.1344170123338699) * float(LUMA_texOff(vec2(1,-1))); +res += vec4(0.0060519003309309,-0.1533465683460236,0.0114194005727768,0.0264683905988932) * float(LUMA_texOff(vec2(1,0))); +res += vec4(0.0244008023291826,0.1881769001483917,-0.0206351149827242,-0.0628309547901154) * float(LUMA_texOff(vec2(1,1))); +res += vec4(0.0075713125988841,0.0508594363927841,0.0430423170328140,-0.0124188791960478) * float(LUMA_texOff(vec2(1,2))); +res += vec4(-0.0166875869035721,-0.0047865519300103,0.0006719123339280,0.0316803231835365) * float(LUMA_texOff(vec2(2,-2))); +res += vec4(-0.0058461269363761,0.0990798473358154,-0.0177743826061487,-0.0066122291609645) * float(LUMA_texOff(vec2(2,-1))); +res += vec4(-0.0972401946783066,-0.0225446373224258,-0.0037693574558944,0.1953062713146210) * float(LUMA_texOff(vec2(2,0))); +res += vec4(-0.0216837190091610,-0.1824268400669098,0.0069816261529922,0.0283037684857845) * float(LUMA_texOff(vec2(2,1))); +res += vec4(-0.0025767991319299,0.0459827110171318,-0.0080216089263558,0.0084134787321091) * float(LUMA_texOff(vec2(2,2))); +return res; +} + +//!HOOK LUMA +//!WHEN OUTPUT.w LUMA.w / 1.300 > OUTPUT.h LUMA.h / 1.300 > * +//!DESC feature map 2 +//!BIND LUMA +//!SAVE FEATURE2 +//!COMPONENTS 4 +vec4 hook() +{ +vec4 res = vec4(0.0541447550058365,0.0088306749239564,-0.0112389577552676,-0.0127860950306058); +res += vec4(0.0142660010606050,0.0137931071221828,0.0061188107356429,-0.0104134222492576) * float(LUMA_texOff(vec2(-2,-2))); +res += vec4(0.0147292809560895,-0.0289912857115269,0.0266769435256720,0.0933856964111328) * float(LUMA_texOff(vec2(-2,-1))); +res += vec4(-0.1734338253736496,0.1116316691040993,-0.1973157376050949,-0.0581855811178684) * float(LUMA_texOff(vec2(-2,0))); +res += vec4(0.0347507223486900,-0.0341566652059555,0.0061667622067034,0.0075258882716298) * float(LUMA_texOff(vec2(-2,1))); +res += vec4(0.0069884369149804,-0.0194250214844942,0.0080830128863454,-0.0036874092184007) * float(LUMA_texOff(vec2(-2,2))); +res += vec4(0.0233764201402664,0.0344744995236397,0.0162145942449570,0.0979529991745949) * float(LUMA_texOff(vec2(-1,-2))); +res += vec4(0.1280796974897385,-0.1018339172005653,-0.0132977198809385,-0.0019474622095004) * float(LUMA_texOff(vec2(-1,-1))); +res += vec4(0.4286882579326630,0.1222677752375603,0.7046694159507751,0.0945475697517395) * float(LUMA_texOff(vec2(-1,0))); +res += vec4(0.1107441782951355,-0.0134433070197701,-0.0174900908023119,-0.1686445474624634) * float(LUMA_texOff(vec2(-1,1))); +res += vec4(0.0321478620171547,0.0065357843413949,0.0300805997103453,0.0420113280415535) * float(LUMA_texOff(vec2(-1,2))); +res += vec4(-0.1240341588854790,0.0950303301215172,-0.0129648456349969,-0.2681856453418732) * float(LUMA_texOff(vec2(0,-2))); +res += vec4(0.4846960902214050,0.0351924635469913,0.0223043337464333,-0.1273630708456039) * float(LUMA_texOff(vec2(0,-1))); +res += vec4(-1.9379507303237915,-0.2444442063570023,0.0291962660849094,-0.3835578560829163) * float(LUMA_texOff(vec2(0,0))); +res += vec4(0.6396278142929077,-0.0765938311815262,-0.0552659817039967,0.4393545985221863) * float(LUMA_texOff(vec2(0,1))); +res += vec4(-0.1969728022813797,-0.0607173256576061,0.0131113547831774,0.0542017817497253) * float(LUMA_texOff(vec2(0,2))); +res += vec4(0.0091696009039879,-0.0031533432193100,-0.0368777588009834,-0.0459998287260532) * float(LUMA_texOff(vec2(1,-2))); +res += vec4(0.1096992492675781,0.2597902715206146,0.0304869692772627,-0.0195200722664595) * float(LUMA_texOff(vec2(1,-1))); +res += vec4(0.2889648377895355,-0.4275591969490051,-0.7414156794548035,0.2695442438125610) * float(LUMA_texOff(vec2(1,0))); +res += vec4(0.0892018377780914,-0.0229137558490038,0.0244414471089840,-0.1926898956298828) * float(LUMA_texOff(vec2(1,1))); +res += vec4(0.0576358586549759,0.0027846973389387,-0.0036861505359411,-0.0253547113388777) * float(LUMA_texOff(vec2(1,2))); +res += vec4(0.0159624069929123,0.0319602824747562,0.0019470085389912,0.0089780492708087) * float(LUMA_texOff(vec2(2,-2))); +res += vec4(0.0552792511880398,0.0543054342269897,0.0134062822908163,0.0545728243887424) * float(LUMA_texOff(vec2(2,-1))); +res += vec4(-0.1170092225074768,0.1963327825069427,0.1503890156745911,0.1891828328371048) * float(LUMA_texOff(vec2(2,0))); +res += vec4(-0.0084421783685684,0.1297017931938171,-0.0330600887537003,-0.0942063704133034) * float(LUMA_texOff(vec2(2,1))); +res += vec4(0.0118440408259630,-0.0337875857949257,0.0055063469335437,0.0254479162395000) * float(LUMA_texOff(vec2(2,2))); +return res; +} + +//!HOOK LUMA +//!WHEN OUTPUT.w LUMA.w / 1.300 > OUTPUT.h LUMA.h / 1.300 > * +//!DESC mapping 1_1 +//!BIND FEATURE1 +//!BIND FEATURE2 +//!SAVE MODEL21 +//!COMPONENTS 4 +vec4 hook() +{ +vec4 res = vec4(-0.0445119962096214,-0.7632357478141785,0.0156328510493040,-0.2424548566341400); +res += mat4(0.1279004216194153,-0.0275541823357344,0.2275633513927460,0.2241709381341934,0.0197204202413559,-0.0456816256046295,-0.1296672523021698,0.0564568229019642,-0.0241488646715879,-0.0237508192658424,-0.1899632662534714,0.4177669584751129,-0.1814560592174530,-0.0526473335921764,0.1154382973909378,-0.0715614855289459) * FEATURE1_texOff(vec2(-1,-1)); +res += mat4(-0.0660311505198479,0.0416736751794815,0.3146112561225891,0.1472041457891464,-0.3456672728061676,-0.0055983816273510,0.0022350433282554,0.0819796621799469,0.0057485047727823,0.1532524228096008,0.0204557459801435,-0.2500547170639038,-0.0524359568953514,-0.1911625266075134,-0.1078366711735725,-0.1296254843473434) * FEATURE2_texOff(vec2(-1,-1)); +res += mat4(0.0904538556933403,-0.0150672039017081,0.3322310745716095,0.0638923197984695,0.5975797176361084,-0.2452044337987900,-0.4947478473186493,-0.0783191770315170,0.5771877169609070,-0.0870653912425041,-0.8966570496559143,-0.2140965163707733,-0.0493861362338066,-0.0380848757922649,-0.1345319598913193,-0.0186063013970852) * FEATURE1_texOff(vec2(-1,0)); +res += mat4(-0.2523841261863708,0.1387074738740921,0.7878478765487671,-0.2251627445220947,0.2277439534664154,0.5417668819427490,0.0866540968418121,-0.1707777529954910,-0.0598246827721596,-0.4717158675193787,-1.2242834568023682,0.0454643070697784,-0.3503442704677582,0.0573085807263851,0.2530198395252228,-0.0207283068448305) * FEATURE2_texOff(vec2(-1,0)); +res += mat4(0.0168380383402109,-0.2142438590526581,-0.0207892972975969,0.3628533780574799,0.2431225180625916,0.3098322153091431,0.4073205888271332,-0.2762102782726288,-0.0197229012846947,0.1305596232414246,-0.5697882771492004,-0.2976251542568207,-0.0551432967185974,0.2614036500453949,-0.1410341411828995,-0.2906406223773956) * FEATURE1_texOff(vec2(-1,1)); +res += mat4(-0.0498303361237049,0.0224859956651926,0.1952174901962280,-0.0311204437166452,0.2501715123653412,-0.5893352627754211,-1.0793941020965576,0.0160885509103537,0.5081620812416077,0.0482814386487007,0.0546359121799469,-0.0501569248735905,0.1400523334741592,-0.0106841633096337,-0.0940591320395470,-0.1791856139898300) * FEATURE2_texOff(vec2(-1,1)); +res += mat4(0.0393299944698811,0.2232691347599030,-0.1055066883563995,-0.1607919186353683,-0.1567825973033905,-0.0042221010662615,-0.0548228211700916,0.2352052628993988,0.1483389288187027,0.7503526806831360,0.0797731876373291,-0.0049001369625330,-0.0242983382195234,-0.0308702979236841,0.0828925222158432,0.0561857633292675) * FEATURE1_texOff(vec2(0,-1)); +res += mat4(0.0926392748951912,-0.0418718457221985,-0.3060409128665924,-0.1883587390184402,0.0284292586147785,-0.3584854304790497,-0.7909982800483704,-0.0187337957322598,-0.2496993243694305,-0.7520986795425415,0.3771523833274841,-0.0259053874760866,0.0337998159229755,0.2209153026342392,0.0708771497011185,-0.2814430892467499) * FEATURE2_texOff(vec2(0,-1)); +res += mat4(-0.5287809371948242,0.5777525901794434,0.0880500450730324,-0.8452472090721130,-0.3393408954143524,-0.2273543328046799,-0.1298527419567108,0.4990308582782745,1.2613251209259033,-0.7636719942092896,1.5694186687469482,-0.4087363779544830,0.0874531939625740,0.7067158818244934,-0.3419588804244995,-0.3265531957149506) * FEATURE1_texOff(vec2(0,0)); +res += mat4(0.8229957222938538,-0.1236215904355049,-0.1859253048896790,1.6684840917587280,0.2000777721405029,-0.1239093989133835,1.5623438358306885,0.1779983490705490,0.1017884835600853,-0.3707404434680939,1.0626678466796875,-0.3124029338359833,0.0659058541059494,-0.3585464656352997,-0.1866402775049210,0.6733445525169373) * FEATURE2_texOff(vec2(0,0)); +res += mat4(-0.5544115900993347,-0.1892931908369064,0.2460739761590958,-0.1056193932890892,-0.4318082630634308,0.1257930994033813,-0.2672747671604156,-0.1690235435962677,0.0018221997888759,-0.4397548139095306,-0.3007801771163940,0.1068472340703011,0.3506655991077423,0.1143834441900253,0.1363849341869354,-0.1417382210493088) * FEATURE1_texOff(vec2(0,1)); +res += mat4(-0.0505668744444847,0.1831464916467667,0.3957343697547913,-0.2295413911342621,-0.3892803490161896,0.5436951518058777,0.1217770799994469,0.0223295800387859,-0.4462866187095642,-0.4055982232093811,-0.3771279454231262,0.0807068347930908,0.2116729617118835,0.0281026475131512,-0.0229265503585339,0.2868605256080627) * FEATURE2_texOff(vec2(0,1)); +res += mat4(0.1962712109088898,-0.2373334914445877,-2.5208437442779541,-0.1988540291786194,0.2224564403295517,-0.1783192902803421,-0.3962321281433105,-0.1685980409383774,0.1910390257835388,0.2554391324520111,0.4586416482925415,0.2779130041599274,-0.2002453953027725,-0.0061091855168343,1.3808131217956543,0.0434907525777817) * FEATURE1_texOff(vec2(1,-1)); +res += mat4(-0.0307611189782619,-0.0524470545351505,-0.5897512435913086,-0.0816674903035164,0.4052906930446625,0.2542210817337036,-1.9041002988815308,0.0835462361574173,-0.2484460622072220,-0.0184739269316196,0.4510098397731781,0.2587619423866272,0.1537084281444550,0.1503131389617920,-0.0742949545383453,0.0613216012716293) * FEATURE2_texOff(vec2(1,-1)); +res += mat4(0.1772638261318207,0.0948876664042473,0.0083848545327783,-0.2919732332229614,0.2566950321197510,0.0288751143962145,-0.4624863862991333,-0.0608786940574646,0.3310996592044830,-0.0104284398257732,0.6334818005561829,-0.0027201652992517,-0.0342350602149963,0.1938806027173996,-0.2464301586151123,0.0125883584842086) * FEATURE1_texOff(vec2(1,0)); +res += mat4(0.4839433431625366,-0.0502159744501114,-1.1114163398742676,-0.3965759575366974,0.2117286175489426,0.0414481423795223,-0.1332397013902664,-0.0549883767962456,-0.1275007277727127,0.7844302654266357,-0.0095163453370333,0.0961041301488876,-0.4759134948253632,-0.4284025132656097,-0.2072399407625198,-0.3953579664230347) * FEATURE2_texOff(vec2(1,0)); +res += mat4(0.1605869531631470,-0.1715892106294632,0.0865620598196983,-0.0464400537312031,-0.2688548862934113,0.1722514480352402,0.0167612321674824,-0.0032994034700096,-0.3451044559478760,-0.2280300110578537,-0.0029796555172652,-0.1597652435302734,0.0500137843191624,0.1023071259260178,-0.0407028235495090,0.2228624969720840) * FEATURE1_texOff(vec2(1,1)); +res += mat4(0.6999920010566711,0.0839441940188408,0.0815469548106194,-0.1509176045656204,-0.0690853074193001,-0.3200871348381042,0.0780162736773491,-0.1449639797210693,0.2868815064430237,0.3962450027465820,-0.3439113497734070,0.2657423913478851,0.0988137871026993,0.3471299111843109,-0.2186402678489685,-0.0648017078638077) * FEATURE2_texOff(vec2(1,1)); +res = max(res, vec4(0.0)) + vec4(1.0311057567596436,0.1051208898425102,0.1158760935068130,0.0466635078191757) * min(res, vec4(0.0)); +return res; +} + +//!HOOK LUMA +//!WHEN OUTPUT.w LUMA.w / 1.300 > OUTPUT.h LUMA.h / 1.300 > * +//!DESC mapping 1_2 +//!BIND FEATURE1 +//!BIND FEATURE2 +//!SAVE MODEL22 +//!COMPONENTS 4 +vec4 hook() +{ +vec4 res = vec4(0.0713458731770515,-0.1403961777687073,-0.0019562745001167,0.0153338573873043); +res += mat4(-0.0950641855597496,-0.1496641039848328,-0.0653550028800964,0.0655386000871658,-0.0118882004171610,0.2012491524219513,-0.2844599783420563,-0.4794720113277435,0.1128025799989700,-0.0173030979931355,-0.0558849945664406,-0.2957552075386047,0.0128202112391591,0.0199047476053238,-0.0091027505695820,-0.0789640173316002) * FEATURE1_texOff(vec2(-1,-1)); +res += mat4(0.1597457975149155,-0.0476507246494293,0.1466529071331024,0.0859163030982018,0.0797316282987595,-0.3380981683731079,0.2370245009660721,-0.1145931258797646,-0.0352988094091415,-0.0444888733327389,-0.2100716233253479,0.1305520236492157,-0.1359029710292816,0.1097442805767059,0.0449938289821148,-0.1155664771795273) * FEATURE2_texOff(vec2(-1,-1)); +res += mat4(-0.0333916284143925,0.2415594160556793,0.0520512908697128,0.1228107511997223,-0.0491011217236519,0.4408806562423706,0.4631956815719604,0.2014560103416443,-0.3688595592975616,0.0367180295288563,0.2484581321477890,-0.1113442853093147,0.1283355057239532,0.0418004281818867,-0.0171243026852608,-0.1231943219900131) * FEATURE1_texOff(vec2(-1,0)); +res += mat4(0.3493446409702301,0.4550022482872009,0.0368724688887596,0.0748724937438965,0.5001406073570251,0.0145555436611176,0.1236629858613014,0.3143120706081390,-0.1951988488435745,-0.0157914645969868,0.0937998965382576,-0.2233840376138687,0.5033411383628845,-0.3183194100856781,-0.2259195148944855,0.3639536798000336) * FEATURE2_texOff(vec2(-1,0)); +res += mat4(-0.0742707476019859,-0.1287801116704941,-0.2533137500286102,0.0666435658931732,-0.0185621567070484,0.1427449285984039,-0.0724751204252243,-0.0781485065817833,-0.2270648330450058,-0.2314778864383698,0.3814929425716400,-0.1655400246381760,0.0408568829298019,-0.1139645278453827,0.1797397136688232,-0.0245632305741310) * FEATURE1_texOff(vec2(-1,1)); +res += mat4(0.1184135973453522,0.0439366139471531,0.0225226897746325,-0.0038526873104274,0.1292685419321060,0.0629177838563919,0.3455114960670471,-0.1857204884290695,-0.4921502172946930,-0.1171003505587578,0.0188624169677496,-0.1101682260632515,0.0676844567060471,0.5154085755348206,-0.0898379907011986,0.3413280248641968) * FEATURE2_texOff(vec2(-1,1)); +res += mat4(-0.2631838321685791,0.0215514600276947,0.3092688918113708,-0.0200904365628958,0.0678770467638969,0.1769931465387344,-0.3653681278228760,-0.3274513185024261,0.4608019888401031,-0.1544784456491470,0.1189439669251442,0.7015876173973083,0.2732816934585571,-0.0545057803392410,-0.3474545478820801,-0.0253226496279240) * FEATURE1_texOff(vec2(0,-1)); +res += mat4(0.0994316861033440,0.0642566010355949,0.2031503319740295,0.2276959568262100,-0.1094077304005623,0.4463521838188171,0.0921792611479759,-0.3033096492290497,-0.0953373983502388,-0.1331395804882050,0.2615413069725037,-0.2874414622783661,-0.0389687754213810,0.0338272154331207,0.2804331183433533,-0.3443813025951385) * FEATURE2_texOff(vec2(0,-1)); +res += mat4(-0.1806042939424515,-0.4840798676013947,0.4222546219825745,0.1238701492547989,0.0117481639608741,-0.5986865758895874,0.3057619929313660,0.1934896260499954,-0.7086342573165894,-0.8567376136779785,0.6944998502731323,-1.4599204063415527,0.0886754393577576,-0.4293498098850250,-0.1524195969104767,0.2418079674243927) * FEATURE1_texOff(vec2(0,0)); +res += mat4(2.1706113815307617,0.3525652289390564,-0.7008359432220459,-0.4825965166091919,-0.3203429281711578,0.8500943183898926,-0.7993509769439697,0.4329842329025269,0.2106771767139435,1.1103280782699585,1.2092385292053223,1.4814503192901611,-0.4147390127182007,-0.7046836614608765,-0.1443170011043549,-0.6811133027076721) * FEATURE2_texOff(vec2(0,0)); +res += mat4(-0.1489356607198715,0.1400019824504852,0.2425604313611984,-0.2098473459482193,-0.1580564379692078,0.1463224738836288,-0.2187854647636414,0.5174596905708313,-0.0143817225471139,-0.0362622961401939,-0.0068237944506109,0.4749472737312317,0.2914732992649078,-0.3306328952312469,-0.2444777786731720,-0.1171946674585342) * FEATURE1_texOff(vec2(0,1)); +res += mat4(0.0455239675939083,0.3496046066284180,0.1297491937875748,-0.2541095912456512,0.3605501055717468,0.2339573651552200,-0.0188565086573362,-0.0526181310415268,0.1471424549818039,0.8212822079658508,0.0819099843502045,-0.0851665437221527,0.3739568293094635,0.1304695755243301,0.1481167376041412,-0.2134698331356049) * FEATURE2_texOff(vec2(0,1)); +res += mat4(-0.2076720446348190,-0.0932599306106567,0.0648527294397354,-0.2374770641326904,-0.0927826911211014,0.1848200261592865,0.4131188094615936,0.3280069231987000,-0.2099185734987259,0.2130926996469498,-0.0362745784223080,0.0191331822425127,0.1590368449687958,0.0303016249090433,0.1207325309514999,0.2451425045728683) * FEATURE1_texOff(vec2(1,-1)); +res += mat4(-0.0135009605437517,-0.0101303057745099,0.0752487555146217,0.0533373840153217,-0.0253537259995937,0.1318614929914474,-0.1263181120157242,0.0249524712562561,-0.1477261483669281,0.3236559033393860,0.0773291289806366,-0.1439673304557800,-0.2005890905857086,0.0892757251858711,0.0398719944059849,0.3675192892551422) * FEATURE2_texOff(vec2(1,-1)); +res += mat4(-0.0193535499274731,-0.2256918102502823,0.0341436080634594,0.0795947611331940,0.1496857404708862,-0.2784725725650787,-0.0582313314080238,-0.2786065340042114,-0.1666128039360046,-0.6534121036529541,0.2695854306221008,-0.0179719906300306,0.0015976354479790,0.0139929885044694,-0.1706486046314240,-0.3274765610694885) * FEATURE1_texOff(vec2(1,0)); +res += mat4(-0.7170836329460144,0.0868831276893616,0.1829078495502472,-0.0076045366004109,0.1525912433862686,-0.2558896839618683,0.0893209800124168,-0.3426039516925812,-0.2871107757091522,-0.2445062994956970,0.1676304638385773,0.2116415053606033,0.0883995518088341,-0.3880331516265869,0.2636835277080536,-0.2514505982398987) * FEATURE2_texOff(vec2(1,0)); +res += mat4(-0.1861270815134048,0.2000686377286911,-0.1501186788082123,0.1525203883647919,0.1969228833913803,0.1174068301916122,-0.1281060427427292,-0.0854888409376144,0.0290613435208797,-0.0538076497614384,-0.0251582786440849,0.0692845508456230,0.0384319014847279,0.2888138592243195,0.1151804402470589,0.0990421250462532) * FEATURE1_texOff(vec2(1,1)); +res += mat4(-0.0344385802745819,0.1270371377468109,0.0922426953911781,-0.0426749102771282,-0.1656492203474045,-0.3273328542709351,-0.0282224025577307,0.1099396124482155,-0.1113230437040329,0.2943290174007416,-0.2181112915277481,-0.3177657723426819,-0.1096536740660667,-0.0508293099701405,-0.0256164856255054,-0.0388228967785835) * FEATURE2_texOff(vec2(1,1)); +res = max(res, vec4(0.0)) + vec4(0.7142407894134521,0.0686190053820610,0.3999933302402496,-1.0247212648391724) * min(res, vec4(0.0)); +return res; +} + +//!HOOK LUMA +//!WHEN OUTPUT.w LUMA.w / 1.300 > OUTPUT.h LUMA.h / 1.300 > * +//!DESC mapping 2_1 +//!BIND MODEL21 +//!BIND MODEL22 +//!SAVE MODEL1 +//!COMPONENTS 4 +vec4 hook() +{ +vec4 res = vec4(0.0203563515096903,0.1902436912059784,-0.0757935121655464,0.0393617525696754); +res += mat4(-0.1080558672547340,-0.0400269515812397,0.1042881682515144,-0.1994346678256989,0.0172465778887272,-0.0829331055283546,-0.1278677284717560,-0.0762506872415543,-0.0593080408871174,-0.0305212251842022,0.1326192617416382,-0.3380933105945587,-0.0722763314843178,-0.1975518912076950,-0.0223602931946516,0.2251029163599014) * MODEL21_texOff(vec2(-1,-1)); +res += mat4(0.1747678220272064,0.0297168865799904,0.1054855734109879,0.0803295820951462,-0.0338115766644478,-0.3885377943515778,-0.3540246784687042,-0.0719623491168022,-0.0656022280454636,-0.0469004511833191,0.1379419565200806,0.0319863893091679,0.0799935683608055,-0.0099127553403378,0.1698455959558487,-0.0108015276491642) * MODEL22_texOff(vec2(-1,-1)); +res += mat4(0.1587898135185242,0.3995443880558014,-0.0333226583898067,0.2373267263174057,-0.1616930961608887,0.0659186244010925,0.0141129801049829,-0.0541022196412086,-0.5743742585182190,0.1121487766504288,0.4259817600250244,0.0280795227736235,-0.3721714317798615,-0.3496374189853668,0.0997273251414299,-0.0079920450225472) * MODEL21_texOff(vec2(-1,0)); +res += mat4(0.0928084030747414,0.3107658624649048,0.1375299990177155,0.1550617516040802,-0.0780353918671608,-0.0102957757189870,-0.2056752145290375,-0.3927979469299316,-1.2112152576446533,0.0213295854628086,0.1396545022726059,0.0492016039788723,-0.0569122135639191,-0.1691886335611343,-0.1535325646400452,0.2800904810428619) * MODEL22_texOff(vec2(-1,0)); +res += mat4(0.2494744062423706,-0.0363066755235195,0.0959179550409317,-0.0048101749271154,-0.0195793900638819,0.0451166369020939,0.1470773071050644,-0.0050059854984283,0.2886958122253418,-0.3221147954463959,-0.7062104344367981,0.1646659970283508,-0.0092520527541637,-0.1254461258649826,0.0217506736516953,-0.0678806379437447) * MODEL21_texOff(vec2(-1,1)); +res += mat4(-0.0686557441949844,-0.0414490625262260,-0.1855954080820084,0.0264346338808537,-0.0296857114881277,-0.0431593284010887,0.0669397041201591,-0.0946076661348343,-0.2036914378404617,-0.1336101740598679,-0.2099903970956802,-0.1327936947345734,-0.1002155169844627,-0.0368575826287270,-0.1660962998867035,0.0728288888931274) * MODEL22_texOff(vec2(-1,1)); +res += mat4(0.5504320859909058,0.2939232587814331,0.4704743027687073,0.2129514217376709,0.0843106731772423,-0.1978624463081360,-0.3298224806785583,0.1919094175100327,0.1980742365121841,-0.0644423812627792,0.0091170109808445,-0.2124856859445572,0.0804558470845222,-0.1130188927054405,-0.6276652812957764,0.1861163526773453) * MODEL21_texOff(vec2(0,-1)); +res += mat4(-0.3357668519020081,0.2093413323163986,0.4355416595935822,0.1550502777099609,-0.6510964035987854,-0.1751857399940491,-0.2060168534517288,-0.1710205078125000,-0.1202360317111015,-0.2500316798686981,0.1074745431542397,-0.2418434321880341,0.0133954072371125,-0.0555886104702950,0.1514673978090286,0.2739115655422211) * MODEL22_texOff(vec2(0,-1)); +res += mat4(-0.3006273508071899,-0.2699472010135651,-0.1982013583183289,-0.0032952548936009,0.0307833012193441,0.3671586215496063,-0.0966020002961159,-0.2836556434631348,0.4297264218330383,0.6171903610229492,0.6723483800888062,0.2705117464065552,-0.1438141316175461,-0.0873940736055374,-0.7001031041145325,-0.2052250355482101) * MODEL21_texOff(vec2(0,0)); +res += mat4(-0.2875024676322937,-1.6230558156967163,-0.6733398437500000,-0.9642448425292969,-0.1964960694313049,0.2485812455415726,0.1236900389194489,-1.1423941850662231,-0.0412602946162224,0.3412002623081207,0.3962794244289398,-0.2490761876106262,-0.0058065578341484,-0.4578708708286285,-0.2418260127305984,0.5357795953750610) * MODEL22_texOff(vec2(0,0)); +res += mat4(0.0062361713498831,0.1925230026245117,0.0824977159500122,0.0561275146901608,0.0929671525955200,0.0698546022176743,0.3816939592361450,0.0395248420536518,-0.0719512030482292,0.0564917400479317,-0.1297784000635147,0.1245511695742607,0.0012355837970972,-0.0990515723824501,0.4213519692420959,-0.1645816713571548) * MODEL21_texOff(vec2(0,1)); +res += mat4(-0.0611936338245869,-0.0220258161425591,-0.0040935277938843,-0.1060328409075737,-0.0583154149353504,-0.0171997752040625,0.1058546081185341,0.2793170809745789,-0.2339317053556442,-0.1972009539604187,-0.0600687190890312,-0.0684379041194916,0.0243016034364700,-0.2111079394817352,-0.2042971849441528,0.0724857896566391) * MODEL22_texOff(vec2(0,1)); +res += mat4(-0.0833447948098183,-0.0533220991492271,0.0767802372574806,0.1182348504662514,-0.0223299078643322,-0.0479344800114632,-0.0119727496057749,0.0524821877479553,-0.0334780365228653,0.0719002187252045,0.0439689308404922,0.0475181229412556,0.0764308497309685,0.0086713796481490,-0.1700707823038101,0.0657354295253754) * MODEL21_texOff(vec2(1,-1)); +res += mat4(0.1391696482896805,0.0739523395895958,0.0565792545676231,-0.0430364646017551,0.0943084582686424,0.0102064209058881,0.0120795257389545,-0.0841303989291191,0.1573246121406555,0.0164279472082853,0.0988841354846954,-0.1430613398551941,-0.0572808869183064,-0.0844292491674423,0.0621565617620945,0.0923799052834511) * MODEL22_texOff(vec2(1,-1)); +res += mat4(-0.1223107874393463,-0.2441930323839188,-0.2410650849342346,-0.0162935722619295,0.0695567727088928,-0.0028583710081875,-0.0059417244046926,0.0715164169669151,-0.0668491795659065,-0.1499572396278381,0.0869924053549767,0.0553652904927731,0.2729566097259521,0.1370039582252502,-0.1282183527946472,-0.1451860070228577) * MODEL21_texOff(vec2(1,0)); +res += mat4(0.1331952214241028,0.0021079662255943,-0.1116734445095062,-0.4168601930141449,0.0534659475088120,0.0037860786542296,-0.0366065911948681,0.1047701835632324,0.1491260826587677,0.0782341659069061,0.0949895009398460,-0.1160908639431000,-0.1057133302092552,-0.2699718773365021,-0.1193305626511574,0.2142304331064224) * MODEL22_texOff(vec2(1,0)); +res += mat4(0.0041565205901861,-0.1065499857068062,-0.0629659667611122,-0.1144768893718719,0.0318886637687683,-0.0562519319355488,0.0043422472663224,0.0226082988083363,-0.1456198990345001,-0.2398656159639359,-0.2625046670436859,-0.0710547044873238,0.0067904205061495,0.0018544088816270,0.1019348874688148,-0.0186133962124586) * MODEL21_texOff(vec2(1,1)); +res += mat4(0.0732532218098640,0.1516859829425812,0.0580205544829369,0.1968977004289627,-0.0066619524732232,-0.1597842127084732,-0.0990600511431694,-0.1059188917279243,0.0718481168150902,-0.2222738713026047,-0.1675696671009064,-0.1500017195940018,-0.0568779110908508,-0.0582777932286263,-0.0844587534666061,-0.0263266414403915) * MODEL22_texOff(vec2(1,1)); +res = max(res, vec4(0.0)) + vec4(-0.2459529191255569,0.7563464641571045,-0.0705636814236641,-0.0094820559024811) * min(res, vec4(0.0)); +return res; +} + +//!HOOK LUMA +//!WHEN OUTPUT.w LUMA.w / 1.300 > OUTPUT.h LUMA.h / 1.300 > * +//!DESC mapping 2_2 +//!BIND MODEL21 +//!BIND MODEL22 +//!SAVE MODEL2 +//!COMPONENTS 4 +vec4 hook() +{ +vec4 res = vec4(-0.0448397286236286,-0.1649267971515656,-0.1192543581128120,-0.0061073559336364); +res += mat4(0.0724840760231018,-0.0480341166257858,-0.1082391515374184,-0.1447021961212158,0.0723197236657143,0.0481830574572086,0.0009448126656935,0.0353565886616707,-0.0653375908732414,0.0029647622723132,-0.0016588598955423,-0.2075651884078979,0.0403469167649746,0.3929971158504486,0.0342363268136978,0.1427230089902878) * MODEL21_texOff(vec2(-1,-1)); +res += mat4(-0.0743464827537537,0.1844420731067657,0.0256296340376139,-0.2808582782745361,0.0351609662175179,0.3277008235454559,-0.0205841138958931,-0.5355809330940247,0.0681906566023827,0.2058052271604538,-0.0479847639799118,-0.3735262751579285,-0.0261550359427929,-0.1148884072899818,-0.2329017966985703,0.0728458985686302) * MODEL22_texOff(vec2(-1,-1)); +res += mat4(-0.1236097738146782,0.1251334398984909,-0.1339431256055832,0.0198749266564846,-0.1325920224189758,-2.2431972026824951,-0.0680834427475929,-0.5671764612197876,-0.3431925177574158,-0.0983135104179382,-0.2207138091325760,-0.2374879121780396,0.0127309206873178,1.3076044321060181,0.0848151743412018,-0.1928595900535583) * MODEL21_texOff(vec2(-1,0)); +res += mat4(-0.0471093133091927,-0.1513628512620926,-0.0134263765066862,-0.1519252359867096,-0.5260242223739624,0.2291621714830399,0.4088975787162781,-0.4315340518951416,0.0933236032724380,-1.0386694669723511,0.0015958193689585,-0.2737887501716614,-0.0246253963559866,-0.2722961604595184,-0.1770633459091187,-0.2291279733181000) * MODEL22_texOff(vec2(-1,0)); +res += mat4(-0.0017552347853780,0.1903935521841049,-0.0740704238414764,-0.0917679518461227,0.0323882810771465,-0.3029108047485352,0.0532565414905548,-0.0651542618870735,0.4868686199188232,0.8539272546768188,0.4151960313320160,0.2619662582874298,-0.0413270294666290,0.1404227763414383,0.1027320474386215,0.3274228572845459) * MODEL21_texOff(vec2(-1,1)); +res += mat4(0.1828346252441406,0.0274682324379683,-0.1169882863759995,0.0327291004359722,0.1786244213581085,-0.6569546461105347,-0.0609031207859516,-0.1676601022481918,-0.1481092721223831,0.2889067530632019,0.1246089115738869,0.2203597426414490,-0.0366856977343559,0.1539470851421356,0.0069492300972342,-0.1544002443552017) * MODEL22_texOff(vec2(-1,1)); +res += mat4(0.2073992937803268,-0.0717074573040009,-0.0196173377335072,-0.0956910699605942,0.0728898122906685,0.0484567955136299,0.3063069283962250,-0.3200540542602539,0.0291527546942234,-0.0265460256487131,0.1168476045131683,-0.2479970753192902,0.1224220171570778,0.0745823010802269,0.1868897676467896,-0.1958049237728119) * MODEL21_texOff(vec2(0,-1)); +res += mat4(0.0019954447634518,-0.0225235987454653,0.0812198966741562,0.0295672398060560,-0.2016931176185608,-0.2239151000976562,-0.2481262385845184,-0.2381946444511414,-0.0520484372973442,-0.1200495883822441,0.2121954560279846,-0.1573531329631805,-0.0198472067713737,0.1001087054610252,-0.1084884032607079,-0.3126969039440155) * MODEL22_texOff(vec2(0,-1)); +res += mat4(0.3838330209255219,0.1678779572248459,0.6496244072914124,0.3783606290817261,-0.2198582738637924,-0.2351343184709549,-0.2852248847484589,0.6310021877288818,0.8083020448684692,0.0039323624223471,-0.0901831910014153,0.0797894075512886,-0.2271467447280884,0.7082978487014771,0.1513756662607193,0.2188975960016251) * MODEL21_texOff(vec2(0,0)); +res += mat4(-0.2871031761169434,0.2316448241472244,0.4947948157787323,0.3308620452880859,-0.0623455122113228,-0.1314185708761215,-0.2664661705493927,0.8725078701972961,0.4541083276271820,0.1433589160442352,-1.1269453763961792,0.6427971124649048,-0.1016561388969421,0.3418317139148712,-0.0991155728697777,-1.0508837699890137) * MODEL22_texOff(vec2(0,0)); +res += mat4(-0.2179604172706604,0.1258949041366577,-0.1155700981616974,-0.0536149404942989,-0.0140614463016391,-0.0091438721865416,-0.0501774959266186,-0.3570724725723267,-0.5832386016845703,0.2004123181104660,0.2986239194869995,-0.8139168024063110,0.0142666567116976,0.0681498944759369,0.1293468028306961,-0.1001938357949257) * MODEL21_texOff(vec2(0,1)); +res += mat4(0.1952836811542511,-0.3092494010925293,0.3063779771327972,0.1934849917888641,0.0746696740388870,-0.3533902466297150,-0.1269576102495193,-0.2237875163555145,0.2470717132091522,-0.2640363574028015,-0.2862776815891266,0.1740108281373978,-0.0963631942868233,0.2631850540637970,0.0400718413293362,-0.3590607047080994) * MODEL22_texOff(vec2(0,1)); +res += mat4(-0.5299927592277527,0.0979989692568779,0.1666737496852875,-0.1547524333000183,-0.0043443185277283,0.1540203243494034,0.0594348423182964,-0.0167275425046682,-0.1043610796332359,0.0504250898957253,0.0456700921058655,0.2525034546852112,0.2241353541612625,-0.1678503304719925,0.1532667279243469,0.2901742458343506) * MODEL21_texOff(vec2(1,-1)); +res += mat4(0.0998796448111534,0.0385462641716003,-0.0762400180101395,-0.1255892217159271,0.0281430184841156,-0.0304958485066891,-0.1440480053424835,-0.1001605167984962,-0.2257689833641052,0.2056092917919159,0.0248535349965096,-0.1383949518203735,-0.0951708629727364,0.0997417271137238,0.0275330394506454,-0.5728432536125183) * MODEL22_texOff(vec2(1,-1)); +res += mat4(0.4256163835525513,0.1745115518569946,-0.2409395426511765,0.3139856457710266,-0.0036795330233872,0.1819283962249756,-0.0864531323313713,0.0102691333740950,-0.3397279977798462,0.1107075437903404,-0.0035228815395385,-0.2207705229520798,-0.1779139339923859,-0.2106117755174637,0.0352664291858673,0.3615589439868927) * MODEL21_texOff(vec2(1,0)); +res += mat4(-0.0345224253833294,-0.0669926702976227,0.0907212942838669,-0.3758732676506042,-0.0452554710209370,-0.1134464666247368,-0.0358871109783649,-0.1858227252960205,-0.0233245138078928,-0.0495684742927551,0.1976234614849091,-0.1165761798620224,-0.0340447537600994,0.1095624342560768,0.0110175255686045,-0.8269239664077759) * MODEL22_texOff(vec2(1,0)); +res += mat4(-0.1379280686378479,0.1004267781972885,0.0723998174071312,-0.1510958224534988,0.0610648579895496,0.0451720170676708,-0.0231927260756493,-0.0251553766429424,0.2306085377931595,0.1033207178115845,-0.1316205114126205,0.1130664870142937,-0.0458516106009483,-0.1152514070272446,-0.0088650323450565,-0.0214479379355907) * MODEL21_texOff(vec2(1,1)); +res += mat4(-0.0545783303678036,-0.0620098188519478,0.0347074456512928,0.1096799224615097,0.0036664425861090,-0.0413107499480247,0.1443250179290771,-0.1161036714911461,-0.0061624986119568,-0.0252977479249239,0.3230019211769104,-0.2536626160144806,-0.0565439648926258,0.0827583819627762,-0.0071726376190782,-0.1983329951763153) * MODEL22_texOff(vec2(1,1)); +res = max(res, vec4(0.0)) + vec4(-0.6312188506126404,-0.1215368881821632,0.2487443536520004,0.4051703512668610) * min(res, vec4(0.0)); +return res; +} + +//!HOOK LUMA +//!WHEN OUTPUT.w LUMA.w / 1.300 > OUTPUT.h LUMA.h / 1.300 > * +//!DESC mapping 3_1 +//!BIND MODEL1 +//!BIND MODEL2 +//!SAVE MODEL21 +//!COMPONENTS 4 +vec4 hook() +{ +vec4 res = vec4(-0.0410279631614685,-0.1111723631620407,-0.0406232848763466,-0.0939496159553528); +res += mat4(0.1221675798296928,0.0083215842023492,-0.0162804014980793,0.0316714197397232,-0.2205813378095627,0.1500435769557953,0.2109555304050446,0.2741867899894714,0.0956874340772629,-0.0896854698657990,-0.1657065600156784,-0.1349759399890900,0.0601499564945698,-0.1523845940828323,-0.1828087568283081,-0.2727653682231903) * MODEL1_texOff(vec2(-1,-1)); +res += mat4(-0.0918163508176804,0.1564485579729080,0.1133174449205399,0.2215953171253204,-0.0623677000403404,-0.0497728772461414,-0.0372809022665024,-0.0258478187024593,-0.1364922970533371,0.1053884625434875,0.3292874991893768,0.2693256139755249,-0.0347631797194481,-0.1470523178577423,0.0096792401745915,-0.0542853325605392) * MODEL2_texOff(vec2(-1,-1)); +res += mat4(0.1331177949905396,-0.0964357852935791,-0.0706946700811386,0.1593225002288818,-0.4815943241119385,0.1224092170596123,-0.0870430991053581,0.0005010276800022,-0.0242684502154589,-0.2256436049938202,0.1367238312959671,0.0474774017930031,0.6886650323867798,-0.0065326127223670,0.1841574758291245,-0.1354993879795074) * MODEL1_texOff(vec2(-1,0)); +res += mat4(-0.1049591675400734,0.0515934228897095,0.1128631457686424,0.1688040047883987,-0.0084041170775890,-0.0006375144002959,-0.0598374009132385,0.1424416452646255,-0.0048398924991488,0.1832167655229568,0.0231959503144026,0.0816788375377655,-0.1321710795164108,0.0397678017616272,-0.0058345394209027,0.5784573554992676) * MODEL2_texOff(vec2(-1,0)); +res += mat4(0.1438693851232529,-0.0694608166813850,-0.0428275354206562,0.1599996536970139,-0.1651254445314407,0.1388883888721466,-0.0895452573895454,0.2569831907749176,0.3150432109832764,-0.0910519883036613,0.0367441214621067,0.1903669685125351,0.2805841267108917,-0.0444608181715012,0.0059385276399553,-0.2585869431495667) * MODEL1_texOff(vec2(-1,1)); +res += mat4(-0.1217494234442711,0.0191769022494555,-0.0065453462302685,0.1391217857599258,0.0998920649290085,-0.0162798929959536,0.0502282194793224,0.0370145924389362,0.0290782172232866,-0.0099554909393191,0.0142515478655696,0.1248661577701569,-0.0076912571676075,0.0251651499420404,0.2190572917461395,0.0020069130696356) * MODEL2_texOff(vec2(-1,1)); +res += mat4(0.2666685581207275,-0.1625511497259140,-0.3938800692558289,-0.0253848694264889,0.0987015441060066,0.2033616453409195,0.3128099143505096,0.4608893990516663,0.0620003379881382,-0.1389972567558289,-0.3095863461494446,-0.4023511111736298,-0.1105777546763420,0.1115406602621078,0.3639950752258301,0.0645622834563255) * MODEL1_texOff(vec2(0,-1)); +res += mat4(-0.2135885655879974,-0.1035343706607819,0.1795026361942291,0.1828210204839706,0.0780984908342361,0.0656728670001030,0.0033678691834211,0.1361345648765564,0.1712654232978821,-0.0172833092510700,-0.0502183400094509,0.2910411655902863,0.0691247656941414,0.1935720741748810,0.0652214139699936,0.1608240753412247) * MODEL2_texOff(vec2(0,-1)); +res += mat4(0.8243460655212402,-0.0979344248771667,-0.0366373993456364,0.1692261099815369,0.5517869591712952,0.3282494544982910,-0.7905511856079102,-0.4462923705577850,-0.0803156569600105,0.1172509342432022,0.1864327639341354,0.1471016854047775,0.1296005547046661,-0.1004103720188141,0.3174172043800354,-0.1181766316294670) * MODEL1_texOff(vec2(0,0)); +res += mat4(0.0259374529123306,-0.0934808850288391,0.3008874654769897,0.3957927823066711,-0.4048821926116943,0.1461934000253677,-0.1819096356630325,-0.1908810287714005,0.3193186521530151,-0.7438099980354309,0.1919509470462799,-0.2065188735723495,0.1752236187458038,-0.6840037107467651,0.1588519066572189,-0.3956064879894257) * MODEL2_texOff(vec2(0,0)); +res += mat4(0.1574442386627197,-0.0114925103262067,-0.1208277940750122,0.2058266401290894,0.2879209220409393,-0.0419875606894493,-0.1902059614658356,-0.2723863720893860,-0.1086223348975182,-0.0870924964547157,0.8605937957763672,0.2656622231006622,-0.1653763055801392,0.0816384851932526,-0.0137870563194156,0.1433854848146439) * MODEL1_texOff(vec2(0,1)); +res += mat4(-0.1565909236669540,-0.0307490080595016,-0.1055604666471481,0.2573592662811279,-0.1186821162700653,0.1141471788287163,-0.0272745657712221,-0.1049114838242531,0.2445316016674042,-0.0027864547446370,-0.1759569346904755,-0.1556979566812515,0.0550616309046745,0.1704383641481400,0.0853662937879562,0.3280856907367706) * MODEL2_texOff(vec2(0,1)); +res += mat4(0.1460669338703156,0.4202052652835846,-0.3638312816619873,-0.0958623066544533,-0.0492525361478329,-0.3664234280586243,0.0794373303651810,0.0399017669260502,0.0629198029637337,0.1662959158420563,-0.1001493930816650,-0.0587460733950138,-0.0396478697657585,0.0017320754704997,0.0314909480512142,-0.0202700830996037) * MODEL1_texOff(vec2(1,-1)); +res += mat4(-0.0964399129152298,0.0380319654941559,0.0396055467426777,0.0265473183244467,-0.0161637403070927,-0.1872924566268921,0.1670000404119492,0.0029466480482370,-0.1093841269612312,-0.3629201948642731,-0.0562992505729198,0.1792684197425842,-0.0203859098255634,0.0983991250395775,0.0058611719869077,0.1627455651760101) * MODEL2_texOff(vec2(1,-1)); +res += mat4(-0.1117974221706390,0.7562329173088074,-0.2046248912811279,0.1677842289209366,-0.2063486129045486,-0.6023545265197754,-0.5739209651947021,0.5110496878623962,-0.0715268924832344,-0.1373793482780457,0.1251420378684998,-0.0477442294359207,0.4961377978324890,0.2688887119293213,0.3146316707134247,-0.5197153687477112) * MODEL1_texOff(vec2(1,0)); +res += mat4(-0.1314805448055267,0.0746279135346413,0.3457699418067932,0.2564856410026550,0.0839370116591454,-0.6136511564254761,-0.4646295011043549,0.0612256154417992,-0.1910563558340073,-0.0935136750340462,-0.2426030039787292,0.2102959007024765,0.1575350016355515,0.6145061254501343,0.3368154168128967,-0.0974092856049538) * MODEL2_texOff(vec2(1,0)); +res += mat4(0.0565315335988998,0.2393359094858170,-0.0932938233017921,0.1555283814668655,0.0123879108577967,-0.1247719228267670,-0.0564610138535500,-0.1125799044966698,-0.0104600470513105,0.0482629500329494,0.2316472232341766,0.1083717569708824,-0.0525921434164047,0.0643989592790604,-0.0525734610855579,-0.0503251366317272) * MODEL1_texOff(vec2(1,1)); +res += mat4(-0.1835366338491440,0.0978360474109650,-0.1111819595098495,0.2109299153089523,0.0509372949600220,-0.1992686837911606,0.0677929744124413,-0.0870024710893631,-0.0412262082099915,-0.0697719156742096,-0.0967373847961426,0.0137308547273278,0.0195730421692133,0.0410240143537521,0.1157210171222687,0.2283479571342468) * MODEL2_texOff(vec2(1,1)); +res = max(res, vec4(0.0)) + vec4(0.1991519331932068,-0.1275756657123566,-0.0622864030301571,0.1586369574069977) * min(res, vec4(0.0)); +return res; +} + +//!HOOK LUMA +//!WHEN OUTPUT.w LUMA.w / 1.300 > OUTPUT.h LUMA.h / 1.300 > * +//!DESC mapping 3_2 +//!BIND MODEL1 +//!BIND MODEL2 +//!SAVE MODEL22 +//!COMPONENTS 4 +vec4 hook() +{ +vec4 res = vec4(-0.0089084329083562,-0.0336172059178352,0.0177190825343132,0.0529975406825542); +res += mat4(-0.0275970958173275,0.0141968233510852,0.1181544512510300,-0.0572245270013809,0.1161347925662994,-0.1156444773077965,-0.2549640238285065,0.0882879272103310,-0.0715355500578880,0.0151285668835044,0.1079384386539459,0.0650847703218460,-0.1597152203321457,0.0669793561100960,0.2084401696920395,-0.0951152443885803) * MODEL1_texOff(vec2(-1,-1)); +res += mat4(0.0404323227703571,-0.0206144321709871,-0.1080420613288879,-0.2038477361202240,0.0248847268521786,-0.0064681121148169,0.0389525443315506,0.0011026862775907,0.0885242074728012,0.0295896343886852,-0.3323790132999420,0.1935138553380966,-0.0466548874974251,0.1023886054754257,0.1257870644330978,-0.1541756242513657) * MODEL2_texOff(vec2(-1,-1)); +res += mat4(-0.0076520540751517,0.0361139886081219,0.1749804913997650,-0.2051989138126373,0.0022692133206874,-0.0282937753945589,-0.2039019316434860,-0.2343468815088272,-0.0357327871024609,-0.0570764988660812,0.2925858795642853,-0.1988349705934525,-0.0584560707211494,-0.0341510921716690,0.1300961822271347,0.5184492468833923) * MODEL1_texOff(vec2(-1,0)); +res += mat4(0.0884973928332329,0.0333527140319347,0.0180535931140184,-0.2655122876167297,0.0433661043643951,0.0104369185864925,0.0010909073753282,-0.0705273598432541,-0.0602585524320602,0.2420269846916199,-0.4731841087341309,-0.8040290474891663,0.3066828548908234,-0.2466925680637360,0.0938910692930222,-0.2002603262662888) * MODEL2_texOff(vec2(-1,0)); +res += mat4(0.0549152903258801,0.0291299298405647,0.0946277007460594,-0.0581608228385448,0.0669180899858475,-0.0635575056076050,-0.2427970170974731,-0.2677550315856934,0.2226776182651520,0.1301570236682892,-0.1519709974527359,0.0671724304556847,-0.0526433289051056,0.1898351758718491,0.2383745312690735,0.2191711813211441) * MODEL1_texOff(vec2(-1,1)); +res += mat4(-0.0234222635626793,0.0238620284944773,0.0427630320191383,-0.1080563366413116,0.0332126952707767,-0.0039051575586200,0.0293126031756401,0.0161924213171005,0.0453971028327942,0.0131999952718616,-0.0689036697149277,0.2349009960889816,0.1013344153761864,0.2706570029258728,0.1191426888108253,-0.2830821871757507) * MODEL2_texOff(vec2(-1,1)); +res += mat4(0.0181465242058039,-0.0571886636316776,0.4875229001045227,-0.4244020283222198,0.4331104159355164,0.1066712513566017,-0.5277034044265747,0.1110567077994347,-0.1179447323083878,-0.0273578558117151,0.1798476576805115,-0.2829602360725403,0.1012385115027428,-0.2528488039970398,0.1697608679533005,0.1121710017323494) * MODEL1_texOff(vec2(0,-1)); +res += mat4(-0.1404130905866623,-0.0984055623412132,-0.0279541295021772,-0.1321212500333786,-0.0841855704784393,0.1336171030998230,-0.1458790600299835,-0.0044095455668867,0.2203754037618637,0.1455714553594589,-0.2362042963504791,-0.0329121425747871,-0.1683547794818878,0.0289597529917955,0.3424547612667084,0.0143845872953534) * MODEL2_texOff(vec2(0,-1)); +res += mat4(0.0287246014922857,0.1948280781507492,0.5998955368995667,0.1192114129662514,-0.6269109249114990,0.8724324703216553,-0.6399638652801514,-0.4201497733592987,-0.3355066180229187,-0.1566904038190842,-0.4396412074565887,0.1525828838348389,0.5573399066925049,0.2324324846267700,0.2762884795665741,0.0406046211719513) * MODEL1_texOff(vec2(0,0)); +res += mat4(0.3890096545219421,-0.0574061162769794,-0.1468243300914764,-0.5953360199928284,-0.1363215148448944,-0.2224670499563217,-0.2237723320722580,0.2738097012042999,-0.4868114292621613,-0.5029351711273193,-0.3570256233215332,-0.1776263266801834,-0.0176672954112291,-0.4318660795688629,1.0395888090133667,0.1728395074605942) * MODEL2_texOff(vec2(0,0)); +res += mat4(0.1337304115295410,-0.0809440389275551,0.1600498855113983,-0.1108811497688293,-0.2376178801059723,-0.1532768607139587,-0.0447455830872059,0.2515332102775574,0.4848278462886810,-0.0915748402476311,-0.0336527302861214,-0.2141884714365005,0.2125129699707031,0.3237875998020172,0.0022272330243140,-0.0167857185006142) * MODEL1_texOff(vec2(0,1)); +res += mat4(0.0457934997975826,0.0510537698864937,-0.0519523508846760,-0.4506326615810394,-0.1029204949736595,0.0116113182157278,-0.1750748157501221,-0.0048758201301098,0.1506977379322052,0.0633068457245827,-0.1628549993038177,-0.0144928665831685,0.1408756822347641,0.2896180152893066,0.0803691521286964,-0.4930096566677094) * MODEL2_texOff(vec2(0,1)); +res += mat4(-0.0484248884022236,0.1371297985315323,-0.1235475391149521,-0.2618594765663147,-0.0280395895242691,0.0248795989900827,0.1204105168581009,0.3246576189994812,0.0426272377371788,-0.0520061068236828,0.0575957447290421,-0.2613646090030670,0.1165295541286469,-0.0390013493597507,-0.0470846109092236,-0.0014663023175672) * MODEL1_texOff(vec2(1,-1)); +res += mat4(-0.1066762879490852,-0.0869804695248604,-0.0099332248792052,-0.1355892717838287,-0.0760413780808449,0.1377770304679871,-0.0263407956808805,0.0880135521292686,0.1496269851922989,-0.0487459264695644,0.1286851912736893,0.2218491584062576,0.1723349541425705,-0.0165541302412748,-0.0690477639436722,-0.2388458102941513) * MODEL2_texOff(vec2(1,-1)); +res += mat4(-0.4236431121826172,0.0465179122984409,-0.1526456624269485,0.1426440477371216,0.5913932919502258,-0.1082349196076393,0.2731275856494904,-0.2687640488147736,-0.4628683030605316,-0.0537119321525097,-0.1597615629434586,0.0528527684509754,-0.3485085070133209,0.1395110934972763,0.0642972290515900,0.0323829315602779) * MODEL1_texOff(vec2(1,0)); +res += mat4(0.0066713397391140,-0.0482029877603054,-0.1707276403903961,-0.1001396998763084,0.0539822019636631,-0.1624453216791153,0.4913550019264221,0.3687861263751984,0.0491421781480312,0.1311376541852951,0.0992425829172134,-0.4636098444461823,-0.3415873646736145,-0.0153833786025643,-0.0270162131637335,-0.0935514941811562) * MODEL2_texOff(vec2(1,0)); +res += mat4(-0.1738258153200150,0.0458541549742222,-0.0653749182820320,-0.0156540926545858,-0.0357586294412613,-0.1486178338527679,0.1798035055398941,-0.1310307979583740,0.0783249065279961,-0.0261360015720129,-0.1047066971659660,0.3385537564754486,-0.0339452810585499,0.2299628853797913,-0.1408322304487228,-0.0352708548307419) * MODEL1_texOff(vec2(1,1)); +res += mat4(0.0463018082082272,0.0565674640238285,-0.0538956597447395,-0.2354862987995148,0.0297824125736952,0.0307939313352108,0.1271791011095047,-0.1025698855519295,0.1060482114553452,-0.0703211054205894,-0.0083062350749969,0.0474255047738552,0.0442508421838284,0.1569559425115585,-0.0442709513008595,-0.1188704669475555) * MODEL2_texOff(vec2(1,1)); +res = max(res, vec4(0.0)) + vec4(0.7366524934768677,1.0013850927352905,-0.0276311747729778,0.0734841898083687) * min(res, vec4(0.0)); +return res; +} + +//!HOOK LUMA +//!WHEN OUTPUT.w LUMA.w / 1.300 > OUTPUT.h LUMA.h / 1.300 > * +//!DESC mapping 4_1 +//!BIND MODEL21 +//!BIND MODEL22 +//!SAVE MODEL1 +//!COMPONENTS 4 +vec4 hook() +{ +vec4 res = vec4(-0.1306160986423492,-0.0808217376470566,-0.2880123555660248,0.0099629526957870); +res += mat4(-0.1033539846539497,0.0541300140321255,-0.0804840475320816,-0.0334571413695812,-0.0264753755182028,0.1118840202689171,0.1186013221740723,-0.0127575425431132,0.2236593365669250,0.0025286162272096,0.0985530614852905,0.0685181617736816,-0.1884875595569611,0.0530862808227539,-0.0482063069939613,0.0375233069062233) * MODEL21_texOff(vec2(-1,-1)); +res += mat4(0.1837068796157837,-0.0632847175002098,0.0016613919287920,0.0392861217260361,0.2923883199691772,-0.1713902205228806,0.1907587945461273,0.0550456829369068,0.0644215345382690,-0.1046456992626190,0.0187383033335209,0.0770180150866508,0.1933846622705460,-0.0455715768039227,0.0375007353723049,-0.1053109914064407) * MODEL22_texOff(vec2(-1,-1)); +res += mat4(-0.0972480997443199,0.2820451855659485,0.0114549007266760,-0.0954328626394272,0.0706252008676529,0.4829064607620239,-0.6371517181396484,0.0005180989392102,0.3280143439769745,0.0665246024727821,-0.0503116399049759,-0.1261110603809357,0.1114177703857422,-0.2053108513355255,0.1428771317005157,0.3926100134849548) * MODEL21_texOff(vec2(-1,0)); +res += mat4(-0.2571723163127899,0.1627264618873596,-0.4940335154533386,-0.1361546218395233,0.0804422944784164,-0.4231885373592377,0.0650202706456184,0.0518481098115444,-0.0502478554844856,-0.1305799931287766,0.1814480125904083,0.0090866927057505,-0.0510044656693935,-0.1691461503505707,0.0922467112541199,-0.0314207412302494) * MODEL22_texOff(vec2(-1,0)); +res += mat4(0.1270498335361481,0.0563284493982792,-0.0435525141656399,0.1569847911596298,0.0576847903430462,0.3461692929267883,-0.0325655154883862,-0.2688976824283600,-0.1341977864503860,-0.1382253766059875,0.2293784171342850,-0.1111817285418510,-0.1402447521686554,-0.3257531225681305,0.0598510466516018,0.1008039116859436) * MODEL21_texOff(vec2(-1,1)); +res += mat4(0.1698816716670990,0.3491003513336182,-0.1367681026458740,-0.1165873408317566,-0.2091718912124634,-0.1487034261226654,-0.0569749698042870,-0.2100717276334763,0.0404917001724243,-0.1372035890817642,0.0689046755433083,-0.0367818064987659,-0.0325474888086319,-0.0114965448155999,-0.0137249026447535,-0.0279692262411118) * MODEL22_texOff(vec2(-1,1)); +res += mat4(-0.0563433989882469,0.0132494345307350,-0.2434540390968323,0.0796563774347305,-0.2109155058860779,0.0387088693678379,-0.0591037571430206,0.0955820381641388,0.4660535752773285,-0.1204202473163605,0.1332369595766068,-0.0285425651818514,-0.3886952698230743,-0.0434980578720570,-0.0849134400486946,0.0802380964159966) * MODEL21_texOff(vec2(0,-1)); +res += mat4(0.0412235632538795,0.1571959257125854,0.2050069272518158,-0.1138664111495018,0.1962715685367584,0.0594439841806889,0.0351715497672558,-0.0129811102524400,0.2055217623710632,-0.0647534057497978,0.0373471938073635,0.0877277255058289,-0.5734645724296570,0.1188675239682198,-0.1145943328738213,-0.1182733029127121) * MODEL22_texOff(vec2(0,-1)); +res += mat4(-0.2004909217357635,-0.4817073047161102,0.5596802830696106,-0.0327854752540588,0.0989314392209053,0.4127818942070007,0.7265836596488953,-0.2692042589187622,0.5195841789245605,-0.2357539832592010,-0.3819393217563629,0.1755530238151550,0.6578183770179749,0.1075539961457253,-0.2688144743442535,0.3242723941802979) * MODEL21_texOff(vec2(0,0)); +res += mat4(-0.3221310675144196,0.2978510260581970,0.2269985526800156,-0.3184116482734680,0.4845580160617828,0.4407236874103546,0.0099756307899952,-0.3121858239173889,-0.3810067176818848,-0.0553649961948395,0.0202834140509367,0.0409953594207764,0.2532750964164734,0.2731618583202362,0.1237529441714287,0.0134243080392480) * MODEL22_texOff(vec2(0,0)); +res += mat4(0.1835541725158691,0.0549701862037182,-0.1749316602945328,-0.2030028849840164,0.0263462308794260,0.2781440317630768,0.0372458845376968,0.3643021881580353,-0.4047883749008179,0.0660117194056511,0.4863115549087524,-0.2024163603782654,-0.6403482556343079,0.2765505611896515,0.1417075097560883,0.5064445734024048) * MODEL21_texOff(vec2(0,1)); +res += mat4(0.6106975078582764,-0.1570862233638763,-0.3223383128643036,-0.2497926801443100,-0.4854303300380707,0.0132978223264217,-0.0609334111213684,0.1285556703805923,-0.1412864029407501,-0.1379042416810989,-0.0258826259523630,0.1357705891132355,-0.1285902857780457,-0.0577826797962189,0.0550044551491737,0.1717510819435120) * MODEL22_texOff(vec2(0,1)); +res += mat4(0.1389609426259995,0.0835867226123810,0.0309768319129944,-0.0278116948902607,-0.0390677824616432,-0.0111810686066747,-0.0025318188127130,0.0069569633342326,0.0347319357097149,0.0191543344408274,0.0314339138567448,-0.0228427499532700,0.0416300334036350,0.0249234102666378,0.1210031509399414,0.1142473593354225) * MODEL21_texOff(vec2(1,-1)); +res += mat4(0.0607251487672329,0.0386395826935768,-0.0219341218471527,-0.1102298423647881,0.1487188935279846,0.0602982006967068,-0.0280748903751373,-0.0211924221366644,0.0042894422076643,-0.0269144997000694,0.0814756453037262,-0.0314031280577183,-0.0213186051696539,-0.1362965404987335,0.0382767543196678,-0.0669511556625366) * MODEL22_texOff(vec2(1,-1)); +res += mat4(-0.2397561967372894,0.3023172020912170,-0.2398054003715515,0.0041919997893274,-0.1016605198383331,-0.1521034836769104,-0.1526568531990051,0.0272433310747147,0.0741761848330498,0.1116370111703873,0.1149727106094360,-0.0809784531593323,-0.1448147594928741,-0.0943927690386772,-0.0086280042305589,0.1243222951889038) * MODEL21_texOff(vec2(1,0)); +res += mat4(-0.0469366572797298,-0.1655988991260529,-0.1029584184288979,-0.1347874104976654,0.2064601778984070,0.0521226711571217,-0.1366733759641647,-0.0041872998699546,0.1077186539769173,0.0184442866593599,-0.2309073060750961,-0.1637075096368790,-0.0417953692376614,-0.3190860450267792,-0.1593534499406815,0.0136412177234888) * MODEL22_texOff(vec2(1,0)); +res += mat4(0.1698798984289169,0.0232755411416292,-0.0876034423708916,-0.3008348643779755,0.0789884999394417,0.0034748215693980,-0.0064704762771726,0.0057828431017697,-0.0190630126744509,-0.0334153175354004,-0.0195646341890097,0.0105131156742573,0.0995147302746773,-0.3130289018154144,-0.0724022984504700,0.0113303456455469) * MODEL21_texOff(vec2(1,1)); +res += mat4(-0.0027791252359748,-0.0193455871194601,-0.0415000133216381,0.0568981170654297,-0.2745247483253479,0.1222846284508705,0.1899162530899048,0.1067754998803139,-0.0561975166201591,-0.1500336527824402,0.0526139959692955,-0.3491798937320709,-0.0692384615540504,-0.0307095069438219,0.0498757846653461,0.0019003645284101) * MODEL22_texOff(vec2(1,1)); +res = max(res, vec4(0.0)) + vec4(0.1552927196025848,0.0782765746116638,0.7966942191123962,-1.1619627475738525) * min(res, vec4(0.0)); +return res; +} + +//!HOOK LUMA +//!WHEN OUTPUT.w LUMA.w / 1.300 > OUTPUT.h LUMA.h / 1.300 > * +//!DESC mapping 4_2 +//!BIND MODEL21 +//!BIND MODEL22 +//!SAVE MODEL2 +//!COMPONENTS 4 +vec4 hook() +{ +vec4 res = vec4(-0.1443098634481430,-0.1343899369239807,-0.0624338127672672,-0.1094277128577232); +res += mat4(-0.0689977407455444,-0.1693786680698395,0.0109281269833446,0.0609922930598259,0.0296908002346754,0.1195700988173485,-0.0694077461957932,0.0971287414431572,0.0253518298268318,0.1213042959570885,0.0703809782862663,0.0055739870294929,-0.1595942378044128,-0.1336689442396164,-0.0622441768646240,-0.0428023114800453) * MODEL21_texOff(vec2(-1,-1)); +res += mat4(0.0860001668334007,-0.0226618759334087,0.1602241247892380,0.0431661494076252,0.1526461094617844,0.2752982378005981,0.0960300788283348,-0.0536719262599945,-0.0171773489564657,0.0457364916801453,-0.0360932648181915,-0.0397153608500957,-0.0277090407907963,0.0729821547865868,-0.0145150292664766,0.0252893269062042) * MODEL22_texOff(vec2(-1,-1)); +res += mat4(-0.1407091915607452,-0.4007499516010284,-0.0302001200616360,-0.0606933943927288,-0.2960600554943085,-0.2263117432594299,0.0721478462219238,-0.4578711986541748,0.0960150733590126,-0.1606502830982208,0.2444226741790771,0.0000882153908606,0.1472496986389160,0.3256779909133911,-0.2132861614227295,0.0339313484728336) * MODEL21_texOff(vec2(-1,0)); +res += mat4(-0.1477648764848709,-0.1487885862588882,-0.1973863691091537,0.0717295333743095,0.0843430235981941,0.6259996294975281,-0.1214931011199951,-0.1274987608194351,0.2359549105167389,0.3002171218395233,-0.0825233608484268,-0.0157950688153505,0.0706149637699127,0.1762917637825012,-0.0611497573554516,-0.0859689489006996) * MODEL22_texOff(vec2(-1,0)); +res += mat4(0.0174895934760571,-0.0567042417824268,0.0409146919846535,0.0258173532783985,0.1421577036380768,0.1234543323516846,-0.1721662431955338,0.1492216140031815,0.1100751459598541,0.0501539446413517,0.1100447699427605,-0.1086079254746437,-0.0608497932553291,0.0087817469611764,0.0714464113116264,-0.1285197436809540) * MODEL21_texOff(vec2(-1,1)); +res += mat4(-0.0017177806003019,-0.1463395059108734,-0.1085453778505325,0.1650195866823196,0.0813829153776169,0.1102061793208122,-0.0578421875834465,-0.0232036896049976,-0.1239888817071915,0.0155465165153146,0.1079114526510239,-0.0420837886631489,-0.0775837749242783,0.0148941157385707,-0.0502299368381500,-0.0654754191637039) * MODEL22_texOff(vec2(-1,1)); +res += mat4(0.0918162539601326,0.0440697595477104,-0.0515748932957649,0.0417411290109158,0.0353216230869293,0.1535954177379608,0.0439723692834377,-0.1288845241069794,0.1076577678322792,-0.1306740194559097,0.0715952813625336,-0.0681907683610916,-0.3798767924308777,0.1023928597569466,-0.0970670804381371,0.0077168666757643) * MODEL21_texOff(vec2(0,-1)); +res += mat4(0.0634560957551003,-0.0550306066870689,0.2073986232280731,0.0520241297781467,0.1162287592887878,-0.2218665480613708,0.3199682831764221,0.0606246069073677,-0.0058511858806014,-0.0667045339941978,-0.0449917949736118,0.0707788690924644,-0.3323366343975067,-0.0763893201947212,-0.0997853428125381,-0.1181001588702202) * MODEL22_texOff(vec2(0,-1)); +res += mat4(-0.3101258873939514,0.2616009712219238,0.0584651045501232,0.1656491309404373,-0.0069236233830452,0.2573371529579163,-0.1793291717767715,-0.2718756198883057,0.0953581258654594,0.0524105131626129,0.1183085516095161,0.0583294369280338,0.5036848187446594,-0.5763167142868042,-0.2119628041982651,-0.3140562772750854) * MODEL21_texOff(vec2(0,0)); +res += mat4(-0.2497755438089371,-0.0146329319104552,-0.2741575539112091,0.2459975033998489,0.3562706708908081,-0.6528629064559937,-0.4287456274032593,0.2055913358926773,0.1739019453525543,-0.3855968713760376,-0.0958273336291313,-0.7066691517829895,0.2365748286247253,-0.3046728968620300,-0.2590373754501343,-0.0496727414429188) * MODEL22_texOff(vec2(0,0)); +res += mat4(-0.0844531357288361,-0.0321611948311329,-0.0951840654015541,0.0577518045902252,-0.1606003493070602,0.2776086628437042,-0.1355003118515015,-0.0880064144730568,-0.1277643740177155,-0.0514567233622074,0.1522682905197144,-0.1040910631418228,-0.2767944037914276,-0.1452194601297379,0.0089118303731084,0.0231996178627014) * MODEL21_texOff(vec2(0,1)); +res += mat4(0.2603267133235931,0.0167464651167393,-0.2064073234796524,0.1782064288854599,0.4890212416648865,0.0559245310723782,0.1221160590648651,-0.0202587731182575,-0.4056585729122162,-0.1839511841535568,0.2775998413562775,0.0024275144096464,-0.2624500989913940,-0.0619418807327747,0.0153478365391493,0.0123427547514439) * MODEL22_texOff(vec2(0,1)); +res += mat4(0.0816635638475418,-0.0134946266189218,0.0594766475260258,-0.0551253929734230,0.0134431896731257,-0.0652195811271667,-0.0563635528087616,-0.0066532371565700,-0.0004114551993553,0.0105680683627725,0.1324467360973358,0.0467248968780041,0.0301312971860170,-0.1073397025465965,-0.0363437235355377,-0.0474153012037277) * MODEL21_texOff(vec2(1,-1)); +res += mat4(0.0199097190052271,0.0901319086551666,0.0448978282511234,0.0505443066358566,0.0438878424465656,-0.0494784042239189,0.0724927335977554,-0.0070675504393876,-0.0012125011999160,0.0295279901474714,0.0705125033855438,0.0555334389209747,-0.0403393507003784,-0.1271172016859055,0.0017914215568453,0.1462216079235077) * MODEL22_texOff(vec2(1,-1)); +res += mat4(-0.2827299833297729,0.2052399665117264,0.0042732120491564,-0.3969024717807770,-0.0782120972871780,0.1960176974534988,-0.0675340741872787,0.0027962317690253,0.0516129024326801,-0.0352642722427845,0.0546326488256454,0.0065340655855834,-0.1062376946210861,0.1364430636167526,-0.0536947809159756,0.2098117172718048) * MODEL21_texOff(vec2(1,0)); +res += mat4(0.0045875865034759,0.2162927240133286,-0.2158576399087906,-0.0047327815555036,0.1251590698957443,0.1279677897691727,-0.1188964918255806,0.0328494384884834,0.0076038073748350,-0.0561547242105007,0.0335608273744583,0.4332321286201477,0.0021786799188703,0.0844521671533585,-0.2102309316396713,-0.0189208015799522) * MODEL22_texOff(vec2(1,0)); +res += mat4(0.0933093801140785,0.1548244059085846,-0.0598701611161232,0.0357220247387886,-0.1141726672649384,0.0536412484943867,-0.0159156844019890,-0.0445508137345314,0.1883231997489929,-0.1547038406133652,0.0530619807541370,0.0059371814131737,0.0602529086172581,-0.0435577929019928,0.0083390390500426,0.0191930737346411) * MODEL21_texOff(vec2(1,1)); +res += mat4(-0.0351041629910469,0.2119503468275070,-0.0841927304863930,0.0079463515430689,0.0683520361781120,-0.1657009869813919,0.0611055232584476,-0.0063667562790215,0.0330024957656860,-0.1810818463563919,0.0872574150562286,0.1485669612884521,-0.1305806934833527,0.0041402997449040,0.0223289318382740,-0.0141495745629072) * MODEL22_texOff(vec2(1,1)); +res = max(res, vec4(0.0)) + vec4(0.5769761204719543,0.1716064810752869,-0.0821026712656021,0.2092144042253494) * min(res, vec4(0.0)); +return res; +} + +//!HOOK LUMA +//!WHEN OUTPUT.w LUMA.w / 1.300 > OUTPUT.h LUMA.h / 1.300 > * +//!DESC sub-band residuals 1 +//!BIND MODEL1 +//!BIND MODEL2 +//!BIND FEATURE1 +//!SAVE RES1 +//!COMPONENTS 4 +vec4 hook() +{ +vec4 res = vec4(0.0245648548007011,-0.4467784762382507,0.0197526942938566,-0.0110000418499112); +res += mat4(0.0302665308117867,-0.9262221455574036,-0.1161134764552116,-0.0506900474429131,0.2716045379638672,-0.0485871583223343,0.0044713355600834,-0.4274623394012451,0.0749531090259552,-0.3700785338878632,0.0350039415061474,-0.0540786534547806,-0.0607390031218529,-0.8019900321960449,0.0923245251178741,0.1258827745914459) * MODEL1_texOff(0); +res += mat4(-0.0649135261774063,0.0815236791968346,0.0067334296181798,0.1277425885200500,-0.0051357815973461,-0.1485908329486847,0.0074226572178304,0.0050623500719666,0.0588018335402012,-0.0692552924156189,0.1288725286722183,-0.0989386290311813,0.0427936837077141,0.0967708528041840,-0.0455632135272026,-0.0711275041103363) * MODEL2_texOff(0); +res += FEATURE1_texOff(0); +res = max(res, vec4(0.0)) + vec4(0.9927186965942383,0.0570580027997494,1.3226752281188965,1.0069466829299927) * min(res, vec4(0.0)); +return res; +} + +//!HOOK LUMA +//!WHEN OUTPUT.w LUMA.w / 1.300 > OUTPUT.h LUMA.h / 1.300 > * +//!DESC sub-band residuals 2 +//!BIND MODEL1 +//!BIND MODEL2 +//!BIND FEATURE2 +//!SAVE RES2 +//!COMPONENTS 4 +vec4 hook() +{ +vec4 res = vec4(-0.0425243787467480,-0.3715015351772308,-0.0256227850914001,-0.2774516046047211); +res += mat4(0.0238118842244148,0.0295480657368898,-0.0066418983042240,0.1021223962306976,-0.0568209178745747,-0.4355100393295288,-0.2700522541999817,-0.2060186564922333,-0.0689613372087479,-0.1689691990613937,-0.0306748505681753,-0.2461252212524414,-0.0057375836186111,-0.1892303228378296,-0.0285871494561434,-0.5032613277435303) * MODEL1_texOff(0); +res += mat4(0.5463213324546814,0.0972800329327583,0.0307560767978430,0.0678058937191963,-0.0356063023209572,-0.7013865113258362,0.1890443563461304,-0.1036657467484474,-0.1745826154947281,-0.2942218780517578,-0.0485423319041729,-0.2983124554157257,-0.0524431839585304,-0.3261034786701202,0.3217246532440186,0.1958018541336060) * MODEL2_texOff(0); +res += FEATURE2_texOff(0); +res = max(res, vec4(0.0)) + vec4(0.1391339898109436,0.0960328355431557,0.6235341429710388,0.1177272796630859) * min(res, vec4(0.0)); +return res; +} + +//!HOOK LUMA +//!WHEN OUTPUT.w LUMA.w / 1.300 > OUTPUT.h LUMA.h / 1.300 > * +//!DESC sub-pixel convolution 1 +//!BIND RES1 +//!BIND RES2 +//!SAVE SUBCONV1 +//!COMPONENTS 4 +vec4 hook() +{ +vec4 res = vec4(0.2010385394096375,0.2058132737874985,0.1918809115886688,0.1961363703012466); +res += mat4x4(-0.0005980331334285,-0.0095877395942807,-0.0149448839947581,-0.0026380482595414,0.0320665836334229,-0.0706205591559410,-0.0054677254520357,0.0215112231671810,-0.0025710910558701,-0.0000433265340689,0.0044494951143861,-0.0034823501482606,-0.0050858515314758,0.0109513988718390,0.0208286065608263,-0.0032168829347938) * RES1_texOff(vec2(-1,-1)); +res += mat4x4(-0.0145305208861828,0.0246876608580351,-0.0038286084309220,-0.0033089490607381,-0.0920709222555161,-0.0767898634076118,0.0012083095498383,-0.0751532614231110,0.0001302754972130,-0.0107085108757019,-0.0010383903281763,-0.0059571005403996,0.0809685289859772,0.0414833538234234,0.0227938480675220,-0.0211347509175539) * RES2_texOff(vec2(-1,-1)); +res += mat4x4(0.0160999298095703,0.0364215746521950,-0.0377063788473606,-0.0449111759662628,-0.0476365163922310,0.1522845029830933,-0.0131391752511263,-0.0476671792566776,-0.0378389135003090,0.0235454943031073,0.0224007442593575,-0.0010372076649219,-0.0089435689151287,-0.0293026417493820,0.0274190884083509,0.0469092652201653) * RES1_texOff(vec2(-1,0)); +res += mat4x4(0.0297575183212757,-0.0132508194074035,-0.0044682323932648,-0.0096222748979926,0.2525918781757355,0.1873829364776611,-0.5599535703659058,-0.2372044622898102,0.0033207221422344,0.0256173480302095,0.0294605866074562,0.0323960892856121,-0.1679904460906982,-0.1278967708349228,0.3168168365955353,0.1978507637977600) * RES2_texOff(vec2(-1,0)); +res += mat4x4(-0.0047590560279787,-0.0149335600435734,0.0033453819341958,-0.0012247267877683,0.1112466752529144,0.0147760482504964,0.0031189601868391,0.0391573049128056,-0.0028154491446912,-0.0036881719715893,-0.0116015253588557,-0.0037573333829641,0.0047581391409039,0.0071071563288569,-0.0033221673220396,0.0004882142529823) * RES1_texOff(vec2(-1,1)); +res += mat4x4(-0.0025197160430253,-0.0018677815096453,0.0038254233077168,0.0041981274262071,-0.1321131736040115,-0.0494364202022552,0.0760654658079147,-0.1386690139770508,-0.0016222692793235,-0.0060105528682470,0.0010201989207417,0.0092753591015935,-0.0194614846259356,0.0087382243946195,-0.0606758072972298,0.0156162241473794) * RES2_texOff(vec2(-1,1)); +res += mat4x4(-0.0073722628876567,0.0012844242155552,0.0241398401558399,-0.0075527969747782,-0.0865194946527481,-0.0610522404313087,0.0289319511502981,-0.0994452014565468,0.0281447004526854,-0.0250582899898291,0.0044891634024680,-0.0246205236762762,0.0112307453528047,-0.0010844616917893,-0.0223584957420826,0.0177635718137026) * RES1_texOff(vec2(0,-1)); +res += mat4x4(-0.0585863515734673,0.0953190475702286,-0.0555586628615856,0.1033507287502289,0.1560877263545990,-0.0690897777676582,-0.0341389514505863,-0.0661668032407761,0.0531073249876499,-0.0266165956854820,-0.0203275382518768,0.0017760475166142,-0.1300747394561768,0.1810652017593384,0.0381597876548767,0.1397419273853302) * RES2_texOff(vec2(0,-1)); +res += mat4x4(0.6259804368019104,0.6062518954277039,0.5450409054756165,0.5966195464134216,-0.0423948727548122,0.0760537460446358,-0.0113651463761926,0.3007817566394806,-0.3218322694301605,0.2713021934032440,-0.3143473267555237,0.2303840517997742,0.3493050038814545,0.3590726852416992,0.4138027429580688,0.3391666412353516) * RES1_texOff(vec2(0,0)); +res += mat4x4(0.0790478289127350,-0.0978994593024254,0.0779844969511032,-0.0823706611990929,0.0094470111653209,0.1671760678291321,0.1201528310775757,-0.2016288936138153,0.3667598366737366,0.3651430010795593,-0.3612343966960907,-0.2978236973285675,-0.4231655597686768,0.0091423410922289,-0.1918412446975708,0.4224558770656586) * RES2_texOff(vec2(0,0)); +res += mat4x4(-0.0186564289033413,0.0274957418441772,-0.0064405309967697,0.0056951809674501,0.4864942431449890,-0.2563461959362030,0.4357284605503082,-0.2976118028163910,0.0374982468783855,0.0167757049202919,0.0305800959467888,0.0232830215245485,0.0138373551890254,-0.0191283021122217,0.0032355054281652,0.0055057541467249) * RES1_texOff(vec2(0,1)); +res += mat4x4(-0.0276355985552073,0.0048149987123907,-0.0251619722694159,-0.0057246969081461,0.0271473955363035,-0.0042668608948588,-0.0594691745936871,0.2255926281213760,-0.0203660242259502,0.0721646770834923,0.0137230781838298,-0.0650938376784325,-0.3049557507038116,0.2035628110170364,-0.2509683668613434,0.1962853819131851) * RES2_texOff(vec2(0,1)); +res += mat4x4(0.0109980758279562,-0.0053752651438117,-0.0112550277262926,0.0024017230607569,0.0362104885280132,0.0084348218515515,-0.0106990104541183,-0.0207723993808031,-0.0014961160486564,0.0066790678538382,0.0028113177977502,0.0025022011250257,-0.0093937022611499,0.0016421369509771,0.0035362334456295,-0.0058064293116331) * RES1_texOff(vec2(1,-1)); +res += mat4x4(0.0138889988884330,-0.0078343702480197,0.0061464929021895,0.0202130675315857,-0.0257590841501951,-0.0366640128195286,0.0250097587704659,-0.0498071312904358,-0.0103149358183146,-0.0001786737266229,-0.0099909817799926,0.0062733208760619,0.0131437368690968,-0.0005469865864143,-0.0388854071497917,0.0612070746719837) * RES2_texOff(vec2(1,-1)); +res += mat4x4(0.0052813654765487,0.0215748809278011,0.0107395220547915,-0.0079439217224717,0.0382786765694618,0.0697424262762070,-0.0415962152183056,0.0657853558659554,0.0209470037370920,-0.0218399092555046,-0.0447359494864941,0.0407319553196430,-0.0040902681648731,-0.0196106657385826,-0.0018554026028141,0.0203906055539846) * RES1_texOff(vec2(1,0)); +res += mat4x4(-0.0106181986629963,0.0084018819034100,0.0131329754367471,-0.0198754761368036,0.1117177084088326,0.0990846082568169,-0.0732304081320763,0.0163581725209951,-0.0648830309510231,-0.0451613292098045,0.0206844564527273,0.0031441387254745,-0.0106161693111062,-0.0567689687013626,0.0782861113548279,-0.0306094046682119) * RES2_texOff(vec2(1,0)); +res += mat4x4(0.0012452082009986,-0.0026056850329041,-0.0096226977184415,-0.0037850935477763,-0.0190967041999102,0.0534373670816422,0.1599360853433609,0.0834670960903168,-0.0070255175232887,0.0012873009545729,0.0030876772943884,-0.0093916896730661,-0.0033529615029693,0.0043485122732818,0.0089034689590335,-0.0067489291541278) * RES1_texOff(vec2(1,1)); +res += mat4x4(0.0004713654634543,-0.0034161377698183,-0.0026913962792605,0.0053522582165897,-0.0040974905714393,0.0273330621421337,-0.0333138220012188,-0.0701237097382545,0.0082997502759099,-0.0183656588196754,-0.0122841577976942,-0.0052855615504086,-0.0023795007728040,-0.0438593104481697,-0.1101513057947159,-0.0182559806853533) * RES2_texOff(vec2(1,1)); +return vec4(res); +} + +//!HOOK LUMA +//!WHEN OUTPUT.w LUMA.w / 1.300 > OUTPUT.h LUMA.h / 1.300 > * +//!WIDTH LUMA.w 2 * +//!HEIGHT LUMA.h 2 * +//!DESC aggregation +//!BIND SUBCONV1 +vec4 hook() +{ +vec2 fcoord = fract(SUBCONV1_pos * SUBCONV1_size); +vec2 base = SUBCONV1_pos + (vec2(0.5) - fcoord) * SUBCONV1_pt; +ivec2 index = ivec2(fcoord * vec2(2)); +vec4 res = SUBCONV1_tex(base); +return vec4(res[index.x * 2 + index.y], 0, 0, 1); +} diff --git a/shaders/KrigBilateral.glsl b/shaders/KrigBilateral.glsl new file mode 100755 index 0000000..172d004 --- /dev/null +++ b/shaders/KrigBilateral.glsl @@ -0,0 +1,217 @@ +// Revised 05/30/22 +// https://gist.github.com/igv/a015fc885d5c22e6891820ad89555637 +// +// KrigBilateral by Shiandow +// +// This library 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 3.0 of the License, or (at your option) any later version. +// +// This library 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 this library. + +//!HOOK CHROMA +//!BIND HOOKED +//!BIND LUMA +//!SAVE LOWRES_Y +//!WIDTH LUMA.w +//!WHEN CHROMA.w LUMA.w < +//!DESC KrigBilateral Downscaling Y pass 1 + +#define offset vec2(0) + +#define axis 1 + +#define Kernel(x) dot(vec3(0.42659, -0.49656, 0.076849), cos(vec3(0, 1, 2) * acos(-1.) * (x + 1.))) + +vec4 hook() { + // Calculate bounds + float low = ceil((LUMA_pos - CHROMA_pt) * LUMA_size - offset - 0.5)[axis]; + float high = floor((LUMA_pos + CHROMA_pt) * LUMA_size - offset - 0.5)[axis]; + + float W = 0.0; + vec4 avg = vec4(0); + vec2 pos = LUMA_pos; + + for (float k = low; k <= high; k++) { + pos[axis] = LUMA_pt[axis] * (k - offset[axis] + 0.5); + float rel = (pos[axis] - LUMA_pos[axis])*CHROMA_size[axis]; + float w = Kernel(rel); + + vec4 y = textureGrad(LUMA_raw, pos, vec2(0.0), vec2(0.0)).xxxx * LUMA_mul; + y.y *= y.y; + avg += w * y; + W += w; + } + avg /= W; + avg.y = abs(avg.y - avg.x * avg.x); + return avg; +} + +//!HOOK CHROMA +//!BIND HOOKED +//!BIND LOWRES_Y +//!SAVE LOWRES_Y +//!WHEN CHROMA.w LUMA.w < +//!DESC KrigBilateral Downscaling Y pass 2 + +#define offset vec2(0) + +#define axis 0 + +#define Kernel(x) dot(vec3(0.42659, -0.49656, 0.076849), cos(vec3(0, 1, 2) * acos(-1.) * (x + 1.))) + +vec4 hook() { + // Calculate bounds + float low = ceil((LOWRES_Y_pos - CHROMA_pt) * LOWRES_Y_size - offset - 0.5)[axis]; + float high = floor((LOWRES_Y_pos + CHROMA_pt) * LOWRES_Y_size - offset - 0.5)[axis]; + + float W = 0.0; + vec4 avg = vec4(0); + vec2 pos = LOWRES_Y_pos; + + for (float k = low; k <= high; k++) { + pos[axis] = LOWRES_Y_pt[axis] * (k - offset[axis] + 0.5); + float rel = (pos[axis] - LOWRES_Y_pos[axis])*CHROMA_size[axis]; + float w = Kernel(rel); + + vec4 y = textureGrad(LOWRES_Y_raw, pos, vec2(0.0), vec2(0.0)).xxxx * LOWRES_Y_mul; + y.y *= y.y; + avg += w * y; + W += w; + } + avg /= W; + avg.y = abs(avg.y - avg.x * avg.x) + LOWRES_Y_texOff(0).y; + return avg; +} + +//!HOOK CHROMA +//!BIND HOOKED +//!BIND LUMA +//!BIND LOWRES_Y +//!WIDTH LUMA.w +//!HEIGHT LUMA.h +//!WHEN CHROMA.w LUMA.w < +//!OFFSET ALIGN +//!DESC KrigBilateral Upscaling UV + +#define sqr(x) dot(x,x) +#define sigma_nsq 256.0/(255.0*255.0) + +#define N 8 + +#define M(i,j) Mx[min(i,j)*N + max(i,j) - (min(i,j)*(min(i,j)+1))/2] + +#define C(i,j) (inversesqrt(1.0 + (X[i].y + X[j].y) / Var) * exp(-0.5 * (sqr(X[i].x - X[j].x) / (localVar + X[i].y + X[j].y) + sqr((coords[i] - coords[j]) / radius))) /*+ (X[i].x - y) * (X[j].x - y) / Var*/) // commented out part works well only on test patterns +#define c(i) (inversesqrt(1.0 + X[i].y / Var) * exp(-0.5 * (sqr(X[i].x - y) / (localVar + X[i].y) + sqr((coords[i] - offset) / radius)))) + +#define getnsum(i) X[i] = vec4(LOWRES_Y_tex(LOWRES_Y_pt*(pos+coords[i]+vec2(0.5))).xy, \ + CHROMA_tex(CHROMA_pt*(pos+coords[i]+vec2(0.5))).xy); \ + w = clamp(1.5 - abs(coords[i]), 0.0, 1.0); \ + total += w.x*w.y*vec4(X[i].x, X[i].x * X[i].x, X[i].y, 1.0); + +#define I3(f, n) f(n) f(n+1) f(n+2) +#define I9(f, n) I3(f, n) I3(f, n+3) I3(f, n+6) + +vec4 hook() { + vec2 pos = CHROMA_pos * HOOKED_size - vec2(0.5); + vec2 offset = pos - round(pos); + pos -= offset; + + vec2 coords[N+1]; + vec4 X[N+1]; + vec2 w; + vec4 total = vec4(0); + + coords[0] = vec2(-1,-1); coords[1] = vec2(-1, 0); coords[2] = vec2(-1, 1); + coords[3] = vec2( 0,-1); coords[4] = vec2( 0, 1); coords[5] = vec2( 1,-1); + coords[6] = vec2( 1, 0); coords[7] = vec2( 1, 1); coords[8] = vec2( 0, 0); + + I9(getnsum, 0) + + total.xyz /= total.w; + float localVar = abs(total.y - total.x * total.x) + sigma_nsq; + float Var = localVar + total.z; + float radius = 1.0; + + float y = LUMA_texOff(0).x; + float Mx[(N*(N+1))/2]; + float b[N]; + vec2 interp = X[N].zw; + + b[0] = c(0) - c(N) - C(0,N) + C(N,N); M(0, 0) = C(0,0) - C(0,N) - C(0,N) + C(N,N); M(0, 1) = C(0,1) - C(1,N) - C(0,N) + C(N,N); M(0, 2) = C(0,2) - C(2,N) - C(0,N) + C(N,N); M(0, 3) = C(0,3) - C(3,N) - C(0,N) + C(N,N); M(0, 4) = C(0,4) - C(4,N) - C(0,N) + C(N,N); M(0, 5) = C(0,5) - C(5,N) - C(0,N) + C(N,N); M(0, 6) = C(0,6) - C(6,N) - C(0,N) + C(N,N); M(0, 7) = C(0,7) - C(7,N) - C(0,N) + C(N,N); + b[1] = c(1) - c(N) - C(1,N) + C(N,N); M(1, 1) = C(1,1) - C(1,N) - C(1,N) + C(N,N); M(1, 2) = C(1,2) - C(2,N) - C(1,N) + C(N,N); M(1, 3) = C(1,3) - C(3,N) - C(1,N) + C(N,N); M(1, 4) = C(1,4) - C(4,N) - C(1,N) + C(N,N); M(1, 5) = C(1,5) - C(5,N) - C(1,N) + C(N,N); M(1, 6) = C(1,6) - C(6,N) - C(1,N) + C(N,N); M(1, 7) = C(1,7) - C(7,N) - C(1,N) + C(N,N); + b[2] = c(2) - c(N) - C(2,N) + C(N,N); M(2, 2) = C(2,2) - C(2,N) - C(2,N) + C(N,N); M(2, 3) = C(2,3) - C(3,N) - C(2,N) + C(N,N); M(2, 4) = C(2,4) - C(4,N) - C(2,N) + C(N,N); M(2, 5) = C(2,5) - C(5,N) - C(2,N) + C(N,N); M(2, 6) = C(2,6) - C(6,N) - C(2,N) + C(N,N); M(2, 7) = C(2,7) - C(7,N) - C(2,N) + C(N,N); + b[3] = c(3) - c(N) - C(3,N) + C(N,N); M(3, 3) = C(3,3) - C(3,N) - C(3,N) + C(N,N); M(3, 4) = C(3,4) - C(4,N) - C(3,N) + C(N,N); M(3, 5) = C(3,5) - C(5,N) - C(3,N) + C(N,N); M(3, 6) = C(3,6) - C(6,N) - C(3,N) + C(N,N); M(3, 7) = C(3,7) - C(7,N) - C(3,N) + C(N,N); + b[4] = c(4) - c(N) - C(4,N) + C(N,N); M(4, 4) = C(4,4) - C(4,N) - C(4,N) + C(N,N); M(4, 5) = C(4,5) - C(5,N) - C(4,N) + C(N,N); M(4, 6) = C(4,6) - C(6,N) - C(4,N) + C(N,N); M(4, 7) = C(4,7) - C(7,N) - C(4,N) + C(N,N); + b[5] = c(5) - c(N) - C(5,N) + C(N,N); M(5, 5) = C(5,5) - C(5,N) - C(5,N) + C(N,N); M(5, 6) = C(5,6) - C(6,N) - C(5,N) + C(N,N); M(5, 7) = C(5,7) - C(7,N) - C(5,N) + C(N,N); + b[6] = c(6) - c(N) - C(6,N) + C(N,N); M(6, 6) = C(6,6) - C(6,N) - C(6,N) + C(N,N); M(6, 7) = C(6,7) - C(7,N) - C(6,N) + C(N,N); + b[7] = c(7) - c(N) - C(7,N) + C(N,N); M(7, 7) = C(7,7) - C(7,N) - C(7,N) + C(N,N); + + b[1] -= b[0] * M(0, 1) / M(0, 0); M(1, 1) -= M(0, 1) * M(0, 1) / M(0, 0); M(1, 2) -= M(0, 2) * M(0, 1) / M(0, 0); M(1, 3) -= M(0, 3) * M(0, 1) / M(0, 0); M(1, 4) -= M(0, 4) * M(0, 1) / M(0, 0); M(1, 5) -= M(0, 5) * M(0, 1) / M(0, 0); M(1, 6) -= M(0, 6) * M(0, 1) / M(0, 0); M(1, 7) -= M(0, 7) * M(0, 1) / M(0, 0); + b[2] -= b[0] * M(0, 2) / M(0, 0); M(2, 2) -= M(0, 2) * M(0, 2) / M(0, 0); M(2, 3) -= M(0, 3) * M(0, 2) / M(0, 0); M(2, 4) -= M(0, 4) * M(0, 2) / M(0, 0); M(2, 5) -= M(0, 5) * M(0, 2) / M(0, 0); M(2, 6) -= M(0, 6) * M(0, 2) / M(0, 0); M(2, 7) -= M(0, 7) * M(0, 2) / M(0, 0); + b[3] -= b[0] * M(0, 3) / M(0, 0); M(3, 3) -= M(0, 3) * M(0, 3) / M(0, 0); M(3, 4) -= M(0, 4) * M(0, 3) / M(0, 0); M(3, 5) -= M(0, 5) * M(0, 3) / M(0, 0); M(3, 6) -= M(0, 6) * M(0, 3) / M(0, 0); M(3, 7) -= M(0, 7) * M(0, 3) / M(0, 0); + b[4] -= b[0] * M(0, 4) / M(0, 0); M(4, 4) -= M(0, 4) * M(0, 4) / M(0, 0); M(4, 5) -= M(0, 5) * M(0, 4) / M(0, 0); M(4, 6) -= M(0, 6) * M(0, 4) / M(0, 0); M(4, 7) -= M(0, 7) * M(0, 4) / M(0, 0); + b[5] -= b[0] * M(0, 5) / M(0, 0); M(5, 5) -= M(0, 5) * M(0, 5) / M(0, 0); M(5, 6) -= M(0, 6) * M(0, 5) / M(0, 0); M(5, 7) -= M(0, 7) * M(0, 5) / M(0, 0); + b[6] -= b[0] * M(0, 6) / M(0, 0); M(6, 6) -= M(0, 6) * M(0, 6) / M(0, 0); M(6, 7) -= M(0, 7) * M(0, 6) / M(0, 0); + b[7] -= b[0] * M(0, 7) / M(0, 0); M(7, 7) -= M(0, 7) * M(0, 7) / M(0, 0); + + b[2] -= b[1] * M(1, 2) / M(1, 1); M(2, 2) -= M(1, 2) * M(1, 2) / M(1, 1); M(2, 3) -= M(1, 3) * M(1, 2) / M(1, 1); M(2, 4) -= M(1, 4) * M(1, 2) / M(1, 1); M(2, 5) -= M(1, 5) * M(1, 2) / M(1, 1); M(2, 6) -= M(1, 6) * M(1, 2) / M(1, 1); M(2, 7) -= M(1, 7) * M(1, 2) / M(1, 1); + b[3] -= b[1] * M(1, 3) / M(1, 1); M(3, 3) -= M(1, 3) * M(1, 3) / M(1, 1); M(3, 4) -= M(1, 4) * M(1, 3) / M(1, 1); M(3, 5) -= M(1, 5) * M(1, 3) / M(1, 1); M(3, 6) -= M(1, 6) * M(1, 3) / M(1, 1); M(3, 7) -= M(1, 7) * M(1, 3) / M(1, 1); + b[4] -= b[1] * M(1, 4) / M(1, 1); M(4, 4) -= M(1, 4) * M(1, 4) / M(1, 1); M(4, 5) -= M(1, 5) * M(1, 4) / M(1, 1); M(4, 6) -= M(1, 6) * M(1, 4) / M(1, 1); M(4, 7) -= M(1, 7) * M(1, 4) / M(1, 1); + b[5] -= b[1] * M(1, 5) / M(1, 1); M(5, 5) -= M(1, 5) * M(1, 5) / M(1, 1); M(5, 6) -= M(1, 6) * M(1, 5) / M(1, 1); M(5, 7) -= M(1, 7) * M(1, 5) / M(1, 1); + b[6] -= b[1] * M(1, 6) / M(1, 1); M(6, 6) -= M(1, 6) * M(1, 6) / M(1, 1); M(6, 7) -= M(1, 7) * M(1, 6) / M(1, 1); + b[7] -= b[1] * M(1, 7) / M(1, 1); M(7, 7) -= M(1, 7) * M(1, 7) / M(1, 1); + + b[3] -= b[2] * M(2, 3) / M(2, 2); M(3, 3) -= M(2, 3) * M(2, 3) / M(2, 2); M(3, 4) -= M(2, 4) * M(2, 3) / M(2, 2); M(3, 5) -= M(2, 5) * M(2, 3) / M(2, 2); M(3, 6) -= M(2, 6) * M(2, 3) / M(2, 2); M(3, 7) -= M(2, 7) * M(2, 3) / M(2, 2); + b[4] -= b[2] * M(2, 4) / M(2, 2); M(4, 4) -= M(2, 4) * M(2, 4) / M(2, 2); M(4, 5) -= M(2, 5) * M(2, 4) / M(2, 2); M(4, 6) -= M(2, 6) * M(2, 4) / M(2, 2); M(4, 7) -= M(2, 7) * M(2, 4) / M(2, 2); + b[5] -= b[2] * M(2, 5) / M(2, 2); M(5, 5) -= M(2, 5) * M(2, 5) / M(2, 2); M(5, 6) -= M(2, 6) * M(2, 5) / M(2, 2); M(5, 7) -= M(2, 7) * M(2, 5) / M(2, 2); + b[6] -= b[2] * M(2, 6) / M(2, 2); M(6, 6) -= M(2, 6) * M(2, 6) / M(2, 2); M(6, 7) -= M(2, 7) * M(2, 6) / M(2, 2); + b[7] -= b[2] * M(2, 7) / M(2, 2); M(7, 7) -= M(2, 7) * M(2, 7) / M(2, 2); + + b[4] -= b[3] * M(3, 4) / M(3, 3); M(4, 4) -= M(3, 4) * M(3, 4) / M(3, 3); M(4, 5) -= M(3, 5) * M(3, 4) / M(3, 3); M(4, 6) -= M(3, 6) * M(3, 4) / M(3, 3); M(4, 7) -= M(3, 7) * M(3, 4) / M(3, 3); + b[5] -= b[3] * M(3, 5) / M(3, 3); M(5, 5) -= M(3, 5) * M(3, 5) / M(3, 3); M(5, 6) -= M(3, 6) * M(3, 5) / M(3, 3); M(5, 7) -= M(3, 7) * M(3, 5) / M(3, 3); + b[6] -= b[3] * M(3, 6) / M(3, 3); M(6, 6) -= M(3, 6) * M(3, 6) / M(3, 3); M(6, 7) -= M(3, 7) * M(3, 6) / M(3, 3); + b[7] -= b[3] * M(3, 7) / M(3, 3); M(7, 7) -= M(3, 7) * M(3, 7) / M(3, 3); + + b[5] -= b[4] * M(4, 5) / M(4, 4); M(5, 5) -= M(4, 5) * M(4, 5) / M(4, 4); M(5, 6) -= M(4, 6) * M(4, 5) / M(4, 4); M(5, 7) -= M(4, 7) * M(4, 5) / M(4, 4); + b[6] -= b[4] * M(4, 6) / M(4, 4); M(6, 6) -= M(4, 6) * M(4, 6) / M(4, 4); M(6, 7) -= M(4, 7) * M(4, 6) / M(4, 4); + b[7] -= b[4] * M(4, 7) / M(4, 4); M(7, 7) -= M(4, 7) * M(4, 7) / M(4, 4); + + b[6] -= b[5] * M(5, 6) / M(5, 5); M(6, 6) -= M(5, 6) * M(5, 6) / M(5, 5); M(6, 7) -= M(5, 7) * M(5, 6) / M(5, 5); + b[7] -= b[5] * M(5, 7) / M(5, 5); M(7, 7) -= M(5, 7) * M(5, 7) / M(5, 5); + + b[7] -= b[6] * M(6, 7) / M(6, 6); M(7, 7) -= M(6, 7) * M(6, 7) / M(6, 6); + + b[7] /= M(7, 7); + interp += b[7] * (X[7] - X[N]).zw; + + b[6] -= M(6, 7) * b[7]; b[6] /= M(6, 6); + interp += b[6] * (X[6] - X[N]).zw; + + b[5] -= M(5, 6) * b[6]; b[5] -= M(5, 7) * b[7]; b[5] /= M(5, 5); + interp += b[5] * (X[5] - X[N]).zw; + + b[4] -= M(4, 5) * b[5]; b[4] -= M(4, 6) * b[6]; b[4] -= M(4, 7) * b[7]; b[4] /= M(4, 4); + interp += b[4] * (X[4] - X[N]).zw; + + b[3] -= M(3, 4) * b[4]; b[3] -= M(3, 5) * b[5]; b[3] -= M(3, 6) * b[6]; b[3] -= M(3, 7) * b[7]; b[3] /= M(3, 3); + interp += b[3] * (X[3] - X[N]).zw; + + b[2] -= M(2, 3) * b[3]; b[2] -= M(2, 4) * b[4]; b[2] -= M(2, 5) * b[5]; b[2] -= M(2, 6) * b[6]; b[2] -= M(2, 7) * b[7]; b[2] /= M(2, 2); + interp += b[2] * (X[2] - X[N]).zw; + + b[1] -= M(1, 2) * b[2]; b[1] -= M(1, 3) * b[3]; b[1] -= M(1, 4) * b[4]; b[1] -= M(1, 5) * b[5]; b[1] -= M(1, 6) * b[6]; b[1] -= M(1, 7) * b[7]; b[1] /= M(1, 1); + interp += b[1] * (X[1] - X[N]).zw; + + b[0] -= M(0, 1) * b[1]; b[0] -= M(0, 2) * b[2]; b[0] -= M(0, 3) * b[3]; b[0] -= M(0, 4) * b[4]; b[0] -= M(0, 5) * b[5]; b[0] -= M(0, 6) * b[6]; b[0] -= M(0, 7) * b[7]; b[0] /= M(0, 0); + interp += b[0] * (X[0] - X[N]).zw; + + return interp.xyxy; +} diff --git a/shaders/SSimDownscaler.glsl b/shaders/SSimDownscaler.glsl new file mode 100755 index 0000000..7fe3cb9 --- /dev/null +++ b/shaders/SSimDownscaler.glsl @@ -0,0 +1,219 @@ +// Revised 05/15/22 +// https://gist.github.com/igv/36508af3ffc84410fe39761d6969be10 +// +// SSimDownscaler by Shiandow +// +// This library 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 3.0 of the License, or (at your option) any later version. +// +// This library 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 this library. + +//!HOOK POSTKERNEL +//!BIND HOOKED +//!BIND PREKERNEL +//!SAVE L2 +//!WIDTH NATIVE_CROPPED.w +//!WHEN NATIVE_CROPPED.h POSTKERNEL.h > +//!COMPONENTS 3 +//!DESC SSimDownscaler L2 pass 1 + +#define axis 1 + +#define offset vec2(0,0) + +#define MN(B,C,x) (x < 1.0 ? ((2.-1.5*B-(C))*x + (-3.+2.*B+C))*x*x + (1.-(B)/3.) : (((-(B)/6.-(C))*x + (B+5.*C))*x + (-2.*B-8.*C))*x+((4./3.)*B+4.*C)) +#define Kernel(x) MN(.0, .5, abs(x)) +#define taps 2.0 + +vec4 hook() { + vec2 base = PREKERNEL_pt * (PREKERNEL_pos * input_size + tex_offset); + + float low = ceil((PREKERNEL_pos - taps*POSTKERNEL_pt) * input_size - offset + tex_offset - 0.5)[axis]; + float high = floor((PREKERNEL_pos + taps*POSTKERNEL_pt) * input_size - offset + tex_offset - 0.5)[axis]; + + float W = 0.0; + vec4 avg = vec4(0); + vec2 pos = base; + + for (float k = low; k <= high; k++) { + pos[axis] = PREKERNEL_pt[axis] * (k - offset[axis] + 0.5); + float rel = (pos[axis] - base[axis])*POSTKERNEL_size[axis]; + float w = Kernel(rel); + + vec4 tex = textureLod(PREKERNEL_raw, pos, 0.0) * PREKERNEL_mul; + avg += w * tex * tex; + W += w; + } + avg /= W; + + return avg; +} + +//!HOOK POSTKERNEL +//!BIND HOOKED +//!BIND L2 +//!SAVE L2 +//!WHEN NATIVE_CROPPED.w POSTKERNEL.w > +//!COMPONENTS 3 +//!DESC SSimDownscaler L2 pass 2 + +#define axis 0 + +#define offset vec2(0,0) + +#define MN(B,C,x) (x < 1.0 ? ((2.-1.5*B-(C))*x + (-3.+2.*B+C))*x*x + (1.-(B)/3.) : (((-(B)/6.-(C))*x + (B+5.*C))*x + (-2.*B-8.*C))*x+((4./3.)*B+4.*C)) +#define Kernel(x) MN(.0, .5, abs(x)) +#define taps 2.0 + +vec4 hook() { + float low = ceil((L2_pos - taps*POSTKERNEL_pt) * L2_size - offset - 0.5)[axis]; + float high = floor((L2_pos + taps*POSTKERNEL_pt) * L2_size - offset - 0.5)[axis]; + + float W = 0.0; + vec4 avg = vec4(0); + vec2 pos = L2_pos; + + for (float k = low; k <= high; k++) { + pos[axis] = L2_pt[axis] * (k - offset[axis] + 0.5); + float rel = (pos[axis] - L2_pos[axis])*POSTKERNEL_size[axis]; + float w = Kernel(rel); + + avg += w * textureLod(L2_raw, pos, 0.0) * L2_mul; + W += w; + } + avg /= W; + + return avg; +} + +//!HOOK POSTKERNEL +//!BIND HOOKED +//!BIND L2 +//!SAVE MR +//!WHEN NATIVE_CROPPED.h POSTKERNEL.h > +//!COMPONENTS 4 +//!DESC SSimDownscaler mean & R + +#define oversharp 0.0 + +#define sigma_nsq 10. / (255.*255.) +#define locality 2.0 + +#define offset vec2(0,0) + +#define Kernel(x) pow(1.0 / locality, abs(x)) +#define taps 3.0 + +#define Luma(rgb) ( dot(rgb, vec3(0.2126, 0.7152, 0.0722)) ) + +mat3x3 ScaleH(vec2 pos) { + float low = ceil(-0.5*taps - offset)[0]; + float high = floor(0.5*taps - offset)[0]; + + float W = 0.0; + mat3x3 avg = mat3x3(0); + + for (float k = low; k <= high; k++) { + pos[0] = HOOKED_pos[0] + HOOKED_pt[0] * k; + float rel = k + offset[0]; + float w = Kernel(rel); + + vec3 L = POSTKERNEL_tex(pos).rgb; + avg += w * mat3x3(L, L*L, L2_tex(pos).rgb); + W += w; + } + avg /= W; + + return avg; +} + +vec4 hook() { + vec2 pos = HOOKED_pos; + + float low = ceil(-0.5*taps - offset)[1]; + float high = floor(0.5*taps - offset)[1]; + + float W = 0.0; + mat3x3 avg = mat3x3(0); + + for (float k = low; k <= high; k++) { + pos[1] = HOOKED_pos[1] + HOOKED_pt[1] * k; + float rel = k + offset[1]; + float w = Kernel(rel); + + avg += w * ScaleH(pos); + W += w; + } + avg /= W; + + float Sl = Luma(max(avg[1] - avg[0] * avg[0], 0.)); + float Sh = Luma(max(avg[2] - avg[0] * avg[0], 0.)); + return vec4(avg[0], mix(sqrt((Sh + sigma_nsq) / (Sl + sigma_nsq)) * (1. + oversharp), clamp(Sh / Sl, 0., 1.), int(Sl > Sh))); +} + +//!HOOK POSTKERNEL +//!BIND HOOKED +//!BIND MR +//!WHEN NATIVE_CROPPED.h POSTKERNEL.h > +//!DESC SSimDownscaler final pass + +#define locality 2.0 + +#define offset vec2(0,0) + +#define Kernel(x) pow(1.0 / locality, abs(x)) +#define taps 3.0 + +#define Gamma(x) ( pow(x, vec3(1.0/2.0)) ) +#define GammaInv(x) ( pow(clamp(x, 0.0, 1.0), vec3(2.0)) ) + +mat3x3 ScaleH(vec2 pos) { + float low = ceil(-0.5*taps - offset)[0]; + float high = floor(0.5*taps - offset)[0]; + + float W = 0.0; + mat3x3 avg = mat3x3(0); + + for (float k = low; k <= high; k++) { + pos[0] = HOOKED_pos[0] + HOOKED_pt[0] * k; + float rel = k + offset[0]; + float w = Kernel(rel); + + vec4 MR = MR_tex(pos); + avg += w * mat3x3(MR.a*MR.rgb, MR.rgb, MR.aaa); + W += w; + } + avg /= W; + + return avg; +} + +vec4 hook() { + vec2 pos = HOOKED_pos; + + float low = ceil(-0.5*taps - offset)[1]; + float high = floor(0.5*taps - offset)[1]; + + float W = 0.0; + mat3x3 avg = mat3x3(0); + + for (float k = low; k <= high; k++) { + pos[1] = HOOKED_pos[1] + HOOKED_pt[1] * k; + float rel = k + offset[1]; + float w = Kernel(rel); + + avg += w * ScaleH(pos); + W += w; + } + avg /= W; + vec4 L = POSTKERNEL_texOff(0); + return vec4(avg[1] + avg[2] * L.rgb - avg[0], L.a); +} diff --git a/shaders/SSimSuperRes.glsl b/shaders/SSimSuperRes.glsl new file mode 100755 index 0000000..8bdbdc9 --- /dev/null +++ b/shaders/SSimSuperRes.glsl @@ -0,0 +1,206 @@ +// Revised 02/07/22 +// https://gist.github.com/igv/2364ffa6e81540f29cb7ab4c9bc05b6b +// +// SSimSuperRes by Shiandow +// +// This library 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 3.0 of the License, or (at your option) any later version. +// +// This library 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 this library. + +//!HOOK POSTKERNEL +//!BIND HOOKED +//!SAVE LOWRES +//!HEIGHT NATIVE_CROPPED.h +//!WHEN NATIVE_CROPPED.h OUTPUT.h < +//!COMPONENTS 4 +//!DESC SSSR Downscaling I + +#define axis 1 + +#define offset vec2(0,0) + +#define MN(B,C,x) (x < 1.0 ? ((2.-1.5*B-(C))*x + (-3.+2.*B+C))*x*x + (1.-(B)/3.) : (((-(B)/6.-(C))*x + (B+5.*C))*x + (-2.*B-8.*C))*x+((4./3.)*B+4.*C)) +#define Kernel(x) MN(0.334, 0.333, abs(x)) +#define taps 2.0 + +#define Luma(rgb) dot(rgb*rgb, vec3(0.2126, 0.7152, 0.0722)) + +vec4 hook() { + float low = ceil((HOOKED_pos - taps/input_size) * HOOKED_size - offset - 0.5)[axis]; + float high = floor((HOOKED_pos + taps/input_size) * HOOKED_size - offset - 0.5)[axis]; + + float W = 0.0; + vec4 avg = vec4(0); + vec2 pos = HOOKED_pos; + vec4 tex; + + for (float k = low; k <= high; k++) { + pos[axis] = HOOKED_pt[axis] * (k - offset[axis] + 0.5); + float rel = (pos[axis] - HOOKED_pos[axis])*input_size[axis]; + float w = Kernel(rel); + + tex.rgb = textureLod(HOOKED_raw, pos, 0.0).rgb * HOOKED_mul; + tex.a = Luma(tex.rgb); + avg += w * tex; + W += w; + } + avg /= W; + + return vec4(avg.rgb, max(abs(avg.a - Luma(avg.rgb)), 5e-7)); +} + +//!HOOK POSTKERNEL +//!BIND LOWRES +//!SAVE LOWRES +//!WIDTH NATIVE_CROPPED.w +//!HEIGHT NATIVE_CROPPED.h +//!WHEN NATIVE_CROPPED.w OUTPUT.w < +//!COMPONENTS 4 +//!DESC SSSR Downscaling II + +#define axis 0 + +#define offset vec2(0,0) + +#define MN(B,C,x) (x < 1.0 ? ((2.-1.5*B-(C))*x + (-3.+2.*B+C))*x*x + (1.-(B)/3.) : (((-(B)/6.-(C))*x + (B+5.*C))*x + (-2.*B-8.*C))*x+((4./3.)*B+4.*C)) +#define Kernel(x) MN(0.334, 0.333, abs(x)) +#define taps 2.0 + +#define Luma(rgb) dot(rgb*rgb, vec3(0.2126, 0.7152, 0.0722)) + +vec4 hook() { + float low = ceil((LOWRES_pos - taps/input_size) * LOWRES_size - offset - 0.5)[axis]; + float high = floor((LOWRES_pos + taps/input_size) * LOWRES_size - offset - 0.5)[axis]; + + float W = 0.0; + vec4 avg = vec4(0); + vec2 pos = LOWRES_pos; + vec4 tex; + + for (float k = low; k <= high; k++) { + pos[axis] = LOWRES_pt[axis] * (k - offset[axis] + 0.5); + float rel = (pos[axis] - LOWRES_pos[axis])*input_size[axis]; + float w = Kernel(rel); + + tex.rgb = textureLod(LOWRES_raw, pos, 0.0).rgb * LOWRES_mul; + tex.a = Luma(tex.rgb); + avg += w * tex; + W += w; + } + avg /= W; + + return vec4(avg.rgb, max(abs(avg.a - Luma(avg.rgb)), 5e-7) + LOWRES_texOff(0).a); +} + +//!HOOK POSTKERNEL +//!BIND PREKERNEL +//!BIND LOWRES +//!SAVE var +//!WIDTH NATIVE_CROPPED.w +//!HEIGHT NATIVE_CROPPED.h +//!WHEN NATIVE_CROPPED.h OUTPUT.h < +//!COMPONENTS 2 +//!DESC SSSR var + +#define spread 1.0 / 4.0 + +#define GetL(x,y) PREKERNEL_tex(PREKERNEL_pt * (PREKERNEL_pos * input_size + tex_offset + vec2(x,y))).rgb +#define GetH(x,y) LOWRES_texOff(vec2(x,y)).rgb + +#define Luma(rgb) dot(rgb*rgb, vec3(0.2126, 0.7152, 0.0722)) +#define diff(x,y) vec2(Luma((GetL(x,y) - meanL)), Luma((GetH(x,y) - meanH))) + +vec4 hook() { + vec3 meanL = GetL(0,0); + vec3 meanH = GetH(0,0); + for (int X=-1; X<=1; X+=2) { + meanL += GetL(X,0) * spread; + meanH += GetH(X,0) * spread; + } + for (int Y=-1; Y<=1; Y+=2) { + meanL += GetL(0,Y) * spread; + meanH += GetH(0,Y) * spread; + } + meanL /= (1.0 + 4.0*spread); + meanH /= (1.0 + 4.0*spread); + + vec2 var = diff(0,0); + for (int X=-1; X<=1; X+=2) + var += diff(X,0) * spread; + + for (int Y=-1; Y<=1; Y+=2) + var += diff(0,Y) * spread; + + return vec4(max(var / (1.0 + 4.0*spread), vec2(1e-6)), 0, 0); +} + +//!HOOK POSTKERNEL +//!BIND HOOKED +//!BIND PREKERNEL +//!BIND LOWRES +//!BIND var +//!WHEN NATIVE_CROPPED.h OUTPUT.h < +//!DESC SSSR final pass + +#define oversharp 0.4 + +// -- Window Size -- +#define taps 3.0 +#define even (taps - 2.0 * floor(taps / 2.0) == 0.0) +#define minX int(1.0-ceil(taps/2.0)) +#define maxX int(floor(taps/2.0)) + +#define Kernel(x) cos(acos(-1.0)*(x)/taps) // Hann kernel + +// -- Input processing -- +#define var(x,y) var_tex(var_pt * (pos + vec2(x,y) + 0.5)).rg +#define GetL(x,y) PREKERNEL_tex(PREKERNEL_pt * (pos + tex_offset + vec2(x,y) + 0.5)).rgb +#define GetH(x,y) LOWRES_tex(LOWRES_pt * (pos + vec2(x,y) + 0.5)) + +#define Luma(rgb) dot(rgb*rgb, vec3(0.2126, 0.7152, 0.0722)) + +vec4 hook() { + vec4 c0 = HOOKED_texOff(0); + + vec2 pos = HOOKED_pos * LOWRES_size - vec2(0.5); + vec2 offset = pos - (even ? floor(pos) : round(pos)); + pos -= offset; + + vec2 mVar = vec2(0.0); + for (int X=-1; X<=1; X++) + for (int Y=-1; Y<=1; Y++) { + vec2 w = clamp(1.5 - abs(vec2(X,Y)), 0.0, 1.0); + mVar += w.r * w.g * vec2(GetH(X,Y).a, 1.0); + } + mVar.r /= mVar.g; + + // Calculate faithfulness force + float weightSum = 0.0; + vec3 diff = vec3(0); + + for (int X = minX; X <= maxX; X++) + for (int Y = minX; Y <= maxX; Y++) + { + float R = (-1.0 - oversharp) * sqrt(var(X,Y).r / (var(X,Y).g + mVar.r)); + + vec2 krnl = Kernel(vec2(X,Y) - offset); + float weight = krnl.r * krnl.g / (Luma((c0.rgb - GetH(X,Y).rgb)) + GetH(X,Y).a); + + diff += weight * (GetL(X,Y) + GetH(X,Y).rgb * R + (-1.0 - R) * (c0.rgb)); + weightSum += weight; + } + diff /= weightSum; + + c0.rgb = ((c0.rgb) + diff); + + return c0; +} diff --git a/shaders/adaptive-sharpen.glsl b/shaders/adaptive-sharpen.glsl new file mode 100755 index 0000000..bbeba42 --- /dev/null +++ b/shaders/adaptive-sharpen.glsl @@ -0,0 +1,233 @@ +// Revised 06/18/22 +// https://gist.github.com/igv/8a77e4eb8276753b54bb94c1c50c317e +// +// Copyright (c) 2015-2021, bacondither +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer +// in this position and unchanged. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Adaptive sharpen - version 2021-10-17 +// Tuned for use post-resize + +//!HOOK OUTPUT +//!BIND HOOKED +//!DESC adaptive-sharpen + +//--------------------------------------- Settings ------------------------------------------------ + +#define curve_height 1.0 // Main control of sharpening strength [>0] + // 0.3 <-> 2.0 is a reasonable range of values + +#define overshoot_ctrl false // Allow for higher overshoot if the current edge pixel + // is surrounded by similar edge pixels + +// Defined values under this row are "optimal" DO NOT CHANGE IF YOU DO NOT KNOW WHAT YOU ARE DOING! + +#define curveslope 0.5 // Sharpening curve slope, high edge values + +#define L_compr_low 0.167 // Light compression, default (0.167=~6x) +#define L_compr_high 0.334 // Light compression, surrounded by edges (0.334=~3x) + +#define D_compr_low 0.250 // Dark compression, default (0.250=4x) +#define D_compr_high 0.500 // Dark compression, surrounded by edges (0.500=2x) + +#define scale_lim 0.1 // Abs max change before compression [>0.01] +#define scale_cs 0.056 // Compression slope above scale_lim + +#define pm_p 1.0 // Power mean p-value [>0-1.0] +//------------------------------------------------------------------------------------------------- + +#define max4(a,b,c,d) ( max(max(a, b), max(c, d)) ) + +// Soft if, fast linear approx +#define soft_if(a,b,c) ( sat((a + b + c + 0.056/2.5)/(maxedge + 0.03/2.5) - 0.85) ) + +// Soft limit, modified tanh approx +#define soft_lim(v,s) ( sat(abs(v/s)*(27.0 + pow(v/s, 2.0))/(27.0 + 9.0*pow(v/s, 2.0)))*s ) + +// Weighted power mean +#define wpmean(a,b,w) ( pow(w*pow(abs(a), pm_p) + abs(1.0-w)*pow(abs(b), pm_p), (1.0/pm_p)) ) + +// Get destination pixel values +#define get(x,y) ( HOOKED_texOff(vec2(x, y)).rgb ) +#define sat(x) ( clamp(x, 0.0, 1.0) ) +#define dxdy(val) ( length(fwidth(val)) ) // =~1/2.5 hq edge without c_comp + +#ifdef LUMA_tex +#define CtL(RGB) RGB.x +#else +#define CtL(RGB) ( sqrt(dot(sat(RGB)*sat(RGB), vec3(0.2126, 0.7152, 0.0722))) ) +#endif + +#define b_diff(pix) ( (blur-luma[pix])*(blur-luma[pix]) ) + +vec4 hook() { + + // [ c22 ] + // [ c24, c9, c23 ] + // [ c21, c1, c2, c3, c18 ] + // [ c19, c10, c4, c0, c5, c11, c16 ] + // [ c20, c6, c7, c8, c17 ] + // [ c15, c12, c14 ] + // [ c13 ] + vec3 c[25] = vec3[](get( 0, 0), get(-1,-1), get( 0,-1), get( 1,-1), get(-1, 0), + get( 1, 0), get(-1, 1), get( 0, 1), get( 1, 1), get( 0,-2), + get(-2, 0), get( 2, 0), get( 0, 2), get( 0, 3), get( 1, 2), + get(-1, 2), get( 3, 0), get( 2, 1), get( 2,-1), get(-3, 0), + get(-2, 1), get(-2,-1), get( 0,-3), get( 1,-2), get(-1,-2)); + + float e[13] = float[](dxdy(c[0]), dxdy(c[1]), dxdy(c[2]), dxdy(c[3]), dxdy(c[4]), + dxdy(c[5]), dxdy(c[6]), dxdy(c[7]), dxdy(c[8]), dxdy(c[9]), + dxdy(c[10]), dxdy(c[11]), dxdy(c[12])); + + // RGB to luma + float luma[25] = float[](CtL(c[0]), CtL(c[1]), CtL(c[2]), CtL(c[3]), CtL(c[4]), CtL(c[5]), CtL(c[6]), + CtL(c[7]), CtL(c[8]), CtL(c[9]), CtL(c[10]), CtL(c[11]), CtL(c[12]), + CtL(c[13]), CtL(c[14]), CtL(c[15]), CtL(c[16]), CtL(c[17]), CtL(c[18]), + CtL(c[19]), CtL(c[20]), CtL(c[21]), CtL(c[22]), CtL(c[23]), CtL(c[24])); + + float c0_Y = luma[0]; + + // Blur, gauss 3x3 + float blur = (2.0 * (luma[2]+luma[4]+luma[5]+luma[7]) + (luma[1]+luma[3]+luma[6]+luma[8]) + 4.0 * luma[0]) / 16.0; + + // Contrast compression, center = 0.5 + float c_comp = sat(0.266666681f + 0.9*exp2(blur * blur * -7.4)); + + // Edge detection + // Relative matrix weights + // [ 1 ] + // [ 4, 5, 4 ] + // [ 1, 5, 6, 5, 1 ] + // [ 4, 5, 4 ] + // [ 1 ] + float edge = ( 1.38*b_diff(0) + + 1.15*(b_diff(2) + b_diff(4) + b_diff(5) + b_diff(7)) + + 0.92*(b_diff(1) + b_diff(3) + b_diff(6) + b_diff(8)) + + 0.23*(b_diff(9) + b_diff(10) + b_diff(11) + b_diff(12)) ) * c_comp; + + vec2 cs = vec2(L_compr_low, D_compr_low); + + if (overshoot_ctrl) { + float maxedge = max4( max4(e[1],e[2],e[3],e[4]), max4(e[5],e[6],e[7],e[8]), + max4(e[9],e[10],e[11],e[12]), e[0] ); + + // [ x ] + // [ z, x, w ] + // [ z, z, x, w, w ] + // [ y, y, y, 0, y, y, y ] + // [ w, w, x, z, z ] + // [ w, x, z ] + // [ x ] + float sbe = soft_if(e[2],e[9], dxdy(c[22]))*soft_if(e[7],e[12],dxdy(c[13])) // x dir + + soft_if(e[4],e[10],dxdy(c[19]))*soft_if(e[5],e[11],dxdy(c[16])) // y dir + + soft_if(e[1],dxdy(c[24]),dxdy(c[21]))*soft_if(e[8],dxdy(c[14]),dxdy(c[17])) // z dir + + soft_if(e[3],dxdy(c[23]),dxdy(c[18]))*soft_if(e[6],dxdy(c[20]),dxdy(c[15])); // w dir + + cs = mix(cs, vec2(L_compr_high, D_compr_high), sat(2.4002*sbe - 2.282)); + } + + // Precalculated default squared kernel weights + const vec3 w1 = vec3(0.5, 1.0, 1.41421356237); // 0.25, 1.0, 2.0 + const vec3 w2 = vec3(0.86602540378, 1.0, 0.54772255751); // 0.75, 1.0, 0.3 + + // Transition to a concave kernel if the center edge val is above thr + vec3 dW = pow(mix( w1, w2, sat(2.4*edge - 0.82)), vec3(2.0)); + + // Use lower weights for pixels in a more active area relative to center pixel area + // This results in narrower and less visible overshoots around sharp edges + float modif_e0 = 3.0 * e[0] + 0.02/2.5; + + float weights[12] = float[](( min(modif_e0/e[1], dW.y) ), + ( dW.x ), + ( min(modif_e0/e[3], dW.y) ), + ( dW.x ), + ( dW.x ), + ( min(modif_e0/e[6], dW.y) ), + ( dW.x ), + ( min(modif_e0/e[8], dW.y) ), + ( min(modif_e0/e[9], dW.z) ), + ( min(modif_e0/e[10], dW.z) ), + ( min(modif_e0/e[11], dW.z) ), + ( min(modif_e0/e[12], dW.z) )); + + weights[0] = (max(max((weights[8] + weights[9])/4.0, weights[0]), 0.25) + weights[0])/2.0; + weights[2] = (max(max((weights[8] + weights[10])/4.0, weights[2]), 0.25) + weights[2])/2.0; + weights[5] = (max(max((weights[9] + weights[11])/4.0, weights[5]), 0.25) + weights[5])/2.0; + weights[7] = (max(max((weights[10] + weights[11])/4.0, weights[7]), 0.25) + weights[7])/2.0; + + // Calculate the negative part of the laplace kernel and the low threshold weight + float lowthrsum = 0.0; + float weightsum = 0.0; + float neg_laplace = 0.0; + + for (int pix = 0; pix < 12; ++pix) + { + float lowthr = sat((20.*4.5*c_comp*e[pix + 1] - 0.221)); + + neg_laplace += luma[pix+1] * luma[pix+1] * weights[pix] * lowthr; + weightsum += weights[pix] * lowthr; + lowthrsum += lowthr / 12.0; + } + + neg_laplace = sqrt(neg_laplace / weightsum); + + // Compute sharpening magnitude function + float sharpen_val = curve_height/(curve_height*curveslope*edge + 0.625); + + // Calculate sharpening diff and scale + float sharpdiff = (c0_Y - neg_laplace)*(lowthrsum*sharpen_val + 0.01); + + // Calculate local near min & max, partial sort + float temp; + + for (int i1 = 0; i1 < 24; i1 += 2) + { + temp = luma[i1]; + luma[i1] = min(luma[i1], luma[i1+1]); + luma[i1+1] = max(temp, luma[i1+1]); + } + + for (int i2 = 24; i2 > 0; i2 -= 2) + { + temp = luma[0]; + luma[0] = min(luma[0], luma[i2]); + luma[i2] = max(temp, luma[i2]); + + temp = luma[24]; + luma[24] = max(luma[24], luma[i2-1]); + luma[i2-1] = min(temp, luma[i2-1]); + } + + float min_dist = min(abs(luma[24] - c0_Y), abs(c0_Y - luma[0])); + min_dist = min(min_dist, scale_lim*(1.0 - scale_cs) + min_dist*scale_cs); + + // Soft limited anti-ringing with tanh, wpmean to control compression slope + sharpdiff = wpmean(max(sharpdiff, 0.0), soft_lim( max(sharpdiff, 0.0), min_dist ), cs.x ) + - wpmean(min(sharpdiff, 0.0), soft_lim( min(sharpdiff, 0.0), min_dist ), cs.y ); + + float sharpdiff_lim = sat(c0_Y + sharpdiff) - c0_Y; + /*float satmul = (c0_Y + max(sharpdiff_lim*0.9, sharpdiff_lim)*0.3 + 0.03)/(c0_Y + 0.03); + vec3 res = c0_Y + sharpdiff_lim + (c[0] - c0_Y)*satmul; + */ + return vec4(sharpdiff_lim + c[0], HOOKED_texOff(0).a); +} diff --git a/shaders/filmgrain.glsl b/shaders/filmgrain.glsl new file mode 100755 index 0000000..8cd305f --- /dev/null +++ b/shaders/filmgrain.glsl @@ -0,0 +1,45 @@ +// Revised (unknown) +// https://raw.githubusercontent.com/haasn/gentoo-conf/xor/home/nand/.mpv/shaders/filmgrain.glsl +// +// Film Grain by haasn +// +//!HOOK LUMA +//!BIND HOOKED +//!DESC gaussian film grain + +#define INTENSITY 0.05 + +float permute(float x) +{ + x = (34.0 * x + 1.0) * x; + return fract(x * 1.0/289.0) * 289.0; +} + +float rand(inout float state) +{ + state = permute(state); + return fract(state * 1.0/41.0); +} + +vec4 hook() +{ + vec3 m = vec3(HOOKED_pos, random) + vec3(1.0); + float state = permute(permute(m.x) + m.y) + m.z; + + const float a0 = 0.151015505647689; + const float a1 = -0.5303572634357367; + const float a2 = 1.365020122861334; + const float b0 = 0.132089632343748; + const float b1 = -0.7607324991323768; + + float p = 0.95 * rand(state) + 0.025; + float q = p - 0.5; + float r = q * q; + + float grain = q * (a2 + (a1 * r + a0) / (r*r + b1*r + b0)); + grain *= 0.255121822830526; // normalize to [-1,1) + + vec4 color = HOOKED_tex(HOOKED_pos); + color.rgb += vec3(INTENSITY * grain); + return color; +}