HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //opt/resolve/Developer/Fusion Fuse/Example 8 Meta Time Burn.fuse
--[[-- 
A Timecode Burn in Fuse
by SR

--]]--

--******************************************************************************************************
-- This Registers the Fuse into Fusion, gives its Name, and Menu location. Location of Help. Can Fuse be edited.
FuRegisterClass("MetaTimeBurn", CT_Tool, {
	REGS_Name          = "Ex9 Meta Time Burn",
	REGS_Category      = "Fuses\\Examples",
	REGS_OpIconString  = "MTB",
	REGS_OpDescription = "Example, Metadata Timecode Burning",
	REGS_HelpTopic     = "Example Location of Help", --This can be a URL
	REGS_URL		   = "www.blackmagicdesign.com",
	--REGS_IconID = "Icons.Tools.Icons.Example",-- This can be Inline as an array of Values
	REG_OpNoMask       = false,
	REG_NoBlendCtrls   = false,
	REG_NoObjMatCtrls  = false,
	REG_NoMotionBlurCtrls = false,
	REG_TimeVariant    = true,  -- this tool must be reprocessed for every frame
	REG_Fuse_NoEdit    = false,
	REG_Fuse_NoReload  = false,
}) -- End of RegisterClass

	
function Create()

	InFps = self:AddInput(tr("FPS"), "FPS", {
		LINKID_DataType = "Number",
		INPID_InputControl = "MultiButtonControl",
		MBTNC_StretchToFit = true,
		{ MBTNC_AddButton = "24" },
		{ MBTNC_AddButton = "25" },
		{ MBTNC_AddButton = "30" },
		{ MBTNC_AddButton = "48" },
		{ MBTNC_AddButton = "50" },
		{ MBTNC_AddButton = "60" },
		})
	InHours = self:AddInput(tr("Hours"), "TCHours", {
		LINKID_DataType    = "Number",
		INPID_InputControl = "SliderControl",
		INP_MaxScale       = 23,
		INP_Integer        = true,
		INP_Default        = 0,
		})
	InMinutes = self:AddInput(tr("Minutes"), "TCMinutes", {
		LINKID_DataType    = "Number",
		INPID_InputControl = "SliderControl",
		INP_MaxScale       = 59,
		INP_Integer        = true,
		INP_Default        = 0,
		})
	InSeconds = self:AddInput(tr("Seconds"), "TCSeconds", {
		LINKID_DataType    = "Number",
		INPID_InputControl = "SliderControl",
		INP_MaxScale       = 59,
		INP_Integer        = true,
		INP_Default        = 0,
		})
	InFrames = self:AddInput(tr("Frames"), "TCFrames", {
		LINKID_DataType    = "Number",
		INPID_InputControl = "SliderControl",
		INP_MaxScale       = 60,
		INP_Integer        = true,
		INP_Default        = 0,
		})

	self:BeginControlNest("Text Settings", "TextNest", false); -- Control Nests group controls with a togglable collapse/expand function
	
	InFont = self:AddInput("Font", "Font", {
		LINKID_DataType    = "Text",
		INPID_InputControl = "FontFileControl",
		IC_ControlGroup    = 2,
		IC_ControlID       = 0, -- Font name ID
		INP_Level          = 1,
		INP_DoNotifyChanged = true,
	})
		
	InFontStyle = self:AddInput("Style", "Style", {
		LINKID_DataType    = "Text",
		INPID_InputControl = "FontFileControl",
		IC_ControlGroup    = 2,
		IC_ControlID       = 1, -- Font style ID
		INP_Level          = 1,
		INP_DoNotifyChanged = true,
	})

		
	InPosition = self:AddInput("Position", "Position", {
		LINKID_DataType      = "Point",
		INPID_InputControl   = "OffsetControl",
		INPID_PreviewControl = "CrosshairControl",
		INP_DefaultX         = 0.1,
		INP_DefaultY         = 0.1,
		})

	InSize = self:AddInput("Size", "Size", {
		LINKID_DataType    = "Number",
		INPID_InputControl = "SliderControl",
		INP_MinScale       = 0.0,
		INP_MaxScale       = 0.5,
		INP_Default        = 0.08,
		})
	
	InJustify = self:AddInput("Justification", "Justification", {
		LINKID_DataType    = "Number",
		INPID_InputControl = "MultiButtonControl",
		INP_Default        = 0.0,
		{ MBTNC_AddButton  = "Left",   MBTNCD_ButtonWidth = 1/3, },
		{ MBTNC_AddButton  = "Center", MBTNCD_ButtonWidth = 1/3, },
		{ MBTNC_AddButton  = "Right",  MBTNCD_ButtonWidth = 1/3, },
		INP_Integer        = true,
		})
	
	InR = self:AddInput("Red", "Red", {
		LINKID_DataType    = "Number",
		INPID_InputControl = "ColorControl",
		INP_MinScale       = 0.0,
		INP_MaxScale       = 1.0,
		INP_Default        = 1.0,
		ICS_Name           = "Color",
		CLRC_ShowWheel     = false,
		IC_ControlGroup    = 1,
		IC_ControlID       = 0, -- Red ID
		})
		
	InG = self:AddInput("Green", "Green", {
		LINKID_DataType    = "Number",
		INPID_InputControl = "ColorControl",
		INP_MinScale       = 0.0,
		INP_MaxScale       = 1.0,
		INP_Default        = 1.0,
		IC_ControlGroup    = 1,
		IC_ControlID       = 1, -- Green ID
		})
		
	InB = self:AddInput("Blue", "Blue", {
		LINKID_DataType    = "Number",
		INPID_InputControl = "ColorControl",
		INP_MinScale       = 0.0,
		INP_MaxScale       = 1.0,
		INP_Default        = 1.0,
		IC_ControlGroup    = 1,
		IC_ControlID       = 2, -- Blue ID
		})
		
	InA = self:AddInput("Alpha", "Alpha", {
		LINKID_DataType    = "Number",
		INPID_InputControl = "ColorControl",
		INP_MinScale       = 0.0,
		INP_MaxScale       = 1.0,
		INP_Default        = 1.0,
		IC_ControlGroup    = 1,
		IC_ControlID       = 3, -- Alpha ID
		})
		
	self:EndControlNest()
	
	InImage = self:AddInput("Input", "Input", {
		LINKID_DataType = "Image",
		LINK_Main       = 1,
		})

	OutImage = self:AddOutput("Output", "Output", {
		LINKID_DataType = "Image",
		LINK_Main       = 1,
		})	
