1 /*
2  * Copyright (C) 2015-2018, by Laszlo Szeremi under the Boost license.
3  *
4  * Pixel Perfect Engine, graphics.transformFunctions module
5  */
6 
7 module pixelperfectengine.graphics.transformfunctions;
8 
9 package static immutable uint[4] maskAC = [0, uint.max, 0, uint.max];
10 
11 import pixelperfectengine.system.platform;
12 
13 static if(USE_INTEL_INTRINSICS) import inteli.emmintrin;
14 
15 
16 /**
17  * Main transform function with fixed point aritmetics. Returns the point where the pixel is needed to be read from.
18  * 256 equals with 1.
19  * The function reads as:
20  * [x',y'] = ([A,B,C,D] * ([x,y] + [sX,sY] - [x_0,y_0]))>>>8 + [x_0,y_0]
21  * ABCD: 
22  * A/0: Horizontal scaling. 256 means no scaling at all, negative values end up in a mirrored image.
23  * B/1: Horizontal shearing. 0 means no shearing at all.
24  * C/2: Vertical shearing. 0 means no shearing at all.
25  * D/3: Vertical scaling. 256 means no scaling at all, negative values end up in a mirrored image.
26  * </ br>
27  * xy:
28  * Contains the screen coordinates. x:0 y:1
29  * </ br>
30  * x0y0:
31  * Origin point. x_0:0/2 y_0:1/3
32  * </ br>
33  * sXsY:
34  * Scrolling point. sX:0/2 sY:1/3
35  */
36 public @nogc int[2] transformFunctionInt(short[2] xy, short[4] ABCD, short[2] x0y0, short[2] sXsY) pure nothrow @trusted {
37 	static if (USE_INTEL_INTRINSICS) {
38 		__m128i result;
39 		short8 xy_, sXsY_, x0y0_, ABCD_;
40 		xy_[0] = xy[0];
41 		xy_[1] = xy[1];
42 		xy_[2] = xy[0];
43 		xy_[3] = xy[1];
44 		sXsY_[0] = sXsY[0];
45 		sXsY_[1] = sXsY[1];
46 		sXsY_[2] = sXsY[0];
47 		sXsY_[3] = sXsY[1];
48 		x0y0_[0] = x0y0[0];
49 		x0y0_[1] = x0y0[1];
50 		x0y0_[2] = x0y0[0];
51 		x0y0_[3] = x0y0[1];
52 		ABCD_[0] = ABCD[0];
53 		ABCD_[1] = ABCD[1];
54 		ABCD_[2] = ABCD[2];
55 		ABCD_[3] = ABCD[3];
56 		xy_ += sXsY_;
57 		xy_ -= x0y0_;
58 		result = _mm_madd_epi16(cast(__m128i)xy_, cast(__m128i)ABCD_);
59 		return [result[0] + x0y0[0], result[1] + x0y0[1]];
60 	} else {
61 		int[2] result;
62 		int[2] nXnY = [xy[0] + sXsY[0] - x0y0[0],  xy[1] + sXsY[1] - x0y0[1]];
63 		result[0] = ((ABCD[0] * nXnY[0] + ABCD[1] * nXnY[1])>>>8) + x0y0[0];
64 		result[1] = ((ABCD[2] * nXnY[0] + ABCD[3] * nXnY[1])>>>8) + x0y0[1];
65 		return result;
66 	}
67 }
68 /**
69  * Relative rotation clockwise by given degrees. Returns the new transform points.
70  * </ br>
71  * theta:
72  * Degrees of clockwise rotation.
73  * </ br>
74  * input:
75  * Input of the transform points at 0 degrees.
76  */
77 public @nogc short[4] rotateFunction(double theta, short[4] input = [256,256,256,256]){
78 	import std.math;
79 	short[4] transformPoints;
80 	theta *= PI / 180;
81 	transformPoints[0] = cast(short)(input[0] * cos(theta));
82 	transformPoints[1] = cast(short)(input[1] * sin(theta));
83 	transformPoints[2] = cast(short)(input[2] * sin(theta) * -1);
84 	transformPoints[3] = cast(short)(input[3] * cos(theta));
85 	return transformPoints;
86 }