#strict 3 /* // Examples: obj->SetTransform([Rotate(90)]); // rotates graphics of obj around center by 90° clock-wise; array brackets necessary! obj->SetTransform([Rotate(90), TranslateY(5)]); // rotates graphics of obj around center by 90° clock-wise and translates it down by 5 pixel // order matters! obj->SetTransform([TranslateY(5), Rotate(90)]); // translates graphics of obj down by 5 pixel and and rotates it around the point 5 pixel above center by 90° clock-wise; effectively the same as rotating around center by 90° and moving to the left by 5 pixel // obj->ResetTransform(); // resets transformation // Translate* and Rotate have a precision parameter, which defaults to 1: obj->SetTransform([TranslateY(500, 1000)]); // translates graphics of obj down by 0.5 pixel obj->SetTransform([TranslateY(1, 2)]); // also translates graphics of obj down by 0.5 pixel // Working with overlays: // base graphic is overlay 0 as usual obj->SetTransform([...], 1); // applies to overlay 1 obj->SetTransform([...], -10); // applies to overlays 0 through 10 (inclusive) obj->SetTransform([...], [1, 5]); // applies to overlays 1 and 5 obj->SetTransform([...], [2, -4, 10, -11, 42]); // applies to overlays 2,3,4 and 10,11 and 42 obj->ResetTransform(overlays); // resets transformations of overlays as specified in SetTransform */ // All matrices are stored linearly in row major order global func ResetTransform(overlays) { for(var overlay in TransformOverlays(overlays)) { if(overlay) { SetObjDrawTransform(1000, 0, 0, 0, 1000, 0, this, overlay); } else { SetObjDrawTransform(); } } } global func SetTransform(array transforms, overlays) { for(var overlay in TransformOverlays(overlays)) { ResetTransform(overlay); AddTransform(transforms, overlay); } } global func AddTransform(array transforms, overlays) { for(var overlay in TransformOverlays(overlays)) { for(var transform in transforms) { SetObjDrawTransform2(transform[0], transform[1], transform[2], transform[3], transform[4], transform[5], transform[6], transform[7], transform[8], overlay); } } } global func TransformOverlays(overlays) { overlays ??= 0; if(GetType(overlays) == C4V_Int) { if(overlays >= 0) return [overlays]; else { var ret = []; overlays = Abs(overlays); for(var i = 0; i <= overlays; ++i) { ret[] = i; } return ret; } } else if(GetType(overlays) == C4V_Array) { var ret = [], last; last = overlays[0]; var i = 1; if(last < 0) { i = 0; last = 0; } else { ret[0] = last; } for(; i < GetLength(overlays); ++i) { var overlay = overlays[i]; if(overlay < 0) { overlay = Abs(overlay); for(var j = last + 1; j <= overlay; ++j) { ret[] = j; } } else { ret[] = overlay; } last = overlay; } return ret; } else { FatalError("TransformOverlays: overlays must be a single integer or an array."); } } global func Rotate(int phi, int prec) { prec ??= 1; var cos = Cos(phi, 1000, prec); var sin = Sin(phi, 1000, prec); return [ cos, -sin, 0, sin, cos, 0, 0, 0, 1000 ]; } global func ScaleXY(int x, int y) { return [ x, 0, 0, 0, y, 0, 0, 0, 1000 ]; } global func ScaleX(int f) { return ScaleXY(f, 1000); } global func ScaleY(int f) { return ScaleXY(1000, f); } global func Scale(int f) { return [ 1000, 0, 0, 0, 1000, 0, 0, 0, 1000000/f ]; } global func TranslateXY(int x, int y, int prec) { prec ??= 1; return [ 1000, 0, x * 1000 / prec, 0, 1000, y * 1000 / prec, 0, 0, 1000 ]; } global func TranslateX(int x, int prec) { return TranslateXY(x, 0, prec); } global func TranslateY(int y, int prec) { return TranslateXY(0, y, prec); } global func MirrorX() { return [ -1000, 0, 0, 0, 1000, 0, 0, 0, 1000 ]; } global func MirrorY() { return [ 1000, 0, 0, 0, -1000, 0, 0, 0, 1000 ]; } global func SkewXY(int x, int y) { return [ 1000, x, 0, y, 1000, 0, 0, 0, 1000 ]; } global func SkewX(int x) { return SkewXY(x, 0); } global func SkewY(int y) { return SkewXY(0, y); } global func Matrix3x3Multiply(array a, array b, int precision) { return [ (a[6] * b[2] + a[3] * b[1] + a[0] * b[0]) / precision, (a[7] * b[2] + a[4] * b[1] + a[1] * b[0]) / precision, (a[8] * b[2] + a[5] * b[1] + a[2] * b[0]) / precision, (a[6] * b[5] + a[3] * b[4] + a[0] * b[3]) / precision, (a[7] * b[5] + a[4] * b[4] + a[1] * b[3]) / precision, (a[8] * b[5] + a[5] * b[4] + a[2] * b[3]) / precision, (a[6] * b[8] + a[3] * b[7] + a[0] * b[6]) / precision, (a[7] * b[8] + a[4] * b[7] + a[1] * b[6]) / precision, (a[8] * b[8] + a[5] * b[7] + a[2] * b[6]) / precision ]; } // Combines several transforms (as used for SetTransform) into one transform. Returns a single transform (like all other transform functions). // May be used to cache transforms. For direct application use SetTransform instead, which implicitly uses the native engine implementation of matrix multiplication. global func PreTransform(array transforms) { if(!transforms || GetLength(transforms) == 0) { FatalError("PreTransform called without transforms."); } else { var ret = transforms[0]; for(var i = 1; i < GetLength(transforms); ++i) { ret = Matrix3x3Multiply(ret, transforms[i], 1000); } return ret; } }