Macro Building Essentials

User avatar
AndrewHazelden
Fusionator
Posts: 1387
Joined: Fri Apr 03, 2015 3:20 pm
Answers: 4
Location: West Dover, Nova Scotia, Canada
Been thanked: 59 times
Contact:

Macro Building Essentials

#1

Post by AndrewHazelden » Fri Oct 06, 2017 5:07 pm

Hi. This thread will be the starting point for a new WSL tutorial series of posts that will hopefully get you started creating, editing, and releasing your own custom Fusion Macros. :cheer:

A macro is a plain text document that has the .setting file extension. It is built with the same general syntax as a Fusion .comp document but is cut down to just the elements of a few nodes and avoids the typical header data used in a full Fusion composite for things like the Fusion timeline and viewer settings.

What's in a Simple Macro Node?

At minimum a Macro starts with a tag that indicates if it is a "MacroOperator" or a "GroupOperator".

The next item is a CustomData "HelpPage" link that allows you to link to a webpage help documentation resource that is accessed from Fusion on Windows by pressing the F1 key when the node is selected in the flow area.

After that comes a series of input entries that are used for exposing both the input connection ports on the macro node which are colored triangle shapes in the Fusion flow area, and the other input settings are used for arranging and setting up the user interface controls that are shown in the Fusion tools section of the UI where the artist adjusts the settings on a node. The order that the input items are listed textually in the raw macro node .setting file is the same order as how they are shown in the Fusion tools UI window.

Next are the output entries on the macro that list all of the outputs that come out of the macro node. These are shown as red square connections on a node. Hovering your mouse pointer over a node connection will list the name of the connection in a popup tool tip, and also write details in the help line at the bottom left of the main Fusion window.
node-output-connections-by-name.png
You should take the time to give meaningful names to the input connections if you have more than one or two of them on a macro. This is helpful as when you drag a connection line from one node to the input connection on another node you can hold down the Alt / Option key and a popup menu will appear that lets you select an input by name. When you eventually create a node with 6+ inputs on it this is the only way to sensibly figure out what you are connecting to. :)
alt-key-node-popup.png
Macro nodes don't have to be used just for processing 2D imagery. You can also add Fusion 3D system based mesh nodes to a macro, cameras, imageplanes, particle emitters, even fuses and plugins installed on your system can have their nodes wrapped inside of, linked to / instanced in a macro.

As long as the fuse or plugin is installed on your workstation, and on any render farm systems you use to output your Fusion rendered composites, the macro node will be able to access those embedded elements without issue. The macro node is merely storing a reference to those items and allowing you to customize the display of the UI elements or add expression links.

Looking at the Contents of a Macro Node
offset-macro-gui.png
This is a very simple example of a macro node that uses only a single transform node internally. It works by exposing the controls required to provide a simple yet very effective 2D offset function that can slide an image vertically or horizontally on the X/Y axis in a resolution independent 0-1 range. When the media supplied as an input to the offset node is transformed it is automatically wrapped around the frame border seam zones.

This macro node could be used to pan a LatLong panorama horizontally to re-center the front facing view angle with out any loss of crispness or softening of the pixels, or the macro node could be used to help with clone/paint work in Fusion when preparing a 1:1 aspect ratio seamless texture map by shifting the edge of the frame to the center of the image.

You should download this example macro and save it to your Fusion use prefs "Macros:/" folder. It will be accessible in Fusion instantly without the need to restart Fusion's GUI.
Code: [Select all] [Expand/Collapse] [Download] (offset.setting)
  1. {
  2.     Tools = ordered() {
  3.         Offset = GroupOperator {
  4.             CtrlWZoom = false,
  5.             CustomData = {
  6.                 HelpPage = "https://www.steakunderwater.com/wesuckless/viewtopic.php?f=6&t=1581&p=11590",
  7.             },
  8.             Inputs = ordered() {
  9.                 MainInput1 = InstanceInput {
  10.                     SourceOp = "SlideTransform",
  11.                     Source = "Input",
  12.                 },
  13.                 Input1 = InstanceInput {
  14.                     SourceOp = "SlideTransform",
  15.                     Source = "Center",
  16.                     Name = "Offset",
  17.                 }
  18.             },
  19.             Outputs = {
  20.                 MainOutput1 = InstanceOutput {
  21.                     SourceOp = "SlideTransform",
  22.                     Source = "Output",
  23.                 }
  24.             },
  25.             ViewInfo = GroupInfo {
  26.                 Pos = { 1122, 89 },
  27.                 Flags = {
  28.                     AllowPan = false,
  29.                     AutoSnap = true
  30.                 },
  31.                 Size = { 126, 64.3, 63, 22 },
  32.                 Direction = "Horizontal",
  33.                 PipeStyle = "Direct",
  34.                 Scale = 1,
  35.                 Offset = { 0, 0 }
  36.             },
  37.             Tools = ordered() {
  38.                 SlideTransform = Transform {
  39.                     CtrlWZoom = false,
  40.                     CtrlWShown = false,
  41.                     NameSet = true,
  42.                     Inputs = {
  43.                         Edges = Input { Value = 1, },
  44.                         FilterMethod = Input { Value = 6, },
  45.                     },
  46.                     ViewInfo = OperatorInfo { Pos = { 0, 10.15 } },
  47.                 }
  48.             },
  49.         }
  50.     },
  51.     ActiveTool = "Offset"
  52. }
When creating your own Fusion macros, a "MacroOperator" tag at the top of the .setting file indicates the node based elements inside of the macro node are hidden superficially from the artist who is using your macro in Fusion. It is still a plain text file on disk so its not like there is any DRM or obfuscation but on the Fusion GUI side of things the internal nodes in the macro are not accessible.

If you change the "MacroOperator" word at the top of a macro node to say "GroupOperator" instead in a programmer's text editor, then your macro is now effectively working as a standard grouped object in Fusion's flow area. With a GroupOperator you can expand the node in the Fusion Flow area to access and adjust any of the internal nodes, edit expressions, and change connections in the macro.

Just make sure not to accidentally break the main input and output wires going from the first and last nodes inside the GroupOperator "canister" to the border of the Group node. if you do break these important connections it will take some manual editing time in a text editor to restore them if you don't undo the edit while you still are able to.

The Offset macro in this tutorial is presented as a GroupOperator node. If you click on the node and expand group icon on the edge of the node in the flow view you will visually see the content that is contained inside the Offset node.
expand-a-group-operator-macro.gif
Any input control that is added to the macro node GUI directly will also reveal any of its corresponding Fusion Viewer window based manipulator handles.

You can see this manipulator control feature at work in the Offset macro node. When you select the node to adjust the settings and view the output in the viewer window, you will see the green "Offset" attribute exposes a transform handle that can be visually clicked on and slid around interactively.
offset-macro-control-handle-in-viewer-window.png
A "MacroOperator" or "GroupOperator" based macro node in Fusion can expose user interface controls that are either directly linked to the attributes on the node, or added indirectly through the use of a more complex but very versatile UserControls based attribute tag that is stored as code on the end of each node.

UserControls allow you to add Lua scripts to buttons and other custom GUI elements which can greatly expand the range of things a macro node can do in a composite. You can even create custom UI popup windows in a macro node like this advanced skill level WSL based Creating a UI Manager GUI Inside of a Node's UserControls Interface tutorial demonstrates.

A UserControl GUI element will typically be placed at the bottom of each node's control list in the Tools tab in Fusion when a UserControl is added to the node. This means that it is best to generally stick to either exposing only native controls in a macro node or to use all custom UserControls elements in the macro node's UI if you want to be able to easily re-arrange the display order of elements in the UI.

You can expression link to native controls or UserControls inside the macro so either approach can be used but you should pick one and be consistent so you have the freedom and flexibility to arrange the Macro GUI layout as you want.

This is a screen shot of the Edit Controls window that is used to visually add and modify UserControls that are attached to a node. This window is shown by right clicking on a node in the tools view and selecting the Edit Controls... item in the contextual menu.
edit-controls-window.png
The Macro Editor Window

When you are getting started with creating a Macro the first dozen or so times you will likely use this basic workflow:

Step 1. Select several nodes in the Fusion flow area.

Step 2. Right click on one of the selected nodes.

Step 3. In the contextual pop-up menu that appears, select the Macro > Create Macro... menu item. This will open up a "Macro Editor" GUI window that is at the same time both your best friend when getting started, and possibly the source of many confusing headaches.

Your goal in learning Fusion macro building should be to get comfortable with the Macro Editor to understand how it works at the base level, use it to quickly select attributes to expose as input controls, and learn how it sets the default ranges on Macro GUI elements.

Then once you are gaining confidence and becoming more comfortable with editing a macro file in the GUI, you should try your best to transition from using solely the GUI based process over to doing that same input and output UI element exposing task in a text editor from code.

Sure, the Macro Editor GUI is a comfortable place to start out at but it is worth commenting that the text editor approach to customizing a macro node in the long term will let you do almost anything you can imagine. This means it really is a required step to truly learn and master (Grok?) the macro node input and output element language syntax if you plan on making more then a dozen macros during your Fusion based compositing carreer. This learned skill pays off quickly. :-)
macro-editor-window.png
Editing a Macro By Hand

A macro .setting file, and a Fusion .comp document can both be syntax highlighted in a programmer's text editor as if it was a .Lua script document. Both of these formats are internally representing what is called a Lua table structure that is simply a way of formatting attributes and values.

As far as a recommended programmer's text editor goes for editing Fusion .setting files, I've found Notepad++ on Windows, and BBEdit on macOS to both be excellent and highly customizable tools. If you are a fulltime developer you will obviously have your own personal preferences and might use another tool for the job.

As long as you have a Lua language syntax highlighter module in your text editor you can more easily edit the Fusion macro file as text since it will show you fancy colors that separate values like numbers, from textual elements like expressions or labels in the Macro file which exist as strings inside of either single / double quotes, or double brackets [[]]. The curly braces {} are used in a .setting file to indicate a separation between each Lua table element.

Pay special attention to commas placed at the end of lines when manually editing a Fusion .comp or .setting file as accidentally deleting one will cause you to spend a lot of time troubleshooting the issue. If you are lazy and have botched the editing of a .setting file by deleting an important comma or curly brace, try renaming it to .comp and loading it in Fusion's GUI. This will give you a hint of the error line number in the Fusion Console tab and save you hunting over the text looking for fine details. :-)

If you just want to add several loose nodes to create a macro .setting file that act more like a template to be added back to future Fusion composites exactly as they are now, you don't need to use the Macro Editor GUI and wrap them inside a single macro node MacroOperator or GroupOperator for compactness. You can just go ahead and copy the block of selected nodes from the Flow area into your clipboard buffer.

Then you can paste this text which is stored in the clipboard as a Lua formatted table right into your programmer's text editor and save it with a filename like "YourMacro.setting". If you copy this .setting file to your Fusion user prefs "Macros:/" folder you will be able to add this macro file to your Fusion composites.

A macro is added to your composite using either the Tools > Macros > menu item, the Add Tools window that can be displayed with the Shift + Spacebar hotkey, from a customized entry in your Fusion toolbar, from a hotkey that is configured using either the Fusion Hotkeys Editor, or for hotkey power users by creating a Fusion user prefs based "Config:/" hotkeys.fu file that allows you to map a hotkey to your custom macro or tool. These topics will be explored later so don't worry if you haven't used all of these techniques yet.

