node_global ()
Returns the "/obj/global" address. If the node does not exist, creates it.
node_parent (node)
Returns the address node.parent()
opmultiparm_ramp (node_channel, node_source, ramp_name, color)
Creates a script for hscript opmultiparm. To reference promoted ramp.
parm_ref_parm_ramp (node_channel, node_source, ramp_name)
Creates a reference from one ramp to another ramp.
I mostly use it for an automated parameter promotion.
parm_ref_parm (node_channel, node_source, parm_name, parm_type)
Creates a reference from one parameter to another parameter.
I mostly use it for an automated parameter promotion.
parm_create (node, type, name, label)
Creates a new parameter in the node interface.
parm_update (node, type, name, default, min, max, hidden, join, ramplib)
Modifies parameter properties (default value, min, max, etc.)
line_parse (node, line, linenum)
It parses a single line of the Attribute Wrangle Snippet. Every line is evaluated to:
- create new parameters
- update parameter properties
- automatically promote the parameter (to parent node, to global node)
qq_expand ()
This function replaces "code shortcuts" into "code snippets" and also updates the parm interface (default values, channel ranges from comments, ramps are generated from custom library). You can build your own libraries of snippets with specific channel ranges and defaults.
parm_generate ()
Parses whole snippet (current wrangle node) and executes line_parse() on each line.
parm_clean ()
Removes all spare parm templates from the selected node.
qq_parse_uberfile ()
Reads qqvex uberfile and writes four files to disk:
1) qq.vfl - library of functions, to be #included
2) uber_qq_shortcuts.vfl - library of shortcuts
3) uber_qq_snippets.vfl - library of snippets
4) uber_qq_helpcard.vfl - just a helpcard
names_counts_in (node, ptg)
Auxiliary function for browsing interface folders.
folders_trygo (node, name, count, dir)
Auxiliary function for browsing interface folders.
folders_tab_go (dir)
Goes to next/previous folder in parameter interface, using a keyboard shortcut.
source code
the following code is maintained also on my github
thank you, great people, I couldn't do this without you.
import re
import hou
import wf_network_ui_ramp_lib
import wf_selection
import wf_midi
reload (wf_midi)
# def node_snippet (node) :
# parm_
# no_snippet = 1
# try :
# snippet = node.parm("snippet")
# except :
# nosnippet = 1
# actualcode = snippet.unexpandedString()
# return snippet
def node_global () :
color = hou.Color(0.0, 0.0, 0.0)
path = "/obj/global"
name = "global"
if hou.node(path) :
existed = 1
return hou.node(path)
else :
existed = 0
node_global = hou.node("/obj").createNode('null',name)
node_global.moveToGoodPosition()
node_global.setUserData("nodeshape", "circle")
node_global.setColor(color)
return node_global
def node_parent (node) :
return node.parent()
def opmultiparm_ramp (node_channel, node_source, ramp_name, color) :
rel_path = node_channel.relativePathTo(node_source)
hscript = 'opmultiparm '
hscript += node_channel.path()
hscript += ' "' + ramp_name + '#pos" "' + rel_path + '/' + ramp_name + '#pos" '
hscript += ' "' + ramp_name + '#interp" "' + rel_path + '/' + ramp_name + '#interp" '
if not color:
hscript += ' "' + ramp_name + '#value" "' + rel_path + '/' + ramp_name + '#value" '
else:
hscript += ' "' + ramp_name + '#cr" "' + rel_path + '/' + ramp_name + '#cr" '
hscript += ' "' + ramp_name + '#cg" "' + rel_path + '/' + ramp_name + '#cg" '
hscript += ' "' + ramp_name + '#cb" "' + rel_path + '/' + ramp_name + '#cb" '
hou.hscript(hscript)
def parm_ref_parm_ramp (node_channel, node_source, ramp_name) :
ramp_source = node_source.parm(ramp_name)
ramp_channel = node_channel.parm(ramp_name)
ramp_channel.set(ramp_source, None, False)
template = ramp_source.parmTemplate().parmType()
color = template == hou.rampParmType.Color
keys = ramp_source.eval().keys()
if color :
parms = ["pos","interp","cr","cg","cb"]
else :
parms = ["pos","interp","value"]
for i in xrange(len(keys)) :
for parm in parms :
parm_source = node_source.parm(ramp_name + str(i + 1) + parm)
parm_channel = node_channel.parm(ramp_name + str(i + 1) + parm)
parm_channel.set(parm_source, None, False)
opmultiparm_ramp (node_channel, node_source, ramp_name, color)
def parm_ref_parm (node_channel, node_source, parm_name, parm_type) :
if parm_type == "rampfloat" or parm_type == "rampcolor" :
parm_ref_parm_ramp(node_channel, node_source, parm_name)
elif parm_type == "vector" :
for dim in ["x","y","z"] :
parm_source = node_source.parm(parm_name + dim)
parm_channel = node_channel.parm(parm_name + dim)
parm_channel.set(parm_source, None, False)
elif parm_type == "color" :
for dim in ["r","g","b"] :
parm_source = node_source.parm(parm_name + dim)
parm_channel = node_channel.parm(parm_name + dim)
parm_channel.set(parm_source, None, False)
else :
parm_source = node_source.parm(parm_name)
parm_channel = node_channel.parm(parm_name)
parm_channel.set(parm_source, None, False)
def parm_create (node, type, name, label) :
if type == "integer" :
new_template = hou.IntParmTemplate(name, name, 1)
if type == "toggle" :
new_template = hou.ToggleParmTemplate(name, name)
if type == "float" :
new_template = hou.FloatParmTemplate(name, name, 1)
if type == "vector" :
new_template = hou.FloatParmTemplate(name, name, 3)
new_template.setLook(hou.parmLook.Regular)
if type == "color" :
new_template = hou.FloatParmTemplate(name, name, 3)
new_template.setNamingScheme(hou.parmNamingScheme.RGBA)
new_template.setLook(hou.parmLook.ColorSquare)
if type == "string" :
new_template = hou.StringParmTemplate(name, label, 1)
new_template.setStringType(hou.stringParmType.Regular)
if type == "file" :
new_template = hou.StringParmTemplate(name, name, 1)
new_template .setStringType(hou.stringParmType.FileReference)
if type == "node" :
new_template = hou.StringParmTemplate(name, name, 1)
new_template.setStringType(hou.stringParmType.NodeReference)
if type == "separator" :
new_template = hou.SeparatorParmTemplate(name)
if type == "label" :
new_template = hou.LabelParmTemplate(name, label, [label], False, True)
if type == "rampfloat" :
new_template = hou.RampParmTemplate(name, name, hou.rampParmType.Float)
new_template.setShowsControls(False)
if type == "rampcolor" :
new_template = hou.RampParmTemplate(name, name, hou.rampParmType.Color)
new_template.setShowsControls(False)
try :
ptg = node.parmTemplateGroup()
ptg.addParmTemplate(new_template)
node.setParmTemplateGroup( ptg )
existed = 0
except:
existed = 1
def parm_update (node, type, name, default="", min="", max="", hidden="", join="", ramplib="") :
ptg = node.parmTemplateGroup()
parmedit = ptg.find( name )
if type == "integer" :
try:
parmedit.setDefaultValue( [int(default)] )
parmedit.setMinValue ( int(min) )
parmedit.setMaxValue ( int(max) )
except:
pass
if type == "toggle" :
try:
parmedit.setDefaultValue( int(default) )
except:
pass
if type == "float" :
try:
parmedit.setDefaultValue( [float(default)] )
parmedit.setMinValue ( float(min) )
parmedit.setMaxValue ( float(max) )
except:
pass
if type == "string" :
try:
parmedit.setDefaultValue( [default] )
except:
pass
if hidden : parmedit.hide(True)
if join : parmedit.setJoinWithNext( True )
if ramplib :
ramp_preset, ramp_basis, ramp_keys, ramp_values = wf_network_ui_ramp_lib.ramp_lib()
try:
i = ramp_preset.index(ramplib)
newRamp = hou.Ramp(ramp_basis[i], ramp_keys[i], ramp_values[i])
node.setParms({name:newRamp})
except:
# comment is "color" or "glob" or anything else
pass
ptg.replace( name, parmedit )
node.setParmTemplateGroup( ptg )
def line_parse (node, line, linenum) :
name = None
label = None
type = None
default = None
min = None
max = None
hidden = None
join = None
ramplib = None
##################
###### type ######
##################
chi = re.findall('chi(["'](w+)['"]',line)
chf = re.findall('chf(["'](w+)['"]',line)
chv = re.findall('chv(["'](w+)['"]',line)
chs = re.findall('chs(["'](w+)['"]',line)
chramp = re.findall('chramp("(w+)"', line)
chlabel = re.findall('//# *(.+)', line)
chseparator = re.findall("//---", line)
chcolor = re.findall('//.*color',line)
chtoggle = re.findall('//.*toggle',line)
chfile = re.findall('//.*file',line)
chnode = re.findall('//.*node',line)
if chi : type = "integer" ; name = chi[0] ; label = name
if chi and chtoggle : type = "toggle" ; name = chi[0] ; label = name
if chf : type = "float" ; name = chf[0] ; label = name
if chv : type = "vector" ; name = chv[0] ; label = name
if chv and chcolor : type = "color" ; name = chv[0] ; label = name
if chs : type = "string" ; name = chs[0] ; label = name
if chs and chfile : type = "file" ; name = chs[0] ; label = name
if chs and chnode : type = "node" ; name = chs[0] ; label = name
if chseparator : type = "separator" ; name = "separ" + str(linenum) ; label = name
if chlabel : type = "label" ; name = "label" + str(linenum) ; label = re.sub("[^0-9a-zA-Z. ]+", "_", chlabel[0])
if chramp : type = "rampfloat" ; name = chramp[0] ; label = name
if chramp and chcolor : type = "rampcolor" ; name = chramp[0] ; label = name
if name :
# check if already referenced
if name.startswith( "../" ) or name.startswith( "/obj/" ) : name == None
if name : parm_create (node, type, name, label)
##################
###### spec ######
##################
parm_join = re.findall('//.*join',line)
parm_hide = re.findall('//.*hide',line)
ramplib = re.findall('chramp(.*//.*?(w+)',line)
defminmax = re.findall("// *([+-]?d+.?d*?|.d+) +in +([+-]?d+.?d*?|.d+) +to +([+-]?d+.?d*|.d+)",line)
if parm_join : join = True
if parm_hide : hidden = True
if ramplib : ramplib = ramplib[0]
if defminmax :
default = defminmax[0][0]
min = defminmax[0][1]
max = defminmax[0][2]
if name : parm_update (node, type, name, default, min, max, hidden, join, ramplib)
###################
### reference ###
###################
ref_parent = re.findall('//.*parent',line)
ref_global = re.findall('//.*global',line)
if ref_parent and name :
node_channel = node
node_source = node_parent(node)
parm_create (node_source, type, name, label)
parm_update (node_source, type, name, default, min, max, hidden, join, ramplib)
parm_ref_parm (node_channel, node_source, name, type)
node.setUserData("nodeshape", "chevron_down")
node.setColor(hou.Color(0.95, 0.27, 0.27))
line = line.replace('"' + name + '"', '"../' + name + '"')
if ref_global and name :
node_channel = node
node_source = node_global()
parm_create (node_source, type, name, label)
parm_update (node_source, type, name, default, min, max, hidden, join, ramplib)
parm_ref_parm (node_channel, node_source, name, type)
node.setUserData("nodeshape", "chevron_down")
node.setColor(hou.Color(0.95, 0.27, 0.27))
line = line.replace('"' + name + '"', '"/obj/global/' + name + '"')
return line
def qq_expand (node,parm_code) :
###################################################
####### qqr qqi qqf // + interface #######
###################################################
actualcode = parm_code.unexpandedString()
lines = actualcode.split('n')
for line in lines:
found = 0
if line.startswith("qqf."):
qq,var = line.split('.')
newline = 'float ' + var + ' = chf("' + var + '"); // 0.5 in 0.0 to 1.0'
found = 1
if line.startswith("qqi."):
qq,var = line.split('.')
newline = 'int ' + var + ' = chi("' + var + '"); // 1 in 0 to 10'
found = 1
if line.startswith("qqr."):
qq,var = line.split('.')
newline = var + ' = chramp("' + var + '",' + var + '); //' + var
found = 1
if line.startswith("qqs."):
qq,var = line.split('.')
newline = 'string ' + var + ' = chs("' + var + '"); // file node'
found = 1
if line.startswith("qqv."):
qq,var = line.split('.')
newline = 'vector ' + var + ' = chv("' + var + '"); // color'
found = 1
if line.startswith("qq@f."):
qq,var = line.split('.')
newline = 'f@' + var + ' = chf("' + var + '"); // 0.5 in 0.0 to 1.0'
found = 1
if line.startswith("qq@i."):
qq,var = line.split('.')
newline = 'i@' + var + ' = chi("' + var + '"); // 1 in 0 to 10'
found = 1
if line.startswith("qq01."):
qq,var = line.split('.')
newline = 'float new_min = chf("new_min"); // -1 in -10 to 10n';
newline += 'float new_max = chf("new_max"); // 1 in -10 to 10n';
newline += var + ' = fit01(' + var + ', new_min, new_max);';
found = 1
if line.startswith("qqx."):
qq,var = line.split('.')
if var.find("//") > 0 :
# comment is defined
var,comment = var.split('//')
comment = " //"+comment
else:
comment = ""
var = var.strip(" ")
newline = '//----n'
newline += 'float ' + var + '_x = chf("' + var + '_x");' + comment + 'n'
newline += 'float ' + var + '_y = chf("' + var + '_y");' + comment + 'n'
newline += 'float ' + var + '_z = chf("' + var + '_z");' + comment + 'n'
newline += 'vector ' + var + ' = set(' + var + '_x, ' + var + '_y, ' + var + '_z);'
found = 1
if line.startswith("qqxx."):
qq,var = line.split('.')
if var.find("//") > 0 :
# comment is defined
var,comment = var.split('//')
comment = " //"+comment
else:
comment = ""
var = var.strip(" ")
newline = '#include "qq.vfl"n'
newline += '//----n'
newline += 'float ' + var + '_x_min = chf("' + var + '_x_min");' + comment + 'n'
newline += 'float ' + var + '_x_max = chf("' + var + '_x_max");' + comment + 'n'
newline += '//----n'
newline += 'float ' + var + '_y_min = chf("' + var + '_y_min");' + comment + 'n'
newline += 'float ' + var + '_y_max = chf("' + var + '_y_max");' + comment + 'n'
newline += '//----n'
newline += 'float ' + var + '_z_min = chf("' + var + '_z_min");' + comment + 'n'
newline += 'float ' + var + '_z_max = chf("' + var + '_z_max");' + comment + 'n'
newline += 'vec_len_fit01( '+ var + '_noise, ' + var + '_x_min, ' + var + '_x_max, ' + var + '_y_min, ' + var + '_y_max, ' + var + '_z_min, ' + var + '_z_max);'
found = 1
if found:
actualcode = actualcode.replace(line,newline,1) # only the first occurrence
parm_code.set(actualcode)
##############################################
####### read library #########
##############################################
import pickle
path_shortcuts = hou.getenv("HOUDINI_USER_PREF_DIR") + "/vex/include/triggers.db"
path_snippets = hou.getenv("HOUDINI_USER_PREF_DIR") + "/vex/include/snippets.db"
with open(path_shortcuts, 'r') as f:
src = pickle.load(f)
with open(path_snippets, 'r') as f:
rep = pickle.load(f)
##############################################
####### replace library ########
##############################################
index = 0
for src_item in src:
rep_item = rep[index]
if src_item in actualcode:
newcode = actualcode.replace(src_item,rep_item)
parm_code.set(newcode)
actualcode = newcode
index = index+1
def parm_generate (node,parm_code) :
snippet = parm_code.unexpandedString()
snippet_updated = ''
lines = snippet.split('n')
for (linenum, line) in enumerate(lines):
wf_midi.check_midi(node, line, linenum)
for (linenum, line) in enumerate(lines):
line_updated = line_parse (node, line, linenum)
snippet_updated += line_updated
if linenum < len(lines)-1 : snippet_updated += 'n'
parm_code.set(snippet_updated)
def parm_clean () :
node = wf_selection.parmnode()
ptg = node.parmTemplateGroup()
ptg.clear()
node.setParmTemplateGroup(ptg)
def qq_parse_uberfile () :
import pickle
path_VEX = hou.getenv("HOUDINI_USER_PREF_DIR") + "/vex/include/"
path_uber = path_VEX + "uber.vfl"
file_uber = open( path_uber )
uber_data = file_uber.read()
snippets = []
shortcuts = []
includes = ""
helplines = ""
blocks = uber_data.split('///------------------------------------------------------------------')
for block in blocks:
block = block.strip("-")
lines = block.split('n')
line_num = len(lines)
line_with_shortcut = -1
for i, line in enumerate(lines) :
if line.startswith("--") :
line_with_shortcut = i
if line_with_shortcut == -1 :
# block is a headline
# -------------------
helplines += "----------------n"
else :
# block is a definition
# ---------------------
snippet = ""
shortcut = ""
include = ""
helpline = ""
# snippet
for i in range( 0 , line_with_shortcut ) :
snippet += lines[i].lstrip("-")
snippet += "n"
snippet = snippet.strip("n")
# include
if lines[line_with_shortcut].startswith("--dont") :
#this definition is just a shortcut without function to be included
pass
else:
include += "//DON'T EDIT THIS FILE, IT GETS OVERWRITTEN BY A SCRIPTn"
for i in range( line_with_shortcut , len(lines) ) :
include += lines[i].lstrip("-")
include += "n"
# helpline
helpline = lines[line_with_shortcut]
helpline = helpline.lstrip("-")
helpline = helpline.split(" ")[1]
helpline = helpline.replace(" ", "")
helpline = helpline.split("(")[0]
# shortcut
shortcut = "qq" + helpline
snippets.append(snippet)
shortcuts.append(shortcut)
includes += include + "n"
helplines += helpline + "n"
# write to disk
# paths
path_includes = path_VEX + "qq.vfl"
path_shortcuts = path_VEX + "triggers.db"
path_snippets = path_VEX + "snippets.db"
path_helpcard = path_VEX + "helpcard.txt"
# files
file_includes = open( path_includes, 'w')
file_shortcuts = open( path_shortcuts, 'w')
file_snippets = open( path_snippets, 'w')
file_helpcard = open( path_helpcard, 'w')
# write
pickle.dump(shortcuts, file_shortcuts)
pickle.dump(snippets, file_snippets )
file_helpcard.write(helplines)
file_includes.write(includes)
def names_counts_in (node, ptg) :
names = []
counts = []
index = -1
for pt in ptg.parmTemplates() :
if pt.type() == hou.parmTemplateType.Folder :
if pt.folderType() == hou.folderType.Tabs :
try:
name = pt.name() + "1"
parm = node.parm(name).eval()
names.append(pt.name())
counts.append(0)
index = index+1
except:
pass
counts[index] = counts[index] + 1
return names, counts
def folders_trygo (node, name, count, dir) :
went = 0
parm = node.parm(name+"1")
actual = parm.eval()
if dir > 0 :
if actual < count-1:
parm.set(actual+1)
went = 1
if dir < 0 :
if actual > 0:
parm.set(actual-1)
went = 1
return went
def folders_tab_go (dir) :
node = wf_selection.parmnode()
A = node.parmTemplateGroup()
A_names, A_counts = names_counts_in (node, A)
for (iA,A_name) in enumerate(A_names) :
A_went = 0
B_went = 0
C_went = 0
A_actual = node.parm(A_name+"1").eval()
A_count = A_counts[iA]
pt_name = A_name
if A_actual > 0:
pt_name += "_" + str(A_actual)
B = node.parmTemplateGroup().find(pt_name)
B_names, B_counts = names_counts_in (node, B)
for (iB,B_name) in enumerate(B_names) :
B_actual = node.parm(B_name+"1").eval()
B_count = B_counts[iB]
pt_name = B_name
if B_actual > 0:
pt_name += "_" + str(B_actual)
C = node.parmTemplateGroup().find(pt_name)
C_names, C_counts = names_counts_in (node, C)
for (iC,C_name) in enumerate(C_names):
C_count = C_counts[iC]
C_went = folders_trygo(node, C_name, C_count , dir)
if C_went == 0:
B_went = folders_trygo(node, B_name, B_count , dir)
if B_went == 0 and C_went == 0:
A_went = folders_trygo(node, A_name, A_count , dir)