root/trunk/scene/parse.d

Revision 52, 28.4 kB (checked in by FeepingCreature, 2 years ago)
  • A stuf
Line 
1 module scene.parse;
2
3 import scene.root, scene.nullobject;
4 import tools.base, base.types, tools.log;
5 public import tools.rd, scene.multival;
6 import tools.mersenne;
7
8 /** And in the parser, the nested matching functions and
9     confusing declarations will look up and shout "REWRITE US! "
10     And I'll whisper: "Maybe later. It sort of works for now. " **/
11
12 class ParseException : Exception { this(string s) { super("parse error: "~s); } }
13
14 struct parse_fns {
15   static {
16     alias SceneObject delegate(ref string) KEY;
17     alias SceneObject function(ref string) ALTKEY;
18     KEY[string] field;
19     KEY opIndexAssign(KEY dg, string key) { field[key] = dg; return dg; }
20     ALTKEY opIndexAssign(ALTKEY fn, string key) { field[key] = fn /todg; return fn; }
21     KEY opIndex(string key) { return field[key]; }
22     KEY* opIn_r(string key) { return key in field; }
23     int opApply(int delegate(ref string, ref KEY) dg) {
24       foreach (key, value; field)
25         if (auto res = dg(key, value)) return res;
26       return 0;
27     }
28   }
29 }
30
31 alias scene.multival.concat concat;
32
33 bool[string] builtin;
34
35 string[string] help;
36
37 const string TOKENS = " {}()[]&,.+-*/=<>;\"\n";
38
39 string filterComments(string text) {
40   string res;
41   int nest_level = 0;
42   text.glomp_parse([
43     "/*": (string pre, ref string post) { if (!nest_level) res ~= pre; nest_level ++; },
44     "*/": (string pre, ref string post) { if (!nest_level) throw new Exception("Too many */"); nest_level --; }
45   ], (string rest) { res ~= rest; });
46   string res2;
47   foreach (i, line; res.split("\n")) {
48     if (i) res2 ~= "\n";
49     res2 ~= line.cutOff("//");
50   }
51   return res2;
52 }
53
54 string getToken(ref string data) {
55   string buffer;
56   const string FLUSH = "buffer = buffer.strip(); if (buffer.length) return buffer; ";
57   while (data.length) {
58     auto old_data = data;
59     auto ch = data[0]; data = data[1 .. $];
60     if (TOKENS.find((&ch)[0..1]) != -1) {
61       data = old_data; // put ch back
62       mixin(FLUSH); // flush the buffer.
63       buffer ~= ch; // if it was empty ..
64       data = data[1 .. $]; // re-remove ch ..
65       mixin(FLUSH); // and flush.
66     } else buffer ~= ch;
67   }
68   return buffer;
69 }
70
71 bool gotToken(ref string s, out string token) {
72   if (!s.length) return false;
73   token = s.getToken();
74   return true;
75 }
76
77 static this() {
78   help["minus"] = ": minus b: CSG invert";
79   help["and"] = ": a and b: CSG intersect";
80   help["or"] = ": a or b: CSG merge";
81 }
82
83 extern(C) bool __workaround_gotInfixCSGEx__(ref string, out SceneObject, int arith_level = 0);
84 bool gotObjCSG(ref string s, out SceneObject so, int arith_level = 0) {
85   return s.__workaround_gotInfixCSGEx__(so, arith_level);
86 }
87 mixin(getWrap!("ObjCSG"));
88
89 bool gotObjRoot(ref string s, out SceneObject so) {
90   string s2 = s, t = getToken(s2);
91   foreach (key, fn; parse_fns) {
92     if (key == t) {
93       s = s2;
94       so = fn(s);
95       return true;
96     }
97   }
98   return false;
99 }
100
101
102 import tools.compat: atoi, atof, find;
103 bool gotInt(ref string s, out int i) {
104   auto s2 = s, t = getToken(s2), neg = false;
105   if (t == "-") {
106     neg = true;
107     t = getToken(s2);
108   }
109   bool isNum = true;
110   foreach (ch; t) if (ch < '0' || ch > '9') isNum = false;
111   if (!isNum) return false;
112   s = s2;
113   i = t.atoi();
114   if (neg) i = -i;
115   return true;
116 }
117 mixin(getWrap!("Int"));
118
119 bool gotFloat(ref string s, out float f) {
120   auto s2 = s, token = getToken(s2);
121   if (token == "infinity" || token == "infty" || token == "inf") { s = s2; f = FP.infinity; return true; }
122   s2 = s;
123   string fp_num;
124   if (s2.accept("-")) fp_num ~= "-";
125   bool isDigit(char c) { return c >= '0' && c <= '9'; }
126   while (s2.length && " \n\t".find(s2[0]) != -1) s2 = s2[1 .. $];
127   while (s2.length && isDigit(s2[0])) { fp_num ~= s2[0]; s2 = s2[1 .. $]; }
128   if (!s2.length || s2[0] != '.') return false;
129   s2 = s2[1 .. $]; fp_num ~= ".";
130   bool match2;
131   while (s2.length && isDigit(s2[0])) { match2 = true; fp_num ~= s2[0]; s2 = s2[1 .. $]; }
132   if (!match2) return false; // 2. is not a valid FP number
133   f = fp_num.atof();
134   s = s2;
135   return true;
136 }
137 mixin(getWrap!("Float"));
138
139 bool gotFloatExt(ref string s, out float f) {
140   if (gotFloat(s, f)) return true;
141   // this has its own case now.
142   // int i;
143   // if (gotInt(s, i)) { f = cast(float) i; return true; }
144   return false;
145 }
146
147 bool gotString(ref string s, out string str) {
148   auto s2 = s;
149   if (s2.accept("\"")) {
150     string buf;
151     while (s2.length && s2[0] != '\"') {
152       buf ~= s2[0];
153       s2 = s2[1 .. $];
154     }
155     if (!s2.length) throw new ParseException("Unterminated string constant "~s);
156     s = s2[1 .. $];
157     str = buf;
158     return true;
159   }
160   s2 = s; auto token = s2.getToken();
161   if (Variables.gotSpecific!(string)(token, str)) {
162     s = s2;
163     return true;
164   }
165   return false;
166 }
167 mixin(getWrap!("String"));
168
169 bool accept(ref string s, string what) {
170   auto s2 = s;
171   while (what.length) {
172     auto backup = s2, what_backup = what;
173     if (s2.getToken() != what.getToken()) {
174       failtext() = what_backup;
175       // failsource = backup.next_text();
176       return false;
177     }
178   }
179   failtext() = "Unknown";
180   s = s2; return true;
181 }
182
183 void expect(ref string s, string what) {
184   if (!s.accept(what))
185     throw new ParseException("Expected `"~what~"' in `"~s~"'");
186 }
187
188 bool gotVector(ref string s, out vec v) {
189   float f;
190   if (mixin(gotMatchExpr("s: [$f<-gotFloatExt$|<$f$>]"))) {
191     v = vec(f);
192     return true;
193   }
194   string fail = *failtext.ptr();
195   with (v) if (mixin(gotMatchExpr("s: <$x<-gotFloatExpr$, $y<-gotFloatExpr$, $z<-gotFloatExpr$>"))) return true;
196  
197   fail ~= " or "~failtext();
198   bool isHexDigit(char c) { return c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F'; }
199   ubyte hexDecode(char c) {
200     if (c >= '0' && c <= '9') return c - '0';
201     else if (c >= 'a' && c <= 'f') return c - 'a' + 10;
202     else if (c >= 'A' && c <= 'F') return c - 'A' + 10;
203   }
204   // 1/240 = (1/16)/15
205   float hexDecode2(char[] ch) in { assert(ch.length == 2); } body { return hexDecode(ch[0])/16f + hexDecode(ch[1])/240f; }
206   auto s2 = s, t = s2.getToken();
207   if (t[0] != '#') goto brk; t = t[1 .. $];
208   if (t.length == 3 || t.length == 6) {
209     // foreach (index, value; array)
210     foreach (ch; t) if (!isHexDigit(ch)) goto brk;
211   } else goto brk;
212   if (t.length == 3) v = vec(hexDecode(t[0])/15f, hexDecode(t[1])/15f, hexDecode(t[2])/15f);
213   else v = vec(hexDecode2(t[0..2]), hexDecode2(t[2..4]), hexDecode2(t[4..6]));
214   s = s2;
215   return true;
216 brk:
217   fail ~= " or hexnum";
218   fail ~= " or "~failtext();
219   failtext() = fail;
220   return false;
221 }
222 mixin(getWrap!("Vector"));
223
224 bool gotMultivalVar(ref string s, out Multival mv) {
225   auto s2 = s, token = s2.getToken();
226   if (Variables.gotVar(token, mv)) {
227     s = s2;
228     return true;
229   }
230   return false;
231 }
232
233 bool gotMultivalSimple(ref string s, out Multival mv, bool allowCSG = false) {
234   if (mixin(gotMatchExpr("s: ($mv$)"))) return true;
235   int i; float f; vec v; string st; SceneObject so;
236   if (allowCSG) return mixin(gotMatchExpr("s: [$f<-gotFloatExt#mv = f$|$i<-gotInt#mv = i$|$v<-gotVector#mv = v$"
237     "|$so<-gotObjCSG#mv=so$"
238     "|$mv<-gotMultivalVar$"
239     "|$st<-gotString#mv = st$"
240     "]"));
241   else return mixin(gotMatchExpr("s: [$f<-gotFloatExt#mv = f$|$i<-gotInt#mv = i$|$v<-gotVector#mv = v$"
242     "|$so<-gotObjRoot#mv=so$"
243     "|$mv<-gotMultivalVar$"
244     "|$st<-gotString#mv = st$"
245     "]"));
246 }
247
248 bool asFloat(Multival mv, out float f) {
249   if (mv.isFloat) { f = mv.f; return true; }
250   if (mv.isInt) { f = mv.i; return true; }
251   return false;
252 }
253
254 Multival merge(string OP)(Multival a, Multival b) {
255   Multival res;
256   // What the fuck was I thinking. Subtraction and division aren't commutative, idiot.
257   // if (b.isFun) swap(a, b); // no need to check for [not-function] [op] [function]
258   bool invertOp;
259   if (b.isFun && !a.isFun) {
260     swap(a, b);
261     invertOp = true;
262   }
263   float af, bf;
264   static if (OP == "%") {
265     const string TABLE = `
266             | Int       | Float
267       ------+-----------+------------
268       Int   | a.i % b.i | a.f % b.i
269       Float | a.i % b.f | a.f % b.f
270     `;
271   } else {
272     const string TABLE = `
273             | Int        | Float      | Vec
274       ------+------------+------------+------
275       Int   | a.i % b.i  | a.f % b.i  | a.v % b.i
276       Float | a.i % b.f  | a.f % b.f  | a.v % b.f
277       Vec   | a.i % b.v  | a.f % b.v  | a.v % b.v
278     `;
279   }
280   mixin(`if (false) { } ` ~ ctTableUnrollColMajor(
281     TABLE,
282     `else if (a.is$COL) { if (false) { } $BODY }`,
283     `else if (b.is$ROW) {
284       // swap operator order
285       res = mixin("$CELL".ctReplace("%", OP));
286       return res;
287     } `
288   ));
289   if (a.isFun) {
290     if (b.isFun) {
291       if (!equal(a.ParamType, b.ParamType))
292         throw new Exception("Cannot unify "~a.type[0 .. getlen(a.type)]~" and "~b.type[0 .. getlen(b.type)]~"!");
293       mixin(`if (false) { } ` ~ ctTableUnrollColMajor(
294         TABLE,
295         `else if (Multival.sample(a.RetType).is$COL) { if (false) { } $BODY }`,
296         `else if (Multival.sample(b.RetType).is$ROW) {
297           res = Multival(stuple(a.fun, b.fun) /xapply/ (Multiproc fn1, Multiproc fn2, Multival p) {
298             auto a = fn1(p), b = fn2(p);
299             return Multival(mixin("$CELL".ctReplace("%", OP)));
300           }, concat("d", a.ParamType, TypeToInfo!(typeof(mixin("$CELL".ctReplace("%", OP))))));
301         }`
302       ));
303     }
304     const string SetRes = `
305       if (invertOp) {
306         res = Multival(
307           strfix!("Multival(cast($RESTYPE) ($VALUE2 "~OP~" $VALUE1))", Multival)(tag=(a.typestr~" "~OP~" "~b.typestr), $PV),
308           concat("d", a.ParamType, TypeToInfo!($RESTYPE))
309         );
310       } else {
311         res = Multival(
312           strfix!("Multival(cast($RESTYPE) ($VALUE1 "~OP~" $VALUE2))", Multival)(tag=(a.typestr~" "~OP~" "~b.typestr), $PV),
313           concat("d", a.ParamType, TypeToInfo!($RESTYPE))
314         );
315       }
316       return res;`;
317     if (a.RetType[0] == 'i' && (b.isInt || b.isFun && b.RetType[0] == 'i')) {
318       const SetResAInt = ctReplace(SetRes, "$PV", "a.fun, $PV", "$VALUE1", "left(rest).i");
319       if (b.isInt) {
320         mixin(ctReplace(SetResAInt, "$PV", "b.i", "$RESTYPE", "int", "$VALUE2", "right"));
321       } else if (b.isFun) {
322         if (!equal(a.ParamType, b.ParamType))
323           throw new Exception(Format("Cannot compose functions of different parameters: ", a, " and ", b));
324         mixin(ctReplace(SetResAInt, "$PV", "b.fun", "$RESTYPE", "int", "$VALUE2", "right(rest).i"));
325       }
326     } else if (a.RetType[0] == 'f' || a.RetType[0] == 'i') {
327       const SetResAFloat = ctReplace(SetRes, "$PV", "a.fun, $PV", "$VALUE1", "left(rest).f");
328       if (a.RetType[0] == 'i' && b.isInt) {
329         mixin(ctReplace(SetResAFloat, "$PV", "b.i", "$RESTYPE", "int", "$VALUE2", "right"));
330       } else if (asFloat(b, bf)) {
331         mixin(ctReplace(SetResAFloat, "$PV", "bf", "$RESTYPE", "float", "$VALUE2", "right"));
332       } else if (OP != "%" && b.isVec) {
333         static if (OP != "%") // don't even generate the code
334           mixin(ctReplace(SetResAFloat, "$PV", "b.v", "$RESTYPE", "vec", "$VALUE2", "right"));
335       } else if (b.isFun) {
336         if (!equal(a.ParamType, b.ParamType))
337           throw new Exception(Format("Cannot compose functions of different parameters: ", a, " and ", b));
338         if (a.RetType[0] == 'i' && b.RetType[0] == 'i') {
339           mixin(ctReplace(SetResAFloat, "$PV", "b.fun", "$RESTYPE", "int", "$VALUE2", "right(rest).i"));
340         } else if (b.RetType[0] == 'f' || b.RetType[0] == 'i') {
341           mixin(ctReplace(SetResAFloat, "$PV", "b.fun", "$RESTYPE", "float", "$VALUE2", "right(rest).f"));
342         } else if (OP != "%" && b.RetType[0] == 'v') {
343           static if (OP != "%")
344             mixin(ctReplace(SetResAFloat, "$PV", "b.fun", "$RESTYPE", "vec", "$VALUE2", "right(rest).v"));
345         }
346       }
347     } else if (OP != "%" && a.RetType[0] == 'v') { // a evaluates to vec
348       static if (OP != "%") {
349         const SetResAVec = ctReplace(SetRes,
350           "$PV", "a.fun, $PV", "$VALUE1", "left(rest).v", "$RESTYPE", "vec"
351         );
352         if (asFloat(b, bf))
353           mixin(ctReplace(SetResAVec, "$PV", "bf", "$VALUE2", "right"));
354         else if (b.isVec)
355           mixin(ctReplace(SetResAVec, "$PV", "b.v", "$VALUE2", "right"));
356         else if (b.isFun) {
357           if (!equal(a.ParamType, b.ParamType))
358             throw new Exception(Format("Cannot compose functions of different parameters: ", a, " and ", b));
359           if (b.RetType[0] == 'f')
360             mixin(ctReplace(SetResAVec, "$PV", "b.fun", "$VALUE2", "right(rest).f"));
361           else if (b.RetType[0] == 'v')
362             mixin(ctReplace(SetResAVec, "$PV", "b.fun", "$VALUE2", "right(rest).v"));
363         }
364       }
365     }
366   }
367   fail(Format("Cannot merge ", a.type, " and ", b.type, " over ", OP));
368 }
369
370 bool gotValueExpr(ref string s, out Multival mv, int depth = 0, bool paramlist = false) {
371   const string MatchBlock = `
372       if (mixin(gotMatchExpr("s: $mv<-gotValueExpr/DEPTH+1, paramlist$"))) {
373         Multival second;
374         while (true) {
375           bool match;
376           foreach (i, bogus; Tuple!(OPS)) {
377             const OP = Tuple!(OPS)[i];
378             if (mixin(gotMatchExpr("s: "~OP~" $second<-gotValueExpr/DEPTH, paramlist$"))) {
379               mv = merge!(OP)(mv, second);
380               match = true;
381             }
382           }
383           if (!match) break;
384         }
385         return true;
386       } else return false;
387   `;
388   switch (depth) {
389     case 0: // match comma expressions (tuples)
390       auto backup = s;
391       if (!s.gotValueExpr(mv, 1, paramlist)) return false;
392 recheck0:
393       bool changed;
394       Multival next;
395       if (paramlist && mixin(gotMatchExpr("s: , $next<-gotValueExpr/0, true$"))) {
396         mv.append(next);
397         changed = true;
398       }
399       if (changed) goto recheck0;
400       return true;
401     case 1: mixin(ctReplace(MatchBlock, "OPS", `"+"[], "-"[]`, "DEPTH", "1")); // match +-
402     case 2: mixin(ctReplace(MatchBlock, "OPS", `"*"[], "/"[]`, "DEPTH", "2")); // match */
403     case 3: mixin(ctReplace(MatchBlock, "OPS", `"%"[]`, "DEPTH", "3")); // match */
404     case 4: // match closer expressions (.op, call)
405       auto backup1 = s;
406       if (!s.gotMultivalSimple(mv, paramlist)) return false;
407 recheck3:
408       bool changed;
409       if (mv.isVec || (mv.isFun && equal(mv.RetType(), "v"))) {
410         int part; // parse <vec>.x
411         if (mixin(gotMatchExpr("s: [.x $# part=0$ |.y $# part=1 $ |.z $# part=2 $ |.length $# part = 3 $]"))) {
412           if (mv.isVec) {
413             if (part == 3) mv = mv.v.length;
414             else mv = mv.v.field[part];
415           } else {
416             if (part == 3) {
417               mv = Multival(mv.fun /xapply/ (Multiproc dg, Multival rest) {
418                 return Multival(dg(rest).v.length);
419               }, concat("d", mv.ParamType, "f"));
420             } else {
421               mv = Multival(stuple(mv.fun, part) /xapply/ (Multiproc dg, int part, Multival rest) {
422                 return Multival(dg(rest).v.field[part]);
423               }, concat("d", mv.ParamType, "f"));
424             }
425           }
426           changed = true;
427         }
428       }
429       if (mv.isFun) {
430         Multival param;
431         // function call
432         auto backup2 = s;
433         if (mixin(gotMatchExpr("s: ($param<-gotValueExpr/0, true$)"))) {
434           // logln("Got param: ", param);
435           // call and composition
436           bool canCall() {
437             return equiv(param.type, mv.ParamType) || (param.isFun() && equiv(param.RetType, mv.ParamType));
438           }
439           if (!canCall) {
440             // try to do tail call
441             Multival tail;
442             SceneObject so;
443             string s2 = s;
444             if (mixin(gotMatchExpr("s2: [$so<-gotObjSimple#tail=so$|$tail$]"))) {
445               param.append(tail);
446               if (!canCall) fail("Call syntax used but types invalid");
447               else s = s2;
448             } else {
449               // can't call
450               fail(Format("Call syntax used but types invalid: ", param.type, " into ", mv.ParamType,
451                 "; ", backup2.next_text(), " into ", backup1.next_text()));
452             }
453           }
454           mv = mv.call(param);
455           // logln("Call -> ", mv);
456           changed = true;
457         }
458       }
459       if (changed) goto recheck3;
460       return true;
461     default: throw new Exception("Unsupported depth for gotValueExpr!");
462   }
463 }
464
465 bool gotFloatExpr(ref string s, out float f) {
466   if (mixin(gotMatchExpr("s: -$f<-gotFloatExpr$"))) { f = -f; return true; }
467   auto s2 = s; // speculative
468   Multival mv;
469   if (!s2.gotValueExpr(mv)) return false;
470   if (!asFloat(mv, f)) return false;
471   s = s2;
472   return true;
473 }
474
475 bool gotVecExpr(ref string s, out vec v) {
476   if (mixin(gotMatchExpr("s: -$v<-gotVecExpr$"))) { v = -v; return true; }
477   auto s2 = s; // speculative again
478   Multival mv;
479   if (!s2.gotValueExpr(mv)) return false;
480   float f;
481   if (asFloat(mv, f)) {
482     v = vec(f);
483   } else if (mv.isVec) {
484     v = mv.v;
485   } else return false;
486   s = s2;
487   return true;
488 }
489
490 bool gotFun(ref string s, out Multiproc dg, string full) {
491   auto s2 = s;
492   Multival mv;
493   if (!s2.gotValueExpr(mv)) return false;
494   if (!mv.isFun) { logln("Type mismatch: expected ", full, ", got ", mv.type[0 .. getlen(mv.type)]); return false; }
495   if (mv.type[0 .. getlen(mv.type)] != full) {
496     logln("Type mismatch: got ", mv.type[0 .. getlen(mv.type)], ", expected ", full);
497     return false;
498   }
499   dg = mv.fun;
500   s = s2;
501   return true;
502 }
503
504 bool gotMultival(ref string s, out Multival mv) {
505   auto s2 = s;
506   if (!s2.gotValueExpr(mv)) return false;
507   s = s2;
508   return true;
509 }
510
511 // does not include csg, just evaluation .. well, unless brackets are used
512 bool gotObjSimple(ref string s, out SceneObject so) {
513   if (mixin(gotMatchExpr("s: ($so$)"))) return true;
514   auto s2 = s;
515   Multival mv;
516   if (!s2.gotValueExpr(mv)) return false;
517   if (!mv.isObj) return false;
518   so = cast(SceneObject) mv.obj;
519   s = s2;
520   return true;
521 }
522
523 mixin Got!(
524   float, gotFloatExpr,
525   int, gotInt,
526   vec, gotVecExpr,
527   string, gotString,
528   SceneObject, gotObjCSG,
529   Multival, gotMultival
530 );
531
532 bool gotComplex(ref string s, out Multival mv) {
533   SceneObject so;
534   if (mixin(gotMatchExpr("s: [$so$ | ($so$)]"))) { mv = so; return true; }
535   return mixin(gotMatchExpr("s: $mv$"));
536 }
537
538 import tools.simplex;
539
540 final class Variables {
541   static {
542     SceneObject set_fn(ref string s) {
543       string name; Multival mv;
544       mixin(MatchExpr("s: ($name$) $mv<-gotComplex$"));
545       set(name, mv);
546       return NullObject;
547     }
548     Multival[string] vars;
549     Object sync;
550     void set(string s, Multival mv) { synchronized(sync) vars[s] = mv; }
551     private void unset(string s) { synchronized(sync) vars.remove(s); }
552     T getSpecific(T)(string name) {
553       Multival mv;
554       if (!gotVar(name, mv)) throw new Exception("Unknown identifier "~name);
555       if (!mv.matches!(T)())
556         throw new Exception(Format(
557           "Unexpected type: wanted ", T.stringof, ", but variable is  ",
558           [0: "float"[], 1: "vec", 2: "SceneObject", 3: "string", 4: "function"][mv.type]
559         ));
560       return mv.get!(T)();
561     }
562     void delegate() genScope(T)(string name, T t) {
563       Multival backup; bool restore;
564       synchronized(sync) if (auto p = name in vars) { backup = *p; restore = true; }
565       name.set(Multival(t));
566       return stuple(name, backup, restore) /apply/ (string st, Multival mv, bool restore) {
567         if (restore) st.set(mv);
568         else st.unset();
569       };
570     }
571     bool gotSpecific(T)(string name, out T t) {
572       Multival mv;
573       if (!gotVar(name, mv)) return false;
574       if (!mv.matches!(T)()) return false;
575       t = mv.get!(T)();
576       return true;
577     }
578     bool gotVar(string s, out Multival mv) {
579       bool res;
580       synchronized(sync)
581         if (auto p = s in vars) {
582           mv = *p;
583           // don't need dup now that we moved offset to implicit
584           // if (mv.isSO && mv.so) mv.so = mv.so.dup;
585           res = true;
586         }
587       return res;
588     }
589   }
590   static this() {
591     sync = new Object;
592     parse_fns["set"] = &set_fn;
593     builtin["set"] = true;
594     vars["x"] = Multival(vec(1, 0, 0));
595     vars["y"] = Multival(vec(0, 1, 0));
596     vars["z"] = Multival(vec(0, 0, 1));
597     vars["sin"] = Multival((Multival mv) { return Multival(cast(float) sin(mv.f)); }, "dff");
598     vars["cos"] = Multival((Multival mv) { return Multival(cast(float) cos(mv.f)); }, "dff");
599     vars["sqr"] = Multival((Multival mv) { return Multival(mv.f * mv.f); }, "dff");
600     vars["sqrt"] = Multival((Multival mv) { return Multival(cast(float) sqrt(mv.f)); }, "dff");
601     vars["checker"] = Multival((Multival mv) {
602       return Multival(stuple(mv[0].v, mv[1].v) /xapply/ (vec a, vec b, Multival m) {
603         auto v = m.v;
604         auto x = cast(uint) lrint(v.x), y = cast(uint) lrint(v.y), z = cast(uint) lrint(v.z);
605         return Multival(((x&1)^(y&1)^(z&1))?a:b);
606       }, TypeToInfo!(vec delegate(vec)));
607     }, TypeToInfo!(vec delegate(vec) delegate(vec, vec)));
608     vars["gensimplex"] = Multival((Multival mv) {
609       auto rng = new Mersenne(lrint(mv.get!(float)));
610       auto sim = Simplex({ return rng(); }); // only used to construct
611       static Multival simpfunc(ref Simplex si, Multival mv) {
612         return Multival(si.noise!(3)(mv.v.tuple));
613       }
614       return Multival(sim /xapply/ &simpfunc, TypeToInfo!(float delegate(vec)));
615     }, TypeToInfo!(float delegate(vec) delegate(float)));
616     vars["mkvec"] = Multival((Multival mv) {
617       if (equal(mv.type, TypeToInfo!(float delegate(vec), float delegate(vec), float delegate(vec)).ptr)) {
618         return Multival(
619           strfix!("Multival(vec(data[0](rest).f, data[1](rest).f, data[2](rest).f))", Multival)
620           (mv.fun, mv[1].fun, mv[2].fun), "dvv"
621         );
622       } else if (equal(mv.type, TypeToInfo!(float delegate(float), float delegate(float), float delegate(float)).ptr)) {
623         return Multival(
624           strfix!("Multival(vec(data[0](rest).f, data[1](rest).f, data[2](rest).f))", Multival)
625           (mv.fun, mv[1].fun, mv[2].fun), "dfv"
626         );
627       } else if (equal(mv.type, TypeToInfo!(float delegate(float)).ptr)) {
628         return Multival(
629           strfix!("Multival(vec(data[0](rest).f))", Multival)
630           (mv.fun), "dfv"
631         );
632       } else if (equal(mv.type, TypeToInfo!(float delegate(vec)).ptr)) {
633         return Multival(
634           strfix!("Multival(vec(data[0](rest).f))", Multival)
635           (mv.fun), "dvv"
636         );
637       } else {
638         logln("Invalid parameter for mkvec: ", mv);
639         dbg_break;
640       }
641     }, TypeToInfo!(vec delegate(vec) delegate(Multival)));
642     vars["ident_float"] = Multival((Multival mv) { return mv; }, TypeToInfo!(float delegate(float)));
643     vars["ident_vec"] = Multival((Multival mv) { return mv; }, TypeToInfo!(vec delegate(vec)));
644     /*vars["pow"] = Multival((Multival mv) {
645       return Multival(mv.f /xapply/ (float factor, Multival mv) {
646         return Multival(stuple(factor, mv.fun) /xapply/ (float factor, Multiproc dg, Multival param) {
647           return Multival(cast(float) pow(dg(param).f, factor));
648         }, TypeToInfo!(float delegate(vec)));
649       }, TypeToInfo!(float delegate(vec) delegate(float delegate(vec))));
650     }, TypeToInfo!(float delegate(vec) delegate(float delegate(vec)) delegate(float)));*/
651     vars["pow"] = Multival((Multival mv) {
652       return Multival(mv.f /xapply/ (float factor, Multival mv) {
653         return Multival(cast(float) pow(mv.f, factor));
654       }, TypeToInfo!(float delegate(float)));
655     }, TypeToInfo!(float delegate(float) delegate(float)));
656     vars["ifgz"] = Multival((Multival mv) {
657       return Multival(stuple(mv.v, mv[1].v) /xapply/ (vec v1, vec v2, Multival mv) {
658         return Multival((mv.f > 0)?v1:v2);
659       }, TypeToInfo!(vec delegate(float)));
660     }, TypeToInfo!(vec delegate(float) delegate(vec, vec)));
661     vars["×"] = Multival((Multival mv) {
662       return Multival(mv[0].v.cross(mv[1].v));
663     }, TypeToInfo!(vec delegate(vec, vec)));
664     vars["angle"] = Multival((Multival mv) {
665       return Multival(mv[0].v.angle(mv[1].v));
666     }, TypeToInfo!(float delegate(vec, vec)));
667     vars["rot"] = Multival((Multival mv) {
668       return Multival(stuple(mv[0].v, mv[1].f) /xapply/ (vec axis, float deg, vec v) {
669         return v.rotate(axis, deg);
670       }, TypeToInfo!(vec delegate(vec)));
671     }, TypeToInfo!(vec delegate(vec) delegate(vec, float)));
672     vars["toSpherical"] = Multival((Multival mv) {
673       vec v = mv.v, res = void;
674       res.x = v.length;
675       res.y = atan2(v.y, v.x);
676       res.z = atan2(sqrt(v.x * v.x + v.y * v.y), v.z);
677       return Multival(res);
678     }, TypeToInfo!(vec delegate(vec)));
679     vars["min"] = Multival((Multival mv) {
680       return Multival(mv.f /xapply/ (float f1, Multival mv) {
681         return Multival(min(f1, mv.f));
682       }, TypeToInfo!(float delegate(float)));
683     }, TypeToInfo!(float delegate(float) delegate(float)));
684     vars["max"] = Multival((Multival mv) {
685       return Multival(mv.f /xapply/ (float f1, Multival mv) {
686         return Multival(max(f1, mv.f));
687       }, TypeToInfo!(float delegate(float)));
688     }, TypeToInfo!(float delegate(float) delegate(float)));
689     vars["int"] = Multival((Multival mv) { return Multival(cast(int) mv.f); }, TypeToInfo!(int delegate(float)));
690     vars["blend"] = Multival((Multival mv) {
691       enforce(mv.length == 2, "Cannot blend more than two values as of yet. ");
692       enforce(mv[0].selftype == mv[1].selftype, "Cannot blend two values of disparate types: ", mv[0].type, " and ", mv[1].type);
693       if (mv[0].isFloat && mv[1].isFloat)
694         return Multival(stuple(mv[0].f, mv[1].f) /xapply/ (float a, float b, Multival c) {
695           auto f = c.f;
696           f -= floor(f);
697           return Multival(a * (1f - f) + b * f);
698         }, TypeToInfo!(float delegate(float)));
699       if (mv[0].isVec && mv[1].isVec)
700         return Multival(stuple(mv[0].v, mv[1].v) /xapply/ (vec a, vec b, Multival c) {
701           auto f = c.f;
702           f -= floor(f);
703           return Multival(a * (1f - f) + b * f);
704         }, TypeToInfo!(vec delegate(float)));
705       assert(false);
706     }, TypeToInfo!(Multival delegate(float) delegate(Multival)));
707     vars["ddf"] = Multival((Multival mv) { // dense data file; lines of raw-encoded floats
708       static Stuple!(int, ubyte[])[string] FileCache;
709       ubyte[] data; int width;
710       synchronized {
711         if (auto p = mv.s in FileCache)
712           ptuple(width, data) = *p;
713         else {
714           auto file = mv.s.read().castLike("");
715           width = file.slice("\n").atoi() * 4;
716           data = cast(ubyte[]) file;
717           FileCache[mv.s] = stuple(width, data);
718         }
719       }
720       return Multival(stuple(data, width) /apply/ (ubyte[] data, int width, Multival mv) {
721         auto line = data[width * mv.i .. width * (mv.i + 1)];
722         return Multival(line /apply/ (ubyte[] line, Multival mv) {
723           int column = mv.i;
724           auto chunk = line[column * 4 .. (column + 1) * 4];
725           return Multival(*cast(float*) chunk.ptr);
726         }, TypeToInfo!(float delegate(int)));
727       }, TypeToInfo!(float delegate(int) delegate(int)));
728     }, TypeToInfo!(float delegate(int) delegate(int) delegate(string)));
729     /// Thank you PoVRay
730     vars["ridged_mf"] = Multival((Multival mv) {
731       auto H = mv.f, lacun = mv[1].f, octaves = cast(int) (mv[2].f + 0.5),
732         offset = mv[3].f, gain = mv[4].f, noise = mv[5].fun;
733       float freq = 1f;
734       // I'm sorry. I'm so sorry ..
735       const string InnerCode = `
736         vec v1 = mv.v;
737         float signal = void;
738         const string recalcSignal = "
739           signal = noise(Multival(v1)).f * 2f - 1f;
740           if (signal < 0f) signal = -signal;
741           signal = offset - signal;
742           signal *= signal; ";
743         mixin(recalcSignal);
744         auto result = signal, weight = 1f;
745         foreach (v; ea[0 .. octaves]) {
746           v1 *= lacun;
747           weight = signal * gain;
748           if (weight > 1f) weight = 1f;
749           if (weight < 0f) weight = 0f;
750           mixin(recalcSignal);
751           signal *= weight;
752           result += signal * v;
753         }
754         return Multival(result);
755       `;
756       struct FewOctaves { float[10] eas; }
757       if (octaves <= 10) {
758         FewOctaves fo = void;
759         foreach (ref v; fo.eas[0 .. octaves]) {
760           v = pow(freq, -H);
761           freq *= lacun;
762         }
763         static Multival octaves1(FewOctaves fea, float lacun, int octaves, float offset, float gain, Multiproc noise, Multival mv) {
764           auto ea = fea.eas[0 .. octaves];
765           mixin(InnerCode);
766         }
767         return Multival(stuple(fo, lacun, octaves, offset, gain, noise) /xapply/ &octaves1, TypeToInfo!(float delegate(vec)));
768       } else {
769         auto ea = new float[octaves];
770         foreach (ref v; ea) {
771           v = pow(freq, -H);
772           freq *= lacun;
773         }
774         static Multival octaves2(float[] ea, float lacun, int octaves, float offset, float gain, Multiproc noise, Multival mv) {
775           mixin(InnerCode);
776         }
777         return Multival(stuple(ea, lacun, octaves, offset, gain, noise) /xapply/ &octaves2, TypeToInfo!(float delegate(vec)));
778       }
779     }, TypeToInfo!(float delegate(vec) delegate(Repeat!(float, 5), float delegate(vec))));
780   }
781 }
Note: See TracBrowser for help on using the browser.