If you want to arrange your custom macros, it helps to place them in sub-folders inside the Fusion user prefs "Macros:/" folder. This will make nested sub-menu items when you access them from Fusion's Tools > Macros > menu.

If you want to create a Macro that includes a Loader or a Saver node that an artist is going to link their own media into, it is helpful to remove the text from the Filename field when originally adding the nodes to a macro. This empty Filename field will cause Fusion to show a File browsing dialog as soon as the macro is added by the end artist to your composite.

Auto Resizing Imagery in a Macro

You will have to pick up a few light duty Fusion expression editing skills if you are going to make a macro that is resolution independent and able to respond automatically to the source image dimensions that are fed into the macro node inputs.

To give a quick hint on this topic, you can read the image width and height coming from a node's output in an expression using code like this:

Reading a Loader Node's Image size:

Code: Select all

Loader1.Output.OriginalWidth
Loader1.Output.OriginalHeight

Reading a Merge Node's Image size:

Code: Select all

Merge.Background.OriginalHeight
Merge.Background.OriginalWidth
You can read the size of a specific image connection on a CustomTool node using:

Code: Select all

ImageGridCustomTool.Image1.Width
ImageGridCustomTool.Image1.Height

ImageGridCustomTool.Image2.Width
ImageGridCustomTool.Image2.Height

ImageGridCustomTool.Image2.Width
ImageGridCustomTool.Image2.Height
If you wanted to set a node to use 50% of the image size of your Loader node you would enter an expression like:

Code: Select all

Loader1.Output.OriginalWidth * 0.5
Loader1.Output.OriginalHeight * 0.5
Adding Macro Nodes to the Fusion Bin Window

If you start to create or use dozens of macros in your compositing jobs you might think about adding them to your own custom Fusion Bin folders.

Each macro node is able to have its own Bin icon. This preview image is typically saved as a .bmp format image if you want the macro node to work successfully across Fusion's three supported operating system platforms and if you want the icon to be displayed identically in Fusion versions 7-9 without issues.
macros-in-a-bin-folder.png
The Bin window preview icon likes to have a .bmp format image with a dimension of 130x100 pixels. If your macro node was called "MyMacro.setting" then you would name your thumbnail preview icon image "MyMacro.bmp". This image is saved in the same folder as the macro .setting file.

As a tip to help you save time, since Fusion is able to save out a BMP format image using a Saver node, you can use your Macro node to actually render its own icon with the help of a resize node set to 130x100 pixels. Don't forget to set Fusion's timeline to render only one frame. You will likely have to rename the Fusion rendered preview icon image filename to take off the frame number component so it will match your macro's .setting file naming convention. :-)

This process of using the macro node to generate your own icon file for the macro is great for image filter based nodes that are distorting an image but would probably be less useful for creating more abstract types of macro node icons.

Here is an example that shows how a folder of macro .setting files and a matching set of BMP preview images are named and formatted:
folder-with-setting-and-macro-icons.png
Macro node .setting files are added to a Fusion Bin folder using the right click New > New Item... menu. You would then sort the file browser dialog by file type to clump the .setting files together and select or multi-select the macro node(s) you want to add. The images for the macros will show up automatically in the Bin view when you add a .setting file to the Bin window.

You can also batch drag and drop several macro .setting files from a desktop Explorer/Finder/Nautilus folder window into a Fusion Bin folder view if you find that approach faster.

The classic Fusion "Create Bin from Directory" Lua script can be used to allow you to have macros placed in a shared Bin folder that are accessible across multiple Fusion artists systems. This approach uses a background process called FusionServer to handle the remote shared Bin access requests and can be handy in a workgroup type of configuration. The only downside to shared Bins is you need to be running Fusion Studio on all the systems as shared Bins is a paid Fusion feature. Also setting this feature up requires some additional installation and set up stages to be configured the first time you use this technique

MacroLUTs Work in the Fusion Viewer Windows

A macro node can also be used as a preview LUT in the Fusion Viewer windows. A macro node that is attached and displayed interactively in the Fusion viewer window is called a MacroLUT in Fusion terminology.

When creating a MacroLUT, the macro node only works correctly if you have a single image input and a single image output on the node. You have to take some effort to make sure the effected media in the MacroLUT node is automatically sized to match your source image content that is loaded in the Viewer.

A MacroLUT node's editable controls are shown in the LUT editor window when you select the LUT > Edit... menu item in the Fusion Viewer windows.
macro-lut-edit-prefs.png
MacroLUTs still have the same .setting file extension as a regular macro node. They are simply placed in the Fusion user prefs "LUTs:/" folder. You will likely have to restart your copy of Fusion to see new MacroLUTs appear in the viewer window LUT menu.

MacroLUTS are fast to prepare and enormously helpful but there is one rule to remember: You don't get to resize the image aspect ratio in the viewer window from inside a MacroLUT. The overall size and aspect ratio of the source image fed into the input of your MacroLUT is the same canvas size you are stuck working inside of with a MacroLUT. This input resolution matches what is rendered as the final output to the viewer window context.

You can downsample the imagery inside the macro node tool chain, or add a padded frame border around the content but you don't get to resize/non-proportionately scale MacroLUT effected content so you will have to be happy with the image aspect ratio you started out with at the beginning node input connection point that feeds the Viewer based content into the MacroLUT. :banghead:

Stereo 3D MacroLUTs

A cool tip is that the Fusion Studio stereo viewer mode is applied after a Fusion MacroLUT is rendered in the viewer window.

This is interesting as it means you can use a MacroLUT to prepare/render/adjust your stereo imagery and then it can be displayed in stereo 3D using Fusion's viewer window when you enable the native stereo 3D glasses icon in the viewer toolbar.
macro-z360-stereo-viewer-window-settings.png
An exotic example of this MacroLUT stereo workflow is the KartaVR Z360 StereoLUT I created back in Spring 2017 that allowed a Fusion artist to convert a stereoscopic 6DOF 360/VR style over/under formatted 2D color panoramic image + a greyscale depthmap into a pair of left and right stereo fullcolor images.

This 360° Stereo MacroLUT workflow gives adjustable stereo depth and tunable stereo settings that are editable on the fly without baking in the stereo view rotation until the final playback stage. Very cool stuff from a 360/VR conceptual workflow view. :-)

You can read more about the Z360 Stereo concept behind that tool. I haven't seen anyone else publicly describe these kinds of MacroLUT stereo viewer techniques in Fusion before KartaVR or afterwards. This is a bit advanced of a Fusion topic to discuss here so I will leave it at this comment for now.
macro-z360-stereo.jpg
Let's Get This Macro Building Series Started!

That's likely enough pre-amble before we start the hands on task of building our first custom Macro tools in Fusion. My goal is to explore each of the main macro creation approaches in more detail. I hope you enjoy these tutorials and it should be a fun.

Please hold off really general Fusion macro creation technique questions until after the next two or so posts show up on this thread since they will likely cover the exact beginning steps you are wondering about now. ;)
You do not have the required permissions to view the files attached to this post.
Last edited by AndrewHazelden on Sun May 20, 2018 8:31 am, edited 6 times in total.

User avatar
rebelorelse
Posts: 16
Joined: Sun Sep 06, 2015 3:59 am
Contact:

Re: Macro Building Essentials

#2

Post by rebelorelse » Fri Oct 06, 2017 6:57 pm

Thank you very much for some light on creating macros!

