github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/op/clip/stroke.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  package clip
     4  
     5  import (
     6  	"encoding/binary"
     7  	"math"
     8  
     9  	"github.com/cybriq/giocore/internal/opconst"
    10  	"github.com/cybriq/giocore/op"
    11  )
    12  
    13  // Stroke represents a stroked path.
    14  type Stroke struct {
    15  	Path  PathSpec
    16  	Style StrokeStyle
    17  
    18  	// Dashes specify the dashes of the stroke.
    19  	// The empty value denotes no dashes.
    20  	Dashes DashSpec
    21  }
    22  
    23  // Op returns a clip operation representing the stroke.
    24  func (s Stroke) Op() Op {
    25  	return Op{
    26  		path:   s.Path,
    27  		stroke: s.Style,
    28  		dashes: s.Dashes,
    29  	}
    30  }
    31  
    32  // StrokeStyle describes how a path should be stroked.
    33  type StrokeStyle struct {
    34  	Width float32 // Width of the stroked path.
    35  
    36  	// Miter is the limit to apply to a miter joint.
    37  	// The zero Miter disables the miter joint; setting Miter to +∞
    38  	// unconditionally enables the miter joint.
    39  	Miter float32
    40  	Cap   StrokeCap  // Cap describes the head or tail of a stroked path.
    41  	Join  StrokeJoin // Join describes how stroked paths are collated.
    42  }
    43  
    44  // StrokeCap describes the head or tail of a stroked path.
    45  type StrokeCap uint8
    46  
    47  const (
    48  	// RoundCap caps stroked paths with a round cap, joining the right-hand and
    49  	// left-hand sides of a stroked path with a half disc of diameter the
    50  	// stroked path's width.
    51  	RoundCap StrokeCap = iota
    52  
    53  	// FlatCap caps stroked paths with a flat cap, joining the right-hand
    54  	// and left-hand sides of a stroked path with a straight line.
    55  	FlatCap
    56  
    57  	// SquareCap caps stroked paths with a square cap, joining the right-hand
    58  	// and left-hand sides of a stroked path with a half square of length
    59  	// the stroked path's width.
    60  	SquareCap
    61  )
    62  
    63  // StrokeJoin describes how stroked paths are collated.
    64  type StrokeJoin uint8
    65  
    66  const (
    67  	// RoundJoin joins path segments with a round segment.
    68  	RoundJoin StrokeJoin = iota
    69  
    70  	// BevelJoin joins path segments with sharp bevels.
    71  	BevelJoin
    72  )
    73  
    74  // Dash records dashes' lengths and phase for a stroked path.
    75  type Dash struct {
    76  	ops   *op.Ops
    77  	macro op.MacroOp
    78  	phase float32
    79  	size  uint8 // size of the pattern
    80  }
    81  
    82  func (d *Dash) Begin(ops *op.Ops) {
    83  	d.ops = ops
    84  	d.macro = op.Record(ops)
    85  	// Write the TypeAux opcode
    86  	data := ops.Write(opconst.TypeAuxLen)
    87  	data[0] = byte(opconst.TypeAux)
    88  }
    89  
    90  func (d *Dash) Phase(v float32) {
    91  	d.phase = v
    92  }
    93  
    94  func (d *Dash) Dash(length float32) {
    95  	if d.size == math.MaxUint8 {
    96  		panic("clip: dash pattern too large")
    97  	}
    98  	data := d.ops.Write(4)
    99  	bo := binary.LittleEndian
   100  	bo.PutUint32(data[0:], math.Float32bits(length))
   101  	d.size++
   102  }
   103  
   104  func (d *Dash) End() DashSpec {
   105  	c := d.macro.Stop()
   106  	return DashSpec{
   107  		spec:  c,
   108  		phase: d.phase,
   109  		size:  d.size,
   110  	}
   111  }
   112  
   113  // DashSpec describes a dashed pattern.
   114  type DashSpec struct {
   115  	spec  op.CallOp
   116  	phase float32
   117  	size  uint8 // size of the pattern
   118  }