]> git.sesse.net Git - nageru-docs/blobdiff - theme.rst
Fix some examples.
[nageru-docs] / theme.rst
index e45d63683efaba9a36975c53a6c4d4723a79b61e..abf7d3be715c90db2c1bb6a74558ef0e0434a5a1 100644 (file)
--- a/theme.rst
+++ b/theme.rst
@@ -94,9 +94,8 @@ this signature:
 “width” and “height” are what you'd expect (the output resolution).
 t contains the current stream time in seconds. “num” contains 0
 for the live view, 1 for the preview view, and 2, 3, 4, … for each
-of the individual stream previews. “signals“ contains a bit of
-information about each input signal, like its current resolution
-or frame rate.
+of the individual stream previews. “signals” contains a bit of
+information about each input signal (see :ref:`signal-info`).
 
 get_scene in return should return a scene. However, before you do that,
 you can set the parameters **strength_first** and **strength_second**
@@ -147,14 +146,16 @@ scaler before mixing; *ResampleEffect* provides one::
   local input0 = scene:add_input()
   input0:display(0)
   local input0_scaled = scene:add_optional_effect(ResampleEffect.new())  -- Implicitly uses input0.
-  scene_or_input.resample_effect:set_int("width", 1280)  -- Could also be set in get_scene().
-  scene_or_input.resample_effect:set_int("height", 720)
+  input0_scaled:set_int("width", 1280)  -- Could also be set in get_scene().
+  input0_scaled:set_int("height", 720)
   input0_scaled:enable()  -- Enable or disable as needed.
 
   local input1 = scene:add_input()
   input1:display(1)
   local input1_scaled = ... -- Similarly here and the rest.
 
+  input1_scaled:enable_if(some_variable)  -- Convenience form for enable() or disable() depending on some_variable.
+
   -- The rest is unchanged.
 
 Clearly, there are four options here; both inputs could be unscaled,
@@ -173,8 +174,8 @@ directly by the GPU) that instead. The scaling is set up like this::
   local input0 = scene:add_input()
   input0:display(0)
   local input0_scaled = scene:add_effect({ResampleEffect.new(), ResizeEffect.new()})  -- Implicitly uses input0.
-  scene_or_input.resample_effect:set_int("width", 1280)  -- Just like before.
-  scene_or_input.resample_effect:set_int("height", 720)
+  input0_scaled:set_int("width", 1280)  -- Just like before.
+  input0_scaled:set_int("height", 720)
 
   -- Pick one in get_scene() like this:
   input0_scaled:choose(ResizeEffect)
@@ -182,7 +183,10 @@ directly by the GPU) that instead. The scaling is set up like this::
   -- Or by numerical index:
   input0_scaled:choose(1)  -- Chooses ResizeEffect
 
-Note that add_effect returns its input for convenience.
+Note that add_effect returns its input for convenience. All alternatives must
+have the same amount of inputs, with an exception for IdentityEffect, which can
+coexist with an effect requiring any amount of inputs (if selected, the IdentityEffect
+just passes its first input unchanged).
 
 Actually, add_optional_effect() is just a wrapper around add_effect() with
 IdentityEffect as the other alternative, and disable() is a convenience version of
@@ -343,6 +347,51 @@ This allows you to e.g. have simple message overlays that you can change
 without restarting Nageru.
 
 
+.. _locking:
+
+Locking alternatives
+--------------------
+
+In some cases, Nageru may be building in alternatives to a scene that you
+don't really need, resulting in combinatorial explosion. (If the number of
+instances is getting high, you will get a warning when finalizing the scene.)
+For instance, in some cases, you know that a given transition scene will never
+be used for previews, just live. In this case, you can replace the call to
+scene:finalize() with::
+
+  scene:finalize(false)
+
+In this case, you guarantee that the scene will never be returned when
+get_scene() is called with the number 0. (Similarly, you can use true
+to *only* use it for the live channel.)
+
+Similarly, inputs can hold four different input types, but in some scenes,
+you may always use them with a specific one, e.g. an image “bg_img”. In this case,
+you may add the input with a specific type right away::
+
+  scene:add_input(bg_img)
+
+Similarly, for a live input, you can do::
+
+  scene:add_input(0)
+
+You can still use scene:display() to change the input, but it needs to be of
+the same *type* as the one you gave to add_input().
+
+Finally, you can specify that some effects only make sense together, reducing
+the number of possibilities further. For instance, you may have an optional
+crop effect followed by a resample, where the resample is only enabled if the
+crop is. If so, you can do this::
+
+   resample_effect:always_disable_if_disabled(crop_effect)
+
+For more advanced exclusions, you may choose to split up the scenes into several
+distinct ones that you manage yourself; indeed, before Nageru 1.9.0, that was
+the only option. At some point, however, you may choose to simply accept the
+added startup time and a bit of extra RAM cost; ease of use and flexibility often
+trumps such concerns.
+
+
 .. _menus:
 
 Theme menus
@@ -375,8 +424,61 @@ labels and function references::
 When the user chooses a menu entry, the given Lua function will
 automatically be called. There are no arguments nor return values.
 
-There currently is no support for checkboxes, submenus, input boxes
+Menus can contain submenus, by giving an array instead of a function::
+
+  ThemeMenu.set(
+    { "Overlay", {
+       { "Version A", select_overlay_a },
+       { "Version B", select_overlay_b }
+    },
+    { "&Reload overlay", reload_html }
+  )
+
+They can also be checkable, or have checkboxes, by adding a third
+array element containing flags for that::
+
+  ThemeMenu.set(
+    { "Enable overlay",  enable_overlay,  Nageru.CHECKED },    -- Currently checked.
+    { "Enable crashing", make_unstable,   Nageru.CHECKABLE }   -- Can be checked, but isn't currently.
+  )
+
+When such an option is selected, you probably want to rebuild the menu to
+reflect the new state.
+
+There currently is no support for input boxes, sliders,
 or the likes. However, do note that since the theme is written in unrestricted
 Lua, so you can use e.g. `lua-http <https://github.com/daurnimator/lua-http>`_
 to listen for external connections and accept more complicated inputs
 from those.
+
+
+.. _signal-info:
+
+Signal information queries
+--------------------------
+
+As previously mentioned, get_scene() takes in a “signals” parameter
+that you can query for information about each signal (numbered from 0;
+live and preview are channels, not signals), like its current resolution
+or frame rate:
+
+  * get_frame_width(signal), get_frame_height(signal): Width and height of the last frame.
+  * get_width(signal), get_height(signal): Width and height of the last *field*
+    (the field height is half of the frame height for an interlaced signal).
+  * get_interlaced(signal): Whether the last frame was interlaced.
+  * get_has_signal(signal): Whether there is a valid input signal.
+  * get_is_connected(signal): Whether there is even a card connected
+    to this signal (USB cards can be swapped in or out); if not,
+    you will get a stream of single-colored frames.
+  * get_frame_rate_nom(signal), get_frame_rate_den(signal): The frame rate
+    of the last frame, as a rational (e.g. 60/1, or 60000/1001 for 59.94).
+  * get_last_subtitle(signal): See :ref:`subtitle-ingest`.
+  * get_human_readable_resolution(signal): The resolution and frame rate in
+    human-readable form (e.g. “1080i59.94”), suitable for e.g. stream titles.
+    Note that Nageru does not follow the EBU recommendation of using
+    frame rate even for interlaced signals (e.g. “1080i25” instead of “1080i50”),
+    since it is little-used and confusing to most users.
+
+You can use this either for display purposes, or for choosing the right
+effect alternatives. In particular, you may want to disable scaling if
+the frame is already of the correct resolution.