end

function drawstring(img, font, style, size, justify, quality, x, y, colour, text)
	local ic = ImageChannel(img, quality) 
	local fs = FillStyle()
	local cs = ChannelStyle()
	
	cs.Color = colour
	ic:SetStyleFill(fs)
	
	-- get the fonts metrics (see http://freetype.sourceforge.net/freetype2/docs/glyphs/index.html for a great guide)
	local font = TextStyleFont(font, style)
	local tfm = TextStyleFontMetrics(font)
	
	-- This is the distance between this line and the next one. 
	local line_height = (tfm.TextAscent + tfm.TextDescent + tfm.TextExternalLeading) * 10 * size 
	local x_move = 0
	
	local mat = Matrix4()
			
	mat:Scale(1.0/tfm.Scale, 1.0/tfm.Scale, 1.0)
	mat:Scale(size, size, 1)
		
	-- set the initial baseline position of the text cursor
	local sh, ch, prevch

	local shape = Shape()
	mat:Move(x, y, 0)
	
	-- split the text into separate lines
	for line in string.gmatch(text, "%C+") do
		
		-- First pass, work out what the total width of this line is going to be
		local line_width = 0
		for i=1,#line do
			ch = line:sub(i,i):byte()
			
			-- is this ignoring kerning?
			line_width = line_width + tfm:CharacterWidth(ch)*10*size
		end
		
		-- Now work out our initial cursor position, based on the justification
		-- 0 = left justify, 
		-- 1 = centered
		-- 2 = right justify
		if justify == 0 then
			--mat:Move(0, 0, 0)
		elseif justify == 1 then
			mat:Move(-line_width/2, 0, 0)
		elseif justify == 2 then 
			mat:Move(-line_width, 0, 0)
		end
	
		-- Second pass, now we assemble the actual shape
		for i=1,#line do
			prevch = ch
			
			-- get the character, or glyph
			ch = line:sub(i,i):byte()
			
			-- first we want to know what the width of the character is,
			-- so we know where to start drawing this next character
			-- not really sure why we multiply this by 10, we just do :-)
			local cw = tfm:CharacterWidth(ch)*10*size
			
			-- if there is a previous character, we need to get the kerning 
			-- between the current character and the last one. 
			if prevch then
				x_offset = tfm:CharacterKerning(prevch, ch)*10*size
				x_move = x_move + x_offset
				mat:Move(x_offset, 0, 0)
			end
			
			-- move the cursor to the center of the character
			mat:Move(cw/2, 0, 0)
			
			-- I think this renders the shape we are interested in
			sh = tfm:GetCharacterShape(ch, false)
			if sh then
				sh = sh:TransformOfShape(mat)
				
				-- move the text cursor to the end of the glyph.
				mat:Move(cw/2, 0, 0)
				x_move = x_move + cw
				
				shape:AddShape(sh)
			end
		end
		
		-- line end, move the cursor back to the start
		if justify == 0 then
			mat:Move(-x_move, -line_height, 0)
		elseif justify == 1 then
			mat:Move(-x_move/2, -line_height, 0)
		elseif justify == 2 then 
			mat:Move(0, -line_height, 0)
		end
		
		x_move = 0
	end
	
	ic:ShapeFill(shape)
	ic:PutToImage("CM_Merge", cs)
	
