diff options
| author | Robert Günzler <r@gnzler.io> | 2020-12-03 12:56:51 +0100 |
|---|---|---|
| committer | Robert Günzler <r@gnzler.io> | 2020-12-07 19:28:05 +0100 |
| commit | 0eb11ed2c3dc235349b87d20bf657f2fb9729994 (patch) | |
| tree | ceba665d591328bb47418ab82bb0de31abff98e5 /.config/mvi/scripts/minimap.lua | |
| parent | e93cee56264c7e1d07b422d66430d996fd8b0c40 (diff) | |
Add bin/mvi and config; mpv-based image viewer
Diffstat (limited to '.config/mvi/scripts/minimap.lua')
| -rw-r--r-- | .config/mvi/scripts/minimap.lua | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/.config/mvi/scripts/minimap.lua b/.config/mvi/scripts/minimap.lua new file mode 100644 index 0000000..faa7f62 --- /dev/null +++ b/.config/mvi/scripts/minimap.lua @@ -0,0 +1,306 @@ +local opts = { + enabled = true, + center = "92,92", + scale = 12, + max_size = "16,16", + image_opacity = "88", + image_color = "BBBBBB", + view_opacity = "BB", + view_color = "222222", + view_above_image = true, + hide_when_full_image_in_view = true, +} +(require 'mp.options').read_options(opts) + +function process(input) + local ret = {} + for str in string.gmatch(input, "([^,]+)") do + ret[#ret + 1] = tonumber(str) + end + return ret +end +opts.center=process(opts.center) +opts.max_size=process(opts.max_size) + +local msg = require 'mp.msg' +local assdraw = require 'mp.assdraw' + +local video_dimensions_stale = true + +function get_video_dimensions() + -- this function is very much ripped from video/out/aspect.c in mpv's source + if not video_dimensions_stale then return _video_dimensions end + local video_params = mp.get_property_native("video-out-params") + if not video_params then + _video_dimensions = nil + return nil + end + if not _timestamp then _timestamp = 0 end + _timestamp = _timestamp + 1 + _video_dimensions = { + timestamp = _timestamp, + top_left = { 0, 0 }, + bottom_right = { 0, 0 }, + size = { 0, 0 }, + ratios = { 0, 0 }, -- by how much the original video got scaled + } + local keep_aspect = mp.get_property_bool("keepaspect") + local w = video_params["w"] + local h = video_params["h"] + local dw = video_params["dw"] + local dh = video_params["dh"] + if mp.get_property_number("video-rotate") % 180 == 90 then + w, h = h,w + dw, dh = dh, dw + end + local window_w, window_h = mp.get_osd_size() + + if keep_aspect then + local unscaled = mp.get_property_native("video-unscaled") + local panscan = mp.get_property_number("panscan") + + local fwidth = window_w + local fheight = math.floor(window_w / dw * dh) + if fheight > window_h or fheight < h then + local tmpw = math.floor(window_h / dh * dw) + if tmpw <= window_w then + fheight = window_h + fwidth = tmpw + end + end + local vo_panscan_area = window_h - fheight + local f_w = fwidth / fheight + local f_h = 1 + if vo_panscan_area == 0 then + vo_panscan_area = window_h - fwidth + f_w = 1 + f_h = fheight / fwidth + end + if unscaled or unscaled == "downscale-big" then + vo_panscan_area = 0 + if unscaled or (dw <= window_w and dh <= window_h) then + fwidth = dw + fheight = dh + end + end + + local scaled_width = fwidth + math.floor(vo_panscan_area * panscan * f_w) + local scaled_height = fheight + math.floor(vo_panscan_area * panscan * f_h) + + local split_scaling = function (dst_size, scaled_src_size, zoom, align, pan) + scaled_src_size = math.floor(scaled_src_size * 2 ^ zoom) + align = (align + 1) / 2 + local dst_start = math.floor((dst_size - scaled_src_size) * align + pan * scaled_src_size) + if dst_start < 0 then + --account for C int cast truncating as opposed to flooring + dst_start = dst_start + 1 + end + local dst_end = dst_start + scaled_src_size; + if dst_start >= dst_end then + dst_start = 0 + dst_end = 1 + end + return dst_start, dst_end + end + local zoom = mp.get_property_number("video-zoom") + + local align_x = mp.get_property_number("video-align-x") + local pan_x = mp.get_property_number("video-pan-x") + _video_dimensions.top_left[1], _video_dimensions.bottom_right[1] = split_scaling(window_w, scaled_width, zoom, align_x, pan_x) + + local align_y = mp.get_property_number("video-align-y") + local pan_y = mp.get_property_number("video-pan-y") + _video_dimensions.top_left[2], _video_dimensions.bottom_right[2] = split_scaling(window_h, scaled_height, zoom, align_y, pan_y) + else + _video_dimensions.top_left[1] = 0 + _video_dimensions.bottom_right[1] = window_w + _video_dimensions.top_left[2] = 0 + _video_dimensions.bottom_right[2] = window_h + end + _video_dimensions.size[1] = _video_dimensions.bottom_right[1] - _video_dimensions.top_left[1] + _video_dimensions.size[2] = _video_dimensions.bottom_right[2] - _video_dimensions.top_left[2] + _video_dimensions.ratios[1] = _video_dimensions.size[1] / w + _video_dimensions.ratios[2] = _video_dimensions.size[2] / h + + if not (_video_dimensions.size[1] > 0 and _video_dimensions.size[2] > 0) then return nil end + video_dimensions_stale = false + return _video_dimensions +end + +for _, p in ipairs({ + "keepaspect", + "video-out-params", + "video-unscaled", + "panscan", + "video-zoom", + "video-align-x", + "video-pan-x", + "video-align-y", + "video-pan-y", + "osd-width", + "osd-height", +}) do + mp.observe_property(p, nil, function() video_dimensions_stale = true end) +end +function draw_ass(ass) + local ww, wh = mp.get_osd_size() + mp.set_osd_ass(ww, wh, ass) +end + +local old_timestamp = -1 + +function refresh_minimap() + local dim = get_video_dimensions() + if not dim then + draw_ass("") + return + end + if dim.timestamp == old_timestamp then return end + old_timestamp = dim.timestamp + local ww, wh = mp.get_osd_size() + if not (ww > 0 and wh > 0) then return end + if opts.hide_when_full_image_in_view then + if dim.top_left[1] >= 0 and + dim.top_left[2] >= 0 and + dim.bottom_right[1] <= ww and + dim.bottom_right[2] <= wh + then + draw_ass("") + return + end + end + local center = { + opts.center[1] * 0.01 * ww, + opts.center[2] * 0.01 * wh + } + local cutoff = { + opts.max_size[1] * 0.01 * ww * 0.5, + opts.max_size[2] * 0.01 * wh * 0.5 + } + local a = assdraw.ass_new() + local draw = function(x, y, w, h, opacity, color) + a:new_event() + a:pos(center[1], center[2]) + a:append("{\\bord0}") + a:append("{\\shad0}") + a:append("{\\c&" .. color .. "&}") + a:append("{\\2a&HFF}") + a:append("{\\3a&HFF}") + a:append("{\\4a&HFF}") + a:append("{\\1a&H" .. opacity .. "}") + w = w * 0.5 + h = h * 0.5 + a:draw_start() + local rounded = {true,true,true,true} -- tl, tr, br, bl + local x0,y0,x1,y1 = x-w, y-h, x+w, y+h + if x0 < -cutoff[1] then + x0 = -cutoff[1] + rounded[4] = false + rounded[1] = false + end + if y0 < -cutoff[2] then + y0 = -cutoff[2] + rounded[1] = false + rounded[2] = false + end + if x1 > cutoff[1] then + x1 = cutoff[1] + rounded[2] = false + rounded[3] = false + end + if y1 > cutoff[2] then + y1 = cutoff[2] + rounded[3] = false + rounded[4] = false + end + + local r = 3 + local c = 0.551915024494 * r + if rounded[0] then + a:move_to(x0 + r, y0) + else + a:move_to(x0,y0) + end + if rounded[1] then + a:line_to(x1 - r, y0) + a:bezier_curve(x1 - r + c, y0, x1, y0 + r - c, x1, y0 + r) + else + a:line_to(x1, y0) + end + if rounded[2] then + a:line_to(x1, y1 - r) + a:bezier_curve(x1, y1 - r + c, x1 - r + c, y1, x1 - r, y1) + else + a:line_to(x1, y1) + end + if rounded[3] then + a:line_to(x0 + r, y1) + a:bezier_curve(x0 + r - c, y1, x0, y1 - r + c, x0, y1 - r) + else + a:line_to(x0, y1) + end + if rounded[4] then + a:line_to(x0, y0 + r) + a:bezier_curve(x0, y0 + r - c, x0 + r - c, y0, x0 + r, y0) + else + a:line_to(x0, y0) + end + a:draw_stop() + end + local image = function() + draw((dim.top_left[1] + dim.size[1]/2 - ww/2) / opts.scale, + (dim.top_left[2] + dim.size[2]/2 - wh/2) / opts.scale, + dim.size[1] / opts.scale, + dim.size[2] / opts.scale, + opts.image_opacity, + opts.image_color) + end + local view = function() + draw(0, + 0, + ww / opts.scale, + wh / opts.scale, + opts.view_opacity, + opts.view_color) + end + if opts.view_above_image then + image() + view() + else + view() + image() + end + draw_ass(a.text) +end + +local active = false + +function enable_minimap() + if active then return end + active = true + mp.register_idle(refresh_minimap) +end + +function disable_minimap() + if not active then return end + active = false + ass.minimap = a.text + draw_ass() + mp.unregister_idle(refresh_minimap) +end + +function toggle() + if active then + disable_minimap() + else + enable_minimap() + end +end + +if opts.enabled then + enable_minimap() +end + +mp.add_key_binding(nil, "minimap-enable", enable) +mp.add_key_binding(nil, "minimap-disable", disable) +mp.add_key_binding(nil, "minimap-toggle", toggle) |