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  }