mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
gpu/internal/shaders: generate shader variants
We're about to add Direct3D support, where shaders are written in HLSL. Rather than write shaders twice (or more), convert them to a GLSL variant understood by the glslcc cross-compiler and generate the OpenGL ES 2.0 and HLSL variants. The HLSL is used by a future change. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+27
-1
@@ -23,7 +23,7 @@ type Backend interface {
|
||||
NilTexture() Texture
|
||||
NewFramebuffer() Framebuffer
|
||||
NewBuffer(typ BufferType, data []byte) Buffer
|
||||
NewProgram(vertexShader, fragmentShader string, attribMap []string) (Program, error)
|
||||
NewProgram(vertexShader, fragmentShader ShaderSources, attribMap []string) (Program, error)
|
||||
SetupVertexArray(slot int, size int, dataType DataType, stride, offset int)
|
||||
|
||||
DepthFunc(f DepthFunc)
|
||||
@@ -39,6 +39,32 @@ type Backend interface {
|
||||
BlendFunc(sfactor, dfactor BlendFactor)
|
||||
}
|
||||
|
||||
type ShaderSources struct {
|
||||
GLES2 string
|
||||
HLSL []byte
|
||||
Uniforms []UniformLocation
|
||||
Inputs []InputLocation
|
||||
}
|
||||
|
||||
type UniformLocation struct {
|
||||
Name string
|
||||
Type DataType
|
||||
Size int
|
||||
Offset int
|
||||
}
|
||||
|
||||
type InputLocation struct {
|
||||
// For GLSL.
|
||||
Name string
|
||||
Location int
|
||||
// For HLSL.
|
||||
Semantic string
|
||||
SemanticIndex int
|
||||
|
||||
Type DataType
|
||||
Size int
|
||||
}
|
||||
|
||||
type BlendFactor uint8
|
||||
|
||||
type DrawMode uint8
|
||||
|
||||
+361
@@ -0,0 +1,361 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// This program generates shader variants for
|
||||
// multiple GPU backends (OpenGL ES, Direct3D 11...)
|
||||
// from a single source.
|
||||
|
||||
type shaderArgs struct {
|
||||
FetchColorExpr string
|
||||
Header string
|
||||
}
|
||||
|
||||
// InputLocation matches gpu.InputLocation.
|
||||
type InputLocation struct {
|
||||
Name string
|
||||
Location int
|
||||
Semantic string
|
||||
SemanticIndex int
|
||||
|
||||
Type DataType
|
||||
Size int
|
||||
}
|
||||
|
||||
type DataType uint8
|
||||
|
||||
// UniformLocation matches gpu.UniformLocation.
|
||||
type UniformLocation struct {
|
||||
Name string
|
||||
Type DataType
|
||||
Size int
|
||||
Offset int
|
||||
}
|
||||
|
||||
const (
|
||||
DataTypeFloat DataType = iota
|
||||
DataTypeShort
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := generate(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "gpu generate: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func generate() error {
|
||||
tmp, err := ioutil.TempDir("", "gpu-generate")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
glslcc, err := exec.LookPath("glslcc")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fxc, err := exec.LookPath("fxc")
|
||||
fxcFound := err == nil
|
||||
shaders, err := filepath.Glob("shaders/*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var out bytes.Buffer
|
||||
out.WriteString("// Code generated by build.go. DO NOT EDIT.\n\n")
|
||||
out.WriteString("package gpu\n\n")
|
||||
|
||||
out.WriteString("var (\n")
|
||||
|
||||
for _, shader := range shaders {
|
||||
const nvariants = 2
|
||||
var variants [nvariants]struct {
|
||||
gles2 string
|
||||
hlslSrc string
|
||||
hlsl []byte
|
||||
inputs []InputLocation
|
||||
uniforms []UniformLocation
|
||||
}
|
||||
args := [nvariants]shaderArgs{
|
||||
{
|
||||
FetchColorExpr: `color.color`,
|
||||
Header: `layout(binding=0) uniform Color { vec4 color; } color;`,
|
||||
},
|
||||
{
|
||||
FetchColorExpr: `texture(tex, vUV)`,
|
||||
Header: `layout(binding=0) uniform sampler2D tex;`,
|
||||
},
|
||||
}
|
||||
for i := range args {
|
||||
gles2, reflect, err := convertShader(tmp, glslcc, shader, "gles", "100", &args[i], false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Make the GL ES 2 source compatible with desktop GL 3.
|
||||
gles2 = "#version 100\n" + gles2
|
||||
inputs, uniforms, err := parseReflection(reflect)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hlsl, _, err := convertShader(tmp, glslcc, shader, "hlsl", "40", &args[i], false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var hlslProf string
|
||||
switch filepath.Ext(shader) {
|
||||
case ".frag":
|
||||
hlslProf = "ps"
|
||||
case ".vert":
|
||||
hlslProf = "vs"
|
||||
default:
|
||||
return fmt.Errorf("unrecognized shader type %s", shader)
|
||||
}
|
||||
var hlslc []byte
|
||||
if fxcFound {
|
||||
hlslc, err = compileHLSL(tmp, fxc, hlsl, "main", hlslProf+"_4_0")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
variants[i].gles2 = gles2
|
||||
variants[i].hlslSrc = hlsl
|
||||
variants[i].hlsl = hlslc
|
||||
variants[i].inputs = inputs
|
||||
variants[i].uniforms = uniforms
|
||||
}
|
||||
name := filepath.Base(shader)
|
||||
name = strings.ReplaceAll(name, ".", "_")
|
||||
fmt.Fprintf(&out, "\tshader_%s = ", name)
|
||||
// If the shader don't use the variant arguments, output
|
||||
// only a single version.
|
||||
multiVariant := variants[0].gles2 != variants[1].gles2
|
||||
if multiVariant {
|
||||
fmt.Fprintf(&out, "[...]ShaderSources{\n")
|
||||
}
|
||||
for _, src := range variants {
|
||||
fmt.Fprintf(&out, "ShaderSources{\n")
|
||||
if len(src.inputs) > 0 {
|
||||
fmt.Fprintf(&out, "Inputs: []InputLocation{\n")
|
||||
for _, inp := range src.inputs {
|
||||
fmt.Fprintf(&out, "{Name: %q, Location: %d, Semantic: %q, ", inp.Name, inp.Location, inp.Semantic)
|
||||
fmt.Fprintf(&out, "SemanticIndex: %d, Type: %d, Size: %d},\n", inp.SemanticIndex, inp.Type, inp.Size)
|
||||
}
|
||||
fmt.Fprintf(&out, "},\n")
|
||||
}
|
||||
if len(src.uniforms) > 0 {
|
||||
fmt.Fprintf(&out, "Uniforms: []UniformLocation{\n")
|
||||
for _, u := range src.uniforms {
|
||||
fmt.Fprintf(&out, "{Name: %q, Type: %d, Size: %d, Offset: %d},\n", u.Name, u.Type, u.Size, u.Offset)
|
||||
}
|
||||
fmt.Fprintf(&out, "},\n")
|
||||
}
|
||||
fmt.Fprintf(&out, "GLES2: %#v,\n", src.gles2)
|
||||
fmt.Fprintf(&out, "/*\n%s\n*/\n", src.hlslSrc)
|
||||
fmt.Fprintf(&out, "HLSL: %#v,\n", src.hlsl)
|
||||
fmt.Fprintf(&out, "}")
|
||||
if multiVariant {
|
||||
fmt.Fprintf(&out, ",")
|
||||
}
|
||||
fmt.Fprintf(&out, "\n")
|
||||
if !multiVariant {
|
||||
break
|
||||
}
|
||||
}
|
||||
if multiVariant {
|
||||
fmt.Fprintf(&out, "}\n")
|
||||
}
|
||||
}
|
||||
out.WriteString(")")
|
||||
gosrc, err := format.Source(out.Bytes())
|
||||
if err != nil {
|
||||
return fmt.Errorf("shader.go: %v", err)
|
||||
}
|
||||
return ioutil.WriteFile("shaders.go", gosrc, 0644)
|
||||
}
|
||||
|
||||
func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, error) {
|
||||
type InputReflection struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Location int `json:"location"`
|
||||
Semantic string `json:"semantic"`
|
||||
SemanticIndex int `json:"semantic_index"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
type UniformMemberReflection struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Offset int `json:"offset"`
|
||||
Size int `json:"size"`
|
||||
}
|
||||
type UniformBufferReflection struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Set int `json:"set"`
|
||||
Binding int `json:"binding"`
|
||||
Size int `json:"block_size"`
|
||||
Members []UniformMemberReflection `json:"members"`
|
||||
}
|
||||
type shaderReflection struct {
|
||||
Inputs []InputReflection `json:"inputs"`
|
||||
UniformBuffers []UniformBufferReflection `json:"uniform_buffers"`
|
||||
}
|
||||
type shaderMetadata struct {
|
||||
VS shaderReflection `json:"vs"`
|
||||
FS shaderReflection `json:"fs"`
|
||||
}
|
||||
var reflect shaderMetadata
|
||||
if err := json.Unmarshal(jsonData, &reflect); err != nil {
|
||||
return nil, nil, fmt.Errorf("parseReflection: %v", err)
|
||||
}
|
||||
var inputs []InputLocation
|
||||
inputRef := reflect.VS.Inputs
|
||||
for _, input := range inputRef {
|
||||
dataType, dataSize, err := parseDataType(input.Type)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
inputs = append(inputs, InputLocation{
|
||||
Name: input.Name,
|
||||
Location: input.Location,
|
||||
Semantic: input.Semantic,
|
||||
SemanticIndex: input.SemanticIndex,
|
||||
Type: dataType,
|
||||
Size: dataSize,
|
||||
})
|
||||
}
|
||||
sort.Slice(inputs, func(i, j int) bool {
|
||||
return inputs[i].Location < inputs[j].Location
|
||||
})
|
||||
var ublocks []UniformLocation
|
||||
shaderBlocks := reflect.VS.UniformBuffers
|
||||
if len(shaderBlocks) == 0 {
|
||||
shaderBlocks = reflect.FS.UniformBuffers
|
||||
}
|
||||
for _, block := range shaderBlocks {
|
||||
for _, member := range block.Members {
|
||||
dataType, size, err := parseDataType(member.Type)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ublocks = append(ublocks, UniformLocation{
|
||||
// Synthetic name generated by glslcc.
|
||||
Name: fmt.Sprintf("_%d.%s", block.ID, member.Name),
|
||||
Type: dataType,
|
||||
Size: size,
|
||||
Offset: member.Offset,
|
||||
})
|
||||
}
|
||||
}
|
||||
return inputs, ublocks, nil
|
||||
}
|
||||
|
||||
func parseDataType(t string) (DataType, int, error) {
|
||||
switch t {
|
||||
case "float":
|
||||
return DataTypeFloat, 1, nil
|
||||
case "float2":
|
||||
return DataTypeFloat, 2, nil
|
||||
case "float3":
|
||||
return DataTypeFloat, 3, nil
|
||||
case "float4":
|
||||
return DataTypeFloat, 4, nil
|
||||
default:
|
||||
return 0, 0, fmt.Errorf("unsupported input data type: %s", t)
|
||||
}
|
||||
}
|
||||
|
||||
func compileHLSL(tmp, fxc, src, entry, profile string) ([]byte, error) {
|
||||
tmpfile := filepath.Join(tmp, "shader.hlsl")
|
||||
if err := ioutil.WriteFile(tmpfile, []byte(src), 0644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outFile := filepath.Join(tmp, "shader.bin")
|
||||
cmd := exec.Command(fxc,
|
||||
"/T", profile,
|
||||
"/E", entry,
|
||||
"/nologo",
|
||||
"/Fo", outFile,
|
||||
tmpfile,
|
||||
)
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ioutil.ReadFile(outFile)
|
||||
}
|
||||
|
||||
func convertShader(tmp, glslcc, path, lang, profile string, args *shaderArgs, flattenUBOs bool) (string, []byte, error) {
|
||||
shaderTmpl, err := template.ParseFiles(path)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := shaderTmpl.Execute(&buf, args); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
tmppath := filepath.Join(tmp, filepath.Base(path))
|
||||
if err := ioutil.WriteFile(tmppath, buf.Bytes(), 0644); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer os.Remove(tmppath)
|
||||
var progFlag string
|
||||
var progSuffix string
|
||||
switch filepath.Ext(path) {
|
||||
case ".vert":
|
||||
progFlag = "--vert"
|
||||
progSuffix = "vs"
|
||||
case ".frag":
|
||||
progFlag = "--frag"
|
||||
progSuffix = "fs"
|
||||
default:
|
||||
return "", nil, fmt.Errorf("unrecognized shader type: %s", path)
|
||||
}
|
||||
cmd := exec.Command(glslcc,
|
||||
"--silent",
|
||||
"--optimize",
|
||||
"--reflect",
|
||||
"--output", filepath.Join(tmp, "shader"),
|
||||
"--lang", lang,
|
||||
"--profile", profile,
|
||||
progFlag, tmppath,
|
||||
)
|
||||
if flattenUBOs {
|
||||
cmd.Args = append(cmd.Args, "--flatten-ubos")
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return "", nil, fmt.Errorf("%s: %v", path, err)
|
||||
}
|
||||
f, err := os.Open(filepath.Join(tmp, "shader_"+progSuffix))
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
defer os.Remove(f.Name())
|
||||
src, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
reflect, err := ioutil.ReadFile(filepath.Join(tmp, "shader_"+progSuffix+".json"))
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return string(src), reflect, nil
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
package gpu
|
||||
|
||||
//go:generate go run build.go
|
||||
+2
-2
@@ -284,8 +284,8 @@ func (b *Backend) DepthFunc(f gpu.DepthFunc) {
|
||||
b.funcs.DepthFunc(glfunc)
|
||||
}
|
||||
|
||||
func (b *Backend) NewProgram(vssrc, fssrc string, attr []string) (gpu.Program, error) {
|
||||
p, err := CreateProgram(b.funcs, vssrc, fssrc, attr)
|
||||
func (b *Backend) NewProgram(vssrc, fssrc gpu.ShaderSources, attr []string) (gpu.Program, error) {
|
||||
p, err := CreateProgram(b.funcs, vssrc.GLES2, fssrc.GLES2, attr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+10
-65
@@ -13,7 +13,6 @@ import (
|
||||
"image"
|
||||
"image/color"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
@@ -376,7 +375,7 @@ func (r *renderer) release() {
|
||||
}
|
||||
|
||||
func newBlitter(ctx Backend) *blitter {
|
||||
prog, err := createColorPrograms(ctx, blitVSrc, blitFSrc)
|
||||
prog, err := createColorPrograms(ctx, shader_blit_vert, shader_blit_frag)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -398,14 +397,14 @@ func newBlitter(ctx Backend) *blitter {
|
||||
case materialTexture:
|
||||
uTex := prog.UniformFor("tex")
|
||||
prog.Uniform1i(uTex, 0)
|
||||
b.vars[i].uUVScale = prog.UniformFor("uvScale")
|
||||
b.vars[i].uUVOffset = prog.UniformFor("uvOffset")
|
||||
b.vars[i].uUVScale = prog.UniformFor("uniforms.uvScale")
|
||||
b.vars[i].uUVOffset = prog.UniformFor("uniforms.uvOffset")
|
||||
case materialColor:
|
||||
b.vars[i].uColor = prog.UniformFor("color")
|
||||
b.vars[i].uColor = prog.UniformFor("color.color")
|
||||
}
|
||||
b.vars[i].z = prog.UniformFor("z")
|
||||
b.vars[i].uScale = prog.UniformFor("scale")
|
||||
b.vars[i].uOffset = prog.UniformFor("offset")
|
||||
b.vars[i].z = prog.UniformFor("uniforms.z")
|
||||
b.vars[i].uScale = prog.UniformFor("uniforms.scale")
|
||||
b.vars[i].uOffset = prog.UniformFor("uniforms.offset")
|
||||
}
|
||||
return b
|
||||
}
|
||||
@@ -417,28 +416,14 @@ func (b *blitter) release() {
|
||||
}
|
||||
}
|
||||
|
||||
func createColorPrograms(ctx Backend, vsSrc, fsSrc string) ([2]Program, error) {
|
||||
func createColorPrograms(ctx Backend, vsSrc ShaderSources, fsSrc [2]ShaderSources) ([2]Program, error) {
|
||||
var prog [2]Program
|
||||
frep := strings.NewReplacer(
|
||||
"HEADER", `
|
||||
uniform sampler2D tex;
|
||||
`,
|
||||
"GET_COLOR", `texture2D(tex, vUV)`,
|
||||
)
|
||||
fsSrcTex := frep.Replace(fsSrc)
|
||||
var err error
|
||||
prog[materialTexture], err = ctx.NewProgram(vsSrc, fsSrcTex, blitAttribs)
|
||||
prog[materialTexture], err = ctx.NewProgram(vsSrc, fsSrc[materialTexture], blitAttribs)
|
||||
if err != nil {
|
||||
return prog, err
|
||||
}
|
||||
frep = strings.NewReplacer(
|
||||
"HEADER", `
|
||||
uniform vec4 color;
|
||||
`,
|
||||
"GET_COLOR", `color`,
|
||||
)
|
||||
fsSrcCol := frep.Replace(fsSrc)
|
||||
prog[materialColor], err = ctx.NewProgram(vsSrc, fsSrcCol, blitAttribs)
|
||||
prog[materialColor], err = ctx.NewProgram(vsSrc, fsSrc[materialColor], blitAttribs)
|
||||
if err != nil {
|
||||
prog[materialTexture].Release()
|
||||
return prog, err
|
||||
@@ -949,43 +934,3 @@ func fillContourMaxY(maxy float32, verts []byte) {
|
||||
bo.PutUint32(verts[i+off:], math.Float32bits(maxy))
|
||||
}
|
||||
}
|
||||
|
||||
const blitVSrc = `
|
||||
#version 100
|
||||
|
||||
precision highp float;
|
||||
|
||||
uniform float z;
|
||||
uniform vec2 scale;
|
||||
uniform vec2 offset;
|
||||
|
||||
attribute vec2 pos;
|
||||
|
||||
attribute vec2 uv;
|
||||
uniform vec2 uvScale;
|
||||
uniform vec2 uvOffset;
|
||||
|
||||
varying vec2 vUV;
|
||||
|
||||
void main() {
|
||||
vec2 p = pos;
|
||||
p *= scale;
|
||||
p += offset;
|
||||
gl_Position = vec4(p, z, 1);
|
||||
vUV = uv*uvScale + uvOffset;
|
||||
}
|
||||
`
|
||||
|
||||
const blitFSrc = `
|
||||
#version 100
|
||||
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 vUV;
|
||||
|
||||
HEADER
|
||||
|
||||
void main() {
|
||||
gl_FragColor = GET_COLOR;
|
||||
}
|
||||
`
|
||||
|
||||
+16
-233
@@ -91,7 +91,7 @@ func newPather(ctx Backend) *pather {
|
||||
}
|
||||
|
||||
func newCoverer(ctx Backend) *coverer {
|
||||
prog, err := createColorPrograms(ctx, coverVSrc, coverFSrc)
|
||||
prog, err := createColorPrograms(ctx, shader_cover_vert, shader_cover_frag)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -104,29 +104,29 @@ func newCoverer(ctx Backend) *coverer {
|
||||
case materialTexture:
|
||||
uTex := prog.UniformFor("tex")
|
||||
prog.Uniform1i(uTex, 0)
|
||||
c.vars[i].uUVScale = prog.UniformFor("uvScale")
|
||||
c.vars[i].uUVOffset = prog.UniformFor("uvOffset")
|
||||
c.vars[i].uUVScale = prog.UniformFor("uniforms.uvScale")
|
||||
c.vars[i].uUVOffset = prog.UniformFor("uniforms.uvOffset")
|
||||
case materialColor:
|
||||
c.vars[i].uColor = prog.UniformFor("color")
|
||||
c.vars[i].uColor = prog.UniformFor("color.color")
|
||||
}
|
||||
uCover := prog.UniformFor("cover")
|
||||
prog.Uniform1i(uCover, 1)
|
||||
c.vars[i].z = prog.UniformFor("z")
|
||||
c.vars[i].uScale = prog.UniformFor("scale")
|
||||
c.vars[i].uOffset = prog.UniformFor("offset")
|
||||
c.vars[i].uCoverUVScale = prog.UniformFor("uvCoverScale")
|
||||
c.vars[i].uCoverUVOffset = prog.UniformFor("uvCoverOffset")
|
||||
c.vars[i].z = prog.UniformFor("uniforms.z")
|
||||
c.vars[i].uScale = prog.UniformFor("uniforms.scale")
|
||||
c.vars[i].uOffset = prog.UniformFor("uniforms.offset")
|
||||
c.vars[i].uCoverUVScale = prog.UniformFor("uniforms.uvCoverScale")
|
||||
c.vars[i].uCoverUVOffset = prog.UniformFor("uniforms.uvCoverOffset")
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func newStenciler(ctx Backend) *stenciler {
|
||||
defFBO := ctx.DefaultFramebuffer()
|
||||
prog, err := ctx.NewProgram(stencilVSrc, stencilFSrc, pathAttribs)
|
||||
prog, err := ctx.NewProgram(shader_stencil_vert, shader_stencil_frag, pathAttribs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
iprog, err := ctx.NewProgram(intersectVSrc, intersectFSrc, intersectAttribs)
|
||||
iprog, err := ctx.NewProgram(shader_intersect_vert, shader_intersect_frag, intersectAttribs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -149,11 +149,11 @@ func newStenciler(ctx Backend) *stenciler {
|
||||
defFBO: defFBO,
|
||||
prog: prog,
|
||||
iprog: iprog,
|
||||
uScale: prog.UniformFor("scale"),
|
||||
uOffset: prog.UniformFor("offset"),
|
||||
uPathOffset: prog.UniformFor("pathOffset"),
|
||||
uIntersectUVScale: iprog.UniformFor("uvScale"),
|
||||
uIntersectUVOffset: iprog.UniformFor("uvOffset"),
|
||||
uScale: prog.UniformFor("uniforms.scale"),
|
||||
uOffset: prog.UniformFor("uniforms.offset"),
|
||||
uPathOffset: prog.UniformFor("uniforms.pathOffset"),
|
||||
uIntersectUVScale: iprog.UniformFor("uvparams.scale"),
|
||||
uIntersectUVOffset: iprog.UniformFor("uvparams.offset"),
|
||||
indexBuf: indexBuf,
|
||||
}
|
||||
}
|
||||
@@ -328,220 +328,3 @@ func (c *coverer) cover(z float32, mat materialType, col [4]float32, scale, off,
|
||||
p.Uniform2f(c.vars[mat].uCoverUVOffset, coverOff.X, coverOff.Y)
|
||||
c.ctx.DrawArrays(DrawModeTriangleStrip, 0, 4)
|
||||
}
|
||||
|
||||
const stencilVSrc = `
|
||||
#version 100
|
||||
|
||||
precision highp float;
|
||||
|
||||
uniform vec2 scale;
|
||||
uniform vec2 offset;
|
||||
uniform vec2 pathOffset;
|
||||
|
||||
attribute vec2 corner;
|
||||
attribute float maxy;
|
||||
attribute vec2 from;
|
||||
attribute vec2 ctrl;
|
||||
attribute vec2 to;
|
||||
|
||||
varying vec2 vFrom;
|
||||
varying vec2 vCtrl;
|
||||
varying vec2 vTo;
|
||||
|
||||
void main() {
|
||||
// Add a one pixel overlap so curve quads cover their
|
||||
// entire curves. Could use conservative rasterization
|
||||
// if available.
|
||||
vec2 from = from + pathOffset;
|
||||
vec2 ctrl = ctrl + pathOffset;
|
||||
vec2 to = to + pathOffset;
|
||||
float maxy = maxy + pathOffset.y;
|
||||
vec2 pos;
|
||||
if (corner.x > 0.0) {
|
||||
// East.
|
||||
pos.x = max(max(from.x, ctrl.x), to.x)+1.0;
|
||||
} else {
|
||||
// West.
|
||||
pos.x = min(min(from.x, ctrl.x), to.x)-1.0;
|
||||
}
|
||||
if (corner.y > 0.0) {
|
||||
// North.
|
||||
pos.y = maxy + 1.0;
|
||||
} else {
|
||||
// South.
|
||||
pos.y = min(min(from.y, ctrl.y), to.y) - 1.0;
|
||||
}
|
||||
vFrom = from-pos;
|
||||
vCtrl = ctrl-pos;
|
||||
vTo = to-pos;
|
||||
pos *= scale;
|
||||
pos += offset;
|
||||
gl_Position = vec4(pos, 1, 1);
|
||||
}
|
||||
`
|
||||
|
||||
const stencilFSrc = `
|
||||
#version 100
|
||||
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 vFrom;
|
||||
varying vec2 vCtrl;
|
||||
varying vec2 vTo;
|
||||
|
||||
uniform sampler2D areaLUT;
|
||||
|
||||
void main() {
|
||||
float dx = vTo.x - vFrom.x;
|
||||
// Sort from and to in increasing order so the root below
|
||||
// is always the positive square root, if any.
|
||||
// We need the direction of the curve below, so this can't be
|
||||
// done from the vertex shader.
|
||||
bool increasing = vTo.x >= vFrom.x;
|
||||
vec2 left = increasing ? vFrom : vTo;
|
||||
vec2 right = increasing ? vTo : vFrom;
|
||||
|
||||
// The signed horizontal extent of the fragment.
|
||||
vec2 extent = clamp(vec2(vFrom.x, vTo.x), -0.5, 0.5);
|
||||
// Find the t where the curve crosses the middle of the
|
||||
// extent, x₀.
|
||||
// Given the Bézier curve with x coordinates P₀, P₁, P₂
|
||||
// where P₀ is at the origin, its x coordinate in t
|
||||
// is given by:
|
||||
//
|
||||
// x(t) = 2(1-t)tP₁ + t²P₂
|
||||
//
|
||||
// Rearranging:
|
||||
//
|
||||
// x(t) = (P₂ - 2P₁)t² + 2P₁t
|
||||
//
|
||||
// Setting x(t) = x₀ and using Muller's quadratic formula ("Citardauq")
|
||||
// for robustnesss,
|
||||
//
|
||||
// t = 2x₀/(2P₁±√(4P₁²+4(P₂-2P₁)x₀))
|
||||
//
|
||||
// which simplifies to
|
||||
//
|
||||
// t = x₀/(P₁±√(P₁²+(P₂-2P₁)x₀))
|
||||
//
|
||||
// Setting v = P₂-P₁,
|
||||
//
|
||||
// t = x₀/(P₁±√(P₁²+(v-P₁)x₀))
|
||||
//
|
||||
// t lie in [0; 1]; P₂ ≥ P₁ and P₁ ≥ 0 since we split curves where
|
||||
// the control point lies before the start point or after the end point.
|
||||
// It can then be shown that only the positive square root is valid.
|
||||
float midx = mix(extent.x, extent.y, 0.5);
|
||||
float x0 = midx - left.x;
|
||||
vec2 p1 = vCtrl - left;
|
||||
vec2 v = right - vCtrl;
|
||||
float t = x0/(p1.x+sqrt(p1.x*p1.x+(v.x-p1.x)*x0));
|
||||
// Find y(t) on the curve.
|
||||
float y = mix(mix(left.y, vCtrl.y, t), mix(vCtrl.y, right.y, t), t);
|
||||
// And the slope.
|
||||
vec2 d_half = mix(p1, v, t);
|
||||
float dy = d_half.y/d_half.x;
|
||||
// Together, y and dy form a line approximation.
|
||||
|
||||
// Compute the fragment area above the line.
|
||||
// The area is symmetric around dy = 0. Scale slope with extent width.
|
||||
float width = extent.y - extent.x;
|
||||
dy = abs(dy*width);
|
||||
|
||||
vec4 sides = vec4(dy*+0.5 + y, dy*-0.5 + y, (+0.5-y)/dy, (-0.5-y)/dy);
|
||||
sides = clamp(sides+0.5, 0.0, 1.0);
|
||||
|
||||
float area = 0.5*(sides.z - sides.z*sides.y + 1.0 - sides.x+sides.x*sides.w);
|
||||
area *= width;
|
||||
|
||||
// Work around issue #13.
|
||||
if (width == 0.0)
|
||||
area = 0.0;
|
||||
|
||||
gl_FragColor.r = area;
|
||||
}
|
||||
`
|
||||
|
||||
const coverVSrc = `
|
||||
#version 100
|
||||
|
||||
precision highp float;
|
||||
|
||||
uniform float z;
|
||||
uniform vec2 scale;
|
||||
uniform vec2 offset;
|
||||
uniform vec2 uvScale;
|
||||
uniform vec2 uvOffset;
|
||||
uniform vec2 uvCoverScale;
|
||||
uniform vec2 uvCoverOffset;
|
||||
|
||||
attribute vec2 pos;
|
||||
|
||||
varying vec2 vCoverUV;
|
||||
|
||||
attribute vec2 uv;
|
||||
varying vec2 vUV;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(pos*scale + offset, z, 1);
|
||||
vUV = uv*uvScale + uvOffset;
|
||||
vCoverUV = uv*uvCoverScale+uvCoverOffset;
|
||||
}
|
||||
`
|
||||
|
||||
const coverFSrc = `
|
||||
#version 100
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Use high precision to be pixel accurate for
|
||||
// large cover atlases.
|
||||
varying highp vec2 vCoverUV;
|
||||
uniform sampler2D cover;
|
||||
varying vec2 vUV;
|
||||
|
||||
HEADER
|
||||
|
||||
void main() {
|
||||
gl_FragColor = GET_COLOR;
|
||||
float cover = abs(texture2D(cover, vCoverUV).r);
|
||||
gl_FragColor *= cover;
|
||||
}
|
||||
`
|
||||
|
||||
const intersectVSrc = `
|
||||
#version 100
|
||||
|
||||
precision highp float;
|
||||
|
||||
attribute vec2 pos;
|
||||
attribute vec2 uv;
|
||||
|
||||
uniform vec2 uvScale;
|
||||
uniform vec2 uvOffset;
|
||||
|
||||
varying vec2 vUV;
|
||||
|
||||
void main() {
|
||||
vec2 p = pos;
|
||||
p.y = -p.y;
|
||||
gl_Position = vec4(p, 0, 1);
|
||||
vUV = uv*uvScale + uvOffset;
|
||||
}
|
||||
`
|
||||
|
||||
const intersectFSrc = `
|
||||
#version 100
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Use high precision to be pixel accurate for
|
||||
// large cover atlases.
|
||||
varying highp vec2 vUV;
|
||||
uniform sampler2D cover;
|
||||
|
||||
void main() {
|
||||
float cover = abs(texture2D(cover, vUV).r);
|
||||
gl_FragColor.r = cover;
|
||||
}
|
||||
`
|
||||
|
||||
+574
@@ -0,0 +1,574 @@
|
||||
// Code generated by build.go. DO NOT EDIT.
|
||||
|
||||
package gpu
|
||||
|
||||
var (
|
||||
shader_blit_frag = [...]ShaderSources{
|
||||
ShaderSources{
|
||||
Uniforms: []UniformLocation{
|
||||
{Name: "_12.color", Type: 0, Size: 4, Offset: 0},
|
||||
},
|
||||
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nstruct Color\n{\n vec4 color;\n};\n\nuniform Color color;\n\nvarying vec2 vUV;\n\nvoid main()\n{\n gl_FragData[0] = color.color;\n}\n\n",
|
||||
/*
|
||||
cbuffer Color : register(b0)
|
||||
{
|
||||
float4 color_color : packoffset(c0);
|
||||
};
|
||||
|
||||
|
||||
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 = color_color;
|
||||
}
|
||||
|
||||
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(nil),
|
||||
},
|
||||
ShaderSources{
|
||||
GLES2: "#version 100\nprecision 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",
|
||||
/*
|
||||
Texture2D<float4> tex : register(t0);
|
||||
SamplerState _tex_sampler : register(s0);
|
||||
|
||||
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 = tex.Sample(_tex_sampler, vUV);
|
||||
}
|
||||
|
||||
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(nil),
|
||||
},
|
||||
}
|
||||
shader_blit_vert = ShaderSources{
|
||||
Inputs: []InputLocation{
|
||||
{Name: "pos", Location: 0, Semantic: "POSITION", SemanticIndex: 0, Type: 0, Size: 2},
|
||||
{Name: "uv", Location: 1, Semantic: "NORMAL", SemanticIndex: 0, Type: 0, Size: 2},
|
||||
},
|
||||
Uniforms: []UniformLocation{
|
||||
{Name: "_15.z", Type: 0, Size: 1, Offset: 0},
|
||||
{Name: "_15.scale", Type: 0, Size: 2, Offset: 8},
|
||||
{Name: "_15.offset", Type: 0, Size: 2, Offset: 16},
|
||||
{Name: "_15.uvScale", Type: 0, Size: 2, Offset: 24},
|
||||
{Name: "_15.uvOffset", Type: 0, Size: 2, Offset: 32},
|
||||
},
|
||||
GLES2: "#version 100\n\nstruct Block\n{\n float z;\n vec2 scale;\n vec2 offset;\n vec2 uvScale;\n vec2 uvOffset;\n};\n\nuniform Block uniforms;\n\nattribute vec2 pos;\nvarying vec2 vUV;\nattribute vec2 uv;\n\nvoid main()\n{\n vec2 p = pos;\n p *= uniforms.scale;\n p += uniforms.offset;\n gl_Position = vec4(p, uniforms.z, 1.0);\n vUV = (uv * uniforms.uvScale) + uniforms.uvOffset;\n}\n\n",
|
||||
/*
|
||||
cbuffer Block : register(b0)
|
||||
{
|
||||
float uniforms_z : packoffset(c0);
|
||||
float2 uniforms_scale : packoffset(c0.z);
|
||||
float2 uniforms_offset : packoffset(c1);
|
||||
float2 uniforms_uvScale : packoffset(c1.z);
|
||||
float2 uniforms_uvOffset : packoffset(c2);
|
||||
};
|
||||
|
||||
|
||||
static float4 gl_Position;
|
||||
static float2 pos;
|
||||
static float2 vUV;
|
||||
static float2 uv;
|
||||
|
||||
struct SPIRV_Cross_Input
|
||||
{
|
||||
float2 pos : POSITION;
|
||||
float2 uv : NORMAL;
|
||||
};
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float2 vUV : TEXCOORD0;
|
||||
float4 gl_Position : SV_Position;
|
||||
};
|
||||
|
||||
void vert_main()
|
||||
{
|
||||
float2 p = pos;
|
||||
p *= uniforms_scale;
|
||||
p += uniforms_offset;
|
||||
gl_Position = float4(p, uniforms_z, 1.0f);
|
||||
vUV = (uv * uniforms_uvScale) + uniforms_uvOffset;
|
||||
}
|
||||
|
||||
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||
{
|
||||
pos = stage_input.pos;
|
||||
uv = stage_input.uv;
|
||||
vert_main();
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.gl_Position = gl_Position;
|
||||
stage_output.vUV = vUV;
|
||||
return stage_output;
|
||||
}
|
||||
|
||||
*/
|
||||
HLSL: []byte(nil),
|
||||
}
|
||||
shader_cover_frag = [...]ShaderSources{
|
||||
ShaderSources{
|
||||
Uniforms: []UniformLocation{
|
||||
{Name: "_12.color", Type: 0, Size: 4, Offset: 0},
|
||||
},
|
||||
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nstruct Color\n{\n vec4 color;\n};\n\nuniform Color color;\n\nuniform mediump sampler2D cover;\n\nvarying highp vec2 vCoverUV;\nvarying vec2 vUV;\n\nvoid main()\n{\n gl_FragData[0] = color.color;\n float cover_1 = abs(texture2D(cover, vCoverUV).x);\n gl_FragData[0] *= cover_1;\n}\n\n",
|
||||
/*
|
||||
cbuffer Color : register(b0)
|
||||
{
|
||||
float4 color_color : packoffset(c0);
|
||||
};
|
||||
|
||||
Texture2D<float4> cover : register(t1);
|
||||
SamplerState _cover_sampler : register(s1);
|
||||
|
||||
static float4 fragColor;
|
||||
static float2 vCoverUV;
|
||||
static float2 vUV;
|
||||
|
||||
struct SPIRV_Cross_Input
|
||||
{
|
||||
float2 vCoverUV : TEXCOORD0;
|
||||
float2 vUV : TEXCOORD1;
|
||||
};
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float4 fragColor : SV_Target0;
|
||||
};
|
||||
|
||||
void frag_main()
|
||||
{
|
||||
fragColor = color_color;
|
||||
float cover_1 = abs(cover.Sample(_cover_sampler, vCoverUV).x);
|
||||
fragColor *= cover_1;
|
||||
}
|
||||
|
||||
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||
{
|
||||
vCoverUV = stage_input.vCoverUV;
|
||||
vUV = stage_input.vUV;
|
||||
frag_main();
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.fragColor = fragColor;
|
||||
return stage_output;
|
||||
}
|
||||
|
||||
*/
|
||||
HLSL: []byte(nil),
|
||||
},
|
||||
ShaderSources{
|
||||
GLES2: "#version 100\nprecision 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",
|
||||
/*
|
||||
Texture2D<float4> tex : register(t0);
|
||||
SamplerState _tex_sampler : register(s0);
|
||||
Texture2D<float4> 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 = tex.Sample(_tex_sampler, vUV);
|
||||
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(nil),
|
||||
},
|
||||
}
|
||||
shader_cover_vert = ShaderSources{
|
||||
Inputs: []InputLocation{
|
||||
{Name: "pos", Location: 0, Semantic: "POSITION", SemanticIndex: 0, Type: 0, Size: 2},
|
||||
{Name: "uv", Location: 1, Semantic: "NORMAL", SemanticIndex: 0, Type: 0, Size: 2},
|
||||
},
|
||||
Uniforms: []UniformLocation{
|
||||
{Name: "_19.z", Type: 0, Size: 1, Offset: 0},
|
||||
{Name: "_19.scale", Type: 0, Size: 2, Offset: 8},
|
||||
{Name: "_19.offset", Type: 0, Size: 2, Offset: 16},
|
||||
{Name: "_19.uvScale", Type: 0, Size: 2, Offset: 24},
|
||||
{Name: "_19.uvOffset", Type: 0, Size: 2, Offset: 32},
|
||||
{Name: "_19.uvCoverScale", Type: 0, Size: 2, Offset: 40},
|
||||
{Name: "_19.uvCoverOffset", Type: 0, Size: 2, Offset: 48},
|
||||
},
|
||||
GLES2: "#version 100\n\nstruct Block\n{\n float z;\n vec2 scale;\n vec2 offset;\n vec2 uvScale;\n vec2 uvOffset;\n vec2 uvCoverScale;\n vec2 uvCoverOffset;\n};\n\nuniform Block uniforms;\n\nattribute vec2 pos;\nvarying vec2 vUV;\nattribute vec2 uv;\nvarying vec2 vCoverUV;\n\nvoid main()\n{\n gl_Position = vec4((pos * uniforms.scale) + uniforms.offset, uniforms.z, 1.0);\n vUV = (uv * uniforms.uvScale) + uniforms.uvOffset;\n vCoverUV = (uv * uniforms.uvCoverScale) + uniforms.uvCoverOffset;\n}\n\n",
|
||||
/*
|
||||
cbuffer Block : register(b0)
|
||||
{
|
||||
float uniforms_z : packoffset(c0);
|
||||
float2 uniforms_scale : packoffset(c0.z);
|
||||
float2 uniforms_offset : packoffset(c1);
|
||||
float2 uniforms_uvScale : packoffset(c1.z);
|
||||
float2 uniforms_uvOffset : packoffset(c2);
|
||||
float2 uniforms_uvCoverScale : packoffset(c2.z);
|
||||
float2 uniforms_uvCoverOffset : packoffset(c3);
|
||||
};
|
||||
|
||||
|
||||
static float4 gl_Position;
|
||||
static float2 pos;
|
||||
static float2 vUV;
|
||||
static float2 uv;
|
||||
static float2 vCoverUV;
|
||||
|
||||
struct SPIRV_Cross_Input
|
||||
{
|
||||
float2 pos : POSITION;
|
||||
float2 uv : NORMAL;
|
||||
};
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float2 vCoverUV : TEXCOORD0;
|
||||
float2 vUV : TEXCOORD1;
|
||||
float4 gl_Position : SV_Position;
|
||||
};
|
||||
|
||||
void vert_main()
|
||||
{
|
||||
gl_Position = float4((pos * uniforms_scale) + uniforms_offset, uniforms_z, 1.0f);
|
||||
vUV = (uv * uniforms_uvScale) + uniforms_uvOffset;
|
||||
vCoverUV = (uv * uniforms_uvCoverScale) + uniforms_uvCoverOffset;
|
||||
}
|
||||
|
||||
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||
{
|
||||
pos = stage_input.pos;
|
||||
uv = stage_input.uv;
|
||||
vert_main();
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.gl_Position = gl_Position;
|
||||
stage_output.vUV = vUV;
|
||||
stage_output.vCoverUV = vCoverUV;
|
||||
return stage_output;
|
||||
}
|
||||
|
||||
*/
|
||||
HLSL: []byte(nil),
|
||||
}
|
||||
shader_intersect_frag = ShaderSources{
|
||||
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nuniform mediump sampler2D cover;\n\nvarying highp vec2 vUV;\n\nvoid main()\n{\n float cover_1 = abs(texture2D(cover, vUV).x);\n gl_FragData[0].x = cover_1;\n}\n\n",
|
||||
/*
|
||||
Texture2D<float4> cover : register(t0);
|
||||
SamplerState _cover_sampler : register(s0);
|
||||
|
||||
static float2 vUV;
|
||||
static float4 fragColor;
|
||||
|
||||
struct SPIRV_Cross_Input
|
||||
{
|
||||
float2 vUV : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float4 fragColor : SV_Target0;
|
||||
};
|
||||
|
||||
void frag_main()
|
||||
{
|
||||
float cover_1 = abs(cover.Sample(_cover_sampler, vUV).x);
|
||||
fragColor.x = cover_1;
|
||||
}
|
||||
|
||||
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(nil),
|
||||
}
|
||||
shader_intersect_vert = ShaderSources{
|
||||
Inputs: []InputLocation{
|
||||
{Name: "pos", Location: 0, Semantic: "POSITION", SemanticIndex: 0, Type: 0, Size: 2},
|
||||
{Name: "uv", Location: 1, Semantic: "NORMAL", SemanticIndex: 0, Type: 0, Size: 2},
|
||||
},
|
||||
Uniforms: []UniformLocation{
|
||||
{Name: "_40.scale", Type: 0, Size: 2, Offset: 0},
|
||||
{Name: "_40.offset", Type: 0, Size: 2, Offset: 8},
|
||||
},
|
||||
GLES2: "#version 100\n\nstruct Block\n{\n vec2 scale;\n vec2 offset;\n};\n\nuniform Block uvparams;\n\nattribute vec2 pos;\nvarying vec2 vUV;\nattribute vec2 uv;\n\nvoid main()\n{\n vec2 p = pos;\n p.y = -p.y;\n gl_Position = vec4(p, 0.0, 1.0);\n vUV = (uv * uvparams.scale) + uvparams.offset;\n}\n\n",
|
||||
/*
|
||||
cbuffer Block : register(b0)
|
||||
{
|
||||
float2 uvparams_scale : packoffset(c0);
|
||||
float2 uvparams_offset : packoffset(c0.z);
|
||||
};
|
||||
|
||||
|
||||
static float4 gl_Position;
|
||||
static float2 pos;
|
||||
static float2 vUV;
|
||||
static float2 uv;
|
||||
|
||||
struct SPIRV_Cross_Input
|
||||
{
|
||||
float2 pos : POSITION;
|
||||
float2 uv : NORMAL;
|
||||
};
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float2 vUV : TEXCOORD0;
|
||||
float4 gl_Position : SV_Position;
|
||||
};
|
||||
|
||||
void vert_main()
|
||||
{
|
||||
float2 p = pos;
|
||||
p.y = -p.y;
|
||||
gl_Position = float4(p, 0.0f, 1.0f);
|
||||
vUV = (uv * uvparams_scale) + uvparams_offset;
|
||||
}
|
||||
|
||||
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||
{
|
||||
pos = stage_input.pos;
|
||||
uv = stage_input.uv;
|
||||
vert_main();
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.gl_Position = gl_Position;
|
||||
stage_output.vUV = vUV;
|
||||
return stage_output;
|
||||
}
|
||||
|
||||
*/
|
||||
HLSL: []byte(nil),
|
||||
}
|
||||
shader_stencil_frag = ShaderSources{
|
||||
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nuniform mediump sampler2D areaLUT;\n\nvarying vec2 vTo;\nvarying vec2 vFrom;\nvarying vec2 vCtrl;\n\nvoid main()\n{\n float dx = vTo.x - vFrom.x;\n bool increasing = vTo.x >= vFrom.x;\n bvec2 _35 = bvec2(increasing);\n vec2 left = vec2(_35.x ? vFrom.x : vTo.x, _35.y ? vFrom.y : vTo.y);\n bvec2 _41 = bvec2(increasing);\n vec2 right = vec2(_41.x ? vTo.x : vFrom.x, _41.y ? vTo.y : vFrom.y);\n vec2 extent = clamp(vec2(vFrom.x, vTo.x), vec2(-0.5), vec2(0.5));\n float midx = mix(extent.x, extent.y, 0.5);\n float x0 = midx - left.x;\n vec2 p1 = vCtrl - left;\n vec2 v = right - vCtrl;\n float t = x0 / (p1.x + sqrt((p1.x * p1.x) + ((v.x - p1.x) * x0)));\n float y = mix(mix(left.y, vCtrl.y, t), mix(vCtrl.y, right.y, t), t);\n vec2 d_half = mix(p1, v, vec2(t));\n float dy = d_half.y / d_half.x;\n float width = extent.y - extent.x;\n dy = abs(dy * width);\n vec4 sides = vec4((dy * 0.5) + y, (dy * (-0.5)) + y, (0.5 - y) / dy, ((-0.5) - y) / dy);\n sides = clamp(sides + vec4(0.5), vec4(0.0), vec4(1.0));\n float area = 0.5 * ((((sides.z - (sides.z * sides.y)) + 1.0) - sides.x) + (sides.x * sides.w));\n area *= width;\n if (width == 0.0)\n {\n area = 0.0;\n }\n gl_FragData[0].x = area;\n}\n\n",
|
||||
/*
|
||||
Texture2D<float4> areaLUT : register(t0);
|
||||
SamplerState _areaLUT_sampler : register(s0);
|
||||
|
||||
static float2 vTo;
|
||||
static float2 vFrom;
|
||||
static float2 vCtrl;
|
||||
static float4 fragCover;
|
||||
|
||||
struct SPIRV_Cross_Input
|
||||
{
|
||||
float2 vFrom : TEXCOORD0;
|
||||
float2 vCtrl : TEXCOORD1;
|
||||
float2 vTo : TEXCOORD2;
|
||||
};
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float4 fragCover : SV_Target0;
|
||||
};
|
||||
|
||||
void frag_main()
|
||||
{
|
||||
float dx = vTo.x - vFrom.x;
|
||||
bool increasing = vTo.x >= vFrom.x;
|
||||
bool2 _35 = increasing.xx;
|
||||
float2 left = float2(_35.x ? vFrom.x : vTo.x, _35.y ? vFrom.y : vTo.y);
|
||||
bool2 _41 = increasing.xx;
|
||||
float2 right = float2(_41.x ? vTo.x : vFrom.x, _41.y ? vTo.y : vFrom.y);
|
||||
float2 extent = clamp(float2(vFrom.x, vTo.x), (-0.5f).xx, 0.5f.xx);
|
||||
float midx = lerp(extent.x, extent.y, 0.5f);
|
||||
float x0 = midx - left.x;
|
||||
float2 p1 = vCtrl - left;
|
||||
float2 v = right - vCtrl;
|
||||
float t = x0 / (p1.x + sqrt((p1.x * p1.x) + ((v.x - p1.x) * x0)));
|
||||
float y = lerp(lerp(left.y, vCtrl.y, t), lerp(vCtrl.y, right.y, t), t);
|
||||
float2 d_half = lerp(p1, v, t.xx);
|
||||
float dy = d_half.y / d_half.x;
|
||||
float width = extent.y - extent.x;
|
||||
dy = abs(dy * width);
|
||||
float4 sides = float4((dy * 0.5f) + y, (dy * (-0.5f)) + y, (0.5f - y) / dy, ((-0.5f) - y) / dy);
|
||||
sides = clamp(sides + 0.5f.xxxx, 0.0f.xxxx, 1.0f.xxxx);
|
||||
float area = 0.5f * ((((sides.z - (sides.z * sides.y)) + 1.0f) - sides.x) + (sides.x * sides.w));
|
||||
area *= width;
|
||||
if (width == 0.0f)
|
||||
{
|
||||
area = 0.0f;
|
||||
}
|
||||
fragCover.x = area;
|
||||
}
|
||||
|
||||
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||
{
|
||||
vTo = stage_input.vTo;
|
||||
vFrom = stage_input.vFrom;
|
||||
vCtrl = stage_input.vCtrl;
|
||||
frag_main();
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.fragCover = fragCover;
|
||||
return stage_output;
|
||||
}
|
||||
|
||||
*/
|
||||
HLSL: []byte(nil),
|
||||
}
|
||||
shader_stencil_vert = ShaderSources{
|
||||
Inputs: []InputLocation{
|
||||
{Name: "corner", Location: 0, Semantic: "POSITION", SemanticIndex: 0, Type: 0, Size: 2},
|
||||
{Name: "maxy", Location: 1, Semantic: "NORMAL", SemanticIndex: 0, Type: 0, Size: 1},
|
||||
{Name: "from", Location: 2, Semantic: "TEXCOORD", SemanticIndex: 0, Type: 0, Size: 2},
|
||||
{Name: "ctrl", Location: 3, Semantic: "TEXCOORD", SemanticIndex: 1, Type: 0, Size: 2},
|
||||
{Name: "to", Location: 4, Semantic: "TEXCOORD", SemanticIndex: 2, Type: 0, Size: 2},
|
||||
},
|
||||
Uniforms: []UniformLocation{
|
||||
{Name: "_15.scale", Type: 0, Size: 2, Offset: 0},
|
||||
{Name: "_15.offset", Type: 0, Size: 2, Offset: 8},
|
||||
{Name: "_15.pathOffset", Type: 0, Size: 2, Offset: 16},
|
||||
},
|
||||
GLES2: "#version 100\n\nstruct Block\n{\n vec2 scale;\n vec2 offset;\n vec2 pathOffset;\n};\n\nuniform Block uniforms;\n\nattribute vec2 from;\nattribute vec2 ctrl;\nattribute vec2 to;\nattribute float maxy;\nattribute vec2 corner;\nvarying vec2 vFrom;\nvarying vec2 vCtrl;\nvarying vec2 vTo;\n\nvoid main()\n{\n vec2 from_1 = from + uniforms.pathOffset;\n vec2 ctrl_1 = ctrl + uniforms.pathOffset;\n vec2 to_1 = to + uniforms.pathOffset;\n float maxy_1 = maxy + uniforms.pathOffset.y;\n vec2 pos;\n if (corner.x > 0.0)\n {\n pos.x = max(max(from_1.x, ctrl_1.x), to_1.x) + 1.0;\n }\n else\n {\n pos.x = min(min(from_1.x, ctrl_1.x), to_1.x) - 1.0;\n }\n if (corner.y > 0.0)\n {\n pos.y = maxy_1 + 1.0;\n }\n else\n {\n pos.y = min(min(from_1.y, ctrl_1.y), to_1.y) - 1.0;\n }\n vFrom = from_1 - pos;\n vCtrl = ctrl_1 - pos;\n vTo = to_1 - pos;\n pos *= uniforms.scale;\n pos += uniforms.offset;\n gl_Position = vec4(pos, 1.0, 1.0);\n}\n\n",
|
||||
/*
|
||||
cbuffer Block : register(b0)
|
||||
{
|
||||
float2 uniforms_scale : packoffset(c0);
|
||||
float2 uniforms_offset : packoffset(c0.z);
|
||||
float2 uniforms_pathOffset : packoffset(c1);
|
||||
};
|
||||
|
||||
|
||||
static float4 gl_Position;
|
||||
static float2 from;
|
||||
static float2 ctrl;
|
||||
static float2 to;
|
||||
static float maxy;
|
||||
static float2 corner;
|
||||
static float2 vFrom;
|
||||
static float2 vCtrl;
|
||||
static float2 vTo;
|
||||
|
||||
struct SPIRV_Cross_Input
|
||||
{
|
||||
float2 corner : POSITION;
|
||||
float maxy : NORMAL;
|
||||
float2 from : TEXCOORD0;
|
||||
float2 ctrl : TEXCOORD1;
|
||||
float2 to : TEXCOORD2;
|
||||
};
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float2 vFrom : TEXCOORD0;
|
||||
float2 vCtrl : TEXCOORD1;
|
||||
float2 vTo : TEXCOORD2;
|
||||
float4 gl_Position : SV_Position;
|
||||
};
|
||||
|
||||
void vert_main()
|
||||
{
|
||||
float2 from_1 = from + uniforms_pathOffset;
|
||||
float2 ctrl_1 = ctrl + uniforms_pathOffset;
|
||||
float2 to_1 = to + uniforms_pathOffset;
|
||||
float maxy_1 = maxy + uniforms_pathOffset.y;
|
||||
float2 pos;
|
||||
if (corner.x > 0.0f)
|
||||
{
|
||||
pos.x = max(max(from_1.x, ctrl_1.x), to_1.x) + 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos.x = min(min(from_1.x, ctrl_1.x), to_1.x) - 1.0f;
|
||||
}
|
||||
if (corner.y > 0.0f)
|
||||
{
|
||||
pos.y = maxy_1 + 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos.y = min(min(from_1.y, ctrl_1.y), to_1.y) - 1.0f;
|
||||
}
|
||||
vFrom = from_1 - pos;
|
||||
vCtrl = ctrl_1 - pos;
|
||||
vTo = to_1 - pos;
|
||||
pos *= uniforms_scale;
|
||||
pos += uniforms_offset;
|
||||
gl_Position = float4(pos, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||
{
|
||||
from = stage_input.from;
|
||||
ctrl = stage_input.ctrl;
|
||||
to = stage_input.to;
|
||||
maxy = stage_input.maxy;
|
||||
corner = stage_input.corner;
|
||||
vert_main();
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.gl_Position = gl_Position;
|
||||
stage_output.vFrom = vFrom;
|
||||
stage_output.vCtrl = vCtrl;
|
||||
stage_output.vTo = vTo;
|
||||
return stage_output;
|
||||
}
|
||||
|
||||
*/
|
||||
HLSL: []byte(nil),
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
#version 310 es
|
||||
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
precision mediump float;
|
||||
|
||||
layout(location=0) in vec2 vUV;
|
||||
|
||||
{{.Header}}
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
fragColor = {{.FetchColorExpr}};
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#version 310 es
|
||||
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(binding = 0) uniform Block {
|
||||
float z;
|
||||
vec2 scale;
|
||||
vec2 offset;
|
||||
vec2 uvScale;
|
||||
vec2 uvOffset;
|
||||
} uniforms;
|
||||
|
||||
layout(location = 0) in vec2 pos;
|
||||
|
||||
layout(location = 1) in vec2 uv;
|
||||
|
||||
layout(location = 0) out vec2 vUV;
|
||||
|
||||
void main() {
|
||||
vec2 p = pos;
|
||||
p *= uniforms.scale;
|
||||
p += uniforms.offset;
|
||||
gl_Position = vec4(p, uniforms.z, 1);
|
||||
vUV = uv*uniforms.uvScale + uniforms.uvOffset;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#version 310 es
|
||||
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
precision mediump float;
|
||||
|
||||
{{.Header}}
|
||||
|
||||
// Use high precision to be pixel accurate for
|
||||
// large cover atlases.
|
||||
layout(location = 0) in highp vec2 vCoverUV;
|
||||
layout(location = 1) in vec2 vUV;
|
||||
|
||||
layout(binding = 1) uniform sampler2D cover;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
fragColor = {{.FetchColorExpr}};
|
||||
float cover = abs(texture(cover, vCoverUV).r);
|
||||
fragColor *= cover;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#version 310 es
|
||||
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(binding = 0) uniform Block {
|
||||
float z;
|
||||
vec2 scale;
|
||||
vec2 offset;
|
||||
vec2 uvScale;
|
||||
vec2 uvOffset;
|
||||
vec2 uvCoverScale;
|
||||
vec2 uvCoverOffset;
|
||||
} uniforms;
|
||||
|
||||
layout(location = 0) in vec2 pos;
|
||||
|
||||
layout(location = 0) out vec2 vCoverUV;
|
||||
|
||||
layout(location = 1) in vec2 uv;
|
||||
layout(location = 1) out vec2 vUV;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(pos*uniforms.scale + uniforms.offset, uniforms.z, 1);
|
||||
vUV = uv*uniforms.uvScale + uniforms.uvOffset;
|
||||
vCoverUV = uv*uniforms.uvCoverScale+uniforms.uvCoverOffset;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#version 310 es
|
||||
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Use high precision to be pixel accurate for
|
||||
// large cover atlases.
|
||||
layout(location = 0) in highp vec2 vUV;
|
||||
|
||||
layout(binding = 0) uniform sampler2D cover;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
float cover = abs(texture(cover, vUV).r);
|
||||
fragColor.r = cover;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#version 310 es
|
||||
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) in vec2 pos;
|
||||
layout(location = 1) in vec2 uv;
|
||||
|
||||
layout(binding = 0) uniform Block {
|
||||
vec2 scale;
|
||||
vec2 offset;
|
||||
} uvparams;
|
||||
|
||||
layout(location = 0) out vec2 vUV;
|
||||
|
||||
void main() {
|
||||
vec2 p = pos;
|
||||
p.y = -p.y;
|
||||
gl_Position = vec4(p, 0, 1);
|
||||
vUV = uv*uvparams.scale + uvparams.offset;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
#version 310 es
|
||||
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
precision mediump float;
|
||||
|
||||
layout(location=0) in vec2 vFrom;
|
||||
layout(location=1) in vec2 vCtrl;
|
||||
layout(location=2) in vec2 vTo;
|
||||
|
||||
layout(binding=0) uniform sampler2D areaLUT;
|
||||
|
||||
layout(location = 0) out vec4 fragCover;
|
||||
|
||||
void main() {
|
||||
float dx = vTo.x - vFrom.x;
|
||||
// Sort from and to in increasing order so the root below
|
||||
// is always the positive square root, if any.
|
||||
// We need the direction of the curve below, so this can't be
|
||||
// done from the vertex shader.
|
||||
bool increasing = vTo.x >= vFrom.x;
|
||||
vec2 left = increasing ? vFrom : vTo;
|
||||
vec2 right = increasing ? vTo : vFrom;
|
||||
|
||||
// The signed horizontal extent of the fragment.
|
||||
vec2 extent = clamp(vec2(vFrom.x, vTo.x), -0.5, 0.5);
|
||||
// Find the t where the curve crosses the middle of the
|
||||
// extent, x₀.
|
||||
// Given the Bézier curve with x coordinates P₀, P₁, P₂
|
||||
// where P₀ is at the origin, its x coordinate in t
|
||||
// is given by:
|
||||
//
|
||||
// x(t) = 2(1-t)tP₁ + t²P₂
|
||||
//
|
||||
// Rearranging:
|
||||
//
|
||||
// x(t) = (P₂ - 2P₁)t² + 2P₁t
|
||||
//
|
||||
// Setting x(t) = x₀ and using Muller's quadratic formula ("Citardauq")
|
||||
// for robustnesss,
|
||||
//
|
||||
// t = 2x₀/(2P₁±√(4P₁²+4(P₂-2P₁)x₀))
|
||||
//
|
||||
// which simplifies to
|
||||
//
|
||||
// t = x₀/(P₁±√(P₁²+(P₂-2P₁)x₀))
|
||||
//
|
||||
// Setting v = P₂-P₁,
|
||||
//
|
||||
// t = x₀/(P₁±√(P₁²+(v-P₁)x₀))
|
||||
//
|
||||
// t lie in [0; 1]; P₂ ≥ P₁ and P₁ ≥ 0 since we split curves where
|
||||
// the control point lies before the start point or after the end point.
|
||||
// It can then be shown that only the positive square root is valid.
|
||||
float midx = mix(extent.x, extent.y, 0.5);
|
||||
float x0 = midx - left.x;
|
||||
vec2 p1 = vCtrl - left;
|
||||
vec2 v = right - vCtrl;
|
||||
float t = x0/(p1.x+sqrt(p1.x*p1.x+(v.x-p1.x)*x0));
|
||||
// Find y(t) on the curve.
|
||||
float y = mix(mix(left.y, vCtrl.y, t), mix(vCtrl.y, right.y, t), t);
|
||||
// And the slope.
|
||||
vec2 d_half = mix(p1, v, t);
|
||||
float dy = d_half.y/d_half.x;
|
||||
// Together, y and dy form a line approximation.
|
||||
|
||||
// Compute the fragment area above the line.
|
||||
// The area is symmetric around dy = 0. Scale slope with extent width.
|
||||
float width = extent.y - extent.x;
|
||||
dy = abs(dy*width);
|
||||
|
||||
vec4 sides = vec4(dy*+0.5 + y, dy*-0.5 + y, (+0.5-y)/dy, (-0.5-y)/dy);
|
||||
sides = clamp(sides+0.5, 0.0, 1.0);
|
||||
|
||||
float area = 0.5*(sides.z - sides.z*sides.y + 1.0 - sides.x+sides.x*sides.w);
|
||||
area *= width;
|
||||
|
||||
// Work around issue #13.
|
||||
if (width == 0.0)
|
||||
area = 0.0;
|
||||
|
||||
fragCover.r = area;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#version 310 es
|
||||
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(binding = 0) uniform Block {
|
||||
vec2 scale;
|
||||
vec2 offset;
|
||||
vec2 pathOffset;
|
||||
} uniforms;
|
||||
|
||||
layout(location=0) in vec2 corner;
|
||||
layout(location=1) in float maxy;
|
||||
layout(location=2) in vec2 from;
|
||||
layout(location=3) in vec2 ctrl;
|
||||
layout(location=4) in vec2 to;
|
||||
|
||||
layout(location=0) out vec2 vFrom;
|
||||
layout(location=1) out vec2 vCtrl;
|
||||
layout(location=2) out vec2 vTo;
|
||||
|
||||
void main() {
|
||||
// Add a one pixel overlap so curve quads cover their
|
||||
// entire curves. Could use conservative rasterization
|
||||
// if available.
|
||||
vec2 from = from + uniforms.pathOffset;
|
||||
vec2 ctrl = ctrl + uniforms.pathOffset;
|
||||
vec2 to = to + uniforms.pathOffset;
|
||||
float maxy = maxy + uniforms.pathOffset.y;
|
||||
vec2 pos;
|
||||
if (corner.x > 0.0) {
|
||||
// East.
|
||||
pos.x = max(max(from.x, ctrl.x), to.x)+1.0;
|
||||
} else {
|
||||
// West.
|
||||
pos.x = min(min(from.x, ctrl.x), to.x)-1.0;
|
||||
}
|
||||
if (corner.y > 0.0) {
|
||||
// North.
|
||||
pos.y = maxy + 1.0;
|
||||
} else {
|
||||
// South.
|
||||
pos.y = min(min(from.y, ctrl.y), to.y) - 1.0;
|
||||
}
|
||||
vFrom = from-pos;
|
||||
vCtrl = ctrl-pos;
|
||||
vTo = to-pos;
|
||||
pos *= uniforms.scale;
|
||||
pos += uniforms.offset;
|
||||
gl_Position = vec4(pos, 1, 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user