github.com/Kintar/etxt@v0.0.0-20221224033739-2fc69f000137/ebiten_yes.go (about)

     1  //go:build !gtxt
     2  
     3  package etxt
     4  
     5  import "image"
     6  import "image/color"
     7  
     8  import "golang.org/x/image/math/fixed"
     9  import "github.com/hajimehoshi/ebiten/v2"
    10  
    11  // Alias to allow compiling the package without Ebitengine (gtxt version).
    12  //
    13  // Without Ebitengine, TargetImage defaults to [image/draw.Image].
    14  type TargetImage = *ebiten.Image
    15  
    16  // A GlyphMask is the image that results from rasterizing a glyph.
    17  // You rarely need to use GlyphMasks directly unless using advanced
    18  // functions.
    19  //
    20  // Without Ebitengine (gtxt version), GlyphMask defaults to [*image.Alpha].
    21  // The image bounds are adjusted to allow drawing the glyph at its
    22  // intended position. In particular, bounds.Min.Y is typically
    23  // negative, with y = 0 corresponding to the glyph's baseline, y < 0
    24  // to the ascending portions and y > 0 to the descending ones.
    25  //
    26  // With Ebitengine, GlyphMask defaults to *ebiten.Image.
    27  type GlyphMask = *ebiten.Image
    28  
    29  // Mix modes specify how to compose colors when drawing glyphs
    30  // on the renderer's target:
    31  //   - Without Ebitengine, the mix modes can be MixOver, MixReplace,
    32  //     MixAdd, MixSub, MixMultiply, MixCut and MixFiftyFifty.
    33  //   - With Ebitengine, mix modes are Ebitengine's composite modes.
    34  //
    35  // I only ever change mix modes to make cutout text, but there's a
    36  // lot of weird people out there, what can I say.
    37  type MixMode = ebiten.CompositeMode
    38  
    39  const defaultMixMode = ebiten.CompositeModeSourceOver
    40  
    41  // The default glyph drawing function used in renderers. Do not confuse with
    42  // the main [Renderer.Draw]() function. DefaultDrawFunc is a low level function,
    43  // rarely necessary except when paired with [Renderer.Traverse]*() operations.
    44  func (self *Renderer) DefaultDrawFunc(dot fixed.Point26_6, mask GlyphMask, _ GlyphIndex) {
    45  	if mask == nil {
    46  		return
    47  	} // spaces and empty glyphs will be nil
    48  
    49  	// TODO: switch to DrawTriangles to reduce overhead?
    50  	// DrawTriangles(vertices []Vertex, indices []uint16, img *Image, options *DrawTrianglesOptions)
    51  	opts := ebiten.DrawImageOptions{}
    52  	srcRect := mask.Bounds()
    53  	opts.GeoM.Translate(float64(dot.X.Floor()+srcRect.Min.X), float64(dot.Y.Floor()+srcRect.Min.Y))
    54  	opts.ColorM.Scale(colorToFloat64(self.mainColor))
    55  	opts.CompositeMode = self.mixMode
    56  	self.target.DrawImage(mask, &opts)
    57  }
    58  
    59  // Convert a color to its float64 [0, 1.0] components.
    60  // This could actually be memorized to make DefaultDrawFunc work better
    61  // in most cases, but I don't know if it's worth the extra complexity.
    62  func colorToFloat64(subject color.Color) (float64, float64, float64, float64) {
    63  	rgbaColor, isRGBA := subject.(color.RGBA)
    64  	if isRGBA {
    65  		r, g, b, a := rgbaColor.R, rgbaColor.G, rgbaColor.B, rgbaColor.A
    66  		return float64(r) / 255, float64(g) / 255, float64(b) / 255, float64(a) / 255
    67  	} else {
    68  		r, g, b, a := subject.RGBA()
    69  		return float64(r) / 65535, float64(g) / 65535, float64(b) / 65535, float64(a) / 65535
    70  	}
    71  }
    72  
    73  // helper function required when working with ebitengine images
    74  func convertAlphaImageToGlyphMask(alpha *image.Alpha) GlyphMask {
    75  	if alpha == nil {
    76  		return nil
    77  	}
    78  
    79  	// NOTICE: since ebiten doesn't have good support for alpha images,
    80  	//         this is quite a pain, but not much we can do from here.
    81  	rgba := image.NewRGBA(alpha.Rect)
    82  	pixels := rgba.Pix
    83  	index := 0
    84  	for _, value := range alpha.Pix {
    85  		// NOTE: we could actually skip when value == 0, no? benchmark?
    86  		pixels[index+0] = value
    87  		pixels[index+1] = value
    88  		pixels[index+2] = value
    89  		pixels[index+3] = value
    90  		index += 4
    91  	}
    92  	return ebiten.NewImageFromImageWithOptions(rgba, &ebiten.NewImageFromImageOptions{PreserveBounds: true})
    93  }