So here is my first macro, it takes to 3:4 images and reveals them in a digital way allowing to change size of the glitches, their own sizes and the position, I have in mind to create a tool that can reveal something like a digital multiscreen and there'll be as many automated animation revealing and obscuring features in as less sliders as possible.
I already have quastions during this making - first any modifiers are eaten when you use 'create macro' from the RMB menu.
the second is can you store S1-S6 presets in a macro, so to have several different working designs of for ex placing of the frames in space, or different offsets in revealing, or some to get different color etc..
  1. {
  2.     Tools = ordered() {
  3.         FaceRecognition_v07 = MacroOperator {
  4.             CtrlWZoom = false,
  5.             Inputs = ordered() {
  6.                 Input1 = InstanceInput {
  7.                     SourceOp = "WirelessLink1_5_4",
  8.                     Source = "Input",
  9.                 },
  10.                 Input2 = InstanceInput {
  11.                     SourceOp = "WirelessLink1_1_4_4",
  12.                     Source = "Input",
  13.                 },
  14.                 Input3 = InstanceInput {
  15.                     SourceOp = "FastNoise1_4_4",
  16.                     Source = "XScale",
  17.                     Default = 2,
  18.                 },
  19.                 Input4 = InstanceInput {
  20.                     SourceOp = "FastNoise1_4_4",
  21.                     Source = "SeetheRate",
  22.                     Default = 0.256,
  23.                 },
  24.                 Input5 = InstanceInput {
  25.                     SourceOp = "ResizeNoise_1",
  26.                     Source = "Width",
  27.                     Default = 11,
  28.                 },
  29.                 Input6 = InstanceInput {
  30.                     SourceOp = "Resize3_5_4",
  31.                     Source = "Width",
  32.                     Default = 1139,
  33.                 },
  34.                 Input7 = InstanceInput {
  35.                     SourceOp = "BrightnessContrast1_5_4",
  36.                     Source = "Brightness",
  37.                     Default = 0,
  38.                 },
  39.                 Input8 = InstanceInput {
  40.                     SourceOp = "BrightnessContrast1_5_4",
  41.                     Source = "Low",
  42.                     ControlGroup = 8,
  43.                     Default = 0.608,
  44.                 },
  45.                 Input9 = InstanceInput {
  46.                     SourceOp = "BrightnessContrast1_5_4",
  47.                     Source = "High",
  48.                     ControlGroup = 8,
  49.                     Default = 1,
  50.                 },
  51.                 Input10 = InstanceInput {
  52.                     SourceOp = "BrightnessContrast1_1_4_4",
  53.                     Source = "Brightness",
  54.                     Expression = "BrightnessContrast1_5_4:GetValue(\"Brightness\",time-RevealOffset)",
  55.                     Default = 0.45,
  56.                 },
  57.                 Input11 = InstanceInput {
  58.                     SourceOp = "ColorCorrector1_4_4",
  59.                     Source = "WheelSaturation1",
  60.                     ControlGroup = 10,
  61.                     Default = 0.4,
  62.                 },
  63.                 Input12 = InstanceInput {
  64.                     SourceOp = "ColorCorrector1_4_4",
  65.                     Source = "WheelTintAngle1",
  66.                     ControlGroup = 10,
  67.                     Default = -0.4657247575602,
  68.                 },
  69.                 Input13 = InstanceInput {
  70.                     SourceOp = "ColorCorrector1_4_4",
  71.                     Source = "WheelTintLength1",
  72.                     ControlGroup = 10,
  73.                     Default = 0.1908,
  74.                 },
  75.                 Input14 = InstanceInput {
  76.                     SourceOp = "Transform2_4_4",
  77.                     Source = "Center",
  78.                     Expression = "Point(Transform1_4_4.Center.X+Transform1_4_4.OffsetX*Size, Transform1_4_4.Center.Y)",
  79.                 },
  80.                 Input15 = InstanceInput {
  81.                     SourceOp = "Transform2_4_4",
  82.                     Source = "Size",
  83.                     Expression = "Transform1_4_4.Size",
  84.                     Default = 0.752,
  85.                 },
  86.                 Input16 = InstanceInput {
  87.                     SourceOp = "Transform1_4_4",
  88.                     Source = "Center",
  89.                 },
  90.                 Input17 = InstanceInput {
  91.                     SourceOp = "Transform1_4_4",
  92.                     Source = "Size",
  93.                     Default = 1,
  94.                 },
  95.                 Input18 = InstanceInput {
  96.                     SourceOp = "Transform1_4_4",
  97.                     Source = "OffsetX",
  98.                     Page = "Controls",
  99.                     Default = 1.128,
  100.                 },
  101.                 Input19 = InstanceInput {
  102.                     SourceOp = "Transform2_6",
  103.                     Source = "Center",
  104.                 },
  105.                 Input20 = InstanceInput {
  106.                     SourceOp = "Transform2_6",
  107.                     Source = "Size",
  108.                     Default = 0.419,
  109.                 }
  110.             },
  111.             Outputs = {
  112.                 MainOutput1 = InstanceOutput {
  113.                     SourceOp = "Transform2_6",
  114.                     Source = "Output",
  115.                 }
  116.             },
  117.             ViewInfo = GroupInfo { Pos = { -385, 280.5 } },
  118.             Tools = ordered() {
  119.                 WirelessLink1_5_4 = Fuse.Wireless {
  120.                     CtrlWShown = false,
  121.                     ViewInfo = OperatorInfo { Pos = { -550, 175.15 } },
  122.                 },
  123.                 WirelessLink1_1_4_4 = Fuse.Wireless {
  124.                     CtrlWShown = false,
  125.                     ViewInfo = OperatorInfo { Pos = { -550, 274.15 } },
  126.                 },
  127.                 BGMaster_4_4 = Background {
  128.                     CtrlWShown = false,
  129.                     NameSet = true,
  130.                     Inputs = {
  131.                         GlobalOut = Input { Value = 215, },
  132.                         Width = Input {
  133.                             Value = 1191,
  134.                             Expression = "Resize3_5_4.Output.OriginalWidth*mlt",
  135.                         },
  136.                         Height = Input {
  137.                             Value = 1588,
  138.                             Expression = "Resize3_5_4.Output.OriginalHeight*mlt",
  139.                         },
  140.                         ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
  141.                         Type = Input { Value = FuID { "Gradient" }, },
  142.                         TopLeftRed = Input { Value = 0.053, },
  143.                         TopLeftGreen = Input { Value = 0.133, },
  144.                         TopLeftBlue = Input { Value = 0.301, },
  145.                         TopLeftAlpha = Input { Value = 0.55, },
  146.                         GradientType = Input { Value = FuID { "Radial" }, },
  147.                         Start = Input { Value = { 0.5, 0.5 }, },
  148.                         Gradient = Input {
  149.                             Value = Gradient {
  150.                                 Colors = {
  151.                                     [0] = { 1, 1, 1, 1 },
  152.                                     [1] = { 0, 0, 0, 1 }
  153.                                 }
  154.                             },
  155.                         },
  156.                     },
  157.                     ViewInfo = OperatorInfo { Pos = { -330, 43.15 } },
  158.                     UserControls = ordered() {
  159.                         Diveder = {
  160.                             INP_MaxAllowed = 4,
  161.                             INP_Integer = false,
  162.                             INPID_InputControl = "SliderControl",
  163.                             INP_MaxScale = 4,
  164.                             INP_Default = 0,
  165.                             INP_MinScale = 0,
  166.                             INP_MinAllowed = 0,
  167.                             LINKID_DataType = "Number",
  168.                             ICS_ControlPage = "Image",
  169.                             LINKS_Name = "Depth"
  170.                         },
  171.                         mlt = {
  172.                             INP_MaxAllowed = 1000000,
  173.                             INP_Integer = false,
  174.                             INPID_InputControl = "SliderControl",
  175.                             INP_MaxScale = 1,
  176.                             INP_Default = 1,
  177.                             INP_MinScale = 0,
  178.                             INP_MinAllowed = -1000000,
  179.                             LINKID_DataType = "Number",
  180.                             ICS_ControlPage = "Image",
  181.                             LINKS_Name = "Mlt"
  182.                         }
  183.                     }
  184.                 },
  185.                 FastNoise1_4_4 = FastNoise {
  186.                     CtrlWShown = false,
  187.                     Inputs = {
  188.                         GlobalOut = Input { Value = 215, },
  189.                         Width = Input {
  190.                             Value = 1191,
  191.                             Expression = "BGMaster_4_4.Output.OriginalWidth",
  192.                         },
  193.                         Height = Input {
  194.                             Value = 1588,
  195.                             Expression = "BGMaster_4_4.Output.OriginalHeight",
  196.                         },
  197.                         ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
  198.                         Discontinuous = Input { Value = 1, },
  199.                         SeetheRate = Input { Value = 0.256, },
  200.                     },
  201.                     ViewInfo = OperatorInfo { Pos = { -330, 10.15 } },
  202.                 },
  203.                 Polygon1_1_4_4 = PolylineMask {
  204.                     ShowHandles = false,
  205.                     DrawMode = "InsertAndModify",
  206.                     DrawMode2 = "InsertAndModify",
  207.                     CtrlWShown = false,
  208.                     Inputs = {
  209.                         BorderWidth = Input { Value = -0.0342, },
  210.                         PaintMode = Input { Value = FuID { "Subtract" }, },
  211.                         MaskWidth = Input { Value = 1920, },
  212.                         MaskHeight = Input { Value = 1080, },
  213.                         PixelAspect = Input { Value = { 1, 1 }, },
  214.                         ClippingMode = Input { Value = FuID { "None" }, },
  215.                         Polyline = Input {
  216.                             SourceOp = "Polygon1_1_4_4Polyline",
  217.                             Source = "Value",
  218.                         },
  219.                         Polyline2 = Input {
  220.                             Value = Polyline {
  221.                             },
  222.                             Disabled = true,
  223.                         },
  224.                         EffectMask = Input {
  225.                             SourceOp = "Polygon1_5_4",
  226.                             Source = "Mask",
  227.                         }
  228.                     },
  229.                     ViewInfo = OperatorInfo { Pos = { -330, 274.15 } },
  230.                 },
  231.                 Polygon1_1_4_4Polyline = BezierSpline {
  232.                     SplineColor = { Red = 173, Green = 255, Blue = 47 },
  233.                     CtrlWShown = false,
  234.                     NameSet = true,
  235.                     KeyFrames = {
  236.                         [5] = { 0, Flags = { Linear = true, LockedY = true }, Value = Polyline {
  237.                                 Closed = true,
  238.                                 Points = {
  239.                                     { Linear = true, X = -0.43, Y = 0.417293233082707, LX = -1.85037170770859e-017, LY = -0.278195488721805, RX = 0.01, RY = 0.0075187969924812 },
  240.                                     { Linear = true, X = -0.4, Y = 0.43984962406015, LX = -0.01, LY = -0.0075187969924812, RX = 0.05, RY = 1.85037170770859e-017 },
  241.                                     { Linear = true, X = -0.25, Y = 0.43984962406015, LX = -0.05, LY = -1.85037170770859e-017, RX = 0.00333333333333335, RY = 0.00250626566416038 },
  242.                                     { Linear = true, X = -0.24, Y = 0.447368421052632, LX = -0.00333333333333335, LY = -0.00250626566416038, RX = 0.08, RY = -1.85037170770859e-017 },
  243.                                     { Linear = true, X = 0, Y = 0.447368421052632, LX = -0.08, LY = 1.85037170770859e-017, RX = 0.0833333333333333, RY = 0 },
  244.                                     { Linear = true, X = 0.25, Y = 0.447368421052632, LX = -0.0833333333333333, LY = 0, RX = 0.00333333333333334, RY = -0.00250626566416038 },
  245.                                     { Linear = true, X = 0.26, Y = 0.43984962406015, LX = -0.00333333333333334, LY = 0.00250626566416038, RX = 0.0466666666666667, RY = 0 },
  246.                                     { Linear = true, X = 0.4, Y = 0.43984962406015, LX = -0.0466666666666667, LY = 0, RX = 0.01, RY = -0.00751879699248122 },
  247.                                     { Linear = true, X = 0.43, Y = 0.417293233082707, LX = -0.01, LY = 0.00751879699248122, RX = 0, RY = -0.278195488721804 },
  248.                                     { Linear = true, X = 0.43, Y = -0.417293233082707, LX = 0, LY = 0.278195488721804, RX = -0.00999999999999999, RY = -0.0075187969924812 },
  249.                                     { Linear = true, X = 0.4, Y = -0.43984962406015, LX = 0.00999999999999999, LY = 0.0075187969924812, RX = -0.0466666666666667, RY = 0 },
  250.                                     { Linear = true, X = 0.26, Y = -0.43984962406015, LX = 0.0466666666666667, LY = 0, RX = -0.00333333333333334, RY = -0.0025062656641604 },
  251.                                     { Linear = true, X = 0.25, Y = -0.447368421052632, LX = 0.00333333333333334, LY = 0.0025062656641604, RX = -0.163333333333333, RY = 0 },
  252.                                     { Linear = true, X = -0.24, Y = -0.447368421052632, LX = 0.163333333333333, LY = 0, RX = -0.00333333333333332, RY = 0.0025062656641604 },
  253.                                     { Linear = true, X = -0.25, Y = -0.43984962406015, LX = 0.00333333333333332, LY = -0.0025062656641604, RX = -0.05, RY = 0 },
  254.                                     { Linear = true, X = -0.4, Y = -0.43984962406015, LX = 0.05, LY = 0, RX = -0.01, RY = 0.00751879699248118 },
  255.                                     { Linear = true, X = -0.43, Y = -0.417293233082707, LX = 0.01, LY = -0.00751879699248118, RX = 1.85037170770859e-017, RY = 0.278195488721805 }
  256.                                 }
  257.                             } }
  258.                     }
  259.                 },
  260.                 Polygon1_5_4 = PolylineMask {
  261.                     ShowHandles = false,
  262.                     DrawMode = "InsertAndModify",
  263.                     DrawMode2 = "InsertAndModify",
  264.                     CtrlWShown = false,
  265.                     Inputs = {
  266.                         MaskWidth = Input { Value = 1920, },
  267.                         MaskHeight = Input { Value = 1080, },
  268.                         PixelAspect = Input { Value = { 1, 1 }, },
  269.                         ClippingMode = Input { Value = FuID { "None" }, },
  270.                         Polyline = Input {
  271.                             SourceOp = "Polygon1_5_4Polyline",
  272.                             Source = "Value",
  273.                         },
  274.                         Polyline2 = Input {
  275.                             Value = Polyline {
  276.                             },
  277.                             Disabled = true,
  278.                         },
  279.                     },
  280.                     ViewInfo = OperatorInfo { Pos = { -330, 241.15 } },
  281.                 },
  282.                 Polygon1_5_4Polyline = BezierSpline {
  283.                     SplineColor = { Red = 173, Green = 255, Blue = 47 },
  284.                     CtrlWShown = false,
  285.                     NameSet = true,
  286.                     KeyFrames = {
  287.                         [5] = { 0, Flags = { Linear = true, LockedY = true }, Value = Polyline {
  288.                                 Closed = true,
  289.                                 Points = {
  290.                                     { Linear = true, X = -0.43, Y = 0.417293233082707, LX = -1.85037170770859e-017, LY = -0.278195488721805, RX = 0.01, RY = 0.0075187969924812 },
  291.                                     { Linear = true, X = -0.4, Y = 0.43984962406015, LX = -0.01, LY = -0.0075187969924812, RX = 0.05, RY = 1.85037170770859e-017 },
  292.                                     { Linear = true, X = -0.25, Y = 0.43984962406015, LX = -0.05, LY = -1.85037170770859e-017, RX = 0.00333333333333335, RY = 0.00250626566416038 },
  293.                                     { Linear = true, X = -0.24, Y = 0.447368421052632, LX = -0.00333333333333335, LY = -0.00250626566416038, RX = 0.08, RY = -1.85037170770859e-017 },
  294.                                     { Linear = true, X = 0, Y = 0.447368421052632, LX = -0.08, LY = 1.85037170770859e-017, RX = 0.0833333333333333, RY = 0 },
  295.                                     { Linear = true, X = 0.25, Y = 0.447368421052632, LX = -0.0833333333333333, LY = 0, RX = 0.00333333333333334, RY = -0.00250626566416038 },
  296.                                     { Linear = true, X = 0.26, Y = 0.43984962406015, LX = -0.00333333333333334, LY = 0.00250626566416038, RX = 0.0466666666666667, RY = 0 },
  297.                                     { Linear = true, X = 0.4, Y = 0.43984962406015, LX = -0.0466666666666667, LY = 0, RX = 0.01, RY = -0.00751879699248122 },
  298.                                     { Linear = true, X = 0.43, Y = 0.417293233082707, LX = -0.01, LY = 0.00751879699248122, RX = 0, RY = -0.278195488721804 },
  299.                                     { Linear = true, X = 0.43, Y = -0.417293233082707, LX = 0, LY = 0.278195488721804, RX = -0.00999999999999999, RY = -0.0075187969924812 },
  300.                                     { Linear = true, X = 0.4, Y = -0.43984962406015, LX = 0.00999999999999999, LY = 0.0075187969924812, RX = -0.0466666666666667, RY = 0 },
  301.                                     { Linear = true, X = 0.26, Y = -0.43984962406015, LX = 0.0466666666666667, LY = 0, RX = -0.00333333333333334, RY = -0.0025062656641604 },
  302.                                     { Linear = true, X = 0.25, Y = -0.447368421052632, LX = 0.00333333333333334, LY = 0.0025062656641604, RX = -0.163333333333333, RY = 0 },
  303.                                     { Linear = true, X = -0.24, Y = -0.447368421052632, LX = 0.163333333333333, LY = 0, RX = -0.00333333333333332, RY = 0.0025062656641604 },
  304.                                     { Linear = true, X = -0.25, Y = -0.43984962406015, LX = 0.00333333333333332, LY = -0.0025062656641604, RX = -0.05, RY = 0 },
  305.                                     { Linear = true, X = -0.4, Y = -0.43984962406015, LX = 0.05, LY = 0, RX = -0.01, RY = 0.00751879699248118 },
  306.                                     { Linear = true, X = -0.43, Y = -0.417293233082707, LX = 0.01, LY = -0.00751879699248118, RX = 1.85037170770859e-017, RY = 0.278195488721805 }
  307.                                 }
  308.                             } }
  309.                     }
  310.                 },
  311.                 Merge8_4_4 = Merge {
  312.                     CtrlWShown = false,
  313.                     Inputs = {
  314.                         Background = Input {
  315.                             SourceOp = "BGMaster_4_4",
  316.                             Source = "Output",
  317.                         },
  318.                         Foreground = Input {
  319.                             SourceOp = "FastNoise1_4_4",
  320.                             Source = "Output",
  321.                         },
  322.                         PerformDepthMerge = Input { Value = 0, },
  323.                     },
  324.                     ViewInfo = OperatorInfo { Pos = { -220, 76.15 } },
  325.                 },
  326.                 Merge7_4_4 = Merge {
  327.                     CtrlWShown = false,
  328.                     Inputs = {
  329.                         Background = Input {
  330.                             SourceOp = "Background7_16_1_1_1_1_4_4",
  331.                             Source = "Output",
  332.                         },
  333.                         Foreground = Input {
  334.                             SourceOp = "WirelessLink1_5_4",
  335.                             Source = "Output",
  336.                         },
  337.                         PerformDepthMerge = Input { Value = 0, },
  338.                         EffectMask = Input {
  339.                             SourceOp = "Polygon1_5_4",
  340.                             Source = "Mask",
  341.                         }
  342.                     },
  343.                     ViewInfo = OperatorInfo { Pos = { -165, 175.15 } },
  344.                 },
  345.                 Background7_16_1_1_1_5_5 = Background {
  346.                     CtrlWShown = false,
  347.                     Inputs = {
  348.                         GlobalOut = Input { Value = 215, },
  349.                         Width = Input {
  350.                             Value = 1191,
  351.                             Expression = "Resize3_5_4.Output.OriginalWidth*mlt",
  352.                         },
  353.                         Height = Input {
  354.                             Value = 1588,
  355.                             Expression = "Resize3_5_4.Output.OriginalHeight*mlt",
  356.                         },
  357.                         ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
  358.                         TopLeftRed = Input { Value = 0.053, },
  359.                         TopLeftGreen = Input { Value = 0.133, },
  360.                         TopLeftBlue = Input { Value = 0.301, },
  361.                         TopLeftAlpha = Input { Value = 0.55, },
  362.                         EffectMask = Input {
  363.                             SourceOp = "Polygon1_1_4_4",
  364.                             Source = "Mask",
  365.                         }
  366.                     },
  367.                     ViewInfo = OperatorInfo { Pos = { -165, 307.15 } },
  368.                     UserControls = ordered() {
  369.                         Diveder = {
  370.                             INP_MaxAllowed = 4,
  371.                             INP_Integer = false,
  372.                             INPID_InputControl = "SliderControl",
  373.                             INP_MaxScale = 4,
  374.                             INP_Default = 0,
  375.                             INP_MinScale = 0,
  376.                             INP_MinAllowed = 0,
  377.                             LINKID_DataType = "Number",
  378.                             ICS_ControlPage = "Image",
  379.                             LINKS_Name = "Depth"
  380.                         },
  381.                         mlt = {
  382.                             INP_MaxAllowed = 1000000,
  383.                             INP_Integer = false,
  384.                             INPID_InputControl = "SliderControl",
  385.                             INP_MaxScale = 1,
  386.                             INP_Default = 1,
  387.                             INP_MinScale = 0,
  388.                             INP_MinAllowed = -1000000,
  389.                             LINKID_DataType = "Number",
  390.                             ICS_ControlPage = "Image",
  391.                             LINKS_Name = "Mlt"
  392.                         }
  393.                     }
  394.                 },
  395.                 Background7_16_1_1_1_1_4_4 = Background {
  396.                     CtrlWShown = false,
  397.                     Inputs = {
  398.                         GlobalOut = Input { Value = 215, },
  399.                         Width = Input {
  400.                             Value = 2659,
  401.                             Expression = "WirelessLink1_5_4.Output.OriginalWidth*mlt",
  402.                         },
  403.                         Height = Input {
  404.                             Value = 3546,
  405.                             Expression = "WirelessLink1_5_4.Output.OriginalHeight*mlt",
  406.                         },
  407.                         ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
  408.                         TopLeftAlpha = Input { Value = 0, },
  409.                         mlt = Input { Value = 1.0131, },
  410.                     },
  411.                     ViewInfo = OperatorInfo { Pos = { -165, 241.15 } },
  412.                     UserControls = ordered() {
  413.                         Diveder = {
  414.                             INP_MaxAllowed = 4,
  415.                             INP_Integer = false,
  416.                             INPID_InputControl = "SliderControl",
  417.                             INP_MaxScale = 4,
  418.                             INP_Default = 0,
  419.                             INP_MinScale = 0,
  420.                             INP_MinAllowed = 0,
  421.                             LINKID_DataType = "Number",
  422.                             ICS_ControlPage = "Image",
  423.                             LINKS_Name = "Depth"
  424.                         },
  425.                         mlt = {
  426.                             INP_MaxAllowed = 1000000,
  427.                             INP_Integer = false,
  428.                             INPID_InputControl = "SliderControl",
  429.                             INP_MaxScale = 1,
  430.                             INP_Default = 1,
  431.                             INP_MinScale = 0,
  432.                             INP_MinAllowed = -1000000,
  433.                             LINKID_DataType = "Number",
  434.                             ICS_ControlPage = "Image",
  435.                             LINKS_Name = "Mlt"
  436.                         }
  437.                     }
  438.                 },
  439.                 Background7_16_1_1_1_5_2_3 = Background {
  440.                     CtrlWShown = false,
  441.                     Inputs = {
  442.                         GlobalOut = Input { Value = 215, },
  443.                         Width = Input {
  444.                             Value = 1191,
  445.                             Expression = "Resize3_5_4.Output.OriginalWidth*mlt",
  446.                         },
  447.                         Height = Input {
  448.                             Value = 1588,
  449.                             Expression = "Resize3_5_4.Output.OriginalHeight*mlt",
  450.                         },
  451.                         ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
  452.                         TopLeftAlpha = Input { Value = 0, },
  453.                     },
  454.                     ViewInfo = OperatorInfo { Pos = { -110, 208.15 } },
  455.                     UserControls = ordered() {
  456.                         Diveder = {
  457.                             INP_MaxAllowed = 4,
  458.                             INP_Integer = false,
  459.                             INPID_InputControl = "SliderControl",
  460.                             INP_MaxScale = 4,
  461.                             INP_Default = 0,
  462.                             INP_MinScale = 0,
  463.                             INP_MinAllowed = 0,
  464.                             LINKID_DataType = "Number",
  465.                             ICS_ControlPage = "Image",
  466.                             LINKS_Name = "Depth"
  467.                         },
  468.                         mlt = {
  469.                             INP_MaxAllowed = 1000000,
  470.                             INP_Integer = false,
  471.                             INPID_InputControl = "SliderControl",
  472.                             INP_MaxScale = 1,
  473.                             INP_Default = 1,
  474.                             INP_MinScale = 0,
  475.                             INP_MinAllowed = -1000000,
  476.                             LINKID_DataType = "Number",
  477.                             ICS_ControlPage = "Image",
  478.                             LINKS_Name = "Mlt"
  479.                         }
  480.                     }
  481.                 },
  482.                 ResizeNoise_1 = BetterResize {
  483.                     CtrlWShown = false,
  484.                     NameSet = true,
  485.                     Inputs = {
  486.                         Width = Input { Value = 29, },
  487.                         Height = Input { Value = 39, },
  488.                         KeepAspect = Input { Value = 1, },
  489.                         PixelAspect = Input { Value = { 1, 1 }, },
  490.                         FilterMethod = Input { Value = 0, },
  491.                         Input = Input {
  492.                             SourceOp = "Merge8_4_4",
  493.                             Source = "Output",
  494.                         },
  495.                     },
  496.                     ViewInfo = OperatorInfo { Pos = { -110, 76.15 } },
  497.                 },
  498.                 Merge6_4_4 = Merge {
  499.                     CtrlWShown = false,
  500.                     Inputs = {
  501.                         Background = Input {
  502.                             SourceOp = "Background7_16_1_1_1_1_4_4",
  503.                             Source = "Output",
  504.                         },
  505.                         Foreground = Input {
  506.                             SourceOp = "WirelessLink1_1_4_4",
  507.                             Source = "Output",
  508.                         },
  509.                         PerformDepthMerge = Input { Value = 0, },
  510.                         EffectMask = Input {
  511.                             SourceOp = "Polygon1_5_4",
  512.                             Source = "Mask",
  513.                         }
  514.                     },
  515.                     ViewInfo = OperatorInfo { Pos = { -110, 274.15 } },
  516.                 },
  517.                 Resize3_5_4 = BetterResize {
  518.                     CtrlWShown = false,
  519.                     Inputs = {
  520.                         Width = Input { Value = 1191, },
  521.                         Height = Input { Value = 1588, },
  522.                         KeepAspect = Input { Value = 1, },
  523.                         PixelAspect = Input { Value = { 1, 1 }, },
  524.                         Input = Input {
  525.                             SourceOp = "Merge7_4_4",
  526.                             Source = "Output",
  527.                         },
  528.                     },
  529.                     ViewInfo = OperatorInfo { Pos = { -55, 175.15 } },
  530.                 },
  531.                 Merge4_4_4 = Merge {
  532.                     CtrlWShown = false,
  533.                     Inputs = {
  534.                         Background = Input {
  535.                             SourceOp = "Background7_16_1_1_1_5_2_3",
  536.                             Source = "Output",
  537.                         },
  538.                         Foreground = Input {
  539.                             SourceOp = "Instance_Resize3_4_4",
  540.                             Source = "Output",
  541.                         },
  542.                         PerformDepthMerge = Input { Value = 0, },
  543.                         EffectMask = Input {
  544.                             SourceOp = "Ranges1_1_4_4",
  545.                             Source = "Mask",
  546.                         }
  547.                     },
  548.                     ViewInfo = OperatorInfo { Pos = { 0, 340.15 } },
  549.                 },
  550.                 Resize3_1_1_4_4 = BetterResize {
  551.                     CtrlWShown = false,
  552.                     Inputs = {
  553.                         Width = Input {
  554.                             Value = 1429,
  555.                             Expression = "Resize3_5_4.Width*1.2",
  556.                         },
  557.                         Height = Input { Value = 1922, },
  558.                         KeepAspect = Input { Value = 1, },
  559.                         PixelAspect = Input { Value = { 1, 1 }, },
  560.                         FilterMethod = Input { Value = 0, },
  561.                         Input = Input {
  562.                             SourceOp = "ResizeNoise_1",
  563.                             Source = "Output",
  564.                         },
  565.                     },
  566.                     ViewInfo = OperatorInfo { Pos = { 0, 43.15 } },
  567.                 },
  568.                 Instance_Resize3_4_4 = BetterResize {
  569.                     CtrlWShown = false,
  570.                     SourceOp = "Resize3_5_4",
  571.                     Inputs = {
  572.                         ResetSize = Input { },
  573.                         Input = Input {
  574.                             SourceOp = "Merge6_4_4",
  575.                             Source = "Output",
  576.                         },
  577.                         StartEndRenderScripts = Input { },
  578.                     },
  579.                     ViewInfo = OperatorInfo { Pos = { 0, 274.15 } },
  580.                 },
  581.                 Merge3_4_4 = Merge {
  582.                     CtrlWShown = false,
  583.                     Inputs = {
  584.                         Background = Input {
  585.                             SourceOp = "Background7_16_1_1_1_5_2_3",
  586.                             Source = "Output",
  587.                         },
  588.                         Foreground = Input {
  589.                             SourceOp = "Resize3_5_4",
  590.                             Source = "Output",
  591.                         },
  592.                         PerformDepthMerge = Input { Value = 0, },
  593.                         EffectMask = Input {
  594.                             SourceOp = "Ranges1_5_4",
  595.                             Source = "Mask",
  596.                         }
  597.                     },
  598.                     ViewInfo = OperatorInfo { Pos = { 55, 175.15 } },
  599.                 },
  600.                 Ranges1_5_4 = RangesMask {
  601.                     CtrlWShown = false,
  602.                     Inputs = {
  603.                         Invert = Input { Value = 1, },
  604.                         MaskWidth = Input { Value = 1920, },
  605.                         MaskHeight = Input { Value = 1080, },
  606.                         PixelAspect = Input { Value = { 1, 1 }, },
  607.                         ClippingMode = Input { Value = FuID { "None" }, },
  608.                         Image = Input {
  609.                             SourceOp = "BrightnessContrast1_5_4",
  610.                             Source = "Output",
  611.                         },
  612.                         ColorRanges = Input {
  613.                             Value = ColorCurves {
  614.                                 Curves = {
  615.                                     {
  616.                                         Points = {
  617.                                             { 0.273, 1 },
  618.                                             { 0.5638, 0.2 },
  619.                                             { 0.7092, 0 },
  620.                                             { 1, 0 }
  621.                                         }
  622.                                     },
  623.                                     {
  624.                                         Points = {
  625.                                             { 0, 0 },
  626.                                             { 0.4, 0 },
  627.                                             { 0.356, 1 },
  628.                                             { 1, 1 }
  629.                                         }
  630.                                     }
  631.                                 }
  632.                             },
  633.                         },
  634.                     },
  635.                     ViewInfo = OperatorInfo { Pos = { 55, 76.15 } },
  636.                 },
  637.                 Transform3_3 = Transform {
  638.                     CtrlWShown = false,
  639.                     Inputs = {
  640.                         Size = Input { Value = 2, },
  641.                         Input = Input {
  642.                             SourceOp = "Ranges1_5_4",
  643.                             Source = "Mask",
  644.                         },
  645.                     },
  646.                     ViewInfo = OperatorInfo { Pos = { 110, 109.15 } },
  647.                 },
  648.                 BrightnessContrast1_5_4 = BrightnessContrast {
  649.                     CtrlWShown = false,
  650.                     Inputs = {
  651.                         Brightness = Input {
  652.                             SourceOp = "BrightnessContrast1_5_4Brightness",
  653.                             Source = "Value",
  654.                         },
  655.                         Low = Input { Value = 0.515, },
  656.                         Input = Input {
  657.                             SourceOp = "Resize3_1_1_4_4",
  658.                             Source = "Output",
  659.                         },
  660.                     },
  661.                     ViewInfo = OperatorInfo { Pos = { 110, 10.15 } },
  662.                 },
  663.                 BrightnessContrast1_5_4Brightness = BezierSpline {
  664.                     SplineColor = { Red = 27, Green = 111, Blue = 232 },
  665.                     CtrlWShown = false,
  666.                     NameSet = true,
  667.                     KeyFrames = {
  668.                         [2] = { -0.487, RH = { 11.3333333333333, -0.174666666666667 }, Flags = { Linear = true } },
  669.                         [30] = { 0.45, LH = { 20.6666666666667, 0.137666666666667 }, Flags = { Linear = true } }
  670.                     }
  671.                 },
  672.                 Merge10_4_4 = Merge {
  673.                     CtrlWShown = false,
  674.                     Inputs = {
  675.                         Background = Input {
  676.                             SourceOp = "Merge4_4_4",
  677.                             Source = "Output",
  678.                         },
  679.                         Foreground = Input {
  680.                             SourceOp = "Background7_16_1_1_1_5_5",
  681.                             Source = "Output",
  682.                         },
  683.                         PerformDepthMerge = Input { Value = 0, },
  684.                         EffectMask = Input {
  685.                             SourceOp = "Instance_Transform3_3",
  686.                             Source = "Output",
  687.                         }
  688.                     },
  689.                     ViewInfo = OperatorInfo { Pos = { 110, 340.15 } },
  690.                 },
  691.                 Merge9_4_4 = Merge {
  692.                     CtrlWShown = false,
  693.                     Inputs = {
  694.                         Background = Input {
  695.                             SourceOp = "Merge3_4_4",
  696.                             Source = "Output",
  697.                         },
  698.                         Foreground = Input {
  699.                             SourceOp = "Background7_16_1_1_1_5_5",
  700.                             Source = "Output",
  701.                         },
  702.                         PerformDepthMerge = Input { Value = 0, },
  703.                         EffectMask = Input {
  704.                             SourceOp = "Transform3_3",
  705.                             Source = "Output",
  706.                         }
  707.                     },
  708.                     ViewInfo = OperatorInfo { Pos = { 165, 175.15 } },
  709.                 },
  710.                 Instance_Transform3_3 = Transform {
  711.                     CtrlWShown = false,
  712.                     SourceOp = "Transform3_3",
  713.                     Inputs = {
  714.                         ReferenceSize = Input { },
  715.                         Input = Input {
  716.                             SourceOp = "Ranges1_1_4_4",
  717.                             Source = "Mask",
  718.                         },
  719.                         StartEndRenderScripts = Input { },
  720.                         EffectMask = Input { }
  721.                     },
  722.                     ViewInfo = OperatorInfo { Pos = { 165, 241.15 } },
  723.                 },
  724.                 TimeSpeed2_1 = TimeSpeed {
  725.                     PassThrough = true,
  726.                     CtrlWShown = false,
  727.                     Inputs = {
  728.                         Delay = Input { Value = 4, },
  729.                         InterpolateBetweenFrames = Input { Value = 0, },
  730.                         SampleSpread = Input { Disabled = true, },
  731.                         Input = Input {
  732.                             SourceOp = "Transform1_5",
  733.                             Source = "Output",
  734.                         },
  735.                     },
  736.                     ViewInfo = OperatorInfo { Pos = { 220, 109.15 } },
  737.                 },
  738.                 BrightnessContrast1_1_4_4 = BrightnessContrast {
  739.                     CtrlWShown = false,
  740.                     Inputs = {
  741.                         Brightness = Input {
  742.                             Value = 0.45,
  743.                             Expression = "BrightnessContrast1_5_4:GetValue(\"Brightness\",time-RevealOffset)",
  744.                         },
  745.                         Low = Input {
  746.                             Value = 0.515,
  747.                             Expression = "BrightnessContrast1_5_4.Low",
  748.                         },
  749.                         High = Input { Expression = "BrightnessContrast1_5_4.High", },
  750.                         Input = Input {
  751.                             SourceOp = "Resize3_1_1_4_4",
  752.                             Source = "Output",
  753.                         },
  754.                         RevealOffset = Input { Value = 6, },
  755.                     },
  756.                     ViewInfo = OperatorInfo { Pos = { 220, 43.15 } },
  757.                     UserControls = ordered() {
  758.                         RevealOffset = {
  759.                             INP_Integer = false,
  760.                             LINKID_DataType = "Number",
  761.                             LINKS_Name = "RevealOffset",
  762.                             INPID_InputControl = "SliderControl",
  763.                             ICS_ControlPage = "Controls",
  764.                             INP_Default = 2
  765.                         }
  766.                     }
  767.                 },
  768.                 Instance_ColorCorrector1_4_4 = ColorCorrector {
  769.                     CtrlWShown = false,
  770.                     SourceOp = "ColorCorrector1_4_4",
  771.                     Inputs = {
  772.                         SnapshotMatch = Input { },
  773.                         ReleaseMatch = Input { },
  774.                         MatchNest = Input { },
  775.                         ResetAllHistogramChanges = Input { },
  776.                         ResetAllColorChanges = Input { },
  777.                         ResetAllLevels = Input { },
  778.                         ResetAllSuppression = Input { },
  779.                         PresetSimpleRanges = Input { },
  780.                         PresetSmoothRanges = Input { },
  781.                         Input = Input {
  782.                             SourceOp = "Merge10_4_4",
  783.                             Source = "Output",
  784.                         },
  785.                         MatchReference = Input { },
  786.                         StartEndRenderScripts = Input { },
  787.                         EffectMask = Input { },
  788.                         MatchMask = Input { }
  789.                     },
  790.                     ViewInfo = OperatorInfo { Pos = { 220, 340.15 } },
  791.                 },
  792.                 Transform1_5 = Transform {
  793.                     CtrlWShown = false,
  794.                     Inputs = {
  795.                         FlipVert = Input { Value = 1, },
  796.                         Input = Input {
  797.                             SourceOp = "BrightnessContrast1_1_4_4",
  798.                             Source = "Output",
  799.                         },
  800.                     },
  801.                     ViewInfo = OperatorInfo { Pos = { 220, 76.15 } },
  802.                 },
  803.                 Ranges1_1_4_4 = RangesMask {
  804.                     CtrlWShown = false,
  805.                     Inputs = {
  806.                         Invert = Input { Value = 1, },
  807.                         MaskWidth = Input { Value = 1920, },
  808.                         MaskHeight = Input { Value = 1080, },
  809.                         PixelAspect = Input { Value = { 1, 1 }, },
  810.                         ClippingMode = Input { Value = FuID { "None" }, },
  811.                         Image = Input {
  812.                             SourceOp = "TimeSpeed2_1",
  813.                             Source = "Output",
  814.                         },
  815.                         ColorRanges = Input {
  816.                             Value = ColorCurves {
  817.                                 Curves = {
  818.                                     {
  819.                                         Points = {
  820.                                             { 0.273, 1 },
  821.                                             { 0.5638, 0.2 },
  822.                                             { 0.7092, 0 },
  823.                                             { 1, 0 }
  824.                                         }
  825.                                     },
  826.                                     {
  827.                                         Points = {
  828.                                             { 0, 0 },
  829.                                             { 0.4, 0 },
  830.                                             { 0.356, 1 },
  831.                                             { 1, 1 }
  832.                                         }
  833.                                     }
  834.                                 }
  835.                             },
  836.                         },
  837.                     },
  838.                     ViewInfo = OperatorInfo { Pos = { 220, 142.15 } },
  839.                 },
  840.                 ColorCorrector1_4_4 = ColorCorrector {
  841.                     CtrlWShown = false,
  842.                     Inputs = {
  843.                         ProcessAlpha = Input { Value = 0, },
  844.                         WheelSaturation1 = Input { Value = 0.4, },
  845.                         WheelTintAngle1 = Input { Value = -0.4657247575602, },
  846.                         WheelTintLength1 = Input { Value = 0.1908, },
  847.                         MasterRGBGain = Input { Value = 0.538, },
  848.                         MasterRGBGamma = Input { Value = 2.026, },
  849.                         ColorRanges = Input {
  850.                             Value = ColorCurves {
  851.                                 Curves = {
  852.                                     {
  853.                                         Points = {
  854.                                             { 0, 1 },
  855.                                             { 0.4, 0.2 },
  856.                                             { 0.6, 0 },
  857.                                             { 1, 0 }
  858.                                         }
  859.                                     },
  860.                                     {
  861.                                         Points = {
  862.                                             { 0, 0 },
  863.                                             { 0.4, 0 },
  864.                                             { 0.6, 0.2 },
  865.                                             { 1, 1 }
  866.                                         }
  867.                                     }
  868.                                 }
  869.                             },
  870.                         },
  871.                         HistogramIgnoreTransparent = Input { Value = 1, },
  872.                         Input = Input {
  873.                             SourceOp = "Merge9_4_4",
  874.                             Source = "Output",
  875.                         },
  876.                     },
  877.                     ViewInfo = OperatorInfo { Pos = { 275, 175.15 } },
  878.                 },
  879.                 Transform2_4_4 = Transform {
  880.                     CtrlWShown = false,
  881.                     Inputs = {
  882.                         Center = Input {
  883.                             Value = { 1.748486, 1.01296296296296 },
  884.                             Expression = "Point(Transform1_4_4.Center.X+Transform1_4_4.OffsetX*Size, Transform1_4_4.Center.Y)",
  885.                         },
  886.                         Size = Input {
  887.                             Value = 1.444,
  888.                             Expression = "Transform1_4_4.Size",
  889.                         },
  890.                         Input = Input {
  891.                             SourceOp = "Instance_ColorCorrector1_4_4",
  892.                             Source = "Output",
  893.                         },
  894.                     },
  895.                     ViewInfo = OperatorInfo { Pos = { 385, 340.15 } },
  896.                 },
  897.                 Transform1_4_4 = Transform {
  898.                     CtrlWShown = false,
  899.                     Inputs = {
  900.                         Center = Input { Value = { 0.16875, 1.01296296296296 }, },
  901.                         Size = Input { Value = 1.444, },
  902.                         Input = Input {
  903.                             SourceOp = "ColorCorrector1_4_4",
  904.                             Source = "Output",
  905.                         },
  906.                         OffsetX = Input { Value = 1.094, },
  907.                     },
  908.                     ViewInfo = OperatorInfo { Pos = { 385, 175.15 } },
  909.                     UserControls = ordered() {
  910.                         OffsetX = {
  911.                             INP_Integer = false,
  912.                             LINKID_DataType = "Number",
  913.                             LINKS_Name = "OffsetX",
  914.                             INPID_InputControl = "SliderControl",
  915.                             ICS_ControlPage = "Controls",
  916.                             INP_Default = 1.5
  917.                         }
  918.                     }
  919.                 },
  920.                 Merge2_6 = Merge {
  921.                     CtrlWShown = false,
  922.                     Inputs = {
  923.                         Background = Input {
  924.                             SourceOp = "Merge1_7",
  925.                             Source = "Output",
  926.                         },
  927.                         Foreground = Input {
  928.                             SourceOp = "Transform2_4_4",
  929.                             Source = "Output",
  930.                         },
  931.                         PerformDepthMerge = Input { Value = 0, },
  932.                     },
  933.                     ViewInfo = OperatorInfo { Pos = { 495, 406.15 } },
  934.                 },
  935.                 Merge1_7 = Merge {
  936.                     CtrlWShown = false,
  937.                     Inputs = {
  938.                         Background = Input {
  939.                             SourceOp = "Background7_16_5_4",
  940.                             Source = "Output",
  941.                         },
  942.                         Foreground = Input {
  943.                             SourceOp = "Transform1_4_4",
  944.                             Source = "Output",
  945.                         },
  946.                         PerformDepthMerge = Input { Value = 0, },
  947.                     },
  948.                     ViewInfo = OperatorInfo { Pos = { 495, 373.15 } },
  949.                 },
  950.                 Transform2_6 = Transform {
  951.                     CtrlWZoom = false,
  952.                     CtrlWShown = false,
  953.                     Inputs = {
  954.                         Center = Input { Value = { 0.334375, 0.380555555555556 }, },
  955.                         Size = Input { Value = 0.325, },
  956.                         Input = Input {
  957.                             SourceOp = "Merge2_6",
  958.                             Source = "Output",
  959.                         },
  960.                     },
  961.                     ViewInfo = OperatorInfo { Pos = { 495, 439.15 } },
  962.                 },
  963.                 Background7_16_5_4 = Background {
  964.                     CtrlWShown = false,
  965.                     Inputs = {
  966.                         GlobalOut = Input { Value = 215, },
  967.                         Width = Input { Value = 1920, },
  968.                         Height = Input { Value = 1080, },
  969.                         ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
  970.                         TopLeftAlpha = Input { Value = 0, },
  971.                     },
  972.                     ViewInfo = OperatorInfo { Pos = { 550, 340.15 } },
  973.                 }
  974.             },
  975.         }
  976.     },
  977.     ActiveTool = "FaceRecognition_v07"
  978. }

