scene.go 5.8 KB

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