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 }