User avatar
AndrewHazelden
Fusionator
Posts: 1387
Joined: Fri Apr 03, 2015 3:20 pm
Answers: 4
Location: West Dover, Nova Scotia, Canada
Been thanked: 59 times
Contact:

Adding S1-S6 Presets to a Macro Node

#3

Post by AndrewHazelden » Fri Oct 06, 2017 7:16 pm

rebelorelse wrote:the second is can you store S1-S6 presets in a macro, so to have several different working designs of for ex placing of the frames in space, or different offsets in revealing, or some to get different color etc..
Hi rebelorelse.

If you want to store presets in a Macro I suggest you try doing that in two stages. The approach would go something like this:

Step 1. First create the default macro you are happy with that has all the controls and expressions exactly as you like them.

Step 2. Place that node into a new Fusion composite. Add your S1-S6 presets to the macro node. Rename the node in the comp by pressing the F2 hotkey if you want to take off any "_1_2_2_1_1" type of numbers that might be added to the end of the node name.

Step 3. Copy this updated Macro node from the flow area into your clipboard buffer. Paste the node text clipping manually into a new text file in your programmer's text editor and save it to disk with the .setting file extension.

When you place this macro node in your composite in the future the S1-S6 settings will be retained on the outer "macro" part of the node you have created.

(As a reminder, all of the internal settings saved on each of the node components that exist deep inside of the macro node will not be changed and stay locked as they were when you created the original node in step 1.)

