clip.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package gpu
  2. import (
  3. "encoding/binary"
  4. "math"
  5. "gioui.org/internal/f32"
  6. "gioui.org/internal/stroke"
  7. )
  8. type quadSplitter struct {
  9. bounds f32.Rectangle
  10. contour uint32
  11. d *drawOps
  12. // scratch space used by calls to stroke.SplitCubic
  13. scratch []stroke.QuadSegment
  14. }
  15. func encodeQuadTo(data []byte, meta uint32, from, ctrl, to f32.Point) {
  16. // inlined code:
  17. // encodeVertex(data, meta, -1, 1, from, ctrl, to)
  18. // encodeVertex(data[vertStride:], meta, 1, 1, from, ctrl, to)
  19. // encodeVertex(data[vertStride*2:], meta, -1, -1, from, ctrl, to)
  20. // encodeVertex(data[vertStride*3:], meta, 1, -1, from, ctrl, to)
  21. // this code needs to stay in sync with `vertex.encode`.
  22. bo := binary.LittleEndian
  23. data = data[:vertStride*4]
  24. // encode the main template
  25. bo.PutUint32(data[4:8], meta)
  26. bo.PutUint32(data[8:12], math.Float32bits(from.X))
  27. bo.PutUint32(data[12:16], math.Float32bits(from.Y))
  28. bo.PutUint32(data[16:20], math.Float32bits(ctrl.X))
  29. bo.PutUint32(data[20:24], math.Float32bits(ctrl.Y))
  30. bo.PutUint32(data[24:28], math.Float32bits(to.X))
  31. bo.PutUint32(data[28:32], math.Float32bits(to.Y))
  32. copy(data[vertStride*1:vertStride*2], data[vertStride*0:vertStride*1])
  33. copy(data[vertStride*2:vertStride*3], data[vertStride*0:vertStride*1])
  34. copy(data[vertStride*3:vertStride*4], data[vertStride*0:vertStride*1])
  35. bo.PutUint32(data[vertStride*0:vertStride*0+4], math.Float32bits(nwCorner))
  36. bo.PutUint32(data[vertStride*1:vertStride*1+4], math.Float32bits(neCorner))
  37. bo.PutUint32(data[vertStride*2:vertStride*2+4], math.Float32bits(swCorner))
  38. bo.PutUint32(data[vertStride*3:vertStride*3+4], math.Float32bits(seCorner))
  39. }
  40. const (
  41. nwCorner = 1*0.25 + 0*0.5
  42. neCorner = 1*0.25 + 1*0.5
  43. swCorner = 0*0.25 + 0*0.5
  44. seCorner = 0*0.25 + 1*0.5
  45. )
  46. func encodeVertex(data []byte, meta uint32, cornerx, cornery int16, from, ctrl, to f32.Point) {
  47. var corner float32
  48. if cornerx == 1 {
  49. corner += .5
  50. }
  51. if cornery == 1 {
  52. corner += .25
  53. }
  54. v := vertex{
  55. Corner: corner,
  56. FromX: from.X,
  57. FromY: from.Y,
  58. CtrlX: ctrl.X,
  59. CtrlY: ctrl.Y,
  60. ToX: to.X,
  61. ToY: to.Y,
  62. }
  63. v.encode(data, meta)
  64. }
  65. func (qs *quadSplitter) encodeQuadTo(from, ctrl, to f32.Point) {
  66. data := qs.d.writeVertCache(vertStride * 4)
  67. encodeQuadTo(data, qs.contour, from, ctrl, to)
  68. }
  69. func (qs *quadSplitter) splitAndEncode(quad stroke.QuadSegment) {
  70. cbnd := f32.Rectangle{
  71. Min: quad.From,
  72. Max: quad.To,
  73. }.Canon()
  74. from, ctrl, to := quad.From, quad.Ctrl, quad.To
  75. // If the curve contain areas where a vertical line
  76. // intersects it twice, split the curve in two x monotone
  77. // lower and upper curves. The stencil fragment program
  78. // expects only one intersection per curve.
  79. // Find the t where the derivative in x is 0.
  80. v0 := ctrl.Sub(from)
  81. v1 := to.Sub(ctrl)
  82. d := v0.X - v1.X
  83. // t = v0 / d. Split if t is in ]0;1[.
  84. if v0.X > 0 && d > v0.X || v0.X < 0 && d < v0.X {
  85. t := v0.X / d
  86. ctrl0 := from.Mul(1 - t).Add(ctrl.Mul(t))
  87. ctrl1 := ctrl.Mul(1 - t).Add(to.Mul(t))
  88. mid := ctrl0.Mul(1 - t).Add(ctrl1.Mul(t))
  89. qs.encodeQuadTo(from, ctrl0, mid)
  90. qs.encodeQuadTo(mid, ctrl1, to)
  91. if mid.X > cbnd.Max.X {
  92. cbnd.Max.X = mid.X
  93. }
  94. if mid.X < cbnd.Min.X {
  95. cbnd.Min.X = mid.X
  96. }
  97. } else {
  98. qs.encodeQuadTo(from, ctrl, to)
  99. }
  100. // Find the y extremum, if any.
  101. d = v0.Y - v1.Y
  102. if v0.Y > 0 && d > v0.Y || v0.Y < 0 && d < v0.Y {
  103. t := v0.Y / d
  104. y := (1-t)*(1-t)*from.Y + 2*(1-t)*t*ctrl.Y + t*t*to.Y
  105. if y > cbnd.Max.Y {
  106. cbnd.Max.Y = y
  107. }
  108. if y < cbnd.Min.Y {
  109. cbnd.Min.Y = y
  110. }
  111. }
  112. qs.bounds = unionRect(qs.bounds, cbnd)
  113. }
  114. // Union is like f32.Rectangle.Union but ignores empty rectangles.
  115. func unionRect(r, s f32.Rectangle) f32.Rectangle {
  116. if r.Min.X > s.Min.X {
  117. r.Min.X = s.Min.X
  118. }
  119. if r.Min.Y > s.Min.Y {
  120. r.Min.Y = s.Min.Y
  121. }
  122. if r.Max.X < s.Max.X {
  123. r.Max.X = s.Max.X
  124. }
  125. if r.Max.Y < s.Max.Y {
  126. r.Max.Y = s.Max.Y
  127. }
  128. return r
  129. }