private void ManipulateMe_ManipulationDelta( object sender, ManipulationDeltaRoutedEventArgs e) { if (forceManipulationsToEnd) { e.Complete(); return; } _previousTransform.Matrix = _transformGroup.Value; Point center = _previousTransform.TransformPoint( new Point(e.Position.X, e.Position.Y)); _compositeTransform.CenterX = center.X; _compositeTransform.CenterY = center.Y; _compositeTransform.Rotation = (e.Delta.Rotation * 180) / Math.PI; _compositeTransform.ScaleX = _compositeTransform.ScaleY = e.Delta.Scale; _compositeTransform.TranslateX = e.Delta.Translation.X; _compositeTransform.TranslateY = e.Delta.Translation.Y; e.Handled = true; }
public Task When_Identity_And_TransformPoint() => RunOnUIThread.ExecuteAsync(() => { var SUT = new MatrixTransform(); Assert.AreEqual(new Point(0, 0), SUT.TransformPoint(new Point(0, 0))); });
public async Task When_Identity_And_TransformPoint() { await Dispatch(() => { var SUT = new MatrixTransform(); Assert.AreEqual(new Point(0, 0), SUT.TransformPoint(new Point(0, 0))); }); }
public Task When_Rotate_And_TransformPoint() => RunOnUIThread.ExecuteAsync(() => { var SUT = new MatrixTransform() { Matrix = MatrixHelper.FromMatrix3x2(Matrix3x2.CreateRotation((float)Math.PI / 2)) }; Assert.AreEqual(new Point(-1, 1), SUT.TransformPoint(new Point(1, 1))); });
public Task When_Translate_And_TransformPoint() => RunOnUIThread.ExecuteAsync(() => { var SUT = new MatrixTransform() { Matrix = MatrixHelper.Create(1, 0, 0, 1, 10, 20) }; Assert.AreEqual(new Point(10, 20), SUT.TransformPoint(new Point(0, 0))); });
/// <summary> /// Store existing transformation in matrix /// and return current center position in respect to this /// </summary> /// <param name="pos"></param> /// <returns></returns> private Point StoreTransformationsAndGetCenter(Point pos) { System.Diagnostics.Debug.WriteLine($"Pos: {pos.ToVector2()}"); // store transformation into matrix previousTransform.Matrix = transformGroup.Value; // return center in respect to previous transformations return(previousTransform.TransformPoint(pos)); }
void Update() { matrix = new MatrixTransform(position, rotation, scale); for (int i = 0; i < points.Length; i++) { Vector3 transformedPosition = matrix.TransformPoint(positions[i]); points[i].transform.position = transformedPosition; } }
public async Task When_Translate_And_TransformPoint() { await Dispatch(() => { var SUT = new MatrixTransform() { Matrix = new Matrix(1, 0, 0, 1, 10, 20) }; Assert.AreEqual(new Point(10, 20), SUT.TransformPoint(new Point(0, 0))); }); }
public async Task When_Rotate_And_TransformPoint() { await Dispatch(() => { var SUT = new MatrixTransform() { Matrix = MatrixHelper.FromMatrix3x2(Matrix3x2.CreateRotation((float)Math.PI / 2)) }; Assert.AreEqual(new Point(-1, 1), SUT.TransformPoint(new Point(1, 1))); }); }
public Task When_RotateQuarter_And_TransformPoint() => RunOnUIThread.ExecuteAsync(() => { var SUT = new MatrixTransform() { Matrix = MatrixHelper.FromMatrix3x2(Matrix3x2.CreateRotation((float)Math.PI / 4)) }; var expected = new Point(0, 1.41421353816986); var res = SUT.TransformPoint(new Point(1, 1)); Assert.AreEqual(expected.X, res.X, 1e-10, $"{expected} != {res}"); Assert.AreEqual(expected.Y, res.Y, 1e-10, $"{expected} != {res}"); });
public void AccumulateDelta(Point position, ManipulationDelta delta) { matrixXform.Matrix = xformGroup.Value; Point center = matrixXform.TransformPoint(position); compositeXform.CenterX = center.X; compositeXform.CenterY = center.Y; compositeXform.TranslateX = delta.Translation.X; compositeXform.TranslateY = delta.Translation.Y; compositeXform.ScaleX = delta.Scale; compositeXform.ScaleY = delta.Scale; compositeXform.Rotation = delta.Rotation; this.Matrix = xformGroup.Value; }
// Process the change resulting from a manipulation void MovingTarget_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) { previousTransform.Matrix = transforms.Value; // Get center point for rotation Point center = previousTransform.TransformPoint(new Point(e.Position.X, e.Position.Y)); deltaTransform.CenterX = center.X; deltaTransform.CenterY = center.Y; // Look at the Delta property of the ManipulationDeltaRoutedEventArgs to retrieve // the rotation, scale, X, and Y changes deltaTransform.TranslateX = e.Delta.Translation.X; deltaTransform.TranslateY = e.Delta.Translation.Y; }
void rectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) { _previousTransform.Matrix = _transformGroup.Value; // 获取操作点相对于此 GeneralTransform 的位置 Point center = _previousTransform.TransformPoint(new Point(e.Position.X, e.Position.Y)); _compositeTransform.CenterX = center.X; _compositeTransform.CenterY = center.Y; _compositeTransform.Rotation = e.Delta.Rotation; _compositeTransform.ScaleX = e.Delta.Scale; _compositeTransform.ScaleY = e.Delta.Scale; _compositeTransform.TranslateX = e.Delta.Translation.X; _compositeTransform.TranslateY = e.Delta.Translation.Y; }
void NewRectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) { //sender = new Rectangle(); _previousTransform.Matrix = _transformGroup.Value; Point center = _previousTransform.TransformPoint(new Point(e.Position.X, e.Position.Y)); _compositeTransform.CenterX = center.X; _compositeTransform.CenterY = center.Y; _compositeTransform.Rotation = e.Delta.Rotation; _compositeTransform.ScaleX = _compositeTransform.ScaleY = e.Delta.Scale; _compositeTransform.TranslateX = e.Delta.Translation.X; _compositeTransform.TranslateY = e.Delta.Translation.Y; e.Handled = true; }
//private bool _pressing_label = false; //private void B_PointerPressed(object sender, PointerRoutedEventArgs e) { // Debug.WriteLine("label pressed"); // _pressing_label = true; //} //private void B_PointerReleased(object sender, PointerRoutedEventArgs e) { // Debug.WriteLine("label release"); // _pressing_label = false; //} private void B_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) { TransformGroup transforms = (sender as Button).RenderTransform as TransformGroup; MatrixTransform previousTransform = transforms.Children[0] as MatrixTransform; CompositeTransform deltaTransform = transforms.Children[1] as CompositeTransform; previousTransform.Matrix = transforms.Value; // Get center point for rotation Point center = previousTransform.TransformPoint(new Point(e.Position.X, e.Position.Y)); deltaTransform.CenterX = center.X; deltaTransform.CenterY = center.Y; // Look at the Delta property of the ManipulationDeltaRoutedEventArgs to retrieve // the rotation, scale, X, and Y changes deltaTransform.Rotation = e.Delta.Rotation; deltaTransform.TranslateX = e.Delta.Translation.X; deltaTransform.TranslateY = e.Delta.Translation.Y; }
void Viewbox_OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) { _previousTransform.Matrix = _transformGroup.Value; var center = _previousTransform.TransformPoint(e.Position); _deltaTransform.CenterX = center.X; _deltaTransform.CenterY = center.Y; _deltaTransform.Rotation = e.Delta.Rotation; _deltaTransform.ScaleX = e.Delta.Scale; _deltaTransform.ScaleY = e.Delta.Scale; _deltaTransform.TranslateX = e.Delta.Translation.X; _deltaTransform.TranslateY = e.Delta.Translation.Y; var control = e.Container as FrameworkElement; var controlRect = new Rect(0, 0, control.DesiredSize.Width, control.DesiredSize.Height); BoundingRect = _transformGroup.TransformBounds(controlRect); }
// Process the change resulting from a manipulation void ManipulateMe_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) { // If the reset button has been pressed, mark the manipulation as completed if (forceManipulationsToEnd) { e.Complete(); return; } previousTransform.Matrix = transforms.Value; // Get center point for rotation Point center = previousTransform.TransformPoint(new Point(e.Position.X, e.Position.Y)); deltaTransform.CenterX = center.X; deltaTransform.CenterY = center.Y; // Look at the Delta property of the ManipulationDeltaRoutedEventArgs to retrieve // the rotation, scale, X, and Y changes deltaTransform.Rotation = e.Delta.Rotation; deltaTransform.TranslateX = e.Delta.Translation.X; deltaTransform.TranslateY = e.Delta.Translation.Y; }
/// <summary> /// Turn a base mesh into a building and surrounding street /// </summary> /// <param name="elevation">Used for specifying the offset of upper layers</param> /// <param name="upsidedown">Set true to generate the underside of a layer of buildings</param> public void Generate(bool upsidedown = false) { //Determine height based on size of base or some global variable float height = Random.Range(minHeight, maxHeight); color = new Color(Random.value, Random.value, Random.value); int baseVertLength = meshFilter.mesh.vertexCount; List <Vector3> vertices = new List <Vector3>(); vertices.AddRange(meshFilter.mesh.vertices); List <int> triangles = new List <int>(); int originalVertCount = vertices.Count; int edges = originalVertCount - 1; int originOfCurrentEdge = 1; //Keeps track of the first point on the currently worked on edge //Create ring of verts around base for (int edgeVert = 0; edgeVert < edges; edgeVert++) { int vertIndex = edgeVert + originOfCurrentEdge; //Lerp ring inwards by bottomTaper Vector3 newCorner = Vector3.Lerp(vertices[vertIndex], vertices[0], bottomTaper); vertices.Add(newCorner); //Create triangles linking bottom and top of current quad int p1 = vertIndex; int p2 = edgeVert + 1 < edges ? p1 + 1 : originOfCurrentEdge; int p3 = vertIndex + edges; int p4 = edgeVert + 1 < edges ? p3 + 1 : originOfCurrentEdge + edges; triangles.Add(p1); triangles.Add(p2); triangles.Add(p3); triangles.Add(p4); triangles.Add(p3); triangles.Add(p2); } originOfCurrentEdge += edges; //Move to top edge of current quad //Create sides of building; sides are composed of seperated quads, unlike bases, so need twice the number of vertices //Duplicate current edge ring for base of side quads for (int edgeVert = 0; edgeVert < edges; edgeVert++) { int vertIndex = edgeVert + originOfCurrentEdge; int nextVertIndex = edgeVert + 1 < edges ? vertIndex + 1 : originOfCurrentEdge; Vector3 newCorner = vertices[vertIndex]; Vector3 nextNewCorner = vertices[nextVertIndex]; vertices.Add(newCorner); vertices.Add(nextNewCorner); } originOfCurrentEdge += edges; //Move to bottom edge of next quad int originOfSideEdge = originOfCurrentEdge; //Cache reference to vert index at base of the side quads, for use after basic shape generation is done //Move 0th vertex to the top of the extrude vertices[0] += Vector3.up * height; //Create ring of verts around top for (int edgeVert = 0; edgeVert < edges; edgeVert++) { int vertIndex = (edgeVert * 2) + originOfCurrentEdge; //Increase vertIndex by 2 each loop because number of vertices are doubled int nextVertIndex = vertIndex + 1; //Duplicate vertex from bottom ring and move upwards Vector3 newCorner = vertices[vertIndex] + (Vector3.up * height); Vector3 nextNewCorner = vertices[nextVertIndex] + (Vector3.up * height); //Lerp vertex inwards by topTaper newCorner = Vector3.Lerp(newCorner, vertices[0], topTaper); nextNewCorner = Vector3.Lerp(nextNewCorner, vertices[0], topTaper); vertices.Add(newCorner); vertices.Add(nextNewCorner); //Skip this step because sides of buildings should be replaced with handmade meshes /* */ } originOfCurrentEdge += edges * 2; //Move to top edge of current quad, multiply by 2 because the edge loop is twice as long for the sides of the building //Duplicate current edge ring for edge of roof quads for (int edgeVert = 0; edgeVert < edges; edgeVert++) { int vertIndex = (edgeVert * 2) + originOfCurrentEdge; //Increase vertIndex by 2 each loop because number of vertices are doubled Vector3 newCorner = vertices[vertIndex]; vertices.Add(newCorner); } originOfCurrentEdge += edges * 2; //Move to bottom edge of next quad, multiply by 2 because the edge loop is twice as long for the sides of the building //Create triangles linking ring 3 and 0 for (int edgeVert = 0; edgeVert < edges; edgeVert++) { int vertIndex = edgeVert + originOfCurrentEdge; int p1 = 0; int p2 = vertIndex; int p3 = edgeVert + 1 < edges ? p2 + 1 : originOfCurrentEdge; triangles.Add(p1); triangles.Add(p2); triangles.Add(p3); } //Fill sides of the building with randomly chosen replacement meshes, or quads if no replacements available for (int edgeVert = 0; edgeVert < edges; edgeVert++) { int vertIndex = (edgeVert * 2) + originOfSideEdge; int p1 = vertIndex; int p2 = p1 + 1; int p3 = vertIndex + (edges * 2); int p4 = p3 + 1; if (replacementMeshes != null && replacementMeshes.Length > 0) { //Pick a replacement mesh to use for this side of the building, and add its vertices and triangles to the mesh int meshIndex = Random.Range(0, replacementMeshes.Length); Mesh replacementMesh = replacementMeshes[meshIndex]; Vector3 minExtents = replacementMesh.bounds.min; Vector3 maxExtents = replacementMesh.bounds.max; Vector3 v1 = vertices[p1]; Vector3 v2 = vertices[p2]; Vector3 v3 = vertices[p3]; Vector3 v4 = vertices[p4]; //Add triangles of replacement mesh, increasing the index by the current vertex list length int triangleIndexOffset = vertices.Count; for (int tri = 0; tri < replacementMesh.triangles.Length; tri++) { triangles.Add(replacementMesh.triangles[tri] + triangleIndexOffset); } //Create a transformation matrix to convert points from the [x, z] plane to the plane of the face Vector3 midpointBottom = Vector3.Lerp(v1, v2, 0.5f); Vector3 midpointTop = Vector3.Lerp(v3, v4, 0.5f); float halfHeight = (midpointTop.y - midpointBottom.y) / 2f; float rotationY = (Mathf.Atan2(v1.x - v2.x, v1.z - v2.z) * Mathf.Rad2Deg) - 90f; //float rotationYTop = (Mathf.Atan2(v3.x - v4.x, v3.z - v4.z) * Mathf.Rad2Deg) - 90f; float relativeX = Mathf.Sqrt(Mathf.Pow(midpointTop.z - midpointBottom.z, 2) + Mathf.Pow(midpointTop.x - midpointBottom.x, 2)); float rotationX = Mathf.Atan2(midpointTop.y - midpointBottom.y, relativeX) * Mathf.Rad2Deg * -1f; float rotationZ = 0f; //Mathf.Atan2(midpointTop.y - midpointBottom.y, midpointTop.x - midpointBottom.x) * Mathf.Rad2Deg; Vector3 transformRotation = new Vector3(rotationX, rotationY, rotationZ); //Vector3 topTransformRotation = new Vector3(rotationX, rotationYTop, rotationZ); //Need to find way to move positions so they rest on the surface float distanceToFace = halfHeight * Mathf.Tan((90f + rotationX) * Mathf.Deg2Rad); Vector3 towardsFace = Vector3.Cross(v1 - v2, Vector3.up); towardsFace.Normalize(); //Debug.Log(halfHeight + " / tan(" + -rotationX + ") = " + distanceToFace); towardsFace *= distanceToFace; Vector3 bottomTransformPosition = midpointBottom + (Vector3.up * halfHeight) + towardsFace; //Move up and forward Vector3 topTransformPosition = midpointTop + (Vector3.up * -halfHeight) - towardsFace; //Move down and backward float meshWidth = maxExtents.x - minExtents.x; float sideWidth = Vector3.Distance(v1, v2); float relativeWidth = sideWidth / meshWidth; float topSideWidth = Vector3.Distance(v3, v4); float topRelativeWidth = topSideWidth / meshWidth; float meshHeight = maxExtents.z - minExtents.z; float sideHeight = Vector3.Distance(midpointBottom, midpointTop); float relativeHeight = sideHeight / meshHeight; float relativeDepth = Mathf.Min(relativeWidth, relativeHeight); Vector3 transformScale = new Vector3(relativeWidth, relativeDepth, relativeHeight); Vector3 topTransformScale = new Vector3(topRelativeWidth, relativeDepth, relativeHeight); MatrixTransform transformMatrix = new MatrixTransform(bottomTransformPosition, transformRotation, transformScale); MatrixTransform topTransformMatrix = new MatrixTransform(topTransformPosition, transformRotation, topTransformScale); //Use positions of defined points to lerp the vertex positions of a replacement mesh, like uv coordinates for (int vertex = 0; vertex < replacementMesh.vertices.Length; vertex++) //Redoing this to use a matrix transformation instead { Vector3 oldVertex = replacementMesh.vertices[vertex]; Vector3 newVertexBottom = transformMatrix.TransformPoint(oldVertex); Vector3 newVertexTop = topTransformMatrix.TransformPoint(oldVertex); //Interpolate between top and bottom vertices by the height of the vertex float interpolant = Mathf.InverseLerp(minExtents.z, maxExtents.z, oldVertex.z); Vector3 newVertex = Vector3.LerpUnclamped(newVertexBottom, newVertexTop, interpolant); vertices.Add(newVertex); } } else { //Fill with triangles instead triangles.Add(p1); triangles.Add(p2); triangles.Add(p3); triangles.Add(p4); triangles.Add(p3); triangles.Add(p2); } } //Flip if upsidedown is true if (upsidedown) { //Flip sign of y position for (int vert = 0; vert < vertices.Count; vert++) { Vector3 flipped = vertices[vert]; flipped.y = -flipped.y; vertices[vert] = flipped; } //Reverse triangles so buildings are visable from outside for (int tri = 0; tri < triangles.Count; tri += 3) { int temp = triangles[tri + 1]; //Cache first vertex in triangle triangles[tri + 1] = triangles[tri + 2]; //Assign first vertex equal to second vertex triangles[tri + 2] = temp; //Assign second vertex to cached first vertex } } List <Color> vertexColors = new List <Color>(); //Color vertices for (int vert = 0; vert < vertices.Count; vert++) { vertexColors.Add(color); } meshFilter.mesh.SetVertices(vertices); meshFilter.mesh.SetColors(vertexColors); //Why are you blue meshFilter.mesh.SetTriangles(triangles, 0); meshFilter.mesh.RecalculateNormals(); }
/// <summary> /// Renders a bitmap using any affine transformation and transparency into this bitmap /// Unlike Silverlight's Render() method, this one uses 2-3 times less memory, and is the same or better quality /// The algorithm is simple dx/dy (bresenham-like) step by step painting, optimized with fixed point and fast bilinear filtering /// It's used in Fantasia Painter for drawing stickers and 3D objects on screen /// </summary> /// <param name="bmp">Destination bitmap.</param> /// <param name="source">The source WriteableBitmap.</param> /// <param name="shouldClear">If true, the the destination bitmap will be set to all clear (0) before rendering.</param> /// <param name="opacity">opacity of the source bitmap to render, between 0 and 1 inclusive</param> /// <param name="transform">Transformation to apply</param> public static void BlitRender(this BitmapBuffer bmp, BitmapBuffer source, bool shouldClear = true, float opacity = 1f, GeneralTransform transform = null) { const int PRECISION_SHIFT = 10; const int PRECISION_VALUE = (1 << PRECISION_SHIFT); const int PRECISION_MASK = PRECISION_VALUE - 1; using (BitmapContext destContext = bmp.GetBitmapContext()) { if (transform == null) { transform = new MatrixTransform(Affine.IdentityMatrix); } int[] destPixels = destContext.Pixels; int destWidth = destContext.Width; int destHeight = destContext.Height; MatrixTransform inverse = transform.Inverse; if (shouldClear) { destContext.Clear(); } using (BitmapContext sourceContext = source.GetBitmapContext(ReadWriteMode.ReadOnly)) { var sourcePixels = sourceContext.Pixels; int sourceWidth = sourceContext.Width; int sourceHeight = sourceContext.Height; RectD sourceRect = new RectD(0, 0, sourceWidth, sourceHeight); RectD destRect = new RectD(0, 0, destWidth, destHeight); RectD bounds = transform.TransformBounds(sourceRect); bounds.Intersect(destRect); int startX = (int)bounds.Left; int startY = (int)bounds.Top; int endX = (int)bounds.Right; int endY = (int)bounds.Bottom; #if NETFX_CORE Point zeroZero = inverse.TransformPoint(new Point(startX, startY)); Point oneZero = inverse.TransformPoint(new Point(startX + 1, startY)); Point zeroOne = inverse.TransformPoint(new Point(startX, startY + 1)); #else PointD zeroZero = inverse.Transform(new PointD(startX, startY)); PointD oneZero = inverse.Transform(new PointD(startX + 1, startY)); PointD zeroOne = inverse.Transform(new PointD(startX, startY + 1)); #endif float sourceXf = ((float)zeroZero.X); float sourceYf = ((float)zeroZero.Y); int dxDx = (int)((((float)oneZero.X) - sourceXf) * PRECISION_VALUE); // for 1 unit in X coord, how much does X change in source texture? int dxDy = (int)((((float)oneZero.Y) - sourceYf) * PRECISION_VALUE); // for 1 unit in X coord, how much does Y change in source texture? int dyDx = (int)((((float)zeroOne.X) - sourceXf) * PRECISION_VALUE); // for 1 unit in Y coord, how much does X change in source texture? int dyDy = (int)((((float)zeroOne.Y) - sourceYf) * PRECISION_VALUE); // for 1 unit in Y coord, how much does Y change in source texture? int sourceX = (int)(((float)zeroZero.X) * PRECISION_VALUE); int sourceY = (int)(((float)zeroZero.Y) * PRECISION_VALUE); int sourceWidthFixed = sourceWidth << PRECISION_SHIFT; int sourceHeightFixed = sourceHeight << PRECISION_SHIFT; int opacityInt = (int)(opacity * 255); int index = 0; for (int destY = startY; destY < endY; destY++) { index = destY * destWidth + startX; int savedSourceX = sourceX; int savedSourceY = sourceY; for (int destX = startX; destX < endX; destX++) { if ((sourceX >= 0) && (sourceX < sourceWidthFixed) && (sourceY >= 0) && (sourceY < sourceHeightFixed)) { // bilinear filtering int xFloor = sourceX >> PRECISION_SHIFT; int yFloor = sourceY >> PRECISION_SHIFT; if (xFloor < 0) { xFloor = 0; } if (yFloor < 0) { yFloor = 0; } int xCeil = xFloor + 1; int yCeil = yFloor + 1; if (xCeil >= sourceWidth) { xFloor = sourceWidth - 1; xCeil = 0; } else { xCeil = 1; } if (yCeil >= sourceHeight) { yFloor = sourceHeight - 1; yCeil = 0; } else { yCeil = sourceWidth; } int i1 = yFloor * sourceWidth + xFloor; int p1 = sourcePixels[i1]; int p2 = sourcePixels[i1 + xCeil]; int p3 = sourcePixels[i1 + yCeil]; int p4 = sourcePixels[i1 + yCeil + xCeil]; int xFrac = sourceX & PRECISION_MASK; int yFrac = sourceY & PRECISION_MASK; // alpha byte a1 = (byte)(p1 >> 24); byte a2 = (byte)(p2 >> 24); byte a3 = (byte)(p3 >> 24); byte a4 = (byte)(p4 >> 24); int comp1, comp2; byte a; if ((a1 == a2) && (a1 == a3) && (a1 == a4)) { if (a1 == 0) { destPixels[index] = 0; sourceX += dxDx; sourceY += dxDy; index++; continue; } a = a1; } else { comp1 = a1 + ((xFrac * (a2 - a1)) >> PRECISION_SHIFT); comp2 = a3 + ((xFrac * (a4 - a3)) >> PRECISION_SHIFT); a = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT)); } // red comp1 = ((byte)(p1 >> 16)) + ((xFrac * (((byte)(p2 >> 16)) - ((byte)(p1 >> 16)))) >> PRECISION_SHIFT); comp2 = ((byte)(p3 >> 16)) + ((xFrac * (((byte)(p4 >> 16)) - ((byte)(p3 >> 16)))) >> PRECISION_SHIFT); byte r = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT)); // green comp1 = ((byte)(p1 >> 8)) + ((xFrac * (((byte)(p2 >> 8)) - ((byte)(p1 >> 8)))) >> PRECISION_SHIFT); comp2 = ((byte)(p3 >> 8)) + ((xFrac * (((byte)(p4 >> 8)) - ((byte)(p3 >> 8)))) >> PRECISION_SHIFT); byte g = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT)); // blue comp1 = ((byte)p1) + ((xFrac * (((byte)p2) - ((byte)p1))) >> PRECISION_SHIFT); comp2 = ((byte)p3) + ((xFrac * (((byte)p4) - ((byte)p3))) >> PRECISION_SHIFT); byte b = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT)); // save updated pixel if (opacityInt != 255) { a = (byte)((a * opacityInt) >> 8); r = (byte)((r * opacityInt) >> 8); g = (byte)((g * opacityInt) >> 8); b = (byte)((b * opacityInt) >> 8); } destPixels[index] = (a << 24) | (r << 16) | (g << 8) | b; } sourceX += dxDx; sourceY += dxDy; index++; } sourceX = savedSourceX + dyDx; sourceY = savedSourceY + dyDy; } } } }