Cheers,
Andrew Hazelden

User avatar
rebelorelse
Posts: 16
Joined: Sun Sep 06, 2015 3:59 am
Contact:

Re: Macro Building Essentials

#4

Post by rebelorelse » Fri Oct 06, 2017 7:44 pm

Thanks!

User avatar
AndrewHazelden
Fusionator
Posts: 1387
Joined: Fri Apr 03, 2015 3:20 pm
Answers: 4
Location: West Dover, Nova Scotia, Canada
Been thanked: 59 times
Contact:

Re: Macro Building Essentials

#5

Post by AndrewHazelden » Fri Oct 06, 2017 7:56 pm

Hi rebelorelse.

If you are going to be doing a lot of editing of a complex macro node in a text editor it is helpful, if at all possible, to limit how many S1-S6 node presets are applied in advance to the hidden "internal nodes" that you are placing inside the MacroOperator or GroupOperator macro when you go to package up the node for the first time.

If these internal nodes that a user will never see or touch have all sorts of presets applied to them individually it will boat the size of the macro node since an array is saved for each S1-S6 entry.

Try and keep all the node presets only on the final "outer most" macro node object you are creating if possible then you will have a heck of a lot less textual content to scroll past if you need to edit or revise the macro later on. This step here can keep your stress down later if you want to manually revise a whole collection of internal macro node settings a few days after you ship a new macro to several other people for testing and feedback. :)

