From f00f3a3359ff7b5826f365b1b5e00dbffeb4e48a Mon Sep 17 00:00:00 2001 From: Egon Elbre Date: Sun, 1 Nov 2020 21:21:19 +0200 Subject: [PATCH] gpu: add linear gradient Signed-off-by: Egon Elbre --- gpu/gpu.go | 209 ++++++++++++++---- gpu/path.go | 40 +++- gpu/shaders.go | 104 +++++++++ gpu/shaders/stencil.vert | 2 +- internal/cmd/convertshaders/main.go | 6 +- internal/opconst/ops.go | 39 ++-- .../rendertest/refs/TestLinearGradient.png | Bin 0 -> 716 bytes .../refs/TestLinearGradientAngled.png | Bin 0 -> 1329 bytes internal/rendertest/render_test.go | 94 ++++++++ op/paint/paint.go | 29 +++ 10 files changed, 452 insertions(+), 71 deletions(-) create mode 100644 internal/rendertest/refs/TestLinearGradient.png create mode 100644 internal/rendertest/refs/TestLinearGradientAngled.png diff --git a/gpu/gpu.go b/gpu/gpu.go index b2adc08c..b89ed379 100644 --- a/gpu/gpu.go +++ b/gpu/gpu.go @@ -79,6 +79,12 @@ type drawState struct { image imageOpData // Current paint.ColorOp, if any. color color.RGBA + + // Current paint.LinearGradientOp. + stop1 f32.Point + stop2 f32.Point + color1 color.RGBA + color2 color.RGBA } type pathOp struct { @@ -109,6 +115,9 @@ type material struct { opaque bool // For materialTypeColor. color f32color.RGBA + // For materialTypeLinearGradient. + color1 f32color.RGBA + color2 f32color.RGBA // For materialTypeTexture. texture *texture uvTrans f32.Affine2D @@ -127,6 +136,13 @@ type imageOpData struct { handle interface{} } +type linearGradientOpData struct { + stop1 f32.Point + color1 color.RGBA + stop2 f32.Point + color2 color.RGBA +} + func (op *clipOp) decode(data []byte) { if opconst.OpType(data[0]) != opconst.TypeClip { panic("invalid op") @@ -184,6 +200,35 @@ func decodeColorOp(data []byte) color.RGBA { } } +func decodeLinearGradientOp(data []byte) linearGradientOpData { + if opconst.OpType(data[0]) != opconst.TypeLinearGradient { + panic("invalid op") + } + bo := binary.LittleEndian + return linearGradientOpData{ + stop1: f32.Point{ + X: math.Float32frombits(bo.Uint32(data[1:])), + Y: math.Float32frombits(bo.Uint32(data[5:])), + }, + stop2: f32.Point{ + X: math.Float32frombits(bo.Uint32(data[9:])), + Y: math.Float32frombits(bo.Uint32(data[13:])), + }, + color1: color.RGBA{ + R: data[17+0], + G: data[17+1], + B: data[17+2], + A: data[17+3], + }, + color2: color.RGBA{ + R: data[21+0], + G: data[21+1], + B: data[21+2], + A: data[21+3], + }, + } +} + func decodePaintOp(data []byte) paint.PaintOp { bo := binary.LittleEndian if opconst.OpType(data[0]) != opconst.TypePaint { @@ -216,13 +261,14 @@ type texture struct { } type blitter struct { - ctx backend.Device - viewport image.Point - prog [2]*program - layout backend.InputLayout - colUniforms *blitColUniforms - texUniforms *blitTexUniforms - quadVerts backend.Buffer + ctx backend.Device + viewport image.Point + prog [3]*program + layout backend.InputLayout + colUniforms *blitColUniforms + texUniforms *blitTexUniforms + linearGradientUniforms *blitLinearGradientUniforms + quadVerts backend.Buffer } type blitColUniforms struct { @@ -242,6 +288,16 @@ type blitTexUniforms struct { } } +type blitLinearGradientUniforms struct { + vert struct { + blitUniforms + _ [12]byte // Padding to a multiple of 16. + } + frag struct { + gradientUniforms + } +} + type uniformBuffer struct { buf backend.Buffer ptr []byte @@ -264,6 +320,11 @@ type colorUniforms struct { color f32color.RGBA } +type gradientUniforms struct { + color1 f32color.RGBA + color2 f32color.RGBA +} + type materialType uint8 const ( @@ -274,6 +335,7 @@ const ( const ( materialColor materialType = iota + materialLinearGradient materialTexture ) @@ -447,8 +509,11 @@ func newBlitter(ctx backend.Device) *blitter { } b.colUniforms = new(blitColUniforms) b.texUniforms = new(blitTexUniforms) + b.linearGradientUniforms = new(blitLinearGradientUniforms) prog, layout, err := createColorPrograms(ctx, shader_blit_vert, shader_blit_frag, - [2]interface{}{&b.colUniforms.vert, &b.texUniforms.vert}, [2]interface{}{&b.colUniforms.frag, nil}) + [3]interface{}{&b.colUniforms.vert, &b.linearGradientUniforms.vert, &b.texUniforms.vert}, + [3]interface{}{&b.colUniforms.frag, &b.linearGradientUniforms.frag, nil}, + ) if err != nil { panic(err) } @@ -465,37 +530,59 @@ func (b *blitter) release() { b.layout.Release() } -func createColorPrograms(b backend.Device, vsSrc backend.ShaderSources, fsSrc [2]backend.ShaderSources, vertUniforms, fragUniforms [2]interface{}) ([2]*program, backend.InputLayout, error) { - var progs [2]*program - prog, err := b.NewProgram(vsSrc, fsSrc[materialTexture]) - if err != nil { - return progs, nil, err +func createColorPrograms(b backend.Device, vsSrc backend.ShaderSources, fsSrc [3]backend.ShaderSources, vertUniforms, fragUniforms [3]interface{}) ([3]*program, backend.InputLayout, error) { + var progs [3]*program + { + prog, err := b.NewProgram(vsSrc, fsSrc[materialTexture]) + if err != nil { + return progs, nil, err + } + var vertBuffer, fragBuffer *uniformBuffer + if u := vertUniforms[materialTexture]; u != nil { + vertBuffer = newUniformBuffer(b, u) + prog.SetVertexUniforms(vertBuffer.buf) + } + if u := fragUniforms[materialTexture]; u != nil { + fragBuffer = newUniformBuffer(b, u) + prog.SetFragmentUniforms(fragBuffer.buf) + } + progs[materialTexture] = newProgram(prog, vertBuffer, fragBuffer) } - var vertBuffer *uniformBuffer - if u := vertUniforms[materialTexture]; u != nil { - vertBuffer = newUniformBuffer(b, u) - prog.SetVertexUniforms(vertBuffer.buf) + { + var vertBuffer, fragBuffer *uniformBuffer + prog, err := b.NewProgram(vsSrc, fsSrc[materialColor]) + if err != nil { + progs[materialTexture].Release() + return progs, nil, err + } + if u := vertUniforms[materialColor]; u != nil { + vertBuffer = newUniformBuffer(b, u) + prog.SetVertexUniforms(vertBuffer.buf) + } + if u := fragUniforms[materialColor]; u != nil { + fragBuffer = newUniformBuffer(b, u) + prog.SetFragmentUniforms(fragBuffer.buf) + } + progs[materialColor] = newProgram(prog, vertBuffer, fragBuffer) } - var fragBuffer *uniformBuffer - if u := fragUniforms[materialTexture]; u != nil { - fragBuffer = newUniformBuffer(b, u) - prog.SetFragmentUniforms(fragBuffer.buf) + { + var vertBuffer, fragBuffer *uniformBuffer + prog, err := b.NewProgram(vsSrc, fsSrc[materialLinearGradient]) + if err != nil { + progs[materialTexture].Release() + progs[materialColor].Release() + return progs, nil, err + } + if u := vertUniforms[materialLinearGradient]; u != nil { + vertBuffer = newUniformBuffer(b, u) + prog.SetVertexUniforms(vertBuffer.buf) + } + if u := fragUniforms[materialLinearGradient]; u != nil { + fragBuffer = newUniformBuffer(b, u) + prog.SetFragmentUniforms(fragBuffer.buf) + } + progs[materialLinearGradient] = newProgram(prog, vertBuffer, fragBuffer) } - progs[materialTexture] = newProgram(prog, vertBuffer, fragBuffer) - prog, err = b.NewProgram(vsSrc, fsSrc[materialColor]) - if err != nil { - progs[materialTexture].Release() - return progs, nil, err - } - if u := vertUniforms[materialColor]; u != nil { - vertBuffer = newUniformBuffer(b, u) - prog.SetVertexUniforms(vertBuffer.buf) - } - if u := fragUniforms[materialColor]; u != nil { - fragBuffer = newUniformBuffer(b, u) - prog.SetFragmentUniforms(fragBuffer.buf) - } - progs[materialColor] = newProgram(prog, vertBuffer, fragBuffer) layout, err := b.NewInputLayout(vsSrc, []backend.InputDesc{ {Type: backend.DataTypeFloat, Size: 2, Offset: 0}, {Type: backend.DataTypeFloat, Size: 2, Offset: 4 * 2}, @@ -503,6 +590,7 @@ func createColorPrograms(b backend.Device, vsSrc backend.ShaderSources, fsSrc [2 if err != nil { progs[materialTexture].Release() progs[materialColor].Release() + progs[materialLinearGradient].Release() return progs, nil, err } return progs, layout, nil @@ -768,6 +856,13 @@ loop: case opconst.TypeColor: state.matType = materialColor state.color = decodeColorOp(encOp.Data) + case opconst.TypeLinearGradient: + state.matType = materialLinearGradient + op := decodeLinearGradientOp(encOp.Data) + state.stop1 = op.stop1 + state.stop2 = op.stop2 + state.color1 = op.color1 + state.color2 = op.color2 case opconst.TypeImage: state.matType = materialTexture state.image = decodeImageOp(encOp.Data, encOp.Refs) @@ -794,7 +889,7 @@ loop: bounds := boundRectF(clip) mat := state.materialFor(d.cache, bnd, off, partialTrans, bounds) - if bounds.Min == (image.Point{}) && bounds.Max == d.viewport && state.rect && mat.opaque && mat.material == materialColor { + if bounds.Min == (image.Point{}) && bounds.Max == d.viewport && state.rect && mat.opaque && (mat.material == materialColor) { // The image is a uniform opaque color and takes up the whole screen. // Scrap images up to and including this image and set clear color. d.zimageOps = d.zimageOps[:0] @@ -857,6 +952,14 @@ func (d *drawState) materialFor(cache *resourceCache, rect f32.Rectangle, off f3 m.material = materialColor m.color = f32color.RGBAFromSRGB(d.color) m.opaque = m.color.A == 1.0 + case materialLinearGradient: + m.material = materialLinearGradient + + m.color1 = f32color.RGBAFromSRGB(d.color1) + m.color2 = f32color.RGBAFromSRGB(d.color2) + m.opaque = m.color1.A == 1.0 && m.color2.A == 1.0 + + m.uvTrans = trans.Mul(gradientSpaceTransform(clip, off, d.stop1, d.stop2)) case materialTexture: m.material = materialTexture dr := boundRectF(rect.Add(off)) @@ -905,7 +1008,7 @@ func (r *renderer) drawZOps(ops []imageOp) { } drc := img.clip scale, off := clipSpaceTransform(drc, r.blitter.viewport) - r.blitter.blit(img.z, m.material, m.color, scale, off, m.uvTrans) + r.blitter.blit(img.z, m.material, m.color, m.color1, m.color2, scale, off, m.uvTrans) } r.ctx.SetDepthTest(false) } @@ -929,7 +1032,7 @@ func (r *renderer) drawOps(ops []imageOp) { var fbo stencilFBO switch img.clipType { case clipTypeNone: - r.blitter.blit(img.z, m.material, m.color, scale, off, m.uvTrans) + r.blitter.blit(img.z, m.material, m.color, m.color1, m.color2, scale, off, m.uvTrans) continue case clipTypePath: fbo = r.pather.stenciler.cover(img.place.Idx) @@ -945,13 +1048,13 @@ func (r *renderer) drawOps(ops []imageOp) { Max: img.place.Pos.Add(drc.Size()), } coverScale, coverOff := texSpaceTransform(toRectF(uv), fbo.size) - r.pather.cover(img.z, m.material, m.color, scale, off, m.uvTrans, coverScale, coverOff) + r.pather.cover(img.z, m.material, m.color, m.color1, m.color2, scale, off, m.uvTrans, coverScale, coverOff) } r.ctx.DepthMask(true) r.ctx.SetDepthTest(false) } -func (b *blitter) blit(z float32, mat materialType, col f32color.RGBA, scale, off f32.Point, uvTrans f32.Affine2D) { +func (b *blitter) blit(z float32, mat materialType, col f32color.RGBA, col1, col2 f32color.RGBA, scale, off f32.Point, uvTrans f32.Affine2D) { p := b.prog[mat] b.ctx.BindProgram(p.prog) var uniforms *blitUniforms @@ -964,6 +1067,14 @@ func (b *blitter) blit(z float32, mat materialType, col f32color.RGBA, scale, of b.texUniforms.vert.blitUniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0} b.texUniforms.vert.blitUniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0} uniforms = &b.texUniforms.vert.blitUniforms + case materialLinearGradient: + b.linearGradientUniforms.frag.color1 = col1 + b.linearGradientUniforms.frag.color2 = col2 + + t1, t2, t3, t4, t5, t6 := uvTrans.Elems() + b.linearGradientUniforms.vert.blitUniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0} + b.linearGradientUniforms.vert.blitUniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0} + uniforms = &b.linearGradientUniforms.vert.blitUniforms } uniforms.z = z uniforms.transform = [4]float32{scale.X, scale.Y, off.X, off.Y} @@ -1036,6 +1147,22 @@ func texSpaceTransform(r f32.Rectangle, bounds image.Point) (f32.Point, f32.Poin return scale, offset } +// gradientSpaceTransform transforms stop1 and stop2 to [(0,0), (1,1)]. +func gradientSpaceTransform(clip image.Rectangle, off f32.Point, stop1, stop2 f32.Point) f32.Affine2D { + d := stop2.Sub(stop1) + l := float32(math.Sqrt(float64(d.X*d.X + d.Y*d.Y))) + a := float32(math.Atan2(float64(-d.Y), float64(d.X))) + + // TODO: optimize + zp := f32.Point{} + return f32.Affine2D{}. + Scale(zp, layout.FPt(clip.Size())). // scale to pixel space + Offset(zp.Sub(off).Add(layout.FPt(clip.Min))). // offset to clip space + Offset(zp.Sub(stop1)). // offset to first stop point + Rotate(zp, a). // rotate to align gradient + Scale(zp, f32.Pt(1/l, 1/l)) // scale gradient to right size +} + // clipSpaceTransform returns the scale and offset that transforms the given // rectangle from a viewport into OpenGL clip space. func clipSpaceTransform(r image.Rectangle, viewport image.Point) (f32.Point, f32.Point) { diff --git a/gpu/path.go b/gpu/path.go index 2dd58755..da02d6ea 100644 --- a/gpu/path.go +++ b/gpu/path.go @@ -27,11 +27,12 @@ type pather struct { } type coverer struct { - ctx backend.Device - prog [2]*program - texUniforms *coverTexUniforms - colUniforms *coverColUniforms - layout backend.InputLayout + ctx backend.Device + prog [3]*program + texUniforms *coverTexUniforms + colUniforms *coverColUniforms + linearGradientUniforms *coverLinearGradientUniforms + layout backend.InputLayout } type coverTexUniforms struct { @@ -51,6 +52,16 @@ type coverColUniforms struct { } } +type coverLinearGradientUniforms struct { + vert struct { + coverUniforms + _ [12]byte // Padding to multiple of 16. + } + frag struct { + gradientUniforms + } +} + type coverUniforms struct { transform [4]float32 uvCoverTransform [4]float32 @@ -149,9 +160,10 @@ func newCoverer(ctx backend.Device) *coverer { } c.colUniforms = new(coverColUniforms) c.texUniforms = new(coverTexUniforms) + c.linearGradientUniforms = new(coverLinearGradientUniforms) prog, layout, err := createColorPrograms(ctx, shader_cover_vert, shader_cover_frag, - [2]interface{}{&c.colUniforms.vert, &c.texUniforms.vert}, - [2]interface{}{&c.colUniforms.frag, nil}, + [3]interface{}{&c.colUniforms.vert, &c.linearGradientUniforms.vert, &c.texUniforms.vert}, + [3]interface{}{&c.colUniforms.frag, &c.linearGradientUniforms.frag, nil}, ) if err != nil { panic(err) @@ -362,11 +374,11 @@ func (s *stenciler) stencilPath(bounds image.Rectangle, offset f32.Point, uv ima } } -func (p *pather) cover(z float32, mat materialType, col f32color.RGBA, scale, off f32.Point, uvTrans f32.Affine2D, coverScale, coverOff f32.Point) { - p.coverer.cover(z, mat, col, scale, off, uvTrans, coverScale, coverOff) +func (p *pather) cover(z float32, mat materialType, col f32color.RGBA, col1, col2 f32color.RGBA, scale, off f32.Point, uvTrans f32.Affine2D, coverScale, coverOff f32.Point) { + p.coverer.cover(z, mat, col, col1, col2, scale, off, uvTrans, coverScale, coverOff) } -func (c *coverer) cover(z float32, mat materialType, col f32color.RGBA, scale, off f32.Point, uvTrans f32.Affine2D, coverScale, coverOff f32.Point) { +func (c *coverer) cover(z float32, mat materialType, col f32color.RGBA, col1, col2 f32color.RGBA, scale, off f32.Point, uvTrans f32.Affine2D, coverScale, coverOff f32.Point) { p := c.prog[mat] c.ctx.BindProgram(p.prog) var uniforms *coverUniforms @@ -374,6 +386,14 @@ func (c *coverer) cover(z float32, mat materialType, col f32color.RGBA, scale, o case materialColor: c.colUniforms.frag.color = col uniforms = &c.colUniforms.vert.coverUniforms + case materialLinearGradient: + c.linearGradientUniforms.frag.color1 = col1 + c.linearGradientUniforms.frag.color2 = col2 + + t1, t2, t3, t4, t5, t6 := uvTrans.Elems() + c.linearGradientUniforms.vert.uvTransformR1 = [4]float32{t1, t2, t3, 0} + c.linearGradientUniforms.vert.uvTransformR2 = [4]float32{t4, t5, t6, 0} + uniforms = &c.linearGradientUniforms.vert.coverUniforms case materialTexture: t1, t2, t3, t4, t5, t6 := uvTrans.Elems() c.texUniforms.vert.uvTransformR1 = [4]float32{t1, t2, t3, 0} diff --git a/gpu/shaders.go b/gpu/shaders.go index d8e84352..d6e37359 100644 --- a/gpu/shaders.go +++ b/gpu/shaders.go @@ -53,6 +53,54 @@ var ( */ HLSL: []byte{0x44, 0x58, 0x42, 0x43, 0xc6, 0x4a, 0x23, 0x81, 0x87, 0xab, 0xe3, 0xca, 0x12, 0x9, 0x7e, 0x2f, 0x5e, 0x2, 0x62, 0x14, 0x1, 0x0, 0x0, 0x0, 0x70, 0x2, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0x84, 0x0, 0x0, 0x0, 0xcc, 0x0, 0x0, 0x0, 0x48, 0x1, 0x0, 0x0, 0x8, 0x2, 0x0, 0x0, 0x3c, 0x2, 0x0, 0x0, 0x41, 0x6f, 0x6e, 0x39, 0x44, 0x0, 0x0, 0x0, 0x44, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0x14, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x1, 0x0, 0x24, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x24, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0x1, 0x0, 0x0, 0x2, 0x0, 0x8, 0xf, 0x80, 0x0, 0x0, 0xe4, 0xa0, 0xff, 0xff, 0x0, 0x0, 0x53, 0x48, 0x44, 0x52, 0x40, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x59, 0x0, 0x0, 0x4, 0x46, 0x8e, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x3, 0xf2, 0x20, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x0, 0x0, 0x6, 0xf2, 0x20, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x8e, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x0, 0x0, 0x1, 0x53, 0x54, 0x41, 0x54, 0x74, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x52, 0x44, 0x45, 0x46, 0xb8, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x44, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x4, 0xff, 0xff, 0x0, 0x1, 0x0, 0x0, 0x90, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x0, 0xab, 0xab, 0x3c, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x5c, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x74, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5f, 0x31, 0x32, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x0, 0xab, 0xab, 0x1, 0x0, 0x3, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x0, 0x49, 0x53, 0x47, 0x4e, 0x2c, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x0, 0xab, 0xab, 0xab, 0x4f, 0x53, 0x47, 0x4e, 0x2c, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x0, 0xab, 0xab}, }, + { + Uniforms: backend.UniformsReflection{ + Blocks: []backend.UniformBlock{{Name: "Gradient", Binding: 0}}, + Locations: []backend.UniformLocation{{Name: "_12._color1", Type: 0x0, Size: 4, Offset: 0}, {Name: "_12._color2", Type: 0x0, Size: 4, Offset: 16}}, + Size: 32, + }, + GLSL100ES: "precision mediump float;\nprecision highp int;\n\nstruct Gradient\n{\n vec4 _color1;\n vec4 _color2;\n};\n\nuniform Gradient _12;\n\nvarying vec2 vUV;\n\nvoid main()\n{\n gl_FragData[0] = mix(_12._color1, _12._color2, vec4(clamp(vUV.x, 0.0, 1.0)));\n}\n\n", + GLSL300ES: "#version 300 es\nprecision mediump float;\nprecision highp int;\n\nlayout(std140) uniform Gradient\n{\n vec4 _color1;\n vec4 _color2;\n} _12;\n\nlayout(location = 0) out vec4 fragColor;\nin vec2 vUV;\n\nvoid main()\n{\n fragColor = mix(_12._color1, _12._color2, vec4(clamp(vUV.x, 0.0, 1.0)));\n}\n\n", + GLSL130: "#version 130\n\nstruct Gradient\n{\n vec4 _color1;\n vec4 _color2;\n};\n\nuniform Gradient _12;\n\nout vec4 fragColor;\nin vec2 vUV;\n\nvoid main()\n{\n fragColor = mix(_12._color1, _12._color2, vec4(clamp(vUV.x, 0.0, 1.0)));\n}\n\n", + GLSL150: "#version 150\n\nstruct Gradient\n{\n vec4 _color1;\n vec4 _color2;\n};\n\nuniform Gradient _12;\n\nout vec4 fragColor;\nin vec2 vUV;\n\nvoid main()\n{\n fragColor = mix(_12._color1, _12._color2, vec4(clamp(vUV.x, 0.0, 1.0)));\n}\n\n", + /* + cbuffer Gradient : register(b0) + { + float4 _12_color1 : packoffset(c0); + float4 _12_color2 : packoffset(c1); + }; + + + static float4 fragColor; + static float2 vUV; + + struct SPIRV_Cross_Input + { + float2 vUV : TEXCOORD0; + }; + + struct SPIRV_Cross_Output + { + float4 fragColor : SV_Target0; + }; + + void frag_main() + { + fragColor = lerp(_12_color1, _12_color2, clamp(vUV.x, 0.0f, 1.0f).xxxx); + } + + SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) + { + vUV = stage_input.vUV; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.fragColor = fragColor; + return stage_output; + } + + */ + HLSL: []byte{0x44, 0x58, 0x42, 0x43, 0xc0, 0x43, 0x72, 0x3d, 0x68, 0xc9, 0x38, 0x57, 0x9f, 0xa3, 0x60, 0xa8, 0xae, 0xd2, 0xa2, 0xf0, 0x1, 0x0, 0x0, 0x0, 0x40, 0x3, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0xcc, 0x0, 0x0, 0x0, 0x74, 0x1, 0x0, 0x0, 0xf0, 0x1, 0x0, 0x0, 0xd8, 0x2, 0x0, 0x0, 0xc, 0x3, 0x0, 0x0, 0x41, 0x6f, 0x6e, 0x39, 0x8c, 0x0, 0x0, 0x0, 0x8c, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0x5c, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x1, 0x0, 0x24, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x24, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0x1f, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x3, 0xb0, 0x1, 0x0, 0x0, 0x2, 0x0, 0x0, 0x18, 0x80, 0x0, 0x0, 0x0, 0xb0, 0x1, 0x0, 0x0, 0x2, 0x1, 0x0, 0xf, 0x80, 0x0, 0x0, 0xe4, 0xa0, 0x2, 0x0, 0x0, 0x3, 0x1, 0x0, 0xf, 0x80, 0x1, 0x0, 0xe4, 0x81, 0x1, 0x0, 0xe4, 0xa0, 0x4, 0x0, 0x0, 0x4, 0x0, 0x0, 0xf, 0x80, 0x0, 0x0, 0xff, 0x80, 0x1, 0x0, 0xe4, 0x80, 0x0, 0x0, 0xe4, 0xa0, 0x1, 0x0, 0x0, 0x2, 0x0, 0x8, 0xf, 0x80, 0x0, 0x0, 0xe4, 0x80, 0xff, 0xff, 0x0, 0x0, 0x53, 0x48, 0x44, 0x52, 0xa0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x59, 0x0, 0x0, 0x4, 0x46, 0x8e, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x62, 0x10, 0x0, 0x3, 0x12, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x3, 0xf2, 0x20, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x0, 0x0, 0x2, 0x2, 0x0, 0x0, 0x0, 0x36, 0x20, 0x0, 0x5, 0x12, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xf2, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x46, 0x8e, 0x20, 0x80, 0x41, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x8e, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x32, 0x0, 0x0, 0xa, 0xf2, 0x20, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0xe, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x46, 0x8e, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x0, 0x0, 0x1, 0x53, 0x54, 0x41, 0x54, 0x74, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x52, 0x44, 0x45, 0x46, 0xe0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x48, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x4, 0xff, 0xff, 0x0, 0x1, 0x0, 0x0, 0xb7, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x47, 0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x0, 0xab, 0xab, 0xab, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x60, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x9c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xac, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x9c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5f, 0x31, 0x32, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x31, 0x0, 0xab, 0x1, 0x0, 0x3, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5f, 0x31, 0x32, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x32, 0x0, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x0, 0xab, 0x49, 0x53, 0x47, 0x4e, 0x2c, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x1, 0x0, 0x0, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x0, 0xab, 0xab, 0xab, 0x4f, 0x53, 0x47, 0x4e, 0x2c, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x0, 0xab, 0xab}, + }, { Textures: []backend.TextureBinding{{Name: "tex", Binding: 0}}, GLSL100ES: "precision mediump float;\nprecision highp int;\n\nuniform mediump sampler2D tex;\n\nvarying vec2 vUV;\n\nvoid main()\n{\n gl_FragData[0] = texture2D(tex, vUV);\n}\n\n", @@ -232,6 +280,62 @@ var ( */ HLSL: []byte{0x44, 0x58, 0x42, 0x43, 0x94, 0xe9, 0xc3, 0x12, 0xd8, 0xfb, 0xb, 0x3b, 0xe, 0xda, 0x43, 0x25, 0xcb, 0x53, 0x1c, 0x9d, 0x1, 0x0, 0x0, 0x0, 0x84, 0x3, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0xcc, 0x0, 0x0, 0x0, 0x74, 0x1, 0x0, 0x0, 0xf0, 0x1, 0x0, 0x0, 0x4, 0x3, 0x0, 0x0, 0x50, 0x3, 0x0, 0x0, 0x41, 0x6f, 0x6e, 0x39, 0x8c, 0x0, 0x0, 0x0, 0x8c, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0x58, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, 0x0, 0x1, 0x0, 0x28, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, 0x0, 0x34, 0x0, 0x1, 0x0, 0x24, 0x0, 0x0, 0x0, 0x34, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0x1f, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0xf, 0xb0, 0x1f, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x90, 0x0, 0x8, 0xf, 0xa0, 0x42, 0x0, 0x0, 0x3, 0x0, 0x0, 0xf, 0x80, 0x0, 0x0, 0xe4, 0xb0, 0x0, 0x8, 0xe4, 0xa0, 0x23, 0x0, 0x0, 0x2, 0x0, 0x0, 0x1, 0x80, 0x0, 0x0, 0x0, 0x80, 0x5, 0x0, 0x0, 0x3, 0x0, 0x0, 0xf, 0x80, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0xe4, 0xa0, 0x1, 0x0, 0x0, 0x2, 0x0, 0x8, 0xf, 0x80, 0x0, 0x0, 0xe4, 0x80, 0xff, 0xff, 0x0, 0x0, 0x53, 0x48, 0x44, 0x52, 0xa0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x59, 0x0, 0x0, 0x4, 0x46, 0x8e, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x5a, 0x0, 0x0, 0x3, 0x0, 0x60, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x58, 0x18, 0x0, 0x4, 0x0, 0x70, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x55, 0x55, 0x0, 0x0, 0x62, 0x10, 0x0, 0x3, 0x32, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x3, 0xf2, 0x20, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x0, 0x0, 0x2, 0x1, 0x0, 0x0, 0x0, 0x45, 0x0, 0x0, 0x9, 0xf2, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x7e, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x60, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x9, 0xf2, 0x20, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x0, 0x10, 0x80, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x8e, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x0, 0x0, 0x1, 0x53, 0x54, 0x41, 0x54, 0x74, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x52, 0x44, 0x45, 0x46, 0xc, 0x1, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x98, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x4, 0xff, 0xff, 0x0, 0x1, 0x0, 0x0, 0xe4, 0x0, 0x0, 0x0, 0x7c, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x8b, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x91, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x5f, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x0, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x0, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x0, 0xab, 0x91, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xb0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xd4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5f, 0x31, 0x32, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x0, 0xab, 0xab, 0x1, 0x0, 0x3, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x0, 0x49, 0x53, 0x47, 0x4e, 0x44, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x0, 0xab, 0xab, 0xab, 0x4f, 0x53, 0x47, 0x4e, 0x2c, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x0, 0xab, 0xab}, }, + { + Uniforms: backend.UniformsReflection{ + Blocks: []backend.UniformBlock{{Name: "Gradient", Binding: 0}}, + Locations: []backend.UniformLocation{{Name: "_12._color1", Type: 0x0, Size: 4, Offset: 0}, {Name: "_12._color2", Type: 0x0, Size: 4, Offset: 16}}, + Size: 32, + }, + Textures: []backend.TextureBinding{{Name: "cover", Binding: 1}}, + GLSL100ES: "precision mediump float;\nprecision highp int;\n\nstruct Gradient\n{\n vec4 _color1;\n vec4 _color2;\n};\n\nuniform Gradient _12;\n\nuniform mediump sampler2D cover;\n\nvarying vec2 vUV;\nvarying highp vec2 vCoverUV;\n\nvoid main()\n{\n gl_FragData[0] = mix(_12._color1, _12._color2, vec4(clamp(vUV.x, 0.0, 1.0)));\n float cover_1 = abs(texture2D(cover, vCoverUV).x);\n gl_FragData[0] *= cover_1;\n}\n\n", + GLSL300ES: "#version 300 es\nprecision mediump float;\nprecision highp int;\n\nlayout(std140) uniform Gradient\n{\n vec4 _color1;\n vec4 _color2;\n} _12;\n\nuniform mediump sampler2D cover;\n\nlayout(location = 0) out vec4 fragColor;\nin vec2 vUV;\nin highp vec2 vCoverUV;\n\nvoid main()\n{\n fragColor = mix(_12._color1, _12._color2, vec4(clamp(vUV.x, 0.0, 1.0)));\n float cover_1 = abs(texture(cover, vCoverUV).x);\n fragColor *= cover_1;\n}\n\n", + GLSL130: "#version 130\n\nstruct Gradient\n{\n vec4 _color1;\n vec4 _color2;\n};\n\nuniform Gradient _12;\n\nuniform sampler2D cover;\n\nout vec4 fragColor;\nin vec2 vUV;\nin vec2 vCoverUV;\n\nvoid main()\n{\n fragColor = mix(_12._color1, _12._color2, vec4(clamp(vUV.x, 0.0, 1.0)));\n float cover_1 = abs(texture(cover, vCoverUV).x);\n fragColor *= cover_1;\n}\n\n", + GLSL150: "#version 150\n\nstruct Gradient\n{\n vec4 _color1;\n vec4 _color2;\n};\n\nuniform Gradient _12;\n\nuniform sampler2D cover;\n\nout vec4 fragColor;\nin vec2 vUV;\nin vec2 vCoverUV;\n\nvoid main()\n{\n fragColor = mix(_12._color1, _12._color2, vec4(clamp(vUV.x, 0.0, 1.0)));\n float cover_1 = abs(texture(cover, vCoverUV).x);\n fragColor *= cover_1;\n}\n\n", + /* + cbuffer Gradient : register(b0) + { + float4 _12_color1 : packoffset(c0); + float4 _12_color2 : packoffset(c1); + }; + + Texture2D cover : register(t1); + SamplerState _cover_sampler : register(s1); + + static float4 fragColor; + static float2 vUV; + static float2 vCoverUV; + + struct SPIRV_Cross_Input + { + float2 vCoverUV : TEXCOORD0; + float2 vUV : TEXCOORD1; + }; + + struct SPIRV_Cross_Output + { + float4 fragColor : SV_Target0; + }; + + void frag_main() + { + fragColor = lerp(_12_color1, _12_color2, clamp(vUV.x, 0.0f, 1.0f).xxxx); + float cover_1 = abs(cover.Sample(_cover_sampler, vCoverUV).x); + fragColor *= cover_1; + } + + SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) + { + vUV = stage_input.vUV; + vCoverUV = stage_input.vCoverUV; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.fragColor = fragColor; + return stage_output; + } + + */ + HLSL: []byte{0x44, 0x58, 0x42, 0x43, 0x94, 0x3e, 0x75, 0x3b, 0x8e, 0x69, 0x34, 0xbf, 0x4a, 0x89, 0xa5, 0x79, 0x1d, 0x8b, 0x25, 0x41, 0x1, 0x0, 0x0, 0x0, 0x54, 0x4, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0x8, 0x1, 0x0, 0x0, 0x1c, 0x2, 0x0, 0x0, 0x98, 0x2, 0x0, 0x0, 0xd4, 0x3, 0x0, 0x0, 0x20, 0x4, 0x0, 0x0, 0x41, 0x6f, 0x6e, 0x39, 0xc8, 0x0, 0x0, 0x0, 0xc8, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0x94, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, 0x0, 0x1, 0x0, 0x28, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, 0x0, 0x34, 0x0, 0x1, 0x0, 0x24, 0x0, 0x0, 0x0, 0x34, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0x1f, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0xf, 0xb0, 0x1f, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x90, 0x0, 0x8, 0xf, 0xa0, 0x42, 0x0, 0x0, 0x3, 0x0, 0x0, 0xf, 0x80, 0x0, 0x0, 0xe4, 0xb0, 0x0, 0x8, 0xe4, 0xa0, 0x1, 0x0, 0x0, 0x2, 0x0, 0x0, 0x12, 0x80, 0x0, 0x0, 0xff, 0xb0, 0x1, 0x0, 0x0, 0x2, 0x1, 0x0, 0xf, 0x80, 0x0, 0x0, 0xe4, 0xa0, 0x2, 0x0, 0x0, 0x3, 0x1, 0x0, 0xf, 0x80, 0x1, 0x0, 0xe4, 0x81, 0x1, 0x0, 0xe4, 0xa0, 0x4, 0x0, 0x0, 0x4, 0x1, 0x0, 0xf, 0x80, 0x0, 0x0, 0x55, 0x80, 0x1, 0x0, 0xe4, 0x80, 0x0, 0x0, 0xe4, 0xa0, 0x23, 0x0, 0x0, 0x2, 0x0, 0x0, 0x1, 0x80, 0x0, 0x0, 0x0, 0x80, 0x5, 0x0, 0x0, 0x3, 0x0, 0x0, 0xf, 0x80, 0x0, 0x0, 0x0, 0x80, 0x1, 0x0, 0xe4, 0x80, 0x1, 0x0, 0x0, 0x2, 0x0, 0x8, 0xf, 0x80, 0x0, 0x0, 0xe4, 0x80, 0xff, 0xff, 0x0, 0x0, 0x53, 0x48, 0x44, 0x52, 0xc, 0x1, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x43, 0x0, 0x0, 0x0, 0x59, 0x0, 0x0, 0x4, 0x46, 0x8e, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x5a, 0x0, 0x0, 0x3, 0x0, 0x60, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x58, 0x18, 0x0, 0x4, 0x0, 0x70, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x55, 0x55, 0x0, 0x0, 0x62, 0x10, 0x0, 0x3, 0x32, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x62, 0x10, 0x0, 0x3, 0x42, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x3, 0xf2, 0x20, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x0, 0x0, 0x2, 0x2, 0x0, 0x0, 0x0, 0x36, 0x20, 0x0, 0x5, 0x12, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xf2, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x46, 0x8e, 0x20, 0x80, 0x41, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x8e, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x32, 0x0, 0x0, 0xa, 0xf2, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0xe, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x46, 0x8e, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x45, 0x0, 0x0, 0x9, 0xf2, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x46, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x7e, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x60, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x8, 0xf2, 0x20, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0xe, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x0, 0x10, 0x80, 0x81, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x3e, 0x0, 0x0, 0x1, 0x53, 0x54, 0x41, 0x54, 0x74, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x52, 0x44, 0x45, 0x46, 0x34, 0x1, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x9c, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x4, 0xff, 0xff, 0x0, 0x1, 0x0, 0x0, 0xb, 0x1, 0x0, 0x0, 0x7c, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x8b, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x91, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x5f, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x0, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x0, 0x47, 0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x0, 0xab, 0xab, 0x91, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xb4, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5f, 0x31, 0x32, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x31, 0x0, 0xab, 0x1, 0x0, 0x3, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5f, 0x31, 0x32, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x32, 0x0, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x0, 0xab, 0x49, 0x53, 0x47, 0x4e, 0x44, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x4, 0x0, 0x0, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x0, 0xab, 0xab, 0xab, 0x4f, 0x53, 0x47, 0x4e, 0x2c, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x0, 0xab, 0xab}, + }, { Textures: []backend.TextureBinding{{Name: "tex", Binding: 0}, {Name: "cover", Binding: 1}}, GLSL100ES: "precision mediump float;\nprecision highp int;\n\nuniform mediump sampler2D tex;\nuniform mediump sampler2D cover;\n\nvarying vec2 vUV;\nvarying highp vec2 vCoverUV;\n\nvoid main()\n{\n gl_FragData[0] = texture2D(tex, vUV);\n float cover_1 = abs(texture2D(cover, vCoverUV).x);\n gl_FragData[0] *= cover_1;\n}\n\n", diff --git a/gpu/shaders/stencil.vert b/gpu/shaders/stencil.vert index 0fe65f57..8b6961cd 100644 --- a/gpu/shaders/stencil.vert +++ b/gpu/shaders/stencil.vert @@ -48,6 +48,6 @@ void main() { vCtrl = ctrl-pos; vTo = to-pos; pos = pos*transform.xy + transform.zw; - gl_Position = vec4(pos, 1, 1); + gl_Position = vec4(pos, 1, 1); } diff --git a/internal/cmd/convertshaders/main.go b/internal/cmd/convertshaders/main.go index 250137e5..4092b572 100644 --- a/internal/cmd/convertshaders/main.go +++ b/internal/cmd/convertshaders/main.go @@ -70,7 +70,7 @@ func generate() error { if ext := filepath.Ext(shader); ext != ".vert" && ext != ".frag" { continue } - const nvariants = 2 + const nvariants = 3 var variants [nvariants]struct { backend.ShaderSources hlslSrc string @@ -80,6 +80,10 @@ func generate() error { FetchColorExpr: `_color`, Header: `layout(binding=0) uniform Color { vec4 _color; };`, }, + { + FetchColorExpr: `mix(_color1, _color2, clamp(vUV.x, 0.0, 1.0))`, + Header: `layout(binding=0) uniform Gradient { vec4 _color1; vec4 _color2; };`, + }, { FetchColorExpr: `texture(tex, vUV)`, Header: `layout(binding=0) uniform sampler2D tex;`, diff --git a/internal/opconst/ops.go b/internal/opconst/ops.go index 62365b8f..fcdb7d4b 100644 --- a/internal/opconst/ops.go +++ b/internal/opconst/ops.go @@ -16,6 +16,7 @@ const ( TypeImage TypePaint TypeColor + TypeLinearGradient TypeArea TypePointerInput TypePass @@ -29,24 +30,25 @@ const ( ) const ( - TypeMacroLen = 1 + 4 + 4 - TypeCallLen = 1 + 4 + 4 - TypeTransformLen = 1 + 4*6 - TypeLayerLen = 1 - TypeRedrawLen = 1 + 8 - TypeImageLen = 1 + 4*4 - TypePaintLen = 1 + 4*4 - TypeColorLen = 1 + 4 - TypeAreaLen = 1 + 1 + 4*4 - TypePointerInputLen = 1 + 1 + 1 - TypePassLen = 1 + 1 - TypeKeyInputLen = 1 + 1 - TypeHideInputLen = 1 - TypePushLen = 1 - TypePopLen = 1 - TypeAuxLen = 1 - TypeClipLen = 1 + 4*4 - TypeProfileLen = 1 + TypeMacroLen = 1 + 4 + 4 + TypeCallLen = 1 + 4 + 4 + TypeTransformLen = 1 + 4*6 + TypeLayerLen = 1 + TypeRedrawLen = 1 + 8 + TypeImageLen = 1 + 4*4 + TypePaintLen = 1 + 4*4 + TypeColorLen = 1 + 4 + TypeLinearGradientLen = 1 + 8*2 + 4*2 + TypeAreaLen = 1 + 1 + 4*4 + TypePointerInputLen = 1 + 1 + 1 + TypePassLen = 1 + 1 + TypeKeyInputLen = 1 + 1 + TypeHideInputLen = 1 + TypePushLen = 1 + TypePopLen = 1 + TypeAuxLen = 1 + TypeClipLen = 1 + 4*4 + TypeProfileLen = 1 ) func (t OpType) Size() int { @@ -59,6 +61,7 @@ func (t OpType) Size() int { TypeImageLen, TypePaintLen, TypeColorLen, + TypeLinearGradientLen, TypeAreaLen, TypePointerInputLen, TypePassLen, diff --git a/internal/rendertest/refs/TestLinearGradient.png b/internal/rendertest/refs/TestLinearGradient.png new file mode 100644 index 0000000000000000000000000000000000000000..e6cb0946c254915c8343b655aefe7706ce404165 GIT binary patch literal 716 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1SEZ8zRh7^V4Cdd;uumf=gqD6S&tk<96nlm zW^unxKUn)e{k8OzvfZ;Hd;I38{7X)>JTXtc`OFcnLyjj@-zp_-zPaZ5>+J`#wpMBG z@`^5ry>4>0!sgxVgF9Ak&7B=ID|XHLp5Kq3y?b3`ESLXg`f+J-`9GUGDxPfKZhxsI zfUQB2A&p@MV*-eAE%);`_rC3ae$KKF7u5f`W!I)#iM_MU7HR%ow&&XHn_gcx+RFrg z4O?Z_es#WmQPtbk<>|*a_22#J6_S5+Y4Vq+&5w^3)!tcNw=Zeux2Jb&D`m|#>Su@N z_Ps7&l6bWI$oh`;9sKo-Cd>zT7>pUtFc^Rs-j%!08u~DOl-hXeyIP|KKLfuX(^m-t zX`V|Z#WKullO615im4s{_vzW6bn*ULNwZbStMdQ$$0r+dp1D5NP=R;*zxKcDV(v^0 zJ=S2-!}wDBlKT&v2Dp#FjFnQ%MSr^4na)0HJaE-8!Ak4Q`%mJ>KfZL_JF|yndf)Qh ze`ZfU@YnFcFO>o*<~%>9kFqaKIDc>>hfEqng!udO_H1wFm-BoOcYwPd#Mto8w$ASN zf7ZAB_s{<4z7%f=^BP!kO7XJ&hwIPABMX8(j$+0j6#2)(!0`XS^4_Zj)#;eB<+vqXUeIJO4ci0R2szNVui&i1xFRKSIc%~ME`UH;eN zq7#?;_PTdgEN62S9_~*|7cUH4IVErKluKlli}OnExMytZ=U>QtnA>)4v?5GhZGO~?3M zoie3%R%F#ppX+$}p%XE&^{HTm%hM|wjr+PHd-ZoOBFgpGch5C>g%$@4y$u*C6;hf6 z$w&h~%6n;OaT>91Z;O%ula_|NICHO7c@oT7g8WSt%S_k@Kxka;aD_GD5NOHegK5kU zh>SWppoD>Vw2{FFCIe}HIEmdVkPcdc_=X)i<>4Kw4b~1HygQ9S1iGMj3A2p-f4%qLbMZv1buksjr+NwzItG zfsMZ6jisy{hN&@^>clFPE0G-YGnvp4%|zTGn2Bfkau#06e6vUH&uWgx}aRbYx-u4Bjbe?-wuS$;$-ebKHr+z<9f85e% zaIDy*o>gf7S;wuGlz?=V@^W(7TI+Zy$3&)cPOEG`HXI(}4p;f*4;@X~n9OR9amz6W zG@a(6lgVXS)|6|ggv*I>>oe!xMZ(dm$z>(hUwlZTa6hM%6l}GCN!G+!N9VadAM!V0 z1_wElW~2>A_RbI%O7l?>E=KR{ViP5wxk^l!o_S_a^UmlygS9gq?g_H-169-5BgXfp zv;_A2N&2R~LZ`?#1M zMXmeIg2Ag{VaEL3T{TaJd6&X6j)y*?UUf&89C^oiJ3jI{vo5pvW8L)qR$~2<&r@p) zJ?VARYfY6q700{m$MxK%vFcmPLXHmD|7-3-6Vn>k)P8~-1ln%L^MC3nq)zYAW-ajA zgl1UvXiEZn2vL``&|h$Ib3i=%S43^g@+ixP)sZOfjhl_x;6BVXzZbVd@Mj=VLD5t! zgN5>p+7GlE6S4|AopXr_$Eem`fYXBKuDJ|82Z;iB&B6hd7Ox_qPis7T6#5h|(nbQx zSc5gfy6sLA5r9gn!PHRXJNZG8<^*_v>Yhcmpi=7zAABC<8$bFCw7W->!mhIn33SV) zV=&&P|2WlEq+w~qd)3}}ttB1O<3 zEDPTZ`^A&M-{FFXhOS zHT3I)NS*Cv$m2t-UW=w42|55_mAD5S+8ArN0h3*LI*P