github.com/kintar/etxt@v0.0.9/feed.go (about) 1 package etxt 2 3 import "golang.org/x/image/math/fixed" 4 5 // TODO: add tests comparing with Draw(). 6 7 // Feeds are the lowest level mechanism to draw text in etxt, 8 // allowing the user to issue each glyph draw call individually 9 // and modifying positions or configurations in between. 10 // 11 // As a rule of thumb, you should only resort to feeds if 12 // neither renderer's Draw* nor Traverse* methods give you 13 // enough control to do what you want. Make sure you are 14 // well acquainted with those methods first. 15 // 16 // Valid Feeds can only be created through [Renderer.NewFeed](). 17 type Feed struct { 18 renderer *Renderer // associated renderer 19 Position fixed.Point26_6 // the feed's working position 20 PrevGlyphIndex GlyphIndex // previous glyph index. used for kern. 21 HasPrevGlyph bool // false after line breaks and others. used for kern. 22 LineBreakX fixed.Int26_6 // the x coordinate set after a line break 23 } 24 25 // Draws the given rune and advances the Feed's position. 26 // 27 // The drawing configuration is taken from the Feed's associated renderer. 28 // 29 // Quantization will be checked before every Draw operation and adjusted 30 // if necessary (even vertical quantization). 31 func (self *Feed) Draw(codePoint rune) { 32 self.DrawGlyph(self.renderer.getGlyphIndex(codePoint)) 33 } 34 35 // Same as Draw, but taking a glyph index instead of a rune. 36 func (self *Feed) DrawGlyph(glyphIndex GlyphIndex) { 37 self.traverseGlyph(glyphIndex, 38 func(dot fixed.Point26_6) { 39 mask := self.renderer.LoadGlyphMask(glyphIndex, dot) 40 self.renderer.DefaultDrawFunc(dot, mask, glyphIndex) 41 }) 42 } 43 44 // Draws the given shape and advances the Feed's position based on 45 // the image bounds width (rect.Dx). Notice that shapes are not cached, 46 // so they may be expensive to use. See also DrawImage. 47 // func (self *Feed) DrawShape(shape emask.Shape) { 48 // 49 // } 50 51 // TODO: ebiten version vs gtxt version 52 // func (self *Feed) DrawImage(img image.Image) 53 54 // Advances the Feed's position without drawing anything. 55 func (self *Feed) Advance(codePoint rune) { 56 // TODO: do we *reaally* need this method? Maybe it is superfluous. 57 self.AdvanceGlyph(self.renderer.getGlyphIndex(codePoint)) 58 } 59 60 // Advances the Feed's position without drawing anything. 61 func (self *Feed) AdvanceGlyph(glyphIndex GlyphIndex) { 62 self.traverseGlyph(glyphIndex, func(fixed.Point26_6) {}) 63 } 64 65 // Advances the Feed's position with a line break. 66 func (self *Feed) LineBreak() { 67 self.Position.X = self.renderer.quantizeX(self.Position.X, self.renderer.direction) // * 68 self.Position.Y = self.renderer.quantizeY(self.Position.Y) 69 self.Position.Y = self.renderer.applyLineAdvance(self.Position) 70 self.Position.X = self.LineBreakX 71 self.HasPrevGlyph = false 72 // * required because applyLineAdvance may call NotifyFractChange later 73 } 74 75 // Private traverse method used for Draw and Advance. 76 func (self *Feed) traverseGlyph(glyphIndex GlyphIndex, f func(fixed.Point26_6)) { 77 // By spec, we always quantize. While this could be done only if 78 // !self.HasPrevGlyph, users may modify the Y position manually and then 79 // be bitten by some combinations of caching and quantization modes. 80 // While I could also just blame me, I decided to be nicer. 81 self.Position.Y = self.renderer.quantizeY(self.Position.Y) 82 83 // create the glyph pair and send it to the proper traverse function 84 gpair := glyphPair{glyphIndex, self.PrevGlyphIndex, self.HasPrevGlyph} 85 switch self.renderer.direction { 86 case RightToLeft: 87 self.Position = self.renderer.traverseGlyphRTL(self.Position, gpair, f) 88 case LeftToRight: 89 self.Position = self.renderer.traverseGlyphLTR(self.Position, gpair, f) 90 default: 91 panic("unhandled switch case") 92 } 93 94 self.HasPrevGlyph = true 95 self.PrevGlyphIndex = glyphIndex 96 }