34 |
elif x < 1.5: return "NONE" |
elif x < 1.5: return "NONE" |
35 |
elif x < 3: return "SCALE_BY_TWO_NV" |
elif x < 3: return "SCALE_BY_TWO_NV" |
36 |
return "SCALE_BY_FOUR_NV" |
return "SCALE_BY_FOUR_NV" |
37 |
|
|
38 |
|
|
39 |
|
def matchop(str,i): |
40 |
|
def opchar(str, i): |
41 |
|
return i < len(str) and str[i] in [ "*", "/", "+", "-", ".", "|" ] |
42 |
|
if opchar(str, i): return i + 1 |
43 |
|
return 0 |
44 |
|
|
45 |
|
def matchid(str, i): |
46 |
|
def idchar(str, i): |
47 |
|
return i < len(str) and ("0" <= str[i] <= "9" or |
48 |
|
"A" <= str[i] <= "Z" or |
49 |
|
"a" <= str[i] <= "z" or |
50 |
|
str[i] == "_") |
51 |
|
if not idchar(str, i): return 0 |
52 |
|
while idchar(str, i): i += 1 |
53 |
|
return i |
54 |
|
|
55 |
|
def matchnum(str, i): |
56 |
|
if (i < len(str) and "0" <= str[i] <= "9") or ( |
57 |
|
i + 1 < len(str) and str[i] == "." and "0" <= str[i + 1] <= "9"): |
58 |
|
while i < len(str) and (str[i] == "." or "0" <= str[i] <= "9"): i += 1 |
59 |
|
return i |
60 |
|
return 0 |
61 |
|
|
62 |
|
def exptree(exp, i): |
63 |
|
if i == len(exp): return ([], i) |
64 |
|
|
65 |
|
if exp[i] in [" ", "\t"]: |
66 |
|
return exptree(exp, i + 1) |
67 |
|
elif exp[i] == "(": |
68 |
|
(subtree, pos) = exptree(exp, i + 1) |
69 |
|
car = ("sub", subtree) |
70 |
|
if pos == len(exp): |
71 |
|
print "WARNING: Missing closing parenthesis" |
72 |
|
else: |
73 |
|
pos += 1 |
74 |
|
elif exp[i] == ")": |
75 |
|
return ([], i) |
76 |
|
else: |
77 |
|
pos = matchnum(exp, i) |
78 |
|
if pos: |
79 |
|
car = (float(exp[i:pos]),) |
80 |
|
else: |
81 |
|
pos = matchid(exp, i) |
82 |
|
if pos: |
83 |
|
car = ("id", exp[i:pos]) |
84 |
|
else: |
85 |
|
pos = matchop(exp, i) |
86 |
|
|
87 |
|
if pos: |
88 |
|
car = (exp[i:pos],) |
89 |
|
else: |
90 |
|
return ([], i) |
91 |
|
|
92 |
|
(cdr,i) = exptree(exp, pos) |
93 |
|
|
94 |
|
return ([car] + cdr,i) |
95 |
|
|
96 |
|
|
97 |
|
def printtree(tree, pre = ""): |
98 |
|
for node in tree: |
99 |
|
if node[0] == "sub": |
100 |
|
printtree(node[1], pre + "> ") |
101 |
|
else: |
102 |
|
if len(node) == 1: node = node[0] |
103 |
|
print pre + str(node) |
104 |
|
|
105 |
|
def parsecomp(name): |
106 |
|
if name in ["a", "alpha"]: return "ALPHA" |
107 |
|
if name in ["b", "blue"]: return "BLUE" |
108 |
|
if name in ["rgb", "color", "col"]: return "RGB" |
109 |
|
return None |
110 |
|
|
111 |
|
def parseregs(tree): |
112 |
|
regmap = { |
113 |
|
"COL0": "PRIMARY_COLOR_NV", |
114 |
|
"COL1": "SECONDARY_COLOR_NV", |
115 |
|
"TEX0": "TEXTURE0", |
116 |
|
"TEX1": "TEXTURE1", |
117 |
|
"TEX2": "TEXTURE2", |
118 |
|
"TEX3": "TEXTURE3", |
119 |
|
"SPARE0": "SPARE0_NV", |
120 |
|
"SPARE1": "SPARE1_NV", |
121 |
|
"FOG": "FOG", |
122 |
|
"CONST0": "CONSTANT_COLOR0_NV", |
123 |
|
"CONST1": "CONSTANT_COLOR1_NV", |
124 |
|
"ZERO": "ZERO", |
125 |
|
"EF": "E_TIMES_F_NV", |
126 |
|
"SPARE0_PLUS_COL1" : "SPARE0_PLUS_SECONDARY_COLOR_NV", |
127 |
|
} |
128 |
|
|
129 |
|
i = 0 |
130 |
|
while i < len(tree): |
131 |
|
node = tree[i] |
132 |
|
if node[0] == "sub": |
133 |
|
parseregs(node[1]) |
134 |
|
else: |
135 |
|
if node[0] == "id" and regmap.has_key(node[1]): |
136 |
|
if (i + 2 < len(tree) and |
137 |
|
tree[i+1] == (".",) and |
138 |
|
tree[i+2][0] == "id" and |
139 |
|
parsecomp(tree[i+2][1])): |
140 |
|
tree[i:i+3] = [("reg", regmap[node[1]], |
141 |
|
parsecomp(tree[i+2][1]))] |
142 |
|
else: |
143 |
|
tree[i:i+1] = [("reg", regmap[node[1]], "RGB")] |
144 |
|
i += 1 |
145 |
|
|
146 |
|
def findregs(list, type = "reg"): |
147 |
|
indlist = [] |
148 |
|
for i in range(0,len(list)): |
149 |
|
if list[i] == type: indlist.append(i) |
150 |
|
return indlist |
151 |
|
|
152 |
|
def parseinput(tree): |
153 |
|
inputmap = { |
154 |
|
("+", "reg"): "SIGNED_IDENTITY_NV", |
155 |
|
("reg",): "UNSIGNED_IDENTITY_NV", |
156 |
|
(2, "reg", "-", 1): "EXPAND_NORMAL_NV", |
157 |
|
(2, "*", "reg", "-", 1): "EXPAND_NORMAL_NV", |
158 |
|
("reg", "-", .5): "HALF_BIAS_NORMAL_NV", |
159 |
|
("-", "reg"): "SIGNED_NEGATE_NV", |
160 |
|
(1, "-", "reg"): "UNSIGNED_INVERT_NV", |
161 |
|
(1, "-", 2, "reg"): "EXPAND_NEGATE_NV", |
162 |
|
(1, "-", 2, "*", "reg"): "EXPAND_NEGATE_NV", |
163 |
|
(.5, "-", "reg"): "HALF_BIAS_NEGATE" |
164 |
|
} |
165 |
|
|
166 |
|
key = tuple(map(lambda node: node[0], tree)) |
167 |
|
|
168 |
|
if inputmap.has_key(key): |
169 |
|
i = findregs(key)[0] |
170 |
|
tree[:] = [("in", tree[i][1], inputmap[key], tree[i][2])] |
171 |
|
else: |
172 |
|
for i in range(0,len(tree)): |
173 |
|
if tree[i][0] == "sub": |
174 |
|
parseinput(tree[i][1]) |
175 |
|
if len(tree[i][1]) == 1: |
176 |
|
tree[i] = tree[i][1][0] |
177 |
|
elif tree[i][0] == "reg": |
178 |
|
tree[i] = ("in", tree[i][1], inputmap["reg",], tree[i][2]) |
179 |
|
|
180 |
|
def setcheck(hash, name, value): |
181 |
|
if hash.has_key(name): |
182 |
|
if hash[name] != value: |
183 |
|
print "ERROR: Incompatible <" + name + ">'s" |
184 |
|
return 0 |
185 |
|
else: |
186 |
|
hash[name] = value |
187 |
|
return 1 |
188 |
|
|
189 |
|
def parseoutput(tree, out, outreg = "OUTREG"): |
190 |
|
|
191 |
|
scale = "NONE" |
192 |
|
bias = "NONE" |
193 |
|
|
194 |
|
outputscale = { |
195 |
|
("*", .5): "SCALE_BY_ONE_HALF_NV", |
196 |
|
("/", 2): "SCALE_BY_ONE_HALF_NV", |
197 |
|
("*", 1): "NONE", |
198 |
|
("*", 2): "SCALE_BY_TWO_NV", |
199 |
|
("*", 4): "SCALE_BY_FOUR_NV" |
200 |
|
} |
201 |
|
outputbias = { |
202 |
|
("-", .5): "BIAS_BY_NEGATIVE_ONE_HALF_NV", |
203 |
|
} |
204 |
|
|
205 |
|
l = map(lambda node: node[0], tree) |
206 |
|
if len(l) >= 2: |
207 |
|
key = tuple(l[1:]) |
208 |
|
if outputscale.has_key(key): |
209 |
|
scale = outputscale[key] |
210 |
|
tree[:] = tree[:-2] |
211 |
|
if len(tree) == 1 and tree[0][0] == "sub": |
212 |
|
tree[:] = tree[0][1] |
213 |
|
|
214 |
|
l = map(lambda node: node[0], tree) |
215 |
|
if len(l) >= 2: |
216 |
|
key = tuple(l[-2:]) |
217 |
|
if outputbias.has_key(key): |
218 |
|
bias = outputbias[key] |
219 |
|
tree[:] = tree[:-2] |
220 |
|
|
221 |
|
setcheck(out, "bias", bias) |
222 |
|
setcheck(out, "scale", scale) |
223 |
|
|
224 |
|
funcmap1 = { |
225 |
|
("in", ".", "in"): ("AB", "TRUE"), |
226 |
|
("in",): ("A", "FALSE"), |
227 |
|
("in", "*", "in"): ("AB", "TRUE"), |
228 |
|
} |
229 |
|
|
230 |
|
funcmap2 = { |
231 |
|
("in", "+", "in"): ("AC", "FALSE"), |
232 |
|
("in", "+", "in", "*", "in"): ("ACD", "FALSE"), |
233 |
|
("in", "*", "in", "+", "in"): ("ABC", "FALSE"), |
234 |
|
("in", "*", "in", "+", "in", "*", "in"): ("ABCD", "FALSE"), |
235 |
|
("in", "|", "in"): ("AC", "TRUE"), |
236 |
|
("in", "|", "in", "*", "in"): ("ACD", "TRUE"), |
237 |
|
("in", "*", "in", "|", "in"): ("ABC", "TRUE"), |
238 |
|
("in", "*", "in", "|", "in", "*", "in"): ("ABCD", "TRUE"), |
239 |
|
} |
240 |
|
|
241 |
|
key = tuple(map(lambda node: node[0], tree)) |
242 |
|
if funcmap1.has_key(key): |
243 |
|
func = funcmap1[key] |
244 |
|
regs = findregs(key, "in") |
245 |
|
|
246 |
|
foo = [ " ".join(tree[reg][1:]) for reg in regs ] |
247 |
|
if len(foo) == 1: foo += ["ZERO UNSIGNED_IDENTITY_NV ALPHA"] |
248 |
|
|
249 |
|
if (out.has_key("A") and out["A"] != foo[0] or |
250 |
|
out.has_key("B") and out["B"] != foo[1] or |
251 |
|
out.has_key("abDot") and out["abDot"] != func[1] or |
252 |
|
out.has_key("abOut")): |
253 |
|
setcheck(out, "C", foo[0]) |
254 |
|
setcheck(out, "D", foo[1]) |
255 |
|
setcheck(out, "cdDot", func[1]) |
256 |
|
setcheck(out, "cdOut", outreg) |
257 |
|
else: |
258 |
|
setcheck(out, "A", foo[0]) |
259 |
|
setcheck(out, "B", foo[1]) |
260 |
|
setcheck(out, "abDot", func[1]) |
261 |
|
setcheck(out, "abOut", outreg) |
262 |
|
|
263 |
|
elif funcmap2.has_key(key): |
264 |
|
func = funcmap2[key] |
265 |
|
regs = findregs(key, "in") |
266 |
|
|
267 |
|
for i in range(0,len(regs)): |
268 |
|
setcheck(out, func[0][i], " ".join(tree[regs[i]][1:])) |
269 |
|
|
270 |
|
for name in "ABCD": |
271 |
|
if name not in func[0]: |
272 |
|
setcheck(out, name, "ZERO UNSIGNED_IDENTITY_NV ALPHA") |
273 |
|
|
274 |
|
setcheck(out, "sumOut", outreg) |
275 |
|
setcheck(out, "muxSum", func[1]) |
276 |
|
else: |
277 |
|
print "Function not recognized" |
278 |
|
printtree(tree) |
279 |
|
return 0 |
280 |
|
|
281 |
|
return 1 |
282 |
|
|
283 |
|
# Parse general combiner stage code from lines such as |
284 |
|
# SPARE0 = (COL0 . COL1 - .5) * 2 |
285 |
|
# SPARE1 = (CONST0 * (1 - COL0) - .5) * 2 |
286 |
|
# SPARE0.alpha = (1 - 2 * COL0.alpha) + COL1.blue |
287 |
|
def parseGeneralCombiner(lines, stage = 0): |
288 |
|
out = { |
289 |
|
"RGB": {}, |
290 |
|
"ALPHA": {} |
291 |
|
} |
292 |
|
|
293 |
|
for line in lines: |
294 |
|
mid = line.find("=") |
295 |
|
if mid == -1: |
296 |
|
print "ERROR: '=' not found:", line |
297 |
|
return "" |
298 |
|
|
299 |
|
(left, lend) = exptree(line, 0) |
300 |
|
(right, rend) = exptree(line, mid + 1) |
301 |
|
if lend < mid: |
302 |
|
print "ERROR: extra input:", line[lend:mid] |
303 |
|
return "" |
304 |
|
if rend < len(line): |
305 |
|
print "ERROR: extra input:", line[rend:] |
306 |
|
return "" |
307 |
|
|
308 |
|
parseregs(left) |
309 |
|
parseregs(right) |
310 |
|
|
311 |
|
if len(left) != 1 or left[0][0] != "reg": |
312 |
|
print "ERROR: left side not a register:" |
313 |
|
printtree(left) |
314 |
|
return "" |
315 |
|
|
316 |
|
outreg = left[0][1] |
317 |
|
outcomp = left[0][2] |
318 |
|
|
319 |
|
parseinput(right) |
320 |
|
if not parseoutput(right, out[outcomp], outreg): |
321 |
|
return "" |
322 |
|
|
323 |
|
code = "".join(map(lambda x: "# " + x + "\n", lines)) |
324 |
|
for comp in "RGB", "ALPHA": |
325 |
|
if out[comp]: |
326 |
|
for var in "A", "B", "C", "D": |
327 |
|
if out[comp].has_key(var): |
328 |
|
code += ( |
329 |
|
"CombinerInputNV COMBINER%s_NV %s VARIABLE_%s_NV %s\n" |
330 |
|
% (stage, comp, var, out[comp][var])) |
331 |
|
|
332 |
|
code += ( |
333 |
|
"CombinerOutputNV COMBINER%s_NV %s %s %s %s %s %s %s %s %s\n" |
334 |
|
% (stage, comp, |
335 |
|
out[comp].get("abOut", "DISCARD_NV"), |
336 |
|
out[comp].get("cdOut", "DISCARD_NV"), |
337 |
|
out[comp].get("sumOut", "DISCARD_NV"), |
338 |
|
out[comp]["scale"], |
339 |
|
out[comp]["bias"], |
340 |
|
out[comp].get("abDot", "FALSE"), |
341 |
|
out[comp].get("cdDot", "FALSE"), |
342 |
|
out[comp].get("muxSum", "FALSE"), |
343 |
|
) |
344 |
|
) |
345 |
|
|
346 |
|
return code |
347 |
|
|
348 |
|
|
349 |
|
# Parse final combiner code from lines such as |
350 |
|
# alpha = 1-SPARE0 |
351 |
|
# EF = COL0 * (1 - COL1.alpha) |
352 |
|
# color = EF * FOG + (1-EF) * SPARE1 |
353 |
|
def parseFinalCombiner(lines): |
354 |
|
code = "".join(map(lambda x: "# " + x + "\n", lines)) |
355 |
|
for line in lines: |
356 |
|
mid = line.find("=") |
357 |
|
if mid == -1: |
358 |
|
print "ERROR: '=' not found:", line |
359 |
|
return "" |
360 |
|
|
361 |
|
(left, lend) = exptree(line, 0) |
362 |
|
(right, rend) = exptree(line, mid + 1) |
363 |
|
if lend < mid: |
364 |
|
print "ERROR: extra input:", line[lend:mid] |
365 |
|
return "" |
366 |
|
if rend < len(line): |
367 |
|
print "ERROR: extra input:", line[rend:] |
368 |
|
return "" |
369 |
|
|
370 |
|
outreg = None |
371 |
|
if len(left) == 1 and left[0][0] == "id": |
372 |
|
if left[0][1] == "EF": |
373 |
|
outreg = "EF" |
374 |
|
else: |
375 |
|
outreg = parsecomp(left[0][1]) |
376 |
|
|
377 |
|
if outreg not in ["EF", "RGB", "ALPHA"]: |
378 |
|
print "ERROR: left side must be EF, color, or alpha:" |
379 |
|
printtree(left) |
380 |
|
return "" |
381 |
|
|
382 |
|
parseregs(right) |
383 |
|
parseinput(right) |
384 |
|
|
385 |
|
key = tuple(map(lambda node: node[0], right)) |
386 |
|
|
387 |
|
if outreg == "EF": |
388 |
|
if key != ("in", "*", "in"): |
389 |
|
print "ERROR: EF must be a product" |
390 |
|
printtree(right) |
391 |
|
return "" |
392 |
|
code += ("FinalCombinerInput VARIABLE_E_NV " + |
393 |
|
" ".join(right[0][1:]) + "\n" + |
394 |
|
"FinalCombinerInput VARIABLE_F_NV " + |
395 |
|
" ".join(right[2][1:]) + "\n") |
396 |
|
elif outreg == "ALPHA": |
397 |
|
if key != ("in",): |
398 |
|
print "ERROR: alpha must be an input mapped register" |
399 |
|
printtree(right) |
400 |
|
return "" |
401 |
|
code += ("FinalCombinerInput VARIABLE_G_NV " + |
402 |
|
" ".join(right[0][1:]) + "\n") |
403 |
|
else: |
404 |
|
funcmap = { |
405 |
|
("in", "*", "in", "+", "in", "*", "in", "+", "in"): "ABACD", |
406 |
|
("in", "*", "in", "+", "in", "*", "in"): "ABAC", |
407 |
|
("in", "*", "in"): "AB", |
408 |
|
("in"): "D", |
409 |
|
} |
410 |
|
if funcmap.has_key(key): |
411 |
|
func = funcmap[key] |
412 |
|
regs = findregs(key, "in") |
413 |
|
|
414 |
|
for i in range(0,len(regs)): |
415 |
|
inreg = [foo for foo in right[regs[i]][1:]] |
416 |
|
|
417 |
|
if i > 0 and func[i] == "A": |
418 |
|
if inreg[1] == "UNSIGNED_IDENTITY_NV": |
419 |
|
inreg[1] = "UNSIGNED_INVERT_NV" |
420 |
|
if inreg[1] == "UNSIGNED_INVERT_NV": |
421 |
|
inreg[1] = "UNSIGNED_IDENTITY_NV" |
422 |
|
if inreg[1] != right[0][2] or inreg[0] != right[0][1]: |
423 |
|
print "ERROR: inconsistent A variables" |
424 |
|
printtree(right) |
425 |
|
return "" |
426 |
|
else: |
427 |
|
code += ("FinalCombinerInput VARIABLE_%s_NV %s\n" |
428 |
|
% (func[i], " ".join(inreg))) |
429 |
|
|
430 |
|
for reg in "ABCD": |
431 |
|
if reg not in func: |
432 |
|
code += ("FinalCombinerInput VARIABLE_%s_NV " |
433 |
|
"ZERO UNSIGNED_IDENTITY_NV ALPHA\n" % reg) |
434 |
|
|
435 |
|
return code |
436 |
|
|