scene.mx raw

   1  // SPDX-License-Identifier: Unlicense OR MIT
   2  
   3  // Scene command types and encoding for the compute renderer.
   4  
   5  package gio
   6  
   7  import (
   8  	"fmt"
   9  	"image"
  10  	"image/color"
  11  	"math"
  12  )
  13  
  14  type Op uint32
  15  
  16  const sceneElemSize = 36
  17  
  18  type Command [sceneElemSize / 4]uint32
  19  
  20  // GPU commands from piet/scene.h in package gioui.org/shaders.
  21  const (
  22  	OpNop Op = iota
  23  	OpLine
  24  	OpQuad
  25  	OpCubic
  26  	OpFillColor
  27  	OpLineWidth
  28  	OpTransform
  29  	OpBeginClip
  30  	OpEndClip
  31  	OpFillImage
  32  	OpSetFillMode
  33  	OpGap
  34  )
  35  
  36  // FillModes, from setup.h.
  37  type FillMode uint32
  38  
  39  const (
  40  	FillModeNonzero = 0
  41  	FillModeStroke  = 1
  42  )
  43  
  44  // CommandSize is the byte size of a Command (sceneElemSize = 36).
  45  const CommandSize = sceneElemSize
  46  
  47  func (c Command) Op() Op {
  48  	return Op(c[0])
  49  }
  50  
  51  func (c Command) String() string {
  52  	switch Op(c[0]) {
  53  	case OpNop:
  54  		return "nop"
  55  	case OpLine:
  56  		from, to := DecodeLine(c)
  57  		return fmt.Sprintf("line(%v, %v)", from, to)
  58  	case OpGap:
  59  		from, to := DecodeGap(c)
  60  		return fmt.Sprintf("gap(%v, %v)", from, to)
  61  	case OpQuad:
  62  		from, ctrl, to := DecodeQuad(c)
  63  		return fmt.Sprintf("quad(%v, %v, %v)", from, ctrl, to)
  64  	case OpCubic:
  65  		from, ctrl0, ctrl1, to := DecodeCubic(c)
  66  		return fmt.Sprintf("cubic(%v, %v, %v, %v)", from, ctrl0, ctrl1, to)
  67  	case OpFillColor:
  68  		return fmt.Sprintf("fillcolor %#.8x", c[1])
  69  	case OpLineWidth:
  70  		return "linewidth"
  71  	case OpTransform:
  72  		t := NewAffine2D(
  73  			math.Float32frombits(c[1]),
  74  			math.Float32frombits(c[3]),
  75  			math.Float32frombits(c[5]),
  76  			math.Float32frombits(c[2]),
  77  			math.Float32frombits(c[4]),
  78  			math.Float32frombits(c[6]),
  79  		)
  80  		return fmt.Sprintf("transform (%v)", t)
  81  	case OpBeginClip:
  82  		bounds := Rectangle{
  83  			Min: Pt(math.Float32frombits(c[1]), math.Float32frombits(c[2])),
  84  			Max: Pt(math.Float32frombits(c[3]), math.Float32frombits(c[4])),
  85  		}
  86  		return fmt.Sprintf("beginclip (%v)", bounds)
  87  	case OpEndClip:
  88  		bounds := Rectangle{
  89  			Min: Pt(math.Float32frombits(c[1]), math.Float32frombits(c[2])),
  90  			Max: Pt(math.Float32frombits(c[3]), math.Float32frombits(c[4])),
  91  		}
  92  		return fmt.Sprintf("endclip (%v)", bounds)
  93  	case OpFillImage:
  94  		return "fillimage"
  95  	case OpSetFillMode:
  96  		return "setfillmode"
  97  	default:
  98  		panic("unreachable")
  99  	}
 100  }
 101  
 102  func Line(start, end Point) Command {
 103  	return Command{
 104  		0: uint32(OpLine),
 105  		1: math.Float32bits(start.X),
 106  		2: math.Float32bits(start.Y),
 107  		3: math.Float32bits(end.X),
 108  		4: math.Float32bits(end.Y),
 109  	}
 110  }
 111  
 112  func Gap(start, end Point) Command {
 113  	return Command{
 114  		0: uint32(OpGap),
 115  		1: math.Float32bits(start.X),
 116  		2: math.Float32bits(start.Y),
 117  		3: math.Float32bits(end.X),
 118  		4: math.Float32bits(end.Y),
 119  	}
 120  }
 121  
 122  func Cubic(start, ctrl0, ctrl1, end Point) Command {
 123  	return Command{
 124  		0: uint32(OpCubic),
 125  		1: math.Float32bits(start.X),
 126  		2: math.Float32bits(start.Y),
 127  		3: math.Float32bits(ctrl0.X),
 128  		4: math.Float32bits(ctrl0.Y),
 129  		5: math.Float32bits(ctrl1.X),
 130  		6: math.Float32bits(ctrl1.Y),
 131  		7: math.Float32bits(end.X),
 132  		8: math.Float32bits(end.Y),
 133  	}
 134  }
 135  
 136  func Quad(start, ctrl, end Point) Command {
 137  	return Command{
 138  		0: uint32(OpQuad),
 139  		1: math.Float32bits(start.X),
 140  		2: math.Float32bits(start.Y),
 141  		3: math.Float32bits(ctrl.X),
 142  		4: math.Float32bits(ctrl.Y),
 143  		5: math.Float32bits(end.X),
 144  		6: math.Float32bits(end.Y),
 145  	}
 146  }
 147  
 148  func Transform(m Affine2D) Command {
 149  	sx, hx, ox, hy, sy, oy := m.Elems()
 150  	return Command{
 151  		0: uint32(OpTransform),
 152  		1: math.Float32bits(sx),
 153  		2: math.Float32bits(hy),
 154  		3: math.Float32bits(hx),
 155  		4: math.Float32bits(sy),
 156  		5: math.Float32bits(ox),
 157  		6: math.Float32bits(oy),
 158  	}
 159  }
 160  
 161  func SetLineWidth(width float32) Command {
 162  	return Command{
 163  		0: uint32(OpLineWidth),
 164  		1: math.Float32bits(width),
 165  	}
 166  }
 167  
 168  func BeginClip(bbox Rectangle) Command {
 169  	return Command{
 170  		0: uint32(OpBeginClip),
 171  		1: math.Float32bits(bbox.Min.X),
 172  		2: math.Float32bits(bbox.Min.Y),
 173  		3: math.Float32bits(bbox.Max.X),
 174  		4: math.Float32bits(bbox.Max.Y),
 175  	}
 176  }
 177  
 178  func EndClip(bbox Rectangle) Command {
 179  	return Command{
 180  		0: uint32(OpEndClip),
 181  		1: math.Float32bits(bbox.Min.X),
 182  		2: math.Float32bits(bbox.Min.Y),
 183  		3: math.Float32bits(bbox.Max.X),
 184  		4: math.Float32bits(bbox.Max.Y),
 185  	}
 186  }
 187  
 188  func FillColor(col color.RGBA) Command {
 189  	return Command{
 190  		0: uint32(OpFillColor),
 191  		1: uint32(col.R)<<24 | uint32(col.G)<<16 | uint32(col.B)<<8 | uint32(col.A),
 192  	}
 193  }
 194  
 195  func FillImage(index int, offset image.Point) Command {
 196  	x := int16(offset.X)
 197  	y := int16(offset.Y)
 198  	return Command{
 199  		0: uint32(OpFillImage),
 200  		1: uint32(index),
 201  		2: uint32(uint16(x)) | uint32(uint16(y))<<16,
 202  	}
 203  }
 204  
 205  func SetFillMode(mode FillMode) Command {
 206  	return Command{
 207  		0: uint32(OpSetFillMode),
 208  		1: uint32(mode),
 209  	}
 210  }
 211  
 212  func DecodeLine(cmd Command) (from, to Point) {
 213  	if cmd[0] != uint32(OpLine) {
 214  		panic("invalid command")
 215  	}
 216  	from = Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2]))
 217  	to = Pt(math.Float32frombits(cmd[3]), math.Float32frombits(cmd[4]))
 218  	return
 219  }
 220  
 221  func DecodeGap(cmd Command) (from, to Point) {
 222  	if cmd[0] != uint32(OpGap) {
 223  		panic("invalid command")
 224  	}
 225  	from = Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2]))
 226  	to = Pt(math.Float32frombits(cmd[3]), math.Float32frombits(cmd[4]))
 227  	return
 228  }
 229  
 230  func DecodeQuad(cmd Command) (from, ctrl, to Point) {
 231  	if cmd[0] != uint32(OpQuad) {
 232  		panic("invalid command")
 233  	}
 234  	from = Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2]))
 235  	ctrl = Pt(math.Float32frombits(cmd[3]), math.Float32frombits(cmd[4]))
 236  	to = Pt(math.Float32frombits(cmd[5]), math.Float32frombits(cmd[6]))
 237  	return
 238  }
 239  
 240  func DecodeCubic(cmd Command) (from, ctrl0, ctrl1, to Point) {
 241  	if cmd[0] != uint32(OpCubic) {
 242  		panic("invalid command")
 243  	}
 244  	from = Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2]))
 245  	ctrl0 = Pt(math.Float32frombits(cmd[3]), math.Float32frombits(cmd[4]))
 246  	ctrl1 = Pt(math.Float32frombits(cmd[5]), math.Float32frombits(cmd[6]))
 247  	to = Pt(math.Float32frombits(cmd[7]), math.Float32frombits(cmd[8]))
 248  	return
 249  }
 250