]> git.sesse.net Git - nageru/blobdiff - theme.lua
Reduce the code duplication in the plain inputs (backport from Solskogen theme).
[nageru] / theme.lua
index aca8c4e7ee9decbfdfb73b89ad6b67ab968c70b4..8bac0a63605c07e64791ffefc8b7fc825cfd2ae7 100644 (file)
--- a/theme.lua
+++ b/theme.lua
@@ -15,8 +15,10 @@ local zoom_poi = 0   -- which input to zoom in on
 local fade_src_signal = 0
 local fade_dst_signal = 0
 
-local input0_neutral_color = {0.5, 0.5, 0.5}
-local input1_neutral_color = {0.5, 0.5, 0.5}
+local neutral_colors = {
+       {0.5, 0.5, 0.5},  -- Input 0.
+       {0.5, 0.5, 0.5}   -- Input 1.
+}
 
 local live_signal_num = 0
 local preview_signal_num = 1
@@ -57,7 +59,6 @@ end
 function make_sbs_input(chain, signal, deint, hq)
        local input = chain:add_live_input(not deint, deint)  -- Override bounce only if not deinterlacing.
        input:connect_signal(signal)
-       local wb_effect = chain:add_effect(WhiteBalanceEffect.new())
 
        local resample_effect = nil
        local resize_effect = nil
@@ -66,6 +67,7 @@ function make_sbs_input(chain, signal, deint, hq)
        else
                resize_effect = chain:add_effect(ResizeEffect.new())
        end
+       local wb_effect = chain:add_effect(WhiteBalanceEffect.new())
 
        local padding_effect = chain:add_effect(IntegralPaddingEffect.new())
 
@@ -113,9 +115,8 @@ function make_fade_input(chain, signal, live, deint, scale)
        local input, wb_effect, resample_effect, last
        if live then
                input = chain:add_live_input(false, deint)
-               wb_effect = chain:add_effect(WhiteBalanceEffect.new())
                input:connect_signal(signal)
-               last = wb_effect
+               last = input
        else
                input = chain:add_effect(ImageInput.new("bg.jpeg"))
                last = input
@@ -128,6 +129,12 @@ function make_fade_input(chain, signal, live, deint, scale)
                last = resample_effect
        end
 
