Upgrading the Vector Math Node
Dynamically change the number of input and output parameters for the selected operation
This commit is contained in:
parent
085146b245
commit
7dae9e38d0
|
@ -4,49 +4,136 @@ import iron.math.Vec4;
|
|||
|
||||
class VectorMathNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
var v = new Vec4();
|
||||
public var property0: String; // Operation
|
||||
public var property1: Bool; // Separator Out
|
||||
var res_v = new Vec4();
|
||||
var res_f = 0.0;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var v1: Vec4 = inputs[0].get();
|
||||
var v2: Vec4 = inputs[1].get();
|
||||
if (v1 == null || v2 == null) return null;
|
||||
v.setFrom(v1);
|
||||
var f = 0.0;
|
||||
var p1: Vec4 = inputs[0].get();
|
||||
if (p1 == null) return null;
|
||||
res_v.setFrom(p1);
|
||||
switch (property0) {
|
||||
case "Add":
|
||||
v.add(v2);
|
||||
case "Subtract":
|
||||
v.sub(v2);
|
||||
case "Average":
|
||||
v.add(v2);
|
||||
v.x *= 0.5;
|
||||
v.y *= 0.5;
|
||||
v.z *= 0.5;
|
||||
case "Dot Product":
|
||||
f = v.dot(v2);
|
||||
v.set(f, f, f);
|
||||
case "Cross Product":
|
||||
v.cross(v2);
|
||||
case "Normalize":
|
||||
v.normalize();
|
||||
case "Multiply":
|
||||
v.x *= v2.x;
|
||||
v.y *= v2.y;
|
||||
v.z *= v2.z;
|
||||
case "Length":
|
||||
f = v.length();
|
||||
case "Distance":
|
||||
f = v.distanceTo(v2);
|
||||
case "Reflect":
|
||||
v.reflect(v2);
|
||||
// 1 arguments: Normalize, Length
|
||||
case "Normalize":
|
||||
res_v.normalize();
|
||||
case "Length":
|
||||
res_f = res_v.length();
|
||||
// 2 arguments: Distance, Reflect
|
||||
case "Distance": {
|
||||
var p2: Vec4 = inputs[1].get();
|
||||
if (p2 == null) return null;
|
||||
res_f = res_v.distanceTo(p2);
|
||||
}
|
||||
case "Reflect": {
|
||||
var p2: Vec4 = inputs[1].get();
|
||||
if (p2 == null) return null;
|
||||
res_v.reflect(p2);
|
||||
}
|
||||
// Many arguments: Add, Subtract, Average, Dot Product, Cross Product, Multiply
|
||||
case "Add": {
|
||||
var p2 = new Vec4();
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
p2 = inputs[i].get();
|
||||
if (p2 == null) return null;
|
||||
res_v.add(p2);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
case "Subtract": {
|
||||
var p2 = new Vec4();
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
p2 = inputs[i].get();
|
||||
if (p2 == null) return null;
|
||||
res_v.sub(p2);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
case "Average": {
|
||||
var p2 = new Vec4();
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
p2 = inputs[i].get();
|
||||
if (p2 == null) return null;
|
||||
res_v.add(p2);
|
||||
res_v.mult(0.5);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
case "Dot Product": {
|
||||
var p2 = new Vec4();
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
p2 = inputs[i].get();
|
||||
if (p2 == null) return null;
|
||||
res_f = res_v.dot(p2);
|
||||
res_v.set(res_f, res_f, res_f);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
case "Cross Product": {
|
||||
var p2 = new Vec4();
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
p2 = inputs[i].get();
|
||||
if (p2 == null) return null;
|
||||
res_v.cross(p2);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
case "Multiply": {
|
||||
var p2 = new Vec4();
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
p2 = inputs[i].get();
|
||||
if (p2 == null) return null;
|
||||
res_v.x *= p2.x;
|
||||
res_v.y *= p2.y;
|
||||
res_v.z *= p2.z;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
case "MultiplyFloats": {
|
||||
var p2_f = 1.0;
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
p2_f = inputs[i].get();
|
||||
if (p2_f == null) return null;
|
||||
res_v.mult(p2_f);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (from == 0) return v;
|
||||
else return f;
|
||||
// Return and check separator
|
||||
switch (from) {
|
||||
case 0: return res_v;
|
||||
case 1:
|
||||
if (property1) {
|
||||
return res_v.x;
|
||||
} else {
|
||||
return res_f;
|
||||
}
|
||||
case 2:
|
||||
if (property1) {
|
||||
return res_v.y;
|
||||
} else {
|
||||
return res_f;
|
||||
}
|
||||
case 3:
|
||||
if (property1) {
|
||||
return res_v.z;
|
||||
} else {
|
||||
return res_f;
|
||||
}
|
||||
case 4:
|
||||
if (property1) return res_f;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +1,149 @@
|
|||
from arm.logicnode.arm_nodes import *
|
||||
|
||||
class VectorMathNode(ArmLogicTreeNode):
|
||||
"""Operates vectors. Some operations uses only the first input."""
|
||||
"""Mathematical operations on vectors."""
|
||||
bl_idname = 'LNVectorMathNode'
|
||||
bl_label = 'Vector Math'
|
||||
arm_section = 'vector'
|
||||
arm_version = 1
|
||||
min_outputs = 2
|
||||
max_outputs = 5
|
||||
|
||||
def get_bool(self):
|
||||
return self['property1']
|
||||
|
||||
def set_bool(self, value):
|
||||
self['property1'] = value
|
||||
if value:
|
||||
if (self.property0 == 'Length') or (self.property0 == 'Distance') or (self.property0 == 'Dot Product'):
|
||||
self.outputs.remove(self.outputs.values()[-1]) # Distance/Length/Scalar
|
||||
self.add_output('NodeSocketFloat', 'X') # Result X
|
||||
self.add_output('NodeSocketFloat', 'Y') # Result Y
|
||||
self.add_output('NodeSocketFloat', 'Z') # Result Z
|
||||
if (self.property0 == 'Length'):
|
||||
self.add_output('NodeSocketFloat', 'Length') # Length
|
||||
if (self.property0 == 'Distance'):
|
||||
self.add_output('NodeSocketFloat', 'Distance') # Distance
|
||||
if (self.property0 == 'Dot Product'):
|
||||
self.add_output('NodeSocketFloat', 'Scalar') # Scalar
|
||||
|
||||
else:
|
||||
if (self.property0 == 'Length') or (self.property0 == 'Distance') or (self.property0 == 'Dot Product'):
|
||||
self.outputs.remove(self.outputs.values()[-1]) # Distance/Length/Scalar
|
||||
self.outputs.remove(self.outputs.values()[-1]) # Result X
|
||||
self.outputs.remove(self.outputs.values()[-1]) # Result Y
|
||||
self.outputs.remove(self.outputs.values()[-1]) # Result Z
|
||||
if (self.property0 == 'Length'):
|
||||
self.add_output('NodeSocketFloat', 'Length') # Length
|
||||
if (self.property0 == 'Distance'):
|
||||
self.add_output('NodeSocketFloat', 'Distance') # Distance
|
||||
if (self.property0 == 'Dot Product'):
|
||||
self.add_output('NodeSocketFloat', 'Scalar') # Scalar
|
||||
|
||||
property1: BoolProperty(name='Separator Out', default=False, set=set_bool, get=get_bool)
|
||||
|
||||
@staticmethod
|
||||
def get_enum_id_value(obj, prop_name, value):
|
||||
return obj.bl_rna.properties[prop_name].enum_items[value].identifier
|
||||
|
||||
@staticmethod
|
||||
def get_count_in(operation_name):
|
||||
return {
|
||||
'Add': 0,
|
||||
'Subtract': 0,
|
||||
'Average': 0,
|
||||
'Dot Product': 0,
|
||||
'Cross Product': 0,
|
||||
'Multiply': 0,
|
||||
'MultiplyFloats': 0,
|
||||
'Distance': 2,
|
||||
'Reflect': 2,
|
||||
'Normalize': 1,
|
||||
'Length': 1
|
||||
}.get(operation_name, 0)
|
||||
|
||||
def get_enum(self):
|
||||
return self['property0']
|
||||
|
||||
def set_enum(self, value):
|
||||
# Checking the selection of another operation
|
||||
select_current = self.get_enum_id_value(self, 'property0', value)
|
||||
select_prev = self.property0
|
||||
if select_prev != select_current:
|
||||
if (select_prev == 'Distance') or (select_prev == 'Length') or (self.property0 == 'Dot Product'):
|
||||
self.outputs.remove(self.outputs.values()[-1])
|
||||
# Many arguments: Add, Subtract, Average, Dot Product, Cross Product, Multiply, MultiplyFloats
|
||||
if (self.get_count_in(select_current) == 0):
|
||||
if (select_current == "MultiplyFloats") or (select_prev == "MultiplyFloats"):
|
||||
while (len(self.inputs) > 1):
|
||||
self.inputs.remove(self.inputs.values()[-1])
|
||||
if (select_current == "MultiplyFloats"):
|
||||
self.add_input('NodeSocketFloat', 'Value ' + str(len(self.inputs)))
|
||||
else:
|
||||
while (len(self.inputs) < 2):
|
||||
self.add_input('NodeSocketVector', 'Value ' + str(len(self.inputs)))
|
||||
if (select_current == 'Dot Product'):
|
||||
self.add_output('NodeSocketFloat', 'Scalar')
|
||||
# 2 arguments: Distance, Reflect
|
||||
if (self.get_count_in(select_current) == 2):
|
||||
count = 2
|
||||
if (select_prev == "MultiplyFloats"):
|
||||
count = 1
|
||||
while (len(self.inputs) > count):
|
||||
self.inputs.remove(self.inputs.values()[-1])
|
||||
while (len(self.inputs) < 2):
|
||||
self.add_input('NodeSocketVector', 'Value ' + str(len(self.inputs)))
|
||||
if (select_current == 'Distance'):
|
||||
self.add_output('NodeSocketFloat', 'Distance')
|
||||
# 1 argument: Normalize, Length
|
||||
if (self.get_count_in(select_current) == 1):
|
||||
while (len(self.inputs) > 1):
|
||||
self.inputs.remove(self.inputs.values()[-1])
|
||||
if (select_current == 'Length'):
|
||||
self.add_output('NodeSocketFloat', 'Length')
|
||||
self['property0'] = value
|
||||
|
||||
property0: EnumProperty(
|
||||
items = [('Add', 'Add', 'Add'),
|
||||
('Dot Product', 'Dot Product', 'Dot Product'),
|
||||
('Multiply', 'Multiply', 'Multiply'),
|
||||
('MultiplyFloats', 'Multiply (Floats)', 'Multiply (Floats)'),
|
||||
('Normalize', 'Normalize', 'Normalize'),
|
||||
('Subtract', 'Subtract', 'Subtract'),
|
||||
('Average', 'Average', 'Average'),
|
||||
('Cross Product', 'Cross Product', 'Cross Product'),
|
||||
('Length', 'Length', 'Length'),
|
||||
('Distance', 'Distance', 'Distance'),
|
||||
('Reflect', 'Reflect', 'Reflect'),
|
||||
],
|
||||
name='', default='Add')
|
||||
('Reflect', 'Reflect', 'Reflect')],
|
||||
name='', default='Add', set=set_enum, get=get_enum)
|
||||
|
||||
def __init__(self):
|
||||
array_nodes[str(id(self))] = self
|
||||
|
||||
def init(self, context):
|
||||
super(VectorMathNode, self).init(context)
|
||||
self.add_input('NodeSocketVector', 'Vector 1', default_value=[0.0, 0.0, 0.0])
|
||||
self.add_input('NodeSocketVector', 'Vector 2', default_value=[0.0, 0.0, 0.0])
|
||||
self['property0'] = 0
|
||||
self['property1'] = False
|
||||
self.add_input('NodeSocketVector', 'Value 0', default_value=[0.0, 0.0, 0.0])
|
||||
self.add_input('NodeSocketVector', 'Value 1', default_value=[0.0, 0.0, 0.0])
|
||||
self.add_output('NodeSocketVector', 'Result')
|
||||
self.add_output('NodeSocketFloat', 'Distance')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
layout.prop(self, 'property1') # Separator Out
|
||||
layout.prop(self, 'property0') # Operation
|
||||
# Buttons
|
||||
if (self.get_count_in(self.property0) == 0):
|
||||
row = layout.row(align=True)
|
||||
column = row.column(align=True)
|
||||
op = column.operator('arm.node_add_input', text='Add Value', icon='PLUS', emboss=True)
|
||||
op.node_index = str(id(self))
|
||||
op.name_format = 'Value {0}'
|
||||
if (self.property0 == "MultiplyFloats"):
|
||||
op.socket_type = 'NodeSocketFloat'
|
||||
else:
|
||||
op.socket_type = 'NodeSocketVector'
|
||||
column = row.column(align=True)
|
||||
op = column.operator('arm.node_remove_input', text='', icon='X', emboss=True)
|
||||
op.node_index = str(id(self))
|
||||
if len(self.inputs) == 2:
|
||||
column.enabled = False
|
Loading…
Reference in a new issue