github.com/utopiagio/gio@v0.0.8/internal/scene/scene.go (about)

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