end
 
function Process(req) 	
	local img = InImage:GetValue(req)
	local fps = InFps:GetValue(req).Value
	local hours = InHours:GetValue(req).Value
	local minutes = InMinutes:GetValue(req).Value
	local seconds = InSeconds:GetValue(req).Value
	local frames = InFrames:GetValue(req).Value
	local currentframe = req.Time


	local rates = { 24, 25, 30, 48, 50, 60 }
	local fpsx = rates[math.min(math.max(fps, 0), 5)+1]

	-- Calculate and format the time code strings
	-- Calculate frames from Time code settings
	local frames_o  = currentframe + frames + fpsx * (seconds + 60*minutes + 3600*hours)

	local frames_s  = frames_o % fpsx
	local seconds_s = math.floor(frames_o / fpsx) % 60
	local minutes_s = math.floor(frames_o / (60*fpsx)) % 60
	local hours_s   = math.floor(frames_o / (3600*fpsx))

	local timecode  = string.format("%02d:%02d:%02d:%02d", hours_s, minutes_s, seconds_s, frames_s)


	local font = InFont:GetValue(req).Value
	local style = InFontStyle:GetValue(req).Value
	local out = img:CopyOf()
	
	local size      = InSize:GetValue(req).Value
	local center    = InPosition:GetValue(req)
	local justify	= InJustify:GetValue(req).Value
	local r         = InR:GetValue(req).Value
	local g         = InG:GetValue(req).Value
	local b         = InB:GetValue(req).Value
	local a         = InA:GetValue(req).Value
	
	local cx = center.X
	local cy = center.Y * (out.Height * out.YScale) / (out.Width * out.XScale)
	local quality = 32
	
	-- if the FontManager list is empty, scan the font list
	-- If the UI has never been shown, as would always be the case on a render node, 
	-- nothing will scan the font list for available fonts. So we check for that here, 
	-- and force a scan if needed.
	if not next( FontManager:GetFontList() ) then
		FontManager:ScanDir()
	end
	
	if req:IsQuick() then 
		quality = 1
	end
	
	-- the drawstring function is doing all the heavy lifting 
	drawstring(out, font, style, size, justify, quality, cx, cy, Pixel{R=r,G=g,B=b,A=a}, timecode)
	
	OutImage:Set(req, out)
end

function NotifyChanged(inp, param, time)
	-- when the tools FontFileControl is first created, the FontManager has not yet 
	-- provided a FontList, so we can't set a default value. Instead we do it here.
	
	if inp == InFont then
		local f = param.Value
		
		if f == nil or string.len(f) == 0 then
			InFont:SetSource(Text("Open Sans"), time)
		end
	elseif inp == InFontStyle then
		local f = param.Value
		
		if f == nil or string.len(f) == 0 then
			InFontStyle:SetSource(Text("Regular"), time)
		end
	end
	
end