Also, there isn't really any downside I can think of during your development work to turning that standard MacroOperator tag on a macro node into a GroupOperator tag. Using a GroupOperator sure makes changing an expression or renaming an internal macro node from "Background7_16_1_1_1_5_5" to something friendlier like "FaceBackground1" a heck of a lot easier to do.

You just press the little group expand button in the flow area on the macro node, edit it visually, then collapse the group again afterwards back down to a compact node shape in your Fusion composite. If you do this task several times in an hour you won't want to go back to the Macro Editor GUI again. :lol:

User avatar
AndrewHazelden
Fusionator
Posts: 1387
Joined: Fri Apr 03, 2015 3:20 pm
Answers: 4
Location: West Dover, Nova Scotia, Canada
Been thanked: 59 times
Contact:

User Controls Based RotateView Macro

#6

Post by AndrewHazelden » Fri Feb 09, 2018 5:14 pm

Node View.png
The RotateView macro allows you to rotate an image in 90° increments and at the same time adjust the image cropping to match. It's handy when working with photos in Fusion where you have a well defined canvas size and aspect ratio you want to preserve. The macro example was designed primarily to be a hands on demo to show how a UserControls based "ComboControl" menu element can be used in a macro.

Download the Macro
Code: [Select all] [Expand/Collapse] [Download] (RotateView.setting)
  1. {
  2.     Tools = ordered() {
  3.         RotateView = GroupOperator {
  4.             CtrlWZoom = false,
  5.             NameSet = true,
  6.             CustomData = {
  7.                 HelpPage = "http://www.andrewhazelden.com/",
  8.             },
  9.             Inputs = ordered() {
  10.                 Input1 = InstanceInput {
  11.                     SourceOp = "PanoMerge",
  12.                     Source = "Background",
  13.                     Name = "Input",
  14.                 }
  15.             },
  16.             Outputs = {
  17.                 Output1 = InstanceOutput {
  18.                     SourceOp = "SetMetadataOrientation",
  19.                     Source = "Output",
  20.                 }
  21.             },
  22.             ViewInfo = GroupInfo {
  23.                 Pos = { 1429.31, 248.186 },
  24.                 Flags = {
  25.                     AllowPan = false,
  26.                     AutoSnap = true
  27.                 },
  28.                 Size = { 395.051, 90.3515, 118, 22 },
  29.                 Direction = "Horizontal",
  30.                 PipeStyle = "Direct",
  31.                 Scale = 1,
  32.                 Offset = { -1378, -235.3 }
  33.             },
  34.             Tools = ordered() {
  35.                 ViewTransform = Transform {
  36.                     CtrlWShown = false,
  37.                     NameSet = true,
  38.                     Inputs = {
  39.                         Angle = Input { Expression = "RotateView.ViewRotation*90", },
  40.                         Input = Input {
  41.                             SourceOp = "PanoMerge",
  42.                             Source = "Output",
  43.                         },
  44.                     },
  45.                     ViewInfo = OperatorInfo { Pos = { 1430, 280.5 } },
  46.                 },
  47.                 ViewCrop = Crop {
  48.                     CtrlWShown = false,
  49.                     NameSet = true,
  50.                     Inputs = {
  51.                         XSize = Input {
  52.                             Value = 3840,
  53.                             Expression = "iif(RotateView.ViewRotation == 0 or RotateView.ViewRotation == 2,PanoMerge.Output.OriginalWidth,PanoMerge.Output.OriginalHeight)",
  54.                         },
  55.                         YSize = Input {
  56.                             Value = 1920,
  57.                             Expression = "iif(RotateView.ViewRotation == 0 or RotateView.ViewRotation == 2,PanoMerge.Output.OriginalHeight,PanoMerge.Output.OriginalWidth)",
  58.                         },
  59.                         KeepCentered = Input { Value = 1, },
  60.                         Input = Input {
  61.                             SourceOp = "ViewTransform",
  62.                             Source = "Output",
  63.                         },
  64.                     },
  65.                     ViewInfo = OperatorInfo { Pos = { 1540, 280.5 } },
  66.                 },
  67.                 PanoMerge = Merge {
  68.                     CtrlWShown = false,
  69.                     NameSet = true,
  70.                     Inputs = {
  71.                         PerformDepthMerge = Input { Value = 0, },
  72.                     },
  73.                     ViewInfo = OperatorInfo { Pos = { 1320, 280.5 } },
  74.                 },             
  75.                 SetMetadataOrientation = Fuse.SetMetaData {
  76.                     NameSet = true,
  77.                     Inputs = {
  78.                         FieldName = Input { Value = "Camera.Orientation", },
  79.                         FieldValue = Input { Value = "1", },
  80.                         Input = Input {
  81.                             SourceOp = "ViewCrop",
  82.                             Source = "Output",
  83.                         },
  84.                     },
  85.                     ViewInfo = OperatorInfo { Pos = { 1650, 280.5 } },
  86.                 }
  87.                
  88.             },
  89.             UserControls = ordered() {
  90.                 ViewRotation = {
  91.                     { CCS_AddString = "0°" },
  92.                     { CCS_AddString = "90°" },
  93.                     { CCS_AddString = "180°" },
  94.                     { CCS_AddString = "270°" },
  95.                     INP_MaxAllowed = 4,
  96.                     INP_Integer = true,
  97.                     INPID_InputControl = "ComboControl",
  98.                     CC_LabelPosition = "Horizontal",
  99.                     INP_MaxScale = 4,
  100.                     INP_Default = 0,
  101.                     INP_MinScale = 0,
  102.                     INP_MinAllowed = 0,
  103.                     LINKID_DataType = "Number",
  104.                     LINKS_Name = "View Rotation",
  105.                 }
  106.             }
  107.         }
  108.     },
  109.     ActiveTool = "RotateView"
  110. }
