forked from joejulian/gio
gpu,gpu/gl: introduce Backend
A recent change made the OpenGL functions an interface of the functions required for the implementation of GPU, a renderer for Gio operations. That allowed for running Gio on external systems where OpenGL is available. However, to allow for non-OpenGL flavored backends such as Vulkan, Metal and Direct3D, this change introduces Backend for the high-level operations required by GPU. This change also adds a concrete backend to package gl. Type Backend is a first cut heavily based on OpenGL. Future changes will add more backends, where the Backend interface quite possibly will need refinement. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+106
-132
@@ -10,12 +10,12 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/gpu/gl"
|
||||
"gioui.org/internal/path"
|
||||
gunsafe "gioui.org/internal/unsafe"
|
||||
)
|
||||
|
||||
type pather struct {
|
||||
ctx *context
|
||||
ctx Backend
|
||||
|
||||
viewport image.Point
|
||||
|
||||
@@ -24,30 +24,30 @@ type pather struct {
|
||||
}
|
||||
|
||||
type coverer struct {
|
||||
ctx *context
|
||||
prog [2]gl.Program
|
||||
ctx Backend
|
||||
prog [2]Program
|
||||
vars [2]struct {
|
||||
z gl.Uniform
|
||||
uScale, uOffset gl.Uniform
|
||||
uUVScale, uUVOffset gl.Uniform
|
||||
uCoverUVScale, uCoverUVOffset gl.Uniform
|
||||
uColor gl.Uniform
|
||||
z Uniform
|
||||
uScale, uOffset Uniform
|
||||
uUVScale, uUVOffset Uniform
|
||||
uCoverUVScale, uCoverUVOffset Uniform
|
||||
uColor Uniform
|
||||
}
|
||||
}
|
||||
|
||||
type stenciler struct {
|
||||
ctx *context
|
||||
defFBO gl.Framebuffer
|
||||
ctx Backend
|
||||
defFBO Framebuffer
|
||||
indexBufQuads int
|
||||
prog gl.Program
|
||||
iprog gl.Program
|
||||
prog Program
|
||||
iprog Program
|
||||
fbos fboSet
|
||||
intersections fboSet
|
||||
uScale, uOffset gl.Uniform
|
||||
uPathOffset gl.Uniform
|
||||
uIntersectUVOffset gl.Uniform
|
||||
uIntersectUVScale gl.Uniform
|
||||
indexBuf gl.Buffer
|
||||
uScale, uOffset Uniform
|
||||
uPathOffset Uniform
|
||||
uIntersectUVOffset Uniform
|
||||
uIntersectUVScale Uniform
|
||||
indexBuf Buffer
|
||||
}
|
||||
|
||||
type fboSet struct {
|
||||
@@ -56,27 +56,29 @@ type fboSet struct {
|
||||
|
||||
type stencilFBO struct {
|
||||
size image.Point
|
||||
fbo gl.Framebuffer
|
||||
tex gl.Texture
|
||||
fbo Framebuffer
|
||||
tex Texture
|
||||
}
|
||||
|
||||
type pathData struct {
|
||||
ncurves int
|
||||
data gl.Buffer
|
||||
data Buffer
|
||||
}
|
||||
|
||||
var (
|
||||
pathAttribs = []string{"corner", "maxy", "from", "ctrl", "to"}
|
||||
attribPathCorner gl.Attrib = 0
|
||||
attribPathMaxY gl.Attrib = 1
|
||||
attribPathFrom gl.Attrib = 2
|
||||
attribPathCtrl gl.Attrib = 3
|
||||
attribPathTo gl.Attrib = 4
|
||||
|
||||
pathAttribs = []string{"corner", "maxy", "from", "ctrl", "to"}
|
||||
intersectAttribs = []string{"pos", "uv"}
|
||||
)
|
||||
|
||||
func newPather(ctx *context) *pather {
|
||||
const (
|
||||
attribPathCorner = 0
|
||||
attribPathMaxY = 1
|
||||
attribPathFrom = 2
|
||||
attribPathCtrl = 3
|
||||
attribPathTo = 4
|
||||
)
|
||||
|
||||
func newPather(ctx Backend) *pather {
|
||||
return &pather{
|
||||
ctx: ctx,
|
||||
stenciler: newStenciler(ctx),
|
||||
@@ -84,7 +86,7 @@ func newPather(ctx *context) *pather {
|
||||
}
|
||||
}
|
||||
|
||||
func newCoverer(ctx *context) *coverer {
|
||||
func newCoverer(ctx Backend) *coverer {
|
||||
prog, err := createColorPrograms(ctx, coverVSrc, coverFSrc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -94,68 +96,58 @@ func newCoverer(ctx *context) *coverer {
|
||||
prog: prog,
|
||||
}
|
||||
for i, prog := range prog {
|
||||
ctx.UseProgram(prog)
|
||||
switch materialType(i) {
|
||||
case materialTexture:
|
||||
uTex := gl.GetUniformLocation(ctx.Functions, prog, "tex")
|
||||
ctx.Uniform1i(uTex, 0)
|
||||
c.vars[i].uUVScale = gl.GetUniformLocation(ctx.Functions, prog, "uvScale")
|
||||
c.vars[i].uUVOffset = gl.GetUniformLocation(ctx.Functions, prog, "uvOffset")
|
||||
uTex := prog.UniformFor("tex")
|
||||
prog.Uniform1i(uTex, 0)
|
||||
c.vars[i].uUVScale = prog.UniformFor("uvScale")
|
||||
c.vars[i].uUVOffset = prog.UniformFor("uvOffset")
|
||||
case materialColor:
|
||||
c.vars[i].uColor = gl.GetUniformLocation(ctx.Functions, prog, "color")
|
||||
c.vars[i].uColor = prog.UniformFor("color")
|
||||
}
|
||||
uCover := gl.GetUniformLocation(ctx.Functions, prog, "cover")
|
||||
ctx.Uniform1i(uCover, 1)
|
||||
c.vars[i].z = gl.GetUniformLocation(ctx.Functions, prog, "z")
|
||||
c.vars[i].uScale = gl.GetUniformLocation(ctx.Functions, prog, "scale")
|
||||
c.vars[i].uOffset = gl.GetUniformLocation(ctx.Functions, prog, "offset")
|
||||
c.vars[i].uCoverUVScale = gl.GetUniformLocation(ctx.Functions, prog, "uvCoverScale")
|
||||
c.vars[i].uCoverUVOffset = gl.GetUniformLocation(ctx.Functions, prog, "uvCoverOffset")
|
||||
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")
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func newStenciler(ctx *context) *stenciler {
|
||||
defFBO := gl.Framebuffer(ctx.GetBinding(gl.FRAMEBUFFER_BINDING))
|
||||
prog, err := gl.CreateProgram(ctx.Functions, stencilVSrc, stencilFSrc, pathAttribs)
|
||||
func newStenciler(ctx Backend) *stenciler {
|
||||
defFBO := ctx.DefaultFramebuffer()
|
||||
prog, err := ctx.NewProgram(stencilVSrc, stencilFSrc, pathAttribs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ctx.UseProgram(prog)
|
||||
iprog, err := gl.CreateProgram(ctx.Functions, intersectVSrc, intersectFSrc, intersectAttribs)
|
||||
iprog, err := ctx.NewProgram(intersectVSrc, intersectFSrc, intersectAttribs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
coverLoc := gl.GetUniformLocation(ctx.Functions, iprog, "cover")
|
||||
ctx.UseProgram(iprog)
|
||||
ctx.Uniform1i(coverLoc, 0)
|
||||
coverLoc := iprog.UniformFor("cover")
|
||||
iprog.Uniform1i(coverLoc, 0)
|
||||
return &stenciler{
|
||||
ctx: ctx,
|
||||
defFBO: defFBO,
|
||||
prog: prog,
|
||||
iprog: iprog,
|
||||
uScale: gl.GetUniformLocation(ctx.Functions, prog, "scale"),
|
||||
uOffset: gl.GetUniformLocation(ctx.Functions, prog, "offset"),
|
||||
uPathOffset: gl.GetUniformLocation(ctx.Functions, prog, "pathOffset"),
|
||||
uIntersectUVScale: gl.GetUniformLocation(ctx.Functions, iprog, "uvScale"),
|
||||
uIntersectUVOffset: gl.GetUniformLocation(ctx.Functions, iprog, "uvOffset"),
|
||||
indexBuf: ctx.CreateBuffer(),
|
||||
uScale: prog.UniformFor("scale"),
|
||||
uOffset: prog.UniformFor("offset"),
|
||||
uPathOffset: prog.UniformFor("pathOffset"),
|
||||
uIntersectUVScale: iprog.UniformFor("uvScale"),
|
||||
uIntersectUVOffset: iprog.UniformFor("uvOffset"),
|
||||
indexBuf: ctx.NewBuffer(BufferTypeIndices),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *fboSet) resize(ctx *context, sizes []image.Point) {
|
||||
func (s *fboSet) resize(ctx Backend, sizes []image.Point) {
|
||||
// Add fbos.
|
||||
for i := len(s.fbos); i < len(sizes); i++ {
|
||||
tex := ctx.CreateTexture()
|
||||
ctx.BindTexture(gl.TEXTURE_2D, tex)
|
||||
ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
||||
ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
|
||||
ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
||||
ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
||||
fbo := ctx.CreateFramebuffer()
|
||||
s.fbos = append(s.fbos, stencilFBO{
|
||||
fbo: fbo,
|
||||
tex: tex,
|
||||
fbo: ctx.NewFramebuffer(),
|
||||
tex: ctx.NewTexture(FilterNearest, FilterNearest),
|
||||
})
|
||||
}
|
||||
// Resize fbos.
|
||||
@@ -168,37 +160,33 @@ func (s *fboSet) resize(ctx *context, sizes []image.Point) {
|
||||
resize = resize || waste > 1.2
|
||||
if resize {
|
||||
f.size = sz
|
||||
ctx.BindTexture(gl.TEXTURE_2D, f.tex)
|
||||
tt := ctx.caps.floatTriple
|
||||
ctx.TexImage2D(gl.TEXTURE_2D, 0, tt.internalFormat, sz.X, sz.Y, tt.format, tt.typ, nil)
|
||||
ctx.BindFramebuffer(gl.FRAMEBUFFER, f.fbo)
|
||||
ctx.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, f.tex, 0)
|
||||
f.tex.Resize(TextureFormatFloat, sz.X, sz.Y)
|
||||
f.fbo.BindTexture(f.tex)
|
||||
}
|
||||
}
|
||||
// Delete extra fbos.
|
||||
s.delete(ctx, len(sizes))
|
||||
}
|
||||
|
||||
func (s *fboSet) invalidate(ctx *context) {
|
||||
func (s *fboSet) invalidate(ctx Backend) {
|
||||
for _, f := range s.fbos {
|
||||
ctx.BindFramebuffer(gl.FRAMEBUFFER, f.fbo)
|
||||
ctx.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0)
|
||||
f.fbo.Invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *fboSet) delete(ctx *context, idx int) {
|
||||
func (s *fboSet) delete(ctx Backend, idx int) {
|
||||
for i := idx; i < len(s.fbos); i++ {
|
||||
f := s.fbos[i]
|
||||
ctx.DeleteFramebuffer(f.fbo)
|
||||
ctx.DeleteTexture(f.tex)
|
||||
f.fbo.Release()
|
||||
f.tex.Release()
|
||||
}
|
||||
s.fbos = s.fbos[:idx]
|
||||
}
|
||||
|
||||
func (s *stenciler) release() {
|
||||
s.fbos.delete(s.ctx, 0)
|
||||
s.ctx.DeleteProgram(s.prog)
|
||||
s.ctx.DeleteBuffer(s.indexBuf)
|
||||
s.prog.Release()
|
||||
s.indexBuf.Release()
|
||||
}
|
||||
|
||||
func (p *pather) release() {
|
||||
@@ -208,22 +196,21 @@ func (p *pather) release() {
|
||||
|
||||
func (c *coverer) release() {
|
||||
for _, p := range c.prog {
|
||||
c.ctx.DeleteProgram(p)
|
||||
p.Release()
|
||||
}
|
||||
}
|
||||
|
||||
func buildPath(ctx *context, p []byte) *pathData {
|
||||
buf := ctx.CreateBuffer()
|
||||
ctx.BindBuffer(gl.ARRAY_BUFFER, buf)
|
||||
ctx.BufferData(gl.ARRAY_BUFFER, p, gl.STATIC_DRAW)
|
||||
func buildPath(ctx Backend, p []byte) *pathData {
|
||||
buf := ctx.NewBuffer(BufferTypeData)
|
||||
buf.Upload(BufferUsageStaticDraw, p)
|
||||
return &pathData{
|
||||
ncurves: len(p) / path.VertStride,
|
||||
data: buf,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pathData) release(ctx *context) {
|
||||
ctx.DeleteBuffer(p.data)
|
||||
func (p *pathData) release() {
|
||||
p.data.Release()
|
||||
}
|
||||
|
||||
func (p *pather) begin(sizes []image.Point) {
|
||||
@@ -239,26 +226,24 @@ func (p *pather) stencilPath(bounds image.Rectangle, offset f32.Point, uv image.
|
||||
}
|
||||
|
||||
func (s *stenciler) beginIntersect(sizes []image.Point) {
|
||||
s.ctx.ActiveTexture(gl.TEXTURE1)
|
||||
s.ctx.BindTexture(gl.TEXTURE_2D, gl.Texture{})
|
||||
s.ctx.ActiveTexture(gl.TEXTURE0)
|
||||
s.ctx.BlendFunc(gl.DST_COLOR, gl.ZERO)
|
||||
s.ctx.NilTexture().Bind(1)
|
||||
s.ctx.BlendFunc(BlendFactorDstColor, BlendFactorZero)
|
||||
// 8 bit coverage is enough, but OpenGL ES only supports single channel
|
||||
// floating point formats. Replace with GL_RGB+GL_UNSIGNED_BYTE if
|
||||
// no floating point support is available.
|
||||
s.intersections.resize(s.ctx, sizes)
|
||||
s.ctx.ClearColor(1.0, 0.0, 0.0, 0.0)
|
||||
s.ctx.UseProgram(s.iprog)
|
||||
s.iprog.Bind()
|
||||
}
|
||||
|
||||
func (s *stenciler) endIntersect() {
|
||||
s.ctx.BindFramebuffer(gl.FRAMEBUFFER, s.defFBO)
|
||||
s.defFBO.Bind()
|
||||
}
|
||||
|
||||
func (s *stenciler) invalidateFBO() {
|
||||
s.intersections.invalidate(s.ctx)
|
||||
s.fbos.invalidate(s.ctx)
|
||||
s.ctx.BindFramebuffer(gl.FRAMEBUFFER, s.defFBO)
|
||||
s.defFBO.Bind()
|
||||
}
|
||||
|
||||
func (s *stenciler) cover(idx int) stencilFBO {
|
||||
@@ -266,31 +251,24 @@ func (s *stenciler) cover(idx int) stencilFBO {
|
||||
}
|
||||
|
||||
func (s *stenciler) begin(sizes []image.Point) {
|
||||
s.ctx.ActiveTexture(gl.TEXTURE1)
|
||||
s.ctx.BindTexture(gl.TEXTURE_2D, gl.Texture{})
|
||||
s.ctx.ActiveTexture(gl.TEXTURE0)
|
||||
s.ctx.BlendFunc(gl.ONE, gl.ONE)
|
||||
s.ctx.NilTexture().Bind(1)
|
||||
s.ctx.BlendFunc(BlendFactorOne, BlendFactorOne)
|
||||
s.fbos.resize(s.ctx, sizes)
|
||||
s.ctx.ClearColor(0.0, 0.0, 0.0, 0.0)
|
||||
s.ctx.UseProgram(s.prog)
|
||||
s.ctx.EnableVertexAttribArray(attribPathCorner)
|
||||
s.ctx.EnableVertexAttribArray(attribPathMaxY)
|
||||
s.ctx.EnableVertexAttribArray(attribPathFrom)
|
||||
s.ctx.EnableVertexAttribArray(attribPathCtrl)
|
||||
s.ctx.EnableVertexAttribArray(attribPathTo)
|
||||
s.ctx.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, s.indexBuf)
|
||||
s.prog.Bind()
|
||||
s.indexBuf.Bind()
|
||||
}
|
||||
|
||||
func (s *stenciler) stencilPath(bounds image.Rectangle, offset f32.Point, uv image.Point, data *pathData) {
|
||||
s.ctx.BindBuffer(gl.ARRAY_BUFFER, data.data)
|
||||
data.data.Bind()
|
||||
s.ctx.Viewport(uv.X, uv.Y, bounds.Dx(), bounds.Dy())
|
||||
// Transform UI coordinates to OpenGL coordinates.
|
||||
texSize := f32.Point{X: float32(bounds.Dx()), Y: float32(bounds.Dy())}
|
||||
scale := f32.Point{X: 2 / texSize.X, Y: 2 / texSize.Y}
|
||||
orig := f32.Point{X: -1 - float32(bounds.Min.X)*2/texSize.X, Y: -1 - float32(bounds.Min.Y)*2/texSize.Y}
|
||||
s.ctx.Uniform2f(s.uScale, scale.X, scale.Y)
|
||||
s.ctx.Uniform2f(s.uOffset, orig.X, orig.Y)
|
||||
s.ctx.Uniform2f(s.uPathOffset, offset.X, offset.Y)
|
||||
s.prog.Uniform2f(s.uScale, scale.X, scale.Y)
|
||||
s.prog.Uniform2f(s.uOffset, orig.X, orig.Y)
|
||||
s.prog.Uniform2f(s.uPathOffset, offset.X, offset.Y)
|
||||
// Draw in batches that fit in uint16 indices.
|
||||
start := 0
|
||||
nquads := data.ncurves / 4
|
||||
@@ -311,27 +289,22 @@ func (s *stenciler) stencilPath(bounds image.Rectangle, offset f32.Point, uv ima
|
||||
indices[i*6+4] = i*4 + 1
|
||||
indices[i*6+5] = i*4 + 3
|
||||
}
|
||||
s.ctx.BufferData(gl.ELEMENT_ARRAY_BUFFER, gl.BytesView(indices), gl.STATIC_DRAW)
|
||||
s.indexBuf.Upload(BufferUsageStaticDraw, gunsafe.BytesView(indices))
|
||||
s.indexBufQuads = batch
|
||||
}
|
||||
off := path.VertStride * start * 4
|
||||
s.ctx.VertexAttribPointer(attribPathCorner, 2, gl.SHORT, false, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).CornerX)))
|
||||
s.ctx.VertexAttribPointer(attribPathMaxY, 1, gl.FLOAT, false, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).MaxY)))
|
||||
s.ctx.VertexAttribPointer(attribPathFrom, 2, gl.FLOAT, false, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).FromX)))
|
||||
s.ctx.VertexAttribPointer(attribPathCtrl, 2, gl.FLOAT, false, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).CtrlX)))
|
||||
s.ctx.VertexAttribPointer(attribPathTo, 2, gl.FLOAT, false, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).ToX)))
|
||||
s.ctx.DrawElements(gl.TRIANGLES, batch*6, gl.UNSIGNED_SHORT, 0)
|
||||
s.ctx.SetupVertexArray(attribPathCorner, 2, DataTypeShort, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).CornerX)))
|
||||
s.ctx.SetupVertexArray(attribPathMaxY, 1, DataTypeFloat, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).MaxY)))
|
||||
s.ctx.SetupVertexArray(attribPathFrom, 2, DataTypeFloat, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).FromX)))
|
||||
s.ctx.SetupVertexArray(attribPathCtrl, 2, DataTypeFloat, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).CtrlX)))
|
||||
s.ctx.SetupVertexArray(attribPathTo, 2, DataTypeFloat, path.VertStride, off+int(unsafe.Offsetof((*(*path.Vertex)(nil)).ToX)))
|
||||
s.ctx.DrawElements(DrawModeTriangles, 0, batch*6)
|
||||
start += batch
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stenciler) end() {
|
||||
s.ctx.DisableVertexAttribArray(attribPathCorner)
|
||||
s.ctx.DisableVertexAttribArray(attribPathMaxY)
|
||||
s.ctx.DisableVertexAttribArray(attribPathFrom)
|
||||
s.ctx.DisableVertexAttribArray(attribPathCtrl)
|
||||
s.ctx.DisableVertexAttribArray(attribPathTo)
|
||||
s.ctx.BindFramebuffer(gl.FRAMEBUFFER, s.defFBO)
|
||||
s.defFBO.Bind()
|
||||
}
|
||||
|
||||
func (p *pather) cover(z float32, mat materialType, col [4]float32, scale, off, uvScale, uvOff, coverScale, coverOff f32.Point) {
|
||||
@@ -339,20 +312,21 @@ func (p *pather) cover(z float32, mat materialType, col [4]float32, scale, off,
|
||||
}
|
||||
|
||||
func (c *coverer) cover(z float32, mat materialType, col [4]float32, scale, off, uvScale, uvOff, coverScale, coverOff f32.Point) {
|
||||
c.ctx.UseProgram(c.prog[mat])
|
||||
p := c.prog[mat]
|
||||
p.Bind()
|
||||
switch mat {
|
||||
case materialColor:
|
||||
c.ctx.Uniform4f(c.vars[mat].uColor, col[0], col[1], col[2], col[3])
|
||||
p.Uniform4f(c.vars[mat].uColor, col[0], col[1], col[2], col[3])
|
||||
case materialTexture:
|
||||
c.ctx.Uniform2f(c.vars[mat].uUVScale, uvScale.X, uvScale.Y)
|
||||
c.ctx.Uniform2f(c.vars[mat].uUVOffset, uvOff.X, uvOff.Y)
|
||||
p.Uniform2f(c.vars[mat].uUVScale, uvScale.X, uvScale.Y)
|
||||
p.Uniform2f(c.vars[mat].uUVOffset, uvOff.X, uvOff.Y)
|
||||
}
|
||||
c.ctx.Uniform1f(c.vars[mat].z, z)
|
||||
c.ctx.Uniform2f(c.vars[mat].uScale, scale.X, scale.Y)
|
||||
c.ctx.Uniform2f(c.vars[mat].uOffset, off.X, off.Y)
|
||||
c.ctx.Uniform2f(c.vars[mat].uCoverUVScale, coverScale.X, coverScale.Y)
|
||||
c.ctx.Uniform2f(c.vars[mat].uCoverUVOffset, coverOff.X, coverOff.Y)
|
||||
c.ctx.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
|
||||
p.Uniform1f(c.vars[mat].z, z)
|
||||
p.Uniform2f(c.vars[mat].uScale, scale.X, scale.Y)
|
||||
p.Uniform2f(c.vars[mat].uOffset, off.X, off.Y)
|
||||
p.Uniform2f(c.vars[mat].uCoverUVScale, coverScale.X, coverScale.Y)
|
||||
p.Uniform2f(c.vars[mat].uCoverUVOffset, coverOff.X, coverOff.Y)
|
||||
c.ctx.DrawArrays(DrawModeTriangleStrip, 0, 4)
|
||||
}
|
||||
|
||||
const stencilVSrc = `
|
||||
|
||||
Reference in New Issue
Block a user