+       -- Make sure to put the white balance after the scaling (usually more efficient).
+       if live then
+               wb_effect = chain:add_effect(WhiteBalanceEffect.new())
+               last = wb_effect
+       end
+
        return {
                input = input,
                wb_effect = wb_effect,
@@ -177,8 +184,6 @@ function make_simple_chain(input_deint, input_scale, hq)
 
        local input = chain:add_live_input(false, input_deint)
        input:connect_signal(0)  -- First input card. Can be changed whenever you want.
-       local wb_effect = chain:add_effect(WhiteBalanceEffect.new())
-       chain:finalize(hq)
 
        local resample_effect, resize_effect
        if scale then
@@ -189,6 +194,9 @@ function make_simple_chain(input_deint, input_scale, hq)
                end
        end
 
+       local wb_effect = chain:add_effect(WhiteBalanceEffect.new())
+       chain:finalize(hq)
+
        return {
                chain = chain,
                input = input,
@@ -234,7 +242,7 @@ function needs_scale(signals, signal_num, width, height)
                -- We assume this is already correctly scaled at load time.
                return false
        end
-       assert(signal_num == INPUT0_SIGNAL_NUM or signal_num == INPUT1_SIGNAL_NUM)
+       assert(is_plain_signal(signal_num))
        return (signals:get_width(signal_num) ~= width or signals:get_height(signal_num) ~= height)
 end
 
@@ -255,10 +263,33 @@ function num_channels()
        return 4
 end
 
+function is_plain_signal(num)
+       return num == INPUT0_SIGNAL_NUM or num == INPUT1_SIGNAL_NUM
+end
+
+-- Helper function to write e.g. “720p60”. The difference between this
+-- and get_channel_resolution_raw() is that this one also can say that
+-- there's no signal.
+function get_channel_resolution(signal_num)
+       res = last_resolution[signal_num]
+       if (not res) or res.height <= 0 then
+               return "no signal"
+       end
+       if not res.has_signal then
+               if res.height == 525 then
+                       -- Special mode for the USB3 cards.
+                       return "no signal"
+               end
+               return get_channel_resolution_raw(res) .. ", no signal"
+       else
+               return get_channel_resolution_raw(res)
+       end
+end
+
 -- Helper function to write e.g. “60” or “59.94”.
-function get_frame_rate(signal_num)
-       local nom = last_resolution[signal_num].frame_rate_nom
-       local den = last_resolution[signal_num].frame_rate_den
+function get_frame_rate(res)
+       local nom = res.frame_rate_nom
+       local den = res.frame_rate_den
        if nom % den == 0 then
                return nom / den
        else
@@ -267,17 +298,11 @@ function get_frame_rate(signal_num)
 end
 
 -- Helper function to write e.g. “720p60”.
-function get_channel_resolution(signal_num)
-       if last_resolution[signal_num] then
-               if not last_resolution[signal_num].has_signal then
-                       return "no signal"
-               elseif last_resolution[signal_num].interlaced then
-                       return last_resolution[signal_num].height .. "i" .. get_frame_rate(signal_num)
-               else
-                       return last_resolution[signal_num].height .. "p" .. get_frame_rate(signal_num)
-               end
+function get_channel_resolution_raw(res)
+       if res.interlaced then
+               return res.height .. "i" .. get_frame_rate(res)
        else
-               return "no signal"
+               return res.height .. "p" .. get_frame_rate(res)
        end
 end
 
@@ -286,13 +311,12 @@ end
 -- Called at the start of the program, and then each frame for live
 -- channels in case they change resolution.
 function channel_name(channel)
-       if channel == 2 then
-               return "Input 1 (" .. get_channel_resolution(0) .. ")"
-       elseif channel == 3 then
-               return "Input 2 (" .. get_channel_resolution(1) .. ")"
-       elseif channel == 4 then
+       local signal_num = channel - 2
+       if is_plain_signal(signal_num) then
+               return "Input " .. (signal_num + 1) .. " (" .. get_channel_resolution(signal_num) .. ")"
+       elseif signal_num == SBS_SIGNAL_NUM then
                return "Side-by-side"
-       elseif channel == 5 then
+       elseif signal_num == STATIC_SIGNAL_NUM then
                return "Static picture"
        end
 end
@@ -300,6 +324,8 @@ end
 -- API ENTRY POINT
 -- Returns, given a channel number, which signal it corresponds to (starting from 0).
 -- Should return -1 if the channel does not correspond to a simple signal.
+-- (The information is used for whether right-click on the channel should bring up
+-- an input selector or not.)
 -- Called once for each channel, at the start of the program.
 -- Will never be called for live (0) or preview (1).
 function channel_signal(channel)
@@ -312,21 +338,51 @@ function channel_signal(channel)
        end
 end
 
+-- API ENTRY POINT
+-- Called every frame. Returns the color (if any) to paint around the given
+-- channel. Returns a CSS color (typically to mark live and preview signals);
+-- "transparent" is allowed.
+-- Will never be called for live (0) or preview (1).
+function channel_color(channel)
+       if channel_involved_in(channel, live_signal_num) then
+               return "#f00"
+       end
+       if channel_involved_in(channel, preview_signal_num) then
+               return "#0f0"
+       end
+       return "transparent"
+end
+
+function channel_involved_in(channel, signal_num)
+       if is_plain_signal(signal_num) then
+               return channel == (signal_num + 2)
+       end
+       if signal_num == SBS_SIGNAL_NUM then
+               return (channel == 2 or channel == 3)
+       end
+       if signal_num == STATIC_SIGNAL_NUM then
+               return (channel == 5)
+       end
+       if signal_num == FADE_SIGNAL_NUM then
+               return (channel_involved_in(channel, fade_src_signal) or
+                       channel_involved_in(channel, fade_dst_signal))
+       end
+       return false
+end
+
 -- API ENTRY POINT
 -- Returns if a given channel supports setting white balance (starting from 2).
 -- Called only once for each channel, at the start of the program.
 function supports_set_wb(channel)
-       return channel == 2 or channel == 3
+       return is_plain_signal(channel - 2)
 end
 
 -- API ENTRY POINT
 -- Gets called with a new gray point when the white balance is changing.
 -- The color is in linear light (not sRGB gamma).
 function set_wb(channel, red, green, blue)
-       if channel == 2 then
-               input0_neutral_color = { red, green, blue }
-       elseif channel == 3 then
-               input1_neutral_color = { red, green, blue }
+       if is_plain_signal(channel - 2) then
+               neutral_colors[channel - 2 + 1] = { red, green, blue }
        end
 end
 
@@ -348,6 +404,7 @@ function get_transitions(t)
        finish_transitions(t)
 
        if live_signal_num == preview_signal_num then
+               -- No transitions possible.
                return {}
        end
 
@@ -356,27 +413,23 @@ function get_transitions(t)
                return {"Cut"}
        end
 
-       if (live_signal_num == INPUT0_SIGNAL_NUM or
-           live_signal_num == INPUT1_SIGNAL_NUM or
-           live_signal_num == STATIC_SIGNAL_NUM) and
-          (preview_signal_num == INPUT0_SIGNAL_NUM or
-           preview_signal_num == INPUT1_SIGNAL_NUM or
-           preview_signal_num == STATIC_SIGNAL_NUM) then
+       if (is_plain_signal(live_signal_num) or live_signal_num == STATIC_SIGNAL_NUM) and
+          (is_plain_signal(preview_signal_num) or preview_signal_num == STATIC_SIGNAL_NUM) then
                return {"Cut", "", "Fade"}
        end
 
        -- Various zooms.
-       if live_signal_num == SBS_SIGNAL_NUM and
-          (preview_signal_num == INPUT0_SIGNAL_NUM or preview_signal_num == INPUT1_SIGNAL_NUM) then
+       if live_signal_num == SBS_SIGNAL_NUM and is_plain_signal(preview_signal_num) then
                return {"Cut", "Zoom in"}
-       elseif (live_signal_num == INPUT0_SIGNAL_NUM or live_signal_num == INPUT1_SIGNAL_NUM) and
-              preview_signal_num == SBS_SIGNAL_NUM then
+       elseif is_plain_signal(live_signal_num) and preview_signal_num == SBS_SIGNAL_NUM then
                return {"Cut", "Zoom out"}
        end
 
        return {"Cut"}
 end
 
+-- API ENTRY POINT
+-- Called when the user clicks a transition button.
 function transition_clicked(num, t)
        if num == 0 then
                -- Cut.
@@ -406,8 +459,7 @@ function transition_clicked(num, t)
                        return
                end
 
-               if (live_signal_num == INPUT0_SIGNAL_NUM and preview_signal_num == INPUT1_SIGNAL_NUM) or
-                  (live_signal_num == INPUT1_SIGNAL_NUM and preview_signal_num == INPUT0_SIGNAL_NUM) then
+               if (is_plain_signal(live_signal_num) and is_plain_signal(preview_signal_num)) then
                        -- We can't zoom between these. Just make a cut.
                        io.write("Cutting from " .. live_signal_num .. " to " .. live_signal_num .. "\n")
                        local temp = live_signal_num
@@ -416,8 +468,7 @@ function transition_clicked(num, t)
                        return
                end
 
-               if live_signal_num == SBS_SIGNAL_NUM and
-                  (preview_signal_num == INPUT0_SIGNAL_NUM or preview_signal_num == INPUT1_SIGNAL_NUM) then
+               if live_signal_num == SBS_SIGNAL_NUM and is_plain_signal(preview_signal_num) then
                        -- Zoom in from SBS to single.
                        transition_start = t
                        transition_end = t + 1.0
@@ -425,8 +476,7 @@ function transition_clicked(num, t)
                        zoom_dst = 1.0
                        zoom_poi = preview_signal_num
                        preview_signal_num = SBS_SIGNAL_NUM
-               elseif (live_signal_num == INPUT0_SIGNAL_NUM or live_signal_num == INPUT1_SIGNAL_NUM) and
-                      preview_signal_num == SBS_SIGNAL_NUM then
+               elseif is_plain_signal(live_signal_num) and preview_signal_num == SBS_SIGNAL_NUM then
                        -- Zoom out from single to SBS.
                        transition_start = t
                        transition_end = t + 1.0
@@ -441,11 +491,9 @@ function transition_clicked(num, t)
 
                -- Fade.
                if (live_signal_num ~= preview_signal_num) and
-                  (live_signal_num == INPUT0_SIGNAL_NUM or
-                   live_signal_num == INPUT1_SIGNAL_NUM or
+                  (is_plain_signal(live_signal_num) or
                    live_signal_num == STATIC_SIGNAL_NUM) and
-                  (preview_signal_num == INPUT0_SIGNAL_NUM or
-                   preview_signal_num == INPUT1_SIGNAL_NUM or
+                  (is_plain_signal(preview_signal_num) or
                    preview_signal_num == STATIC_SIGNAL_NUM) then
                        transition_start = t
                        transition_end = t + 1.0
@@ -516,7 +564,7 @@ function get_chain(num, t, width, height, signals)
        last_resolution = input_resolution
 
        if num == 0 then  -- Live.
-               if live_signal_num == INPUT0_SIGNAL_NUM or live_signal_num == INPUT1_SIGNAL_NUM then  -- Plain input.
+               if is_plain_signal(live_signal_num) then  -- Plain inputs.
                        local input_type = get_input_type(signals, live_signal_num)
                        local input_scale = needs_scale(signals, live_signal_num, width, height)
                        local chain = simple_chains[input_type][input_scale][true]
@@ -565,7 +613,7 @@ function get_chain(num, t, width, height, signals)
                        prepare = function()
                                chain.input:connect_signal(INPUT0_SIGNAL_NUM)
                                set_scale_parameters_if_needed(chain, width, height)
-                               set_neutral_color(chain.wb_effect, input0_neutral_color)
+                               set_neutral_color(chain.wb_effect, neutral_colors[1])
                        end
                        return chain.chain, prepare
                end
@@ -589,25 +637,15 @@ function get_chain(num, t, width, height, signals)
        end
 
        -- Individual preview inputs.
-       if num == INPUT0_SIGNAL_NUM + 2 then
-               local input_type = get_input_type(signals, INPUT0_SIGNAL_NUM)
-               local input_scale = needs_scale(signals, INPUT0_SIGNAL_NUM, width, height)
-               local chain = simple_chains[input_type][input_scale][false]
-               prepare = function()
-                       chain.input:connect_signal(INPUT0_SIGNAL_NUM)
-                       set_scale_parameters_if_needed(chain, width, height)
-                       set_neutral_color(chain.wb_effect, input0_neutral_color)
-               end
-               return chain.chain, prepare
-       end
-       if num == INPUT1_SIGNAL_NUM + 2 then
-               local input_type = get_input_type(signals, INPUT1_SIGNAL_NUM)
-               local input_scale = needs_scale(signals, INPUT1_SIGNAL_NUM, width, height)
+       if is_plain_signal(num - 2) then
+               local signal_num = num - 2
+               local input_type = get_input_type(signals, signal_num)
+               local input_scale = needs_scale(signals, signal_num, width, height)
                local chain = simple_chains[input_type][input_scale][false]
                prepare = function()
-                       chain.input:connect_signal(INPUT1_SIGNAL_NUM)
+                       chain.input:connect_signal(signal_num)
                        set_scale_parameters_if_needed(chain, width, height)
-                       set_neutral_color(chain.wb_effect, input1_neutral_color)
+                       set_neutral_color(chain.wb_effect, neutral_colors[signal_num + 1])
                end
                return chain.chain, prepare
        end
@@ -633,12 +671,20 @@ function place_rectangle(resample_effect, resize_effect, padding_effect, x0, y0,
        local srcy0 = 0.0
        local srcy1 = 1.0
 
+       padding_effect:set_int("width", screen_width)
+       padding_effect:set_int("height", screen_height)
+
        -- Cull.
        if x0 > screen_width or x1 < 0.0 or y0 > screen_height or y1 < 0.0 then
-               resample_effect:set_int("width", 1)
-               resample_effect:set_int("height", 1)
-               resample_effect:set_float("zoom_x", screen_width)
-               resample_effect:set_float("zoom_y", screen_height)
+               if resample_effect ~= nil then
+                       resample_effect:set_int("width", 1)
+                       resample_effect:set_int("height", 1)
+                       resample_effect:set_float("zoom_x", screen_width)
+                       resample_effect:set_float("zoom_y", screen_height)
+               else
+                       resize_effect:set_int("width", 1)
+                       resize_effect:set_int("height", 1)
+               end
                padding_effect:set_int("left", screen_width + 100)
                padding_effect:set_int("top", screen_height + 100)
                return
@@ -721,8 +767,8 @@ end
 function prepare_sbs_chain(chain, t, screen_width, screen_height, input_resolution)
        chain.input0.input:connect_signal(0)
        chain.input1.input:connect_signal(1)
-       set_neutral_color(chain.input0.wb_effect, input0_neutral_color)
-       set_neutral_color(chain.input1.wb_effect, input1_neutral_color)
+       set_neutral_color(chain.input0.wb_effect, neutral_colors[1])
+       set_neutral_color(chain.input1.wb_effect, neutral_colors[2])
 
        -- First input is positioned (16,48) from top-left.
        local width0 = round(848 * screen_width/1280.0)
@@ -782,19 +828,17 @@ function set_neutral_color(effect, color)
 end
 
 function set_neutral_color_from_signal(effect, signal)
-       if signal == INPUT0_SIGNAL_NUM then
-               set_neutral_color(effect, input0_neutral_color)
-       else
-               set_neutral_color(effect, input1_neutral_color)
+       if is_plain_signal(signal) then
+               set_neutral_color(effect, neutral_colors[signal - INPUT0_SIGNAL_NUM + 1])
        end
 end
 
 function calc_fade_progress(t, transition_start, transition_end)
        local tt = (t - transition_start) / (transition_end - transition_start)
        if tt < 0.0 then
-               tt = 0.0
+               return 0.0
        elseif tt > 1.0 then
-               tt = 1.0
+               return 1.0
        end
 
        -- Make the fade look maybe a tad more natural, by pumping it