Expand the Group

Once you add the "RotateView.setting" file to your Fusion composite you can expand the group node to look at the internals of the node to see how it functions. Expressions are used to link the ComboControl attribute on the GroupOperator node to the actual nodes inside the macro that carry out the work.

There are four nodes present inside the RotateView macro named PanoMerge (a Merge node), ViewTransform (a Transform node), ViewCrop (a Crop node), and SetMetadataOrientation (a SetMetadata fuse node).
Rotate View Expanded Group.png
ComboControl UserControls
Rotate View Controls.png
The "ViewRotation" ComboControl has 4 menu entries:
  • 90°
  • 180°
  • 270°
These 4 menu entry items are accessed in expressions using a ViewRotation integer value range of 0-3. The first item in the menu "0°" has a value of 0, and the final item "270°" has a value of 3.

This menu is created as a UserControls attribute on the node using the syntax of:

Code: Select all

			UserControls = ordered() {
				ViewRotation = {
					{ CCS_AddString = "0°" },
					{ CCS_AddString = "90°" },
					{ CCS_AddString = "180°" },
					{ CCS_AddString = "270°" },
					INP_MaxAllowed = 4,
					INP_Integer = true,
					INPID_InputControl = "ComboControl",
					CC_LabelPosition = "Horizontal",
					INP_MaxScale = 4,
					INP_Default = 0,
					INP_MinScale = 0,
					INP_MinAllowed = 0,
					LINKID_DataType = "Number",
					LINKS_Name = "View Rotation",
				}
			}
Reading the Image Dimensions

A merge node named "PanoMerge" is placed inside the macro. The OriginalWidth and OriginalHeight output's from this node will be used to provide pixel based image dimensions to the Crop node that is placed further down in the node flow.

The Width of the image is accessible inside of the macro using the expression value from the PanoMerge node of:

Code: Select all

PanoMerge.Output.OriginalWidth
The Height of the image is accessible inside of the macro using the expression value from the PanoMerge node of:

Code: Select all

PanoMerge.Output.OriginalHeight
Rotating the View

The macro has a Transform node added with an Angle expression. This is used to adjust the view rotation based upon selecting one of the 4 possible view rotation angles from the ComboControl menu and multiplying it by 90 degrees:

Code: Select all

RotateView.ViewRotation*90
Auto-Cropping the View

Since rotating the image between portrait and landscape layouts will change the image aspect ratio, a Crop node has its XSize and YSize dimensions changed automatically at the same time.

A check of the current RotateView.ViewRotation ComboControl is done with the help of the "iff(comparison,true,false)" simple expression operator. The double equals sign == used in the comparison checks if the left and right values are the same in the iff command.

For the XSize expression, the "or" operator in the middle of the comparison of "RotateView.ViewRotation == 0 or RotateView.ViewRotation == 2" allows the two portrait layouts positions of 0°(ViewRotation 0) and 180°(ViewRotation 2) to be done at the same time. If the output is true from iif then the Crop size is set to match the input image width. If the output is false then the image was rotated on its side and the new image width is set to match the original input image height.

XSize Expression:

Code: Select all

iif(RotateView.ViewRotation == 0 or RotateView.ViewRotation == 2,PanoMerge.Output.OriginalWidth,PanoMerge.Output.OriginalHeight)
YSize Expression:

Code: Select all

iif(RotateView.ViewRotation == 0 or RotateView.ViewRotation == 2,PanoMerge.Output.OriginalHeight,PanoMerge.Output.OriginalWidth)
Note: The Crop node's Keep Centered control automatically adjusts the fitting as the image is resized so the crop adjustments are easier to do.

Updating the EXIF Metadata

Finally the "SetMetaData" fuse is used to override the existing EXIF metadata "Camera.Orientation" tag so it is set to "1" which represents an upright image.
You do not have the required permissions to view the files attached to this post.

User avatar
AndrewHazelden
Fusionator
Posts: 1387
Joined: Fri Apr 03, 2015 3:20 pm
Answers: 4
Location: West Dover, Nova Scotia, Canada
Been thanked: 59 times
Contact:

Creating a Macro with a User Controls Interface

#7

Post by AndrewHazelden » Fri Jun 08, 2018 9:04 am

If you want to see a detailed step by step tutorial on the workflow to create a new macro from scratch with a custom 100% User Controls based user interface and named input connections check out @SecondMan's latest work on this WSL thread:

How to deal with edges when using Sobel filter?

viewtopic.php?p=17389#p17389

Here is a sneak peek of the finished Macro that was created:

Edge Finder Macro GUI.png

Note: This thread also has some neat workflow tips I added at the end that show how you can add Custom Page tabs, buttons to open folders and webpages, and an inline help HTML view with images done with embedded UI Manager code.

Fusion - Show UI Manager Help Window.png
You do not have the required permissions to view the files attached to this post.

User avatar
Bencio
Posts: 5
Joined: Mon Sep 24, 2018 1:36 am
Contact:

Re: Macro Building Essentials

#8

Post by Bencio » Thu Sep 27, 2018 8:18 am

Hi, i have a question, i'm trying to do a set of titles for a youtube series i edit and i can't understand how to animate build in and build out keyframes.
I'll try to explain better: in apple motion i can animate a title, let's say a simple slide in from frame 0 to 30, then at frame 30 i can put a special "build in" marker, i'll do the same thing for the slide out animation, and then save it as fcpx title.
When i use this title in Final Cut i can change the lenght of the title but it knows that the duration of the build in and build out animation have to be the same and have to be at the start and at the end of the clip, (it can even deactivate the animation trough a checkbox), is it possible to have the same automation between fusion and resolve?

User avatar
SirEdric
Fusionator
Posts: 1960
Joined: Tue Aug 05, 2014 10:04 am
Answers: 4
Real name: Eric Westphal
Been thanked: 136 times
Contact:

