228 lines
5.9 KiB
Lua
228 lines
5.9 KiB
Lua
--[[
|
|
==README==
|
|
|
|
No GUI, pretty straightforward.
|
|
|
|
For example, to make a line bend in an arc and transition from blue to red, do this:
|
|
|
|
{\frz10\c&HFF0000&}This is a line of tex{\frz350\c&H0000FF&}t
|
|
|
|
Run the automation and it'll add a tag before each character to make the rotation and color
|
|
transition change smoothly across the line.
|
|
|
|
Rotations are locked to less than 180 degree rotations. If you want a bend of more than 180,
|
|
then split it up into multiple rotations of less than 180 each. This script is meant for
|
|
convenience above all, so it runs with a single button press and no time-consuming options menu.
|
|
|
|
]]--
|
|
|
|
script_name = "Gradient by character"
|
|
script_description = "Smoothly transforms tags across your line, by character."
|
|
script_version = "1.3.1"
|
|
script_author = "lyger"
|
|
script_namespace = "lyger.GradientByChar"
|
|
|
|
local DependencyControl = require("l0.DependencyControl")
|
|
local rec = DependencyControl{
|
|
feed = "https://raw.githubusercontent.com/TypesettingTools/lyger-Aegisub-Scripts/master/DependencyControl.json",
|
|
{
|
|
{"lyger.LibLyger", version = "2.0.0", url = "http://github.com/TypesettingTools/lyger-Aegisub-Scripts"},
|
|
"aegisub.util", "aegisub.re"
|
|
}
|
|
}
|
|
local LibLyger, util, re = rec:requireModules()
|
|
local libLyger = LibLyger()
|
|
|
|
function grad_char(sub,sel)
|
|
libLyger:set_sub(sub, sel)
|
|
|
|
for si,li in ipairs(sel) do
|
|
--Read in the line
|
|
this_line=libLyger.lines[li]
|
|
|
|
--Make sure line starts with tags
|
|
if this_line.text:find("^{")==nil then this_line.text="{}"..this_line.text end
|
|
|
|
--Turn all \1c tags into \c tags, just for convenience
|
|
this_line.text=this_line.text:gsub("\\1c","\\c")
|
|
|
|
--Make line table
|
|
this_table={}
|
|
x=1
|
|
for thistag,thistext in this_line.text:gsub("}","}\t"):gmatch("({[^{}]*})([^{}]*)") do
|
|
this_table[x]={tag=thistag,text=thistext:gsub("\t","")}
|
|
x=x+1
|
|
end
|
|
|
|
if #this_table<2 then
|
|
aegisub.log("There must be more than one tag block in the line!")
|
|
return
|
|
end
|
|
|
|
--Transform these tags
|
|
transform_tags={
|
|
"c","2c","3c","4c",
|
|
"alpha","1a","2a","3a",
|
|
"fscx","fscy","fax","fay",
|
|
"frx","fry","frz",
|
|
"fs","fsp",
|
|
"bord","shad",
|
|
"xbord","ybord","xshad","yshad",
|
|
"blur","be"
|
|
}
|
|
|
|
--Make state table
|
|
this_state = LibLyger.make_state_table(this_table,transform_tags)
|
|
|
|
--Style lookup
|
|
this_style = libLyger:style_lookup(this_line)
|
|
|
|
--Running record of the state of the line
|
|
current_state={}
|
|
|
|
--Outer control loop
|
|
for i=2,#this_table,1 do
|
|
--Update current state
|
|
for ctag,cval in pairs(this_state[i-1]) do
|
|
current_state[ctag]=cval
|
|
end
|
|
|
|
--Stores state of each character, to prevent redundant tags
|
|
char_state=util.deep_copy(current_state)
|
|
|
|
--Local function for interpolation
|
|
local function handle_interpolation(factor,tag,sval,eval)
|
|
local param_type, ivalue = libLyger.param_type, ""
|
|
--Handle differently depending on the type of tag
|
|
if param_type[tag]=="alpha" then
|
|
ivalue=interpolate_alpha(factor,sval,eval)
|
|
elseif param_type[tag]=="color" then
|
|
ivalue=interpolate_color(factor,sval,eval)
|
|
elseif param_type[tag]=="angle" then
|
|
nstart=tonumber(sval)
|
|
nend=tonumber(eval)
|
|
|
|
--Use "Rotate in shortest direction" by default
|
|
nstart=nstart%360
|
|
nend=nend%360
|
|
ndelta=nend-nstart
|
|
if math.abs(ndelta)>180 then nstart=nstart+(ndelta*360)/math.abs(ndelta) end
|
|
|
|
--Interpolate
|
|
nvalue=interpolate(factor,nstart,nend)
|
|
if nvalue<0 then nvalue=nvalue+360 end
|
|
|
|
--Convert to string
|
|
ivalue=libLyger.float2str(nvalue)
|
|
|
|
elseif param_type[tag]=="number" then
|
|
nstart=tonumber(sval)
|
|
nend=tonumber(eval)
|
|
|
|
--Interpolate and convert to string
|
|
ivalue=libLyger.float2str(interpolate(factor,nstart,nend))
|
|
end
|
|
return ivalue
|
|
end
|
|
|
|
local ttext=this_table[i-1].text
|
|
|
|
if ttext:len()>0 then
|
|
|
|
--Rebuilt text
|
|
local rtext=""
|
|
|
|
--Skip the first character
|
|
local first=true
|
|
|
|
--Starting values
|
|
idx=1
|
|
|
|
matches=re.find(ttext,'\\\\[Nh]|\\X')
|
|
|
|
total=#matches
|
|
|
|
for _,match in ipairs(matches) do
|
|
|
|
ch=match.str
|
|
|
|
if not first then
|
|
--Interpolation factor
|
|
factor=idx/total
|
|
|
|
idx=idx+1
|
|
|
|
--Do nothing if the character is a space
|
|
if ch:find("%s")~=nil then
|
|
rtext=rtext..ch
|
|
else
|
|
|
|
--The tags in and out of the time statement
|
|
local non_time_tags=""
|
|
|
|
--Go through all the state tags in this tag block
|
|
for ttag,tparam in pairs(this_state[i]) do
|
|
--Figure out the starting state of the param
|
|
local sparam=current_state[ttag]
|
|
if sparam==nil then sparam=this_style[ttag] end
|
|
if type(sparam)~="number" then sparam=sparam:gsub("%)","") end--Just in case a \t tag snuck in
|
|
|
|
--Prevent redundancy
|
|
if sparam~=tparam then
|
|
--The string version of the interpolated parameter
|
|
local iparam=handle_interpolation(factor,ttag,sparam,tparam)
|
|
|
|
if iparam~=tostring(char_state[ttag]) then
|
|
non_time_tags=non_time_tags.."\\"..ttag..iparam
|
|
char_state[ttag]=iparam
|
|
end
|
|
end
|
|
end
|
|
|
|
if non_time_tags:len() < 1 then
|
|
--If no tags were added, do nothing
|
|
rtext=rtext..ch
|
|
else
|
|
--The final tag, with a star to indicate it was added through interpolation
|
|
rtext=rtext.."{*"..non_time_tags.."}"..ch
|
|
end
|
|
|
|
end
|
|
else
|
|
rtext=rtext..ch
|
|
end
|
|
first=false
|
|
end
|
|
|
|
this_table[i-1].text=rtext
|
|
|
|
end
|
|
|
|
end
|
|
|
|
rebuilt_text=""
|
|
|
|
for i,val in pairs(this_table) do
|
|
rebuilt_text=rebuilt_text..val.tag..val.text
|
|
end
|
|
this_line.text=rebuilt_text
|
|
sub[li]=this_line
|
|
end
|
|
|
|
aegisub.set_undo_point(script_name)
|
|
end
|
|
|
|
function remove_grad_char(sub,sel)
|
|
for si,li in ipairs(sel) do
|
|
this_line=sub[li]
|
|
this_line.text=this_line.text:gsub("{%*[^{}]*}","")
|
|
sub[li]=this_line
|
|
end
|
|
end
|
|
|
|
-- Register the macro
|
|
rec:registerMacros{
|
|
{"Apply Gradient", script_description, grad_char},
|
|
{"Remove Gradient", "Removes gradient generated by #{script_name}", remove_grad_char}
|
|
}
|