1 /** 
2  * Copyright: Enalye
3  * License: Zlib
4  * Authors: Enalye
5  */
6 module grimoire.stdlib.vec2;
7 
8 import std.conv : to;
9 import std.math;
10 import grimoire.assembly, grimoire.compiler, grimoire.runtime;
11 import grimoire.stdlib.util;
12 
13 private {
14     string _vec2iTypeName, _vec2fTypeName;
15     /// Ratio to multiply with to get a value in radians from a value in degrees.
16     enum double _degToRad = std.math.PI / 180.0;
17     /// Ratio to multiply with to get a value in degrees from a value in radians.
18     enum double _radToDeg = 180.0 / std.math.PI;
19 }
20 
21 package void grLoadStdLibVec2(GrLibrary library) {
22     library.addClass("Vec2", ["x", "y"], [
23             grAny("T", (t, d) {
24                 return (t.baseType == grInt) || (t.baseType == grFloat);
25             }), grAny("T")
26             ], ["T"]);
27 
28     GrType vec2iType = library.addTypeAlias("Vec2i", grGetClassType("Vec2", [
29                 grInt
30             ]));
31     GrType vec2fType = library.addTypeAlias("Vec2f", grGetClassType("Vec2", [
32                 grFloat
33             ]));
34 
35     _vec2iTypeName = grMangleComposite("Vec2", [grInt]);
36     _vec2fTypeName = grMangleComposite("Vec2", [grFloat]);
37 
38     // Ctors
39     library.addPrimitive(&_vec2i_1, "Vec2", [grInt], [vec2iType]);
40     library.addPrimitive(&_vec2f_1, "Vec2", [grFloat], [vec2fType]);
41     library.addPrimitive(&_vec2i_2, "Vec2", [grInt, grInt], [vec2iType]);
42     library.addPrimitive(&_vec2f_2, "Vec2", [grFloat, grFloat], [vec2fType]);
43 
44     library.addPrimitive(&_vec2i_0, "Vec2i", [], [vec2iType]);
45     library.addPrimitive(&_vec2i_1, "Vec2i", [grInt], [vec2iType]);
46     library.addPrimitive(&_vec2i_2, "Vec2i", [grInt, grInt], [vec2iType]);
47 
48     library.addPrimitive(&_vec2f_0, "Vec2f", [], [vec2fType]);
49     library.addPrimitive(&_vec2f_1, "Vec2f", [grFloat], [vec2fType]);
50     library.addPrimitive(&_vec2f_2, "Vec2f", [grFloat, grFloat], [vec2fType]);
51 
52     // Cast
53     library.addCast(&_vec2i_vec2f, vec2iType, vec2fType);
54     library.addCast(&_vec2f_vec2i, vec2fType, vec2iType);
55 
56     // Prints
57     library.addPrimitive(&_printVec2i, "print", [vec2iType]);
58     library.addPrimitive(&_printlVec2i, "printl", [vec2iType]);
59     library.addPrimitive(&_printVec2f, "print", [vec2fType]);
60     library.addPrimitive(&_printlVec2f, "printl", [vec2fType]);
61 
62     // Operators
63     static foreach (op; ["+", "-", "*", "/", "%"]) {
64         library.addOperator(&_opBinaryVec2i!op, op, [vec2iType, vec2iType], vec2iType);
65         library.addOperator(&_opBinaryScalarVec2i!op, op, [vec2iType, grInt], vec2iType);
66         library.addOperator(&_opBinaryScalarRightVec2i!op, op, [
67                 grFloat, vec2iType
68                 ], vec2iType);
69     }
70     static foreach (op; ["==", "!=", ">=", "<=", ">", "<"]) {
71         library.addOperator(&_opBinaryCompareVec2i!op, op, [
72                 vec2iType, vec2iType
73                 ], grBool);
74     }
75 
76     static foreach (op; ["+", "-", "*", "/", "%"]) {
77         library.addOperator(&_opBinaryCompareVec2f!op, op, [
78                 vec2fType, vec2fType
79                 ], vec2fType);
80         library.addOperator(&_opBinaryScalarVec2f!op, op, [vec2fType, grFloat], vec2fType);
81         library.addOperator(&_opBinaryScalarRightVec2f!op, op, [
82                 grFloat, vec2fType
83                 ], vec2fType);
84     }
85     static foreach (op; ["==", "!=", ">=", "<=", ">", "<"]) {
86         library.addOperator(&_opBinaryCompareVec2f!op, op, [
87                 vec2fType, vec2fType
88                 ], grBool);
89     }
90 
91     // Utility
92     library.addPrimitive(&_oneVec2i, "Vec2i_one", [], [vec2iType]);
93     library.addPrimitive(&_oneVec2f, "Vec2f_one", [], [vec2fType]);
94     library.addPrimitive(&_halfVec2f, "Vec2f_half", [], [vec2fType]);
95     library.addPrimitive(&_upVec2i, "Vec2i_up", [], [vec2iType]);
96     library.addPrimitive(&_upVec2f, "Vec2f_up", [], [vec2fType]);
97     library.addPrimitive(&_downVec2i, "Vec2i_down", [], [vec2iType]);
98     library.addPrimitive(&_downVec2f, "Vec2f_down", [], [vec2fType]);
99     library.addPrimitive(&_leftVec2i, "Vec2i_left", [], [vec2iType]);
100     library.addPrimitive(&_leftVec2f, "Vec2f_left", [], [vec2fType]);
101     library.addPrimitive(&_rightVec2i, "Vec2i_right", [], [vec2iType]);
102     library.addPrimitive(&_rightVec2f, "Vec2f_right", [], [vec2fType]);
103 
104     library.addPrimitive(&_unpackVec2i, "unpack", [vec2iType], [grInt, grInt]);
105     library.addPrimitive(&_unpackVec2f, "unpack", [vec2fType], [
106             grFloat, grFloat
107             ]);
108 
109     library.addPrimitive(&_isZeroVec2i, "zero?", [vec2iType], [grBool]);
110     library.addPrimitive(&_isZeroVec2f, "zero?", [vec2fType], [grBool]);
111 
112     // Operations
113     library.addPrimitive(&_sumVec2i, "sum", [vec2iType], [grInt]);
114     library.addPrimitive(&_sumVec2f, "sum", [vec2fType], [grFloat]);
115     library.addPrimitive(&_distanceVec2i, "distance", [vec2iType, vec2iType], [
116             grFloat
117             ]);
118     library.addPrimitive(&_distanceVec2f, "distance", [vec2fType, vec2fType], [
119             grFloat
120             ]);
121     library.addPrimitive(&_distanceVec2i, "distanceSq", [vec2iType, vec2iType], [
122             grFloat
123             ]);
124     library.addPrimitive(&_distanceVec2f, "distanceSq", [vec2fType, vec2fType], [
125             grFloat
126             ]);
127     library.addPrimitive(&_dotVec2i, "dot", [vec2iType, vec2iType], [grFloat]);
128     library.addPrimitive(&_dotVec2f, "dot", [vec2fType, vec2fType], [grFloat]);
129     library.addPrimitive(&_crossVec2i, "cross", [vec2iType, vec2iType], [
130             grFloat
131             ]);
132     library.addPrimitive(&_crossVec2f, "cross", [vec2fType, vec2fType], [
133             grFloat
134             ]);
135     library.addPrimitive(&_normalVec2i, "normal", [vec2iType], [vec2iType]);
136     library.addPrimitive(&_normalVec2f, "normal", [vec2fType], [vec2fType]);
137     library.addPrimitive(&_angleVec2i, "angle", [vec2iType], [grFloat]);
138     library.addPrimitive(&_angleVec2f, "angle", [vec2fType], [grFloat]);
139     library.addPrimitive(&_rotateVec2f, "rotate!", [vec2fType, grFloat], [
140             vec2fType
141             ]);
142     library.addPrimitive(&_rotatedVec2f, "rotate", [vec2fType, grFloat], [
143             vec2fType
144             ]);
145     library.addPrimitive(&_angledVec2f, "Vec2f_angled", [grFloat], [vec2fType]);
146     library.addPrimitive(&_lengthVec2i, "length", [vec2iType], [grFloat]);
147     library.addPrimitive(&_lengthVec2f, "length", [vec2fType], [grFloat]);
148     library.addPrimitive(&_lengthSquaredVec2i, "lengthSq", [vec2iType], [
149             grFloat
150             ]);
151     library.addPrimitive(&_lengthSquaredVec2f, "lengthSq", [vec2fType], [
152             grFloat
153             ]);
154     library.addPrimitive(&_normalizeVec2f, "normalize!", [vec2fType], [
155             vec2fType
156             ]);
157     library.addPrimitive(&_normalizedVec2f, "normalize", [vec2fType], [
158             vec2fType
159             ]);
160 }
161 
162 // Ctors ------------------------------------------
163 private void _vec2i_0(GrCall call) {
164     GrObject self = call.createObject(_vec2iTypeName);
165     if(!self) {
166         call.raise("UnknownClassError");
167         return;
168     }
169     self.setInt("x", 0);
170     self.setInt("y", 0);
171     call.setObject(self);
172 }
173 
174 private void _vec2i_1(GrCall call) {
175     GrObject self = call.createObject(_vec2iTypeName);
176     if(!self) {
177         call.raise("UnknownClassError");
178         return;
179     }
180     const GrInt value = call.getInt(0);
181     self.setInt("x", value);
182     self.setInt("y", value);
183     call.setObject(self);
184 }
185 
186 private void _vec2i_2(GrCall call) {
187     GrObject self = call.createObject(_vec2iTypeName);
188     if(!self) {
189         call.raise("UnknownClassError");
190         return;
191     }
192     self.setInt("x", call.getInt(0));
193     self.setInt("y", call.getInt(1));
194     call.setObject(self);
195 }
196 
197 private void _vec2f_0(GrCall call) {
198     GrObject self = call.createObject(_vec2fTypeName);
199     if(!self) {
200         call.raise("UnknownClassError");
201         return;
202     }
203     self.setFloat("x", 0f);
204     self.setFloat("y", 0f);
205     call.setObject(self);
206 }
207 
208 private void _vec2f_1(GrCall call) {
209     GrObject self = call.createObject(_vec2fTypeName);
210     if(!self) {
211         call.raise("UnknownClassError");
212         return;
213     }
214     const GrFloat value = call.getFloat(0);
215     self.setFloat("x", value);
216     self.setFloat("y", value);
217     call.setObject(self);
218 }
219 
220 private void _vec2f_2(GrCall call) {
221     GrObject self = call.createObject(_vec2fTypeName);
222     if(!self) {
223         call.raise("UnknownClassError");
224         return;
225     }
226     self.setFloat("x", call.getFloat(0));
227     self.setFloat("y", call.getFloat(1));
228     call.setObject(self);
229 }
230 
231 // Cast ------------------------------------------
232 private void _vec2i_vec2f(GrCall call) {
233     GrObject self = call.getObject(0);
234     if (!self) {
235         call.raise("NullError");
236         return;
237     }
238     GrObject v = call.createObject(_vec2fTypeName);
239     if(!v) {
240         call.raise("UnknownClassError");
241         return;
242     }
243     v.setFloat("x", cast(GrFloat) self.getInt("x"));
244     v.setFloat("y", cast(GrFloat) self.getInt("y"));
245     call.setObject(v);
246 }
247 
248 private void _vec2f_vec2i(GrCall call) {
249     GrObject self = call.getObject(0);
250     if (!self) {
251         call.raise("NullError");
252         return;
253     }
254     GrObject v = call.createObject(_vec2iTypeName);
255     if(!v) {
256         call.raise("UnknownClassError");
257         return;
258     }
259     v.setInt("x", cast(GrInt) self.getFloat("x"));
260     v.setInt("y", cast(GrInt) self.getFloat("y"));
261     call.setObject(v);
262 }
263 
264 // Prints ------------------------------------------
265 private void _printVec2i(GrCall call) {
266     GrObject self = call.getObject(0);
267     if (!self) {
268         _stdOut("Vec2(0, 0)");
269         return;
270     }
271     _stdOut("Vec2(" ~ to!GrString(self.getInt("x")) ~ ", " ~ to!GrString(self.getInt("y")) ~ ")");
272 }
273 
274 private void _printlVec2i(GrCall call) {
275     GrObject self = call.getObject(0);
276     if (!self) {
277         _stdOut("{0;0}\n");
278         return;
279     }
280     _stdOut("Vec2(" ~ to!GrString(self.getInt("x")) ~ ", " ~ to!GrString(self.getInt("y")) ~ ")\n");
281 }
282 
283 private void _printVec2f(GrCall call) {
284     GrObject self = call.getObject(0);
285     if (!self) {
286         _stdOut("{0;0}");
287         return;
288     }
289     _stdOut("Vec2(" ~ to!GrString(self.getFloat("x")) ~ ", " ~ to!GrString(self.getFloat("y")) ~ ")");
290 }
291 
292 private void _printlVec2f(GrCall call) {
293     GrObject self = call.getObject(0);
294     if (!self) {
295         _stdOut("{0;0}\n");
296         return;
297     }
298     _stdOut("Vec2(" ~ to!GrString(self.getFloat("x")) ~ ", " ~ to!GrString(self.getFloat("y")) ~ ")\n");
299 }
300 
301 /// Operators ------------------------------------------
302 private void _opBinaryVec2i(string op)(GrCall call) {
303     GrObject self = call.createObject(_vec2iTypeName);
304     if(!self) {
305         call.raise("UnknownClassError");
306         return;
307     }
308     GrObject v1 = call.getObject(0);
309     GrObject v2 = call.getObject(1);
310     if (!v1 || !v2) {
311         call.raise("NullError");
312         return;
313     }
314     mixin("self.setInt(\"x\", v1.getInt(\"x\")" ~ op ~ "v2.getInt(\"x\"));");
315     mixin("self.setInt(\"y\", v1.getInt(\"y\")" ~ op ~ "v2.getInt(\"y\"));");
316     call.setObject(self);
317 }
318 
319 private void _opBinaryScalarVec2i(string op)(GrCall call) {
320     GrObject self = call.createObject(_vec2iTypeName);
321     if(!self) {
322         call.raise("UnknownClassError");
323         return;
324     }
325     GrObject v = call.getObject(0);
326     const GrInt s = call.getInt(1);
327     if (!v) {
328         call.raise("NullError");
329         return;
330     }
331     mixin("self.setInt(\"x\", v.getInt(\"x\")" ~ op ~ "s);");
332     mixin("self.setInt(\"y\", v.getInt(\"y\")" ~ op ~ "s);");
333     call.setObject(self);
334 }
335 
336 private void _opBinaryScalarRightVec2i(string op)(GrCall call) {
337     GrObject self = call.createObject(_vec2iTypeName);
338     if(!self) {
339         call.raise("UnknownClassError");
340         return;
341     }
342     GrObject v = call.getObject(0);
343     const GrInt s = call.getInt(1);
344     if (!v) {
345         call.raise("NullError");
346         return;
347     }
348     mixin("self.setInt(\"x\", s" ~ op ~ "v.getInt(\"x\"));");
349     mixin("self.setInt(\"y\", s" ~ op ~ "v.getInt(\"y\"));");
350     call.setObject(self);
351 }
352 
353 private void _opBinaryCompareVec2i(string op)(GrCall call) {
354     GrObject v1 = call.getObject(0);
355     GrObject v2 = call.getObject(1);
356     if (!v1 || !v2) {
357         call.raise("NullError");
358         return;
359     }
360     mixin("call.setBool(
361         v1.getInt(\"x\")" ~ op ~ "v2.getInt(\"x\") &&
362         v1.getInt(\"y\")" ~ op ~ "v2.getInt(\"y\"));");
363 }
364 
365 private void _opBinaryVec2f(string op)(GrCall call) {
366     GrObject self = call.createObject(_vec2fTypeName);
367     if(!self) {
368         call.raise("UnknownClassError");
369         return;
370     }
371     GrObject v1 = call.getObject(0);
372     GrObject v2 = call.getObject(1);
373     if (!v1 || !v2) {
374         call.raise("NullError");
375         return;
376     }
377     mixin("self.setFloat(\"x\", v1.getFloat(\"x\")" ~ op ~ "v2.getFloat(\"x\"));");
378     mixin("self.setFloat(\"y\", v1.getFloat(\"y\")" ~ op ~ "v2.getFloat(\"y\"));");
379     call.setObject(self);
380 }
381 
382 private void _opBinaryScalarVec2f(string op)(GrCall call) {
383     GrObject self = call.createObject(_vec2fTypeName);
384     if(!self) {
385         call.raise("UnknownClassError");
386         return;
387     }
388     GrObject v = call.getObject(0);
389     const GrFloat s = call.getFloat(1);
390     if (!v) {
391         call.raise("NullError");
392         return;
393     }
394     mixin("self.setFloat(\"x\", v.getFloat(\"x\")" ~ op ~ "s);");
395     mixin("self.setFloat(\"y\", v.getFloat(\"y\")" ~ op ~ "s);");
396     call.setObject(self);
397 }
398 
399 private void _opBinaryScalarRightVec2f(string op)(GrCall call) {
400     GrObject self = call.createObject(_vec2fTypeName);
401     if(!self) {
402         call.raise("UnknownClassError");
403         return;
404     }
405     GrObject v = call.getObject(0);
406     const GrFloat s = call.getFloat(1);
407     if (!v) {
408         call.raise("NullError");
409         return;
410     }
411     mixin("self.setFloat(\"x\", s" ~ op ~ "v.getFloat(\"x\"));");
412     mixin("self.setFloat(\"y\", s" ~ op ~ "v.getFloat(\"y\"));");
413     call.setObject(self);
414 }
415 
416 private void _opBinaryCompareVec2f(string op)(GrCall call) {
417     GrObject v1 = call.getObject(0);
418     GrObject v2 = call.getObject(1);
419     if (!v1 || !v2) {
420         call.raise("NullError");
421         return;
422     }
423     mixin("call.setBool(
424         v1.getFloat(\"x\")" ~ op ~ "v2.getFloat(\"x\") &&
425         v1.getFloat(\"y\")" ~ op
426             ~ "v2.getFloat(\"y\"));");
427 }
428 
429 // Utility ------------------------------------------
430 private void _oneVec2i(GrCall call) {
431     GrObject self = call.createObject(_vec2iTypeName);
432     if(!self) {
433         call.raise("UnknownClassError");
434         return;
435     }
436     self.setInt("x", 1);
437     self.setInt("y", 1);
438     call.setObject(self);
439 }
440 
441 private void _oneVec2f(GrCall call) {
442     GrObject self = call.createObject(_vec2fTypeName);
443     if(!self) {
444         call.raise("UnknownClassError");
445         return;
446     }
447     self.setFloat("x", 1f);
448     self.setFloat("y", 1f);
449     call.setObject(self);
450 }
451 
452 private void _halfVec2f(GrCall call) {
453     GrObject self = call.createObject(_vec2fTypeName);
454     if(!self) {
455         call.raise("UnknownClassError");
456         return;
457     }
458     self.setFloat("x", .5f);
459     self.setFloat("y", .5f);
460     call.setObject(self);
461 }
462 
463 private void _upVec2i(GrCall call) {
464     GrObject self = call.createObject(_vec2iTypeName);
465     if(!self) {
466         call.raise("UnknownClassError");
467         return;
468     }
469     self.setInt("y", 1);
470     call.setObject(self);
471 }
472 
473 private void _upVec2f(GrCall call) {
474     GrObject self = call.createObject(_vec2fTypeName);
475     if(!self) {
476         call.raise("UnknownClassError");
477         return;
478     }
479     self.setFloat("y", 1f);
480     call.setObject(self);
481 }
482 
483 private void _downVec2i(GrCall call) {
484     GrObject self = call.createObject(_vec2iTypeName);
485     if(!self) {
486         call.raise("UnknownClassError");
487         return;
488     }
489     self.setInt("y", -1);
490     call.setObject(self);
491 }
492 
493 private void _downVec2f(GrCall call) {
494     GrObject self = call.createObject(_vec2fTypeName);
495     if(!self) {
496         call.raise("UnknownClassError");
497         return;
498     }
499     self.setFloat("y", -1f);
500     call.setObject(self);
501 }
502 
503 private void _leftVec2i(GrCall call) {
504     GrObject self = call.createObject(_vec2iTypeName);
505     if(!self) {
506         call.raise("UnknownClassError");
507         return;
508     }
509     self.setInt("x", -1);
510     call.setObject(self);
511 }
512 
513 private void _leftVec2f(GrCall call) {
514     GrObject self = call.createObject(_vec2fTypeName);
515     if(!self) {
516         call.raise("UnknownClassError");
517         return;
518     }
519     self.setFloat("x", -1f);
520     call.setObject(self);
521 }
522 
523 private void _rightVec2i(GrCall call) {
524     GrObject self = call.createObject(_vec2iTypeName);
525     if(!self) {
526         call.raise("UnknownClassError");
527         return;
528     }
529     self.setInt("x", 1);
530     call.setObject(self);
531 }
532 
533 private void _rightVec2f(GrCall call) {
534     GrObject self = call.createObject(_vec2fTypeName);
535     if(!self) {
536         call.raise("UnknownClassError");
537         return;
538     }
539     self.setFloat("x", 1f);
540     call.setObject(self);
541 }
542 
543 private void _unpackVec2i(GrCall call) {
544     GrObject self = call.getObject(0);
545     if (!self) {
546         call.raise("NullError");
547         return;
548     }
549     call.setInt(self.getInt("x"));
550     call.setInt(self.getInt("y"));
551 }
552 
553 private void _unpackVec2f(GrCall call) {
554     GrObject self = call.getObject(0);
555     if (!self) {
556         call.raise("NullError");
557         return;
558     }
559     call.setFloat(self.getFloat("x"));
560     call.setFloat(self.getFloat("y"));
561 }
562 
563 private void _isZeroVec2i(GrCall call) {
564     GrObject self = call.getObject(0);
565     if (!self) {
566         call.raise("NullError");
567         return;
568     }
569     call.setBool(self.getInt("x") == 0 && self.getInt("y") == 0);
570 }
571 
572 private void _isZeroVec2f(GrCall call) {
573     GrObject self = call.getObject(0);
574     if (!self) {
575         call.raise("NullError");
576         return;
577     }
578     call.setBool(self.getFloat("x") == 0f && self.getFloat("y") == 0f);
579 }
580 
581 // Operations ------------------------------------------
582 private void _sumVec2i(GrCall call) {
583     GrObject self = call.getObject(0);
584     if (!self) {
585         call.raise("NullError");
586         return;
587     }
588     call.setInt(self.getInt("x") + self.getInt("y"));
589 }
590 
591 private void _sumVec2f(GrCall call) {
592     GrObject self = call.getObject(0);
593     if (!self) {
594         call.raise("NullError");
595         return;
596     }
597     call.setFloat(self.getFloat("x") + self.getFloat("y"));
598 }
599 
600 private void _distanceVec2i(GrCall call) {
601     GrObject v1 = call.getObject(0);
602     GrObject v2 = call.getObject(1);
603     if (!v1 || !v2) {
604         call.raise("NullError");
605         return;
606     }
607     const GrFloat px = v1.getInt("x") - v2.getInt("x");
608     const GrFloat py = v1.getInt("y") - v2.getInt("y");
609     call.setFloat(std.math.sqrt(px * px + py * py));
610 }
611 
612 private void _distanceVec2f(GrCall call) {
613     GrObject v1 = call.getObject(0);
614     GrObject v2 = call.getObject(1);
615     if (!v1 || !v2) {
616         call.raise("NullError");
617         return;
618     }
619     const GrFloat px = v1.getFloat("x") - v2.getFloat("x");
620     const GrFloat py = v1.getFloat("y") - v2.getFloat("y");
621     call.setFloat(std.math.sqrt(px * px + py * py));
622 }
623 
624 private void _distanceSquaredVec2i(GrCall call) {
625     GrObject v1 = call.getObject(0);
626     GrObject v2 = call.getObject(1);
627     if (!v1 || !v2) {
628         call.raise("NullError");
629         return;
630     }
631     const GrFloat px = v1.getInt("x") - v2.getInt("x");
632     const GrFloat py = v1.getInt("y") - v2.getInt("y");
633     call.setFloat(px * px + py * py);
634 }
635 
636 private void _distanceSquaredVec2f(GrCall call) {
637     GrObject v1 = call.getObject(0);
638     GrObject v2 = call.getObject(1);
639     if (!v1 || !v2) {
640         call.raise("NullError");
641         return;
642     }
643     const GrFloat px = v1.getFloat("x") - v2.getFloat("x");
644     const GrFloat py = v1.getFloat("y") - v2.getFloat("y");
645     call.setFloat(px * px + py * py);
646 }
647 
648 private void _dotVec2i(GrCall call) {
649     GrObject v1 = call.getObject(0);
650     GrObject v2 = call.getObject(1);
651     if (!v1 || !v2) {
652         call.raise("NullError");
653         return;
654     }
655     call.setFloat(v1.getInt("x") * v2.getInt("x") + v1.getInt("y") * v2.getInt("y"));
656 }
657 
658 private void _dotVec2f(GrCall call) {
659     GrObject v1 = call.getObject(0);
660     GrObject v2 = call.getObject(1);
661     if (!v1 || !v2) {
662         call.raise("NullError");
663         return;
664     }
665     call.setFloat(v1.getFloat("x") * v2.getFloat("x") + v1.getFloat("y") * v2.getFloat("y"));
666 }
667 
668 private void _crossVec2i(GrCall call) {
669     GrObject v1 = call.getObject(0);
670     GrObject v2 = call.getObject(1);
671     if (!v1 || !v2) {
672         call.raise("NullError");
673         return;
674     }
675     call.setFloat(v1.getInt("x") * v2.getInt("y") - v1.getInt("y") * v2.getInt("x"));
676 }
677 
678 private void _crossVec2f(GrCall call) {
679     GrObject v1 = call.getObject(0);
680     GrObject v2 = call.getObject(1);
681     if (!v1 || !v2) {
682         call.raise("NullError");
683         return;
684     }
685     call.setFloat(v1.getFloat("x") * v2.getFloat("y") - v1.getFloat("y") * v2.getFloat("x"));
686 }
687 
688 private void _normalVec2i(GrCall call) {
689     GrObject self = call.getObject(0);
690     if (!self) {
691         call.raise("NullError");
692         return;
693     }
694     GrObject v = call.createObject(_vec2iTypeName);
695     if(!v) {
696         call.raise("UnknownClassError");
697         return;
698     }
699     v.setInt("x", -self.getInt("y"));
700     v.setInt("y", self.getInt("x"));
701     call.setObject(v);
702 }
703 
704 private void _normalVec2f(GrCall call) {
705     GrObject self = call.getObject(0);
706     if (!self) {
707         call.raise("NullError");
708         return;
709     }
710     GrObject v = call.createObject(_vec2fTypeName);
711     if(!v) {
712         call.raise("UnknownClassError");
713         return;
714     }
715     v.setFloat("x", -self.getFloat("y"));
716     v.setFloat("y", self.getFloat("x"));
717     call.setObject(v);
718 }
719 
720 private void _angleVec2i(GrCall call) {
721     GrObject self = call.getObject(0);
722     if (!self) {
723         call.raise("NullError");
724         return;
725     }
726     call.setFloat(std.math.atan2(cast(GrFloat) self.getInt("y"),
727             cast(GrFloat) self.getInt("x")) * _radToDeg);
728 }
729 
730 private void _angleVec2f(GrCall call) {
731     GrObject self = call.getObject(0);
732     if (!self) {
733         call.raise("NullError");
734         return;
735     }
736     call.setFloat(std.math.atan2(self.getFloat("y"), self.getFloat("x")) * _radToDeg);
737 }
738 
739 private void _rotateVec2f(GrCall call) {
740     GrObject self = call.getObject(0);
741     if (!self) {
742         call.raise("NullError");
743         return;
744     }
745     const GrFloat radians = call.getFloat(1) * _degToRad;
746     const GrFloat px = self.getFloat("x"), py = self.getFloat("y");
747     const GrFloat c = std.math.cos(radians);
748     const GrFloat s = std.math.sin(radians);
749     self.setFloat("x", px * c - py * s);
750     self.setFloat("y", px * s + py * c);
751     call.setObject(self);
752 }
753 
754 private void _rotatedVec2f(GrCall call) {
755     GrObject self = call.getObject(0);
756     if (!self) {
757         call.raise("NullError");
758         return;
759     }
760     const GrFloat radians = call.getFloat(1) * _degToRad;
761     const GrFloat px = self.getFloat("x"), py = self.getFloat("y");
762     const GrFloat c = std.math.cos(radians);
763     const GrFloat s = std.math.sin(radians);
764 
765     GrObject v = call.createObject(_vec2fTypeName);
766     if(!v) {
767         call.raise("UnknownClassError");
768         return;
769     }
770     v.setFloat("x", px * c - py * s);
771     v.setFloat("y", px * s + py * c);
772     call.setObject(v);
773 }
774 
775 private void _angledVec2f(GrCall call) {
776     const GrFloat radians = call.getFloat(0) * _degToRad;
777     GrObject v = call.createObject(_vec2fTypeName);
778     if(!v) {
779         call.raise("UnknownClassError");
780         return;
781     }
782     v.setFloat("x", std.math.cos(radians));
783     v.setFloat("y", std.math.sin(radians));
784     call.setObject(v);
785 }
786 
787 private void _lengthVec2i(GrCall call) {
788     GrObject self = call.getObject(0);
789     if (!self) {
790         call.raise("NullError");
791         return;
792     }
793     const GrInt x = self.getInt("x");
794     const GrInt y = self.getInt("y");
795     call.setFloat(std.math.sqrt(cast(GrFloat)(x * x + y * y)));
796 }
797 
798 private void _lengthVec2f(GrCall call) {
799     GrObject self = call.getObject(0);
800     if (!self) {
801         call.raise("NullError");
802         return;
803     }
804     const GrFloat x = self.getFloat("x");
805     const GrFloat y = self.getFloat("y");
806     call.setFloat(std.math.sqrt(x * x + y * y));
807 }
808 
809 private void _lengthSquaredVec2i(GrCall call) {
810     GrObject self = call.getObject(0);
811     if (!self) {
812         call.raise("NullError");
813         return;
814     }
815     const GrInt x = self.getInt("x");
816     const GrInt y = self.getInt("y");
817     call.setFloat(x * x + y * y);
818 }
819 
820 private void _lengthSquaredVec2f(GrCall call) {
821     GrObject self = call.getObject(0);
822     if (!self) {
823         call.raise("NullError");
824         return;
825     }
826     const GrFloat x = self.getFloat("x");
827     const GrFloat y = self.getFloat("y");
828     call.setFloat(x * x + y * y);
829 }
830 
831 private void _normalizeVec2f(GrCall call) {
832     GrObject self = call.getObject(0);
833     if (!self) {
834         call.raise("NullError");
835         return;
836     }
837     const GrFloat x = self.getFloat("x");
838     const GrFloat y = self.getFloat("y");
839     const GrFloat len = std.math.sqrt(x * x + y * y);
840     if (len == 0) {
841         self.setFloat("x", len);
842         self.setFloat("y", len);
843         return;
844     }
845     self.setFloat("x", x / len);
846     self.setFloat("y", y / len);
847     call.setObject(self);
848 }
849 
850 private void _normalizedVec2f(GrCall call) {
851     GrObject self = call.getObject(0);
852     if (!self) {
853         call.raise("NullError");
854         return;
855     }
856     GrFloat x = self.getFloat("x");
857     GrFloat y = self.getFloat("y");
858     const GrFloat len = std.math.sqrt(x * x + y * y);
859 
860     if (len == 0) {
861         x = len;
862         y = len;
863         return;
864     }
865     x /= len;
866     y /= len;
867 
868     GrObject v = call.createObject(_vec2fTypeName);
869     if(!v) {
870         call.raise("UnknownClassError");
871         return;
872     }
873     v.setFloat("x", x);
874     v.setFloat("y", y);
875     call.setObject(v);
876 }