Re: Macro Building Essentials

#9

Post by SirEdric » Thu Sep 27, 2018 8:48 am

I'm not sure about the interactivity directly with the Resolve Timeline,
but at least in the Fusion page one could a simple setup like this:

Code: Select all

{
	Tools = ordered() {
		TimeStretcher1 = TimeStretcher {
			CtrlWZoom = false,
			Inputs = {
				SourceTime = Input {
					Value = 69,
					Expression = "time<Hold_Frame and time or time>Hold_Frame+Hold_Time and time-Hold_Time or Hold_Frame",
				},
				InterpolateBetweenFrames = Input { Value = 0, },
				SampleSpread = Input { Disabled = true, },
				Input = Input {
					SourceOp = "Text1",
					Source = "Output",
				},
			},
			ViewInfo = OperatorInfo { Pos = { 165, 16.5 } },
			UserControls = ordered() {
				Hold_Frame = {
					LINKS_Name = "Hold_Frame",
					INP_Integer = true,
					LINKID_DataType = "Number",
					ICS_ControlPage = "Controls",
					INPID_InputControl = "SliderControl",
					INP_MinScale = 0,
					INP_MaxScale = 100,
					INP_Default = 26
				},
				Hold_Time = {
					INP_MaxAllowed = 1000000,
					INP_Integer = true,
					INPID_InputControl = "SliderControl",
					INP_MaxScale = 100,
					INP_Default = 50,
					INP_MinScale = 1,
					INP_MinAllowed = -1000000,
					LINKID_DataType = "Number",
					ICS_ControlPage = "Controls",
					LINKS_Name = "Hold_Time"
				}
			}
		},
		Text1 = TextPlus {
			Inputs = {
				Width = Input { Value = 1920, },
				Height = Input { Value = 1080, },
				["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
				Center = Input {
					SourceOp = "XYPath1",
					Source = "Value",
				},
				Size = Input { Value = 0.1966, },
				Font = Input { Value = "Open Sans", },
				StyledText = Input { Value = "Title", },
				Style = Input { Value = "Bold", },
				ManualFontKerningPlacement = Input {
					Value = StyledText {
						Array = {
						},
						Value = ""
					},
				},
			},
			ViewInfo = OperatorInfo { Pos = { 55, 16.5 } },
		},
		XYPath1 = XYPath {
			ShowKeyPoints = false,
			DrawMode = "ModifyOnly",
			Inputs = {
				X = Input {
					SourceOp = "XYPath1X",
					Source = "Value",
				},
				Y = Input {
					SourceOp = "XYPath1Y",
					Source = "Value",
				},
			},
		},
		XYPath1X = BezierSpline {
			SplineColor = { Red = 255, Green = 0, Blue = 0 },
			NameSet = true,
			KeyFrames = {
				[0] = { -0.5, RH = { 8.333325, 1.5 }, Flags = { Linear = true } },
				[25] = { 0.5, LH = { 16.666675, 0.5 }, RH = { 25.6666666666667, 0.5 } },
				[27] = { 0.5, LH = { 26.3333333333333, 0.5 }, RH = { 35.333325, 0.5 }, Flags = { Linear = true } },
				[52] = { 1.5, LH = { 43.666675, -0.5 } }
			}
		},
		XYPath1Y = BezierSpline {
			SplineColor = { Red = 0, Green = 255, Blue = 0 },
			NameSet = true,
			KeyFrames = {
				[0] = { 0.5, RH = { 8.33333333333333, 0.5 }, Flags = { Linear = true } },
				[25] = { 0.5, LH = { 16.6666666666667, 0.5 }, RH = { 25.6666666666667, 0.5 }, Flags = { Linear = true } },
				[27] = { 0.5, LH = { 26.3333333333333, 0.5 }, RH = { 35.3333333333333, 0.5 }, Flags = { Linear = true } },
				[52] = { 0.5, LH = { 43.6666666666667, 0.5 }, Flags = { Linear = true } }
			}
		}
	}
}

User avatar
Bencio
Posts: 5
Joined: Mon Sep 24, 2018 1:36 am
Contact:

Re: Macro Building Essentials

#10

Post by Bencio » Thu Sep 27, 2018 9:36 am

wow thanks, now i have control over how much frames the animation has to hold before the "build out", to link it to the clip lenght I did expression, putting the hold_time equal to (comp.GlobalEnd)-((build in lenght)+(build out lenght)) build in and out lenghts are fixed and decided by me, after a bit of research and trial and error i found the "comp.GlobalEnd" expression but it took some time, is there a glossary with all the possible syntax of the expressions?

P.S. It works in Resolve too!

User avatar
ShadowMaker SdR
Fusionista
Posts: 653
Joined: Sun Sep 21, 2014 6:17 am
Answers: 4
Been thanked: 17 times

Re: Macro Building Essentials

#11

Post by ShadowMaker SdR » Thu Sep 27, 2018 1:32 pm

SirEdric wrote:
Thu Sep 27, 2018 8:48 am
I'm not sure about the interactivity directly with the Resolve Timeline,
but at least in the Fusion page one could a simple setup like this:

Code: Select all

{
	Tools = ordered() {
		TimeStretcher1 = TimeStretcher {
			CtrlWZoom = false,
			Inputs = {
				SourceTime = Input {
					Value = 69,
					Expression = "time<Hold_Frame and time or time>Hold_Frame+Hold_Time and time-Hold_Time or Hold_Frame",
				},
				InterpolateBetweenFrames = Input { Value = 0, },
				SampleSpread = Input { Disabled = true, },
				Input = Input {
					SourceOp = "Text1",
					Source = "Output",
				},
			},
			ViewInfo = OperatorInfo { Pos = { 165, 16.5 } },
			UserControls = ordered() {
				Hold_Frame = {
					LINKS_Name = "Hold_Frame",
					INP_Integer = true,
					LINKID_DataType = "Number",
					ICS_ControlPage = "Controls",
					INPID_InputControl = "SliderControl",
					INP_MinScale = 0,
					INP_MaxScale = 100,
					INP_Default = 26
				},
				Hold_Time = {
					INP_MaxAllowed = 1000000,
					INP_Integer = true,
					INPID_InputControl = "SliderControl",
					INP_MaxScale = 100,
					INP_Default = 50,
					INP_MinScale = 1,
					INP_MinAllowed = -1000000,
					LINKID_DataType = "Number",
					ICS_ControlPage = "Controls",
					LINKS_Name = "Hold_Time"
				}
			}
		},
		Text1 = TextPlus {
			Inputs = {
				Width = Input { Value = 1920, },
				Height = Input { Value = 1080, },
				["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
				Center = Input {
					SourceOp = "XYPath1",
					Source = "Value",
				},
				Size = Input { Value = 0.1966, },
				Font = Input { Value = "Open Sans", },
				StyledText = Input { Value = "Title", },
				Style = Input { Value = "Bold", },
				ManualFontKerningPlacement = Input {
					Value = StyledText {
						Array = {
						},
						Value = ""
					},
				},
			},
			ViewInfo = OperatorInfo { Pos = { 55, 16.5 } },
		},
		XYPath1 = XYPath {
			ShowKeyPoints = false,
			DrawMode = "ModifyOnly",
			Inputs = {
				X = Input {
					SourceOp = "XYPath1X",
					Source = "Value",
				},
				Y = Input {
					SourceOp = "XYPath1Y",
					Source = "Value",
				},
			},
		},
		XYPath1X = BezierSpline {
			SplineColor = { Red = 255, Green = 0, Blue = 0 },
			NameSet = true,
			KeyFrames = {
				[0] = { -0.5, RH = { 8.333325, 1.5 }, Flags = { Linear = true } },
				[25] = { 0.5, LH = { 16.666675, 0.5 }, RH = { 25.6666666666667, 0.5 } },
				[27] = { 0.5, LH = { 26.3333333333333, 0.5 }, RH = { 35.333325, 0.5 }, Flags = { Linear = true } },
				[52] = { 1.5, LH = { 43.666675, -0.5 } }
			}
		},
		XYPath1Y = BezierSpline {
			SplineColor = { Red = 0, Green = 255, Blue = 0 },
			NameSet = true,
			KeyFrames = {
				[0] = { 0.5, RH = { 8.33333333333333, 0.5 }, Flags = { Linear = true } },
				[25] = { 0.5, LH = { 16.6666666666667, 0.5 }, RH = { 25.6666666666667, 0.5 }, Flags = { Linear = true } },
				[27] = { 0.5, LH = { 26.3333333333333, 0.5 }, RH = { 35.3333333333333, 0.5 }, Flags = { Linear = true } },
				[52] = { 0.5, LH = { 43.6666666666667, 0.5 }, Flags = { Linear = true } }
			}
		}
	}
}
That's wonderful stuff Eric. Would you mind explaining the formule in the expression? I can't make heads or tails of it.

User avatar
Greg Bovine
Double M
Posts: 129
Joined: Fri Feb 02, 2018 6:07 am
Location: Oslo, Norway
Been thanked: 2 times
Contact:

Re: Macro Building Essentials

#12

Post by Greg Bovine » Thu Sep 27, 2018 2:14 pm

ShadowMaker SdR wrote:
Thu Sep 27, 2018 1:32 pm
That's wonderful stuff Eric. Would you mind explaining the formule in the expression? I can't make heads or tails of it.
IMHO adding parenthesis to an expression can do wonders for readability and making things clearer what portions are clumped together by the and & the or operations. :)

This would be reformatted roughly as:
((time < Hold_Frame) and (time)) or ((time > Hold_Frame) + ((Hold_Time) and (time - Hold_Time))) or (Hold_Frame)

User avatar
SecondMan
Site Admin
Posts: 3579
Joined: Thu Jul 31, 2014 5:31 pm
Answers: 5
Location: Vancouver, Canada
Been thanked: 104 times
Contact:

Re: Macro Building Essentials

#13

Post by SecondMan » Thu Sep 27, 2018 3:48 pm

ShadowMaker SdR wrote:
Thu Sep 27, 2018 1:32 pm
Would you mind explaining the formule in the expression? I can't make heads or tails of it.

That type of expression was also the topic of the first episode of the S-Files.

User avatar
SirEdric
Fusionator
Posts: 1960
Joined: Tue Aug 05, 2014 10:04 am
Answers: 4
Real name: Eric Westphal
Been thanked: 136 times
Contact:

Re: Macro Building Essentials

#14

Post by SirEdric » Thu Sep 27, 2018 9:33 pm

SecondMan wrote:
Thu Sep 27, 2018 3:48 pm
That type of expression was also the topic of the first episode of the S-Files.
Which is where I got the inspiration from.
Things came to a full circle...:-)

User avatar
Bencio
Posts: 5
Joined: Mon Sep 24, 2018 1:36 am
Contact:

Re: Macro Building Essentials

#15

Post by Bencio » Fri Sep 28, 2018 9:17 am

Thank you very much for the help, all this is not as intuitive as the apple environment but i see it's much much more powerful (also a very nice pc costs half the price as a mac).

Last question then i'll have everything i need to build my custom titles (for now), is it possible to make versions of a node accessible in the macro editor? talking about this guys:
Image

Right now i solved changing the to GroupOperator in a text edit tool, and then i can access everything from resolve in the fusion tab but i would prefer to have a cleaner tool panel in resolve