-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathTemplate.cs
More file actions
184 lines (153 loc) · 4.75 KB
/
Template.cs
File metadata and controls
184 lines (153 loc) · 4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
using UnityEngine;
using System.Collections.Generic;
using Forge.Operators;
using Forge.Extensions;
namespace Forge {
[System.Serializable]
public class Template : ScriptableObject {
public delegate void ChangedHandler(Template template);
public event ChangedHandler Changed;
public Dictionary<string, Operator> Operators = new Dictionary<string, Operator>();
public List<IOConnection> Connections = new List<IOConnection>();
public string JSON = "";
private Dictionary<IOConnection, int> _connectionPriorities;
private void CommitChanges() {
TemplateSerializer.Serialize(this);
if (Changed != null) Changed(this);
}
void OnEnable() {
TemplateSerializer.Deserialize(this);
}
public void AddOperator(Operator op) {
Operators.Add(op.GUID, op);
CommitChanges();
}
public void RemoveOperator(Operator op) {
for (int i = Connections.Count-1; i >= 0; i--) {
if (Connections[i].From.GUID == op.GUID || Connections[i].To.GUID == op.GUID) {
Connections.Remove(Connections[i]);
}
}
Operators.Remove(op.GUID);
CommitChanges();
}
public Operator OperatorWithGUID(string GUID) {
foreach (var kvp in Operators) {
if (kvp.Value.GUID == GUID) return kvp.Value;
}
return null;
}
public void Connect(Operator outOp, IOOutlet output, Operator inOp, IOOutlet input) {
Connections.Add(new IOConnection() { From=outOp, Output=output, To=inOp, Input=input });
CommitChanges();
}
public void Disconnect(IOConnection conn) {
Connections.Remove(conn);
CommitChanges();
}
public void MoveConnection(IOConnection conn, int newIndex) {
Connections.Remove(conn);
Connections.Insert(newIndex, conn);
CommitChanges();
}
public IOConnection[] ConnectionsTo(Operator toOp, IOOutlet input) {
var conns = new List<IOConnection>();
foreach (IOConnection conn in Connections) {
if (conn.To.GUID == toOp.GUID && conn.Input == input) {
conns.Add(conn);
}
}
return conns.ToArray();
}
public Parameter[] Parameters {
get {
List<Parameter> inputs = new List<Parameter>();
foreach (KeyValuePair<string, Operator> op in Operators) {
if (op.Value is Parameter) {
inputs.Add(op.Value as Parameter);
}
}
return inputs.ToArray();
}
}
public void Clear() {
Operators.Clear();
Connections.Clear();
}
// Retrieves the first Operator with IsGeometryOutput = true
public Operator GetGeometryOutput() {
foreach (var kvp in Operators) {
if (kvp.Value.IsGeometryOutput) {
return kvp.Value;
}
}
return null;
}
private int GetPriority(IOConnection conn) {
if (_connectionPriorities.ContainsKey(conn)) {
return _connectionPriorities[conn];
} else {
var priority = 0;
foreach (var input in conn.From.Inputs) {
IOConnection[] conns = ConnectionsTo(conn.From, input);
foreach (var prior in conns) {
priority++;
priority += GetPriority(prior);
}
}
_connectionPriorities.Add(conn, priority);
return priority;
}
}
private int CompareConnectionPriority(IOConnection a, IOConnection b) {
int priorityA = _connectionPriorities[a];
int priorityB = _connectionPriorities[b];
if (priorityA < priorityB) return -1;
else if (priorityA > priorityB) return 1;
else return 0;
}
public virtual Geometry Build(ProceduralAsset asset) {
// Reset multi imputs
foreach (var kvp in Operators) {
foreach (IOOutlet input in kvp.Value.Inputs) {
if (input.DataType.IsCollection()) {
var clearMethod = input.DataType.GetMethod("Clear");
if (clearMethod != null) {
object collection = kvp.Value.GetValue(input);
clearMethod.Invoke(collection, null);
}
}
}
}
// Sort the connections by build priority
List<IOConnection> buildOrder = new List<IOConnection>();
_connectionPriorities = new Dictionary<IOConnection, int>();
foreach (var conn in Connections) {
GetPriority(conn);
buildOrder.Add(conn);
}
buildOrder.Sort(CompareConnectionPriority);
var geoOutputOp = GetGeometryOutput();
if (geoOutputOp != null) {
// Asset Parameters
foreach (Parameter par in Parameters) {
par.SetValue(par.ParameterInput, asset.GetParameter(par.GUID));
}
// Connections
foreach (IOConnection conn in buildOrder) {
object val = conn.From.GetValue(conn.Output);
conn.To.SetValue(conn.Input, val);
}
// For now, we just retrieve the Output with the Geometry type in the
// Operator marked as IsGeometryOutput. In the future, the template will
// have specialized output nodes instead.
foreach (IOOutlet output in geoOutputOp.Outputs) {
if (output.DataType == typeof(Geometry)) {
return geoOutputOp.GetValue<Geometry>(output);
}
}
}
return Geometry.Empty;
}
}
}