github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/mobile/sprite/portable/affine.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package portable 6 7 import ( 8 "image" 9 "image/draw" 10 11 "golang.org/x/mobile/f32" 12 ) 13 14 // affine draws each pixel of dst using bilinear interpolation of the 15 // affine-transformed position in src. This is equivalent to: 16 // 17 // for each (x,y) in dst: 18 // dst(x,y) = bilinear interpolation of src(a*(x,y)) 19 // 20 // While this is the simpler implementation, it can be counter- 21 // intuitive as an affine transformation is usually described in terms 22 // of the source, not the destination. For example, a scale transform 23 // 24 // Affine{{2, 0, 0}, {0, 2, 0}} 25 // 26 // will produce a dst that is half the size of src. To perform a 27 // traditional affine transform, use the inverse of the affine matrix. 28 func affine(dst *image.RGBA, src image.Image, srcb image.Rectangle, mask image.Image, a *f32.Affine, op draw.Op) { 29 b := dst.Bounds() 30 var maskb image.Rectangle 31 if mask != nil { 32 maskb = mask.Bounds().Add(srcb.Min) 33 } 34 35 for y := b.Min.Y; y < b.Max.Y; y++ { 36 for x := b.Min.X; x < b.Max.X; x++ { 37 // Interpolate from the bounds of the src sub-image 38 // to the bounds of the dst sub-image. 39 ix, iy := pt(a, x-b.Min.X, y-b.Min.Y) 40 sx := ix + float32(srcb.Min.X) 41 sy := iy + float32(srcb.Min.Y) 42 if !inBounds(srcb, sx, sy) { 43 continue 44 } 45 46 // m is the maximum color value returned by image.Color.RGBA. 47 const m = 1<<16 - 1 48 49 ma := uint32(m) 50 if mask != nil { 51 mx := ix + float32(maskb.Min.X) 52 my := iy + float32(maskb.Min.Y) 53 if !inBounds(maskb, mx, my) { 54 continue 55 } 56 _, _, _, ma = bilinear(mask, mx, my).RGBA() 57 } 58 59 sr, sg, sb, sa := bilinear(src, sx, sy).RGBA() 60 off := (y-dst.Rect.Min.Y)*dst.Stride + (x-dst.Rect.Min.X)*4 61 62 if op == draw.Over { 63 dr := uint32(dst.Pix[off+0]) 64 dg := uint32(dst.Pix[off+1]) 65 db := uint32(dst.Pix[off+2]) 66 da := uint32(dst.Pix[off+3]) 67 68 // dr, dg, db, and da are all 8-bit color at the moment, ranging 69 // in [0,255]. We work in 16-bit color, and so would normally do: 70 // dr |= dr << 8 71 // and similarly for the other values, but instead we multiply by 0x101 72 // to shift these to 16-bit colors, ranging in [0,65535]. 73 // This yields the same result, but is fewer arithmetic operations. 74 // 75 // This logic comes from drawCopyOver in the image/draw package. 76 a := m - (sa * ma / m) 77 a *= 0x101 78 79 dst.Pix[off+0] = uint8((dr*a + sr*ma) / m >> 8) 80 dst.Pix[off+1] = uint8((dg*a + sg*ma) / m >> 8) 81 dst.Pix[off+2] = uint8((db*a + sb*ma) / m >> 8) 82 dst.Pix[off+3] = uint8((da*a + sa*ma) / m >> 8) 83 } else { 84 dst.Pix[off+0] = uint8(sr * ma / m >> 8) 85 dst.Pix[off+1] = uint8(sg * ma / m >> 8) 86 dst.Pix[off+2] = uint8(sb * ma / m >> 8) 87 dst.Pix[off+3] = uint8(sa * ma / m >> 8) 88 } 89 } 90 } 91 } 92 93 func inBounds(b image.Rectangle, x, y float32) bool { 94 if x < float32(b.Min.X) || x >= float32(b.Max.X) { 95 return false 96 } 97 if y < float32(b.Min.Y) || y >= float32(b.Max.Y) { 98 return false 99 } 100 return true 101 } 102 103 func pt(a *f32.Affine, x0, y0 int) (x1, y1 float32) { 104 fx := float32(x0) + 0.5 105 fy := float32(y0) + 0.5 106 x1 = fx*a[0][0] + fy*a[0][1] + a[0][2] 107 y1 = fx*a[1][0] + fy*a[1][1] + a[1][2] 108 return x1, y1 109 }