offscreen backend now has its own type, can be used as image when drawing images
This commit is contained in:
parent
122488e64c
commit
9c3cccabdd
9 changed files with 176 additions and 94 deletions
|
@ -26,6 +26,9 @@ type Backend interface {
|
||||||
|
|
||||||
GetImageData(x, y, w, h int) *image.RGBA
|
GetImageData(x, y, w, h int) *image.RGBA
|
||||||
PutImageData(img *image.RGBA, x, y int)
|
PutImageData(img *image.RGBA, x, y int)
|
||||||
|
|
||||||
|
CanUseAsImage(b Backend) bool
|
||||||
|
AsImage() Image // can return nil if not supported
|
||||||
}
|
}
|
||||||
|
|
||||||
// FillStyle is the color and other details on how to fill
|
// FillStyle is the color and other details on how to fill
|
||||||
|
|
|
@ -42,11 +42,10 @@ type GoGLBackend struct {
|
||||||
|
|
||||||
ptsBuf []float32
|
ptsBuf []float32
|
||||||
|
|
||||||
offscreen bool
|
|
||||||
offscrBuf offscreenBuffer
|
|
||||||
offscrImg Image
|
|
||||||
|
|
||||||
glChan chan func()
|
glChan chan func()
|
||||||
|
|
||||||
|
activateFn func()
|
||||||
|
disableTextureRenderTarget func()
|
||||||
}
|
}
|
||||||
|
|
||||||
type offscreenBuffer struct {
|
type offscreenBuffer struct {
|
||||||
|
@ -70,6 +69,7 @@ func New(x, y, w, h int) (*GoGLBackend, error) {
|
||||||
fw: float64(w),
|
fw: float64(w),
|
||||||
fh: float64(h),
|
fh: float64(h),
|
||||||
ptsBuf: make([]float32, 0, 4096),
|
ptsBuf: make([]float32, 0, 4096),
|
||||||
|
glChan: make(chan func()),
|
||||||
}
|
}
|
||||||
|
|
||||||
gl.GetError() // clear error state
|
gl.GetError() // clear error state
|
||||||
|
@ -211,26 +211,54 @@ func New(x, y, w, h int) (*GoGLBackend, error) {
|
||||||
|
|
||||||
gl.Disable(gl.SCISSOR_TEST)
|
gl.Disable(gl.SCISSOR_TEST)
|
||||||
|
|
||||||
|
b.activateFn = func() {
|
||||||
|
gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
|
||||||
|
gl.Viewport(int32(b.x), int32(b.y), int32(b.w), int32(b.h))
|
||||||
|
}
|
||||||
|
b.disableTextureRenderTarget = func() {
|
||||||
|
gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
|
||||||
|
}
|
||||||
|
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOffscreen(w, h int, alpha bool) (*GoGLBackend, error) {
|
type GoGLBackendOffscreen struct {
|
||||||
|
GoGLBackend
|
||||||
|
|
||||||
|
offscrBuf offscreenBuffer
|
||||||
|
offscrImg Image
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOffscreen(w, h int, alpha bool) (*GoGLBackendOffscreen, error) {
|
||||||
b, err := New(0, 0, w, h)
|
b, err := New(0, 0, w, h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
b.offscreen = true
|
bo := &GoGLBackendOffscreen{}
|
||||||
b.offscrBuf.alpha = alpha
|
bo.offscrBuf.alpha = alpha
|
||||||
return b, nil
|
|
||||||
|
b.activateFn = func() {
|
||||||
|
b.enableTextureRenderTarget(&bo.offscrBuf)
|
||||||
|
gl.Viewport(0, 0, int32(b.w), int32(b.h))
|
||||||
|
bo.offscrImg.w = bo.offscrBuf.w
|
||||||
|
bo.offscrImg.h = bo.offscrBuf.h
|
||||||
|
bo.offscrImg.tex = bo.offscrBuf.tex
|
||||||
|
bo.offscrImg.flip = true
|
||||||
|
}
|
||||||
|
b.disableTextureRenderTarget = func() {
|
||||||
|
b.enableTextureRenderTarget(&bo.offscrBuf)
|
||||||
|
}
|
||||||
|
|
||||||
|
bo.GoGLBackend = *b
|
||||||
|
|
||||||
|
return bo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetBounds updates the bounds of the canvas. This would
|
// SetBounds updates the bounds of the canvas. This would
|
||||||
// usually be called for example when the window is resized
|
// usually be called for example when the window is resized
|
||||||
func (b *GoGLBackend) SetBounds(x, y, w, h int) {
|
func (b *GoGLBackend) SetBounds(x, y, w, h int) {
|
||||||
if !b.offscreen {
|
|
||||||
b.x, b.y = x, y
|
b.x, b.y = x, y
|
||||||
b.fx, b.fy = float64(x), float64(y)
|
b.fx, b.fy = float64(x), float64(y)
|
||||||
}
|
|
||||||
b.w, b.h = w, h
|
b.w, b.h = w, h
|
||||||
b.fw, b.fh = float64(w), float64(h)
|
b.fw, b.fh = float64(w), float64(h)
|
||||||
if b == activeContext {
|
if b == activeContext {
|
||||||
|
@ -239,6 +267,11 @@ func (b *GoGLBackend) SetBounds(x, y, w, h int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetBounds updates the size of the offscreen texture
|
||||||
|
func (b *GoGLBackendOffscreen) SetBounds(w, h int) {
|
||||||
|
b.GoGLBackend.SetBounds(0, 0, w, h)
|
||||||
|
}
|
||||||
|
|
||||||
func (b *GoGLBackend) Size() (int, int) {
|
func (b *GoGLBackend) Size() (int, int) {
|
||||||
return b.w, b.h
|
return b.w, b.h
|
||||||
}
|
}
|
||||||
|
@ -256,39 +289,39 @@ var activeContext *GoGLBackend
|
||||||
func (b *GoGLBackend) activate() {
|
func (b *GoGLBackend) activate() {
|
||||||
if activeContext != b {
|
if activeContext != b {
|
||||||
activeContext = b
|
activeContext = b
|
||||||
if b.offscreen {
|
b.activateFn()
|
||||||
gl.Viewport(0, 0, int32(b.w), int32(b.h))
|
|
||||||
b.enableTextureRenderTarget(&b.offscrBuf)
|
|
||||||
b.offscrImg.w = b.offscrBuf.w
|
|
||||||
b.offscrImg.h = b.offscrBuf.h
|
|
||||||
b.offscrImg.tex = b.offscrBuf.tex
|
|
||||||
} else {
|
|
||||||
gl.Viewport(int32(b.x), int32(b.y), int32(b.w), int32(b.h))
|
|
||||||
b.disableTextureRenderTarget()
|
|
||||||
}
|
}
|
||||||
|
b.runGLQueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
loop:
|
func (b *GoGLBackend) runGLQueue() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case f := <-b.glChan:
|
case f := <-b.glChan:
|
||||||
f()
|
f()
|
||||||
default:
|
default:
|
||||||
break loop
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *GoGLBackend) DeleteOffscreen() {
|
func (b *GoGLBackendOffscreen) Delete() {
|
||||||
if !b.offscreen {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
gl.DeleteTextures(1, &b.offscrBuf.tex)
|
gl.DeleteTextures(1, &b.offscrBuf.tex)
|
||||||
gl.DeleteFramebuffers(1, &b.offscrBuf.frameBuf)
|
gl.DeleteFramebuffers(1, &b.offscrBuf.frameBuf)
|
||||||
gl.DeleteRenderbuffers(1, &b.offscrBuf.renderStencilBuf)
|
gl.DeleteRenderbuffers(1, &b.offscrBuf.renderStencilBuf)
|
||||||
b.offscreen = false
|
}
|
||||||
|
|
||||||
b.activate()
|
func (b *GoGLBackend) CanUseAsImage(b2 backendbase.Backend) bool {
|
||||||
|
_, ok := b2.(*GoGLBackendOffscreen)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *GoGLBackend) AsImage() backendbase.Image {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *GoGLBackendOffscreen) AsImage() backendbase.Image {
|
||||||
|
return &b.offscrImg
|
||||||
}
|
}
|
||||||
|
|
||||||
type glColor struct {
|
type glColor struct {
|
||||||
|
@ -463,14 +496,6 @@ func (b *GoGLBackend) enableTextureRenderTarget(offscr *offscreenBuffer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *GoGLBackend) disableTextureRenderTarget() {
|
|
||||||
if b.offscreen {
|
|
||||||
b.enableTextureRenderTarget(&b.offscrBuf)
|
|
||||||
} else {
|
|
||||||
gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type vec [2]float64
|
type vec [2]float64
|
||||||
|
|
||||||
func (v1 vec) sub(v2 vec) vec {
|
func (v1 vec) sub(v2 vec) vec {
|
||||||
|
|
|
@ -17,6 +17,7 @@ type Image struct {
|
||||||
tex uint32
|
tex uint32
|
||||||
deleted bool
|
deleted bool
|
||||||
opaque bool
|
opaque bool
|
||||||
|
flip bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *GoGLBackend) LoadImage(src image.Image) (backendbase.Image, error) {
|
func (b *GoGLBackend) LoadImage(src image.Image) (backendbase.Image, error) {
|
||||||
|
@ -34,6 +35,7 @@ func (b *GoGLBackend) LoadImage(src image.Image) (backendbase.Image, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
img.b = b
|
||||||
|
|
||||||
runtime.SetFinalizer(img, func(img *Image) {
|
runtime.SetFinalizer(img, func(img *Image) {
|
||||||
if !img.deleted {
|
if !img.deleted {
|
||||||
|
@ -207,6 +209,7 @@ func (img *Image) Replace(src image.Image) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
newImg.b = img.b
|
||||||
*img = *newImg
|
*img = *newImg
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -225,6 +228,11 @@ func (b *GoGLBackend) DrawImage(dimg backendbase.Image, sx, sy, sw, sh float64,
|
||||||
sw /= float64(img.w)
|
sw /= float64(img.w)
|
||||||
sh /= float64(img.h)
|
sh /= float64(img.h)
|
||||||
|
|
||||||
|
if img.flip {
|
||||||
|
sy += sh
|
||||||
|
sh = -sh
|
||||||
|
}
|
||||||
|
|
||||||
var buf [16]float32
|
var buf [16]float32
|
||||||
data := buf[:0]
|
data := buf[:0]
|
||||||
for _, pt := range pts {
|
for _, pt := range pts {
|
||||||
|
|
|
@ -252,8 +252,8 @@ func rewriteMain(src string) string {
|
||||||
"type XMobileBackend struct {\n\tglctx gl.Context\n\n", 1)
|
"type XMobileBackend struct {\n\tglctx gl.Context\n\n", 1)
|
||||||
src = strings.Replace(src, "func New(x, y, w, h int) (*XMobileBackend, error) {",
|
src = strings.Replace(src, "func New(x, y, w, h int) (*XMobileBackend, error) {",
|
||||||
"func New(glctx gl.Context, x, y, w, h int) (*XMobileBackend, error) {", 1)
|
"func New(glctx gl.Context, x, y, w, h int) (*XMobileBackend, error) {", 1)
|
||||||
src = strings.Replace(src, "func NewOffscreen(w, h int, alpha bool) (*XMobileBackend, error)",
|
src = strings.Replace(src, "func NewOffscreen(w, h int, alpha bool) (*XMobileBackendOffscreen, error)",
|
||||||
"func NewOffscreen(glctx gl.Context, w, h int, alpha bool) (*XMobileBackend, error)", 1)
|
"func NewOffscreen(glctx gl.Context, w, h int, alpha bool) (*XMobileBackendOffscreen, error)", 1)
|
||||||
|
|
||||||
src = rewriteCalls(src, "New", func(params []string) string {
|
src = rewriteCalls(src, "New", func(params []string) string {
|
||||||
return "New(glctx, " + strings.Join(params, ", ") + ")"
|
return "New(glctx, " + strings.Join(params, ", ") + ")"
|
||||||
|
|
|
@ -17,6 +17,7 @@ type Image struct {
|
||||||
tex gl.Texture
|
tex gl.Texture
|
||||||
deleted bool
|
deleted bool
|
||||||
opaque bool
|
opaque bool
|
||||||
|
flip bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *XMobileBackend) LoadImage(src image.Image) (backendbase.Image, error) {
|
func (b *XMobileBackend) LoadImage(src image.Image) (backendbase.Image, error) {
|
||||||
|
@ -34,6 +35,7 @@ func (b *XMobileBackend) LoadImage(src image.Image) (backendbase.Image, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
img.b = b
|
||||||
|
|
||||||
runtime.SetFinalizer(img, func(img *Image) {
|
runtime.SetFinalizer(img, func(img *Image) {
|
||||||
if !img.deleted {
|
if !img.deleted {
|
||||||
|
@ -209,6 +211,7 @@ func (img *Image) Replace(src image.Image) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
newImg.b = img.b
|
||||||
*img = *newImg
|
*img = *newImg
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -227,6 +230,11 @@ func (b *XMobileBackend) DrawImage(dimg backendbase.Image, sx, sy, sw, sh float6
|
||||||
sw /= float64(img.w)
|
sw /= float64(img.w)
|
||||||
sh /= float64(img.h)
|
sh /= float64(img.h)
|
||||||
|
|
||||||
|
if img.flip {
|
||||||
|
sy += sh
|
||||||
|
sh = -sh
|
||||||
|
}
|
||||||
|
|
||||||
var buf [16]float32
|
var buf [16]float32
|
||||||
data := buf[:0]
|
data := buf[:0]
|
||||||
for _, pt := range pts {
|
for _, pt := range pts {
|
||||||
|
|
|
@ -46,11 +46,10 @@ type XMobileBackend struct {
|
||||||
|
|
||||||
ptsBuf []float32
|
ptsBuf []float32
|
||||||
|
|
||||||
offscreen bool
|
|
||||||
offscrBuf offscreenBuffer
|
|
||||||
offscrImg Image
|
|
||||||
|
|
||||||
glChan chan func()
|
glChan chan func()
|
||||||
|
|
||||||
|
activateFn func()
|
||||||
|
disableTextureRenderTarget func()
|
||||||
}
|
}
|
||||||
|
|
||||||
type offscreenBuffer struct {
|
type offscreenBuffer struct {
|
||||||
|
@ -73,6 +72,7 @@ func New(glctx gl.Context, x, y, w, h int) (*XMobileBackend, error) {
|
||||||
fw: float64(w),
|
fw: float64(w),
|
||||||
fh: float64(h),
|
fh: float64(h),
|
||||||
ptsBuf: make([]float32, 0, 4096),
|
ptsBuf: make([]float32, 0, 4096),
|
||||||
|
glChan: make(chan func()),
|
||||||
}
|
}
|
||||||
|
|
||||||
b.glctx.GetError() // clear error state
|
b.glctx.GetError() // clear error state
|
||||||
|
@ -214,26 +214,54 @@ func New(glctx gl.Context, x, y, w, h int) (*XMobileBackend, error) {
|
||||||
|
|
||||||
b.glctx.Disable(gl.SCISSOR_TEST)
|
b.glctx.Disable(gl.SCISSOR_TEST)
|
||||||
|
|
||||||
|
b.activateFn = func() {
|
||||||
|
b.glctx.BindFramebuffer(gl.FRAMEBUFFER, gl.Framebuffer{Value: 0})
|
||||||
|
b.glctx.Viewport(b.x, b.y, b.w, b.h)
|
||||||
|
}
|
||||||
|
b.disableTextureRenderTarget = func() {
|
||||||
|
b.glctx.BindFramebuffer(gl.FRAMEBUFFER, gl.Framebuffer{Value: 0})
|
||||||
|
}
|
||||||
|
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOffscreen(glctx gl.Context, w, h int, alpha bool) (*XMobileBackend, error) {
|
type XMobileBackendOffscreen struct {
|
||||||
|
XMobileBackend
|
||||||
|
|
||||||
|
offscrBuf offscreenBuffer
|
||||||
|
offscrImg Image
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOffscreen(glctx gl.Context, w, h int, alpha bool) (*XMobileBackendOffscreen, error) {
|
||||||
b, err := New(glctx, 0, 0, w, h)
|
b, err := New(glctx, 0, 0, w, h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
b.offscreen = true
|
bo := &XMobileBackendOffscreen{}
|
||||||
b.offscrBuf.alpha = alpha
|
bo.offscrBuf.alpha = alpha
|
||||||
return b, nil
|
|
||||||
|
b.activateFn = func() {
|
||||||
|
b.enableTextureRenderTarget(&bo.offscrBuf)
|
||||||
|
b.glctx.Viewport(0, 0, b.w, b.h)
|
||||||
|
bo.offscrImg.w = bo.offscrBuf.w
|
||||||
|
bo.offscrImg.h = bo.offscrBuf.h
|
||||||
|
bo.offscrImg.tex = bo.offscrBuf.tex
|
||||||
|
bo.offscrImg.flip = true
|
||||||
|
}
|
||||||
|
b.disableTextureRenderTarget = func() {
|
||||||
|
b.enableTextureRenderTarget(&bo.offscrBuf)
|
||||||
|
}
|
||||||
|
|
||||||
|
bo.XMobileBackend = *b
|
||||||
|
|
||||||
|
return bo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetBounds updates the bounds of the canvas. This would
|
// SetBounds updates the bounds of the canvas. This would
|
||||||
// usually be called for example when the window is resized
|
// usually be called for example when the window is resized
|
||||||
func (b *XMobileBackend) SetBounds(x, y, w, h int) {
|
func (b *XMobileBackend) SetBounds(x, y, w, h int) {
|
||||||
if !b.offscreen {
|
|
||||||
b.x, b.y = x, y
|
b.x, b.y = x, y
|
||||||
b.fx, b.fy = float64(x), float64(y)
|
b.fx, b.fy = float64(x), float64(y)
|
||||||
}
|
|
||||||
b.w, b.h = w, h
|
b.w, b.h = w, h
|
||||||
b.fw, b.fh = float64(w), float64(h)
|
b.fw, b.fh = float64(w), float64(h)
|
||||||
if b == activeContext {
|
if b == activeContext {
|
||||||
|
@ -242,6 +270,11 @@ func (b *XMobileBackend) SetBounds(x, y, w, h int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetBounds updates the size of the offscreen texture
|
||||||
|
func (b *XMobileBackendOffscreen) SetBounds(w, h int) {
|
||||||
|
b.XMobileBackend.SetBounds(0, 0, w, h)
|
||||||
|
}
|
||||||
|
|
||||||
func (b *XMobileBackend) Size() (int, int) {
|
func (b *XMobileBackend) Size() (int, int) {
|
||||||
return b.w, b.h
|
return b.w, b.h
|
||||||
}
|
}
|
||||||
|
@ -259,39 +292,39 @@ var activeContext *XMobileBackend
|
||||||
func (b *XMobileBackend) activate() {
|
func (b *XMobileBackend) activate() {
|
||||||
if activeContext != b {
|
if activeContext != b {
|
||||||
activeContext = b
|
activeContext = b
|
||||||
if b.offscreen {
|
b.activateFn()
|
||||||
b.glctx.Viewport(0, 0, b.w, b.h)
|
|
||||||
b.enableTextureRenderTarget(&b.offscrBuf)
|
|
||||||
b.offscrImg.w = b.offscrBuf.w
|
|
||||||
b.offscrImg.h = b.offscrBuf.h
|
|
||||||
b.offscrImg.tex = b.offscrBuf.tex
|
|
||||||
} else {
|
|
||||||
b.glctx.Viewport(b.x, b.y, b.w, b.h)
|
|
||||||
b.disableTextureRenderTarget()
|
|
||||||
}
|
}
|
||||||
|
b.runGLQueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
loop:
|
func (b *XMobileBackend) runGLQueue() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case f := <-b.glChan:
|
case f := <-b.glChan:
|
||||||
f()
|
f()
|
||||||
default:
|
default:
|
||||||
break loop
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *XMobileBackend) DeleteOffscreen() {
|
func (b *XMobileBackendOffscreen) Delete() {
|
||||||
if !b.offscreen {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b.glctx.DeleteTexture(b.offscrBuf.tex)
|
b.glctx.DeleteTexture(b.offscrBuf.tex)
|
||||||
b.glctx.DeleteFramebuffer(b.offscrBuf.frameBuf)
|
b.glctx.DeleteFramebuffer(b.offscrBuf.frameBuf)
|
||||||
b.glctx.DeleteRenderbuffer(b.offscrBuf.renderStencilBuf)
|
b.glctx.DeleteRenderbuffer(b.offscrBuf.renderStencilBuf)
|
||||||
b.offscreen = false
|
}
|
||||||
|
|
||||||
b.activate()
|
func (b *XMobileBackend) CanUseAsImage(b2 backendbase.Backend) bool {
|
||||||
|
_, ok := b2.(*XMobileBackendOffscreen)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *XMobileBackend) AsImage() backendbase.Image {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *XMobileBackendOffscreen) AsImage() backendbase.Image {
|
||||||
|
return &b.offscrImg
|
||||||
}
|
}
|
||||||
|
|
||||||
type glColor struct {
|
type glColor struct {
|
||||||
|
@ -466,14 +499,6 @@ func (b *XMobileBackend) enableTextureRenderTarget(offscr *offscreenBuffer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *XMobileBackend) disableTextureRenderTarget() {
|
|
||||||
if b.offscreen {
|
|
||||||
b.enableTextureRenderTarget(&b.offscrBuf)
|
|
||||||
} else {
|
|
||||||
b.glctx.BindFramebuffer(gl.FRAMEBUFFER, gl.Framebuffer{Value: 0})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type vec [2]float64
|
type vec [2]float64
|
||||||
|
|
||||||
func (v1 vec) sub(v2 vec) vec {
|
func (v1 vec) sub(v2 vec) vec {
|
||||||
|
|
22
canvas.go
22
canvas.go
|
@ -20,9 +20,6 @@ import (
|
||||||
type Canvas struct {
|
type Canvas struct {
|
||||||
b backendbase.Backend
|
b backendbase.Backend
|
||||||
|
|
||||||
w, h int
|
|
||||||
fw, fh float64
|
|
||||||
|
|
||||||
path Path2D
|
path Path2D
|
||||||
convex bool
|
convex bool
|
||||||
rect bool
|
rect bool
|
||||||
|
@ -138,8 +135,6 @@ func New(backend backendbase.Backend) *Canvas {
|
||||||
stateStack: make([]drawState, 0, 20),
|
stateStack: make([]drawState, 0, 20),
|
||||||
images: make(map[interface{}]*Image),
|
images: make(map[interface{}]*Image),
|
||||||
}
|
}
|
||||||
w, h := backend.Size()
|
|
||||||
cv.setBounds(w, h)
|
|
||||||
cv.state.lineWidth = 1
|
cv.state.lineWidth = 1
|
||||||
cv.state.lineAlpha = 1
|
cv.state.lineAlpha = 1
|
||||||
cv.state.miterLimitSqr = 100
|
cv.state.miterLimitSqr = 100
|
||||||
|
@ -150,19 +145,20 @@ func New(backend backendbase.Backend) *Canvas {
|
||||||
return cv
|
return cv
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cv *Canvas) setBounds(w, h int) {
|
// Width returns the internal width of the canvas
|
||||||
cv.w, cv.h = w, h
|
func (cv *Canvas) Width() int {
|
||||||
cv.fw, cv.fh = float64(w), float64(h)
|
w, _ := cv.b.Size()
|
||||||
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
// Width returns the internal width of the canvas
|
|
||||||
func (cv *Canvas) Width() int { return cv.w }
|
|
||||||
|
|
||||||
// Height returns the internal height of the canvas
|
// Height returns the internal height of the canvas
|
||||||
func (cv *Canvas) Height() int { return cv.h }
|
func (cv *Canvas) Height() int {
|
||||||
|
_, h := cv.b.Size()
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
// Size returns the internal width and height of the canvas
|
// Size returns the internal width and height of the canvas
|
||||||
func (cv *Canvas) Size() (int, int) { return cv.w, cv.h }
|
func (cv *Canvas) Size() (int, int) { return cv.b.Size() }
|
||||||
|
|
||||||
func (cv *Canvas) tf(v vec) vec {
|
func (cv *Canvas) tf(v vec) vec {
|
||||||
v, _ = v.mulMat(cv.state.transform)
|
v, _ = v.mulMat(cv.state.transform)
|
||||||
|
|
16
images.go
16
images.go
|
@ -42,7 +42,8 @@ func (cv *Canvas) LoadImage(src interface{}) (*Image, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case *Canvas:
|
case *Canvas:
|
||||||
src = cv.GetImageData(0, 0, cv.Width(), cv.Height())
|
w, h := cv.b.Size()
|
||||||
|
src = cv.GetImageData(0, 0, w, h)
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("Unsupported source type")
|
return nil, errors.New("Unsupported source type")
|
||||||
}
|
}
|
||||||
|
@ -82,6 +83,19 @@ func (cv *Canvas) getImage(src interface{}) *Image {
|
||||||
}
|
}
|
||||||
cv.images[v] = img
|
cv.images[v] = img
|
||||||
return img
|
return img
|
||||||
|
case *Canvas:
|
||||||
|
if !cv.b.CanUseAsImage(v.b) {
|
||||||
|
w, h := v.Size()
|
||||||
|
return cv.getImage(v.GetImageData(0, 0, w, h))
|
||||||
|
}
|
||||||
|
bimg := v.b.AsImage()
|
||||||
|
if bimg == nil {
|
||||||
|
w, h := v.Size()
|
||||||
|
return cv.getImage(v.GetImageData(0, 0, w, h))
|
||||||
|
}
|
||||||
|
img := &Image{cv: cv, img: bimg}
|
||||||
|
cv.images[v] = img
|
||||||
|
return img
|
||||||
}
|
}
|
||||||
fmt.Fprintf(os.Stderr, "Unknown image type: %T\n", src)
|
fmt.Fprintf(os.Stderr, "Unknown image type: %T\n", src)
|
||||||
cv.images[src] = nil
|
cv.images[src] = nil
|
||||||
|
|
7
text.go
7
text.go
|
@ -96,14 +96,17 @@ func (cv *Canvas) FillText(str string, x, y float64) {
|
||||||
curX += float64(kern) / 64
|
curX += float64(kern) / 64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w, h := cv.b.Size()
|
||||||
|
fw, fh := float64(w), float64(h)
|
||||||
|
|
||||||
p0 := cv.tf(vec{float64(bounds.Min.X) + curX, float64(bounds.Min.Y) + y})
|
p0 := cv.tf(vec{float64(bounds.Min.X) + curX, float64(bounds.Min.Y) + y})
|
||||||
p1 := cv.tf(vec{float64(bounds.Min.X) + curX, float64(bounds.Max.Y) + y})
|
p1 := cv.tf(vec{float64(bounds.Min.X) + curX, float64(bounds.Max.Y) + y})
|
||||||
p2 := cv.tf(vec{float64(bounds.Max.X) + curX, float64(bounds.Max.Y) + y})
|
p2 := cv.tf(vec{float64(bounds.Max.X) + curX, float64(bounds.Max.Y) + y})
|
||||||
p3 := cv.tf(vec{float64(bounds.Max.X) + curX, float64(bounds.Min.Y) + y})
|
p3 := cv.tf(vec{float64(bounds.Max.X) + curX, float64(bounds.Min.Y) + y})
|
||||||
inside := (p0[0] >= 0 || p1[0] >= 0 || p2[0] >= 0 || p3[0] >= 0) &&
|
inside := (p0[0] >= 0 || p1[0] >= 0 || p2[0] >= 0 || p3[0] >= 0) &&
|
||||||
(p0[1] >= 0 || p1[1] >= 0 || p2[1] >= 0 || p3[1] >= 0) &&
|
(p0[1] >= 0 || p1[1] >= 0 || p2[1] >= 0 || p3[1] >= 0) &&
|
||||||
(p0[0] < cv.fw || p1[0] < cv.fw || p2[0] < cv.fw || p3[0] < cv.fw) &&
|
(p0[0] < fw || p1[0] < fw || p2[0] < fw || p3[0] < fw) &&
|
||||||
(p0[1] < cv.fh || p1[1] < cv.fh || p2[1] < cv.fh || p3[1] < cv.fh)
|
(p0[1] < fh || p1[1] < fh || p2[1] < fh || p3[1] < fh)
|
||||||
|
|
||||||
if !curInside && inside {
|
if !curInside && inside {
|
||||||
curInside = true
|
curInside = true
|
||||||
|
|
Loading…
Reference in a new issue