mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
internal/ui: refactoring: add ui.SetError
This is a preparation to move uiContext to the package internal/ui.
This commit is contained in:
parent
2c68124f0e
commit
b282b1805b
7
image.go
7
image.go
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/mipmap"
|
"github.com/hajimehoshi/ebiten/v2/internal/mipmap"
|
||||||
|
"github.com/hajimehoshi/ebiten/v2/internal/ui"
|
||||||
)
|
)
|
||||||
|
|
||||||
// panicOnErrorAtImageAt indicates whether (*Image).At panics on an error or not.
|
// panicOnErrorAtImageAt indicates whether (*Image).At panics on an error or not.
|
||||||
@ -718,7 +719,7 @@ func (i *Image) at(x, y int) (r, g, b, a uint8) {
|
|||||||
if panicOnErrorAtImageAt {
|
if panicOnErrorAtImageAt {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
theUIContext.setError(err)
|
ui.SetError(err)
|
||||||
return 0, 0, 0, 0
|
return 0, 0, 0, 0
|
||||||
}
|
}
|
||||||
return pix[0], pix[1], pix[2], pix[3]
|
return pix[0], pix[1], pix[2], pix[3]
|
||||||
@ -746,7 +747,7 @@ func (i *Image) Set(x, y int, clr color.Color) {
|
|||||||
r, g, b, a := clr.RGBA()
|
r, g, b, a := clr.RGBA()
|
||||||
pix := []byte{byte(r >> 8), byte(g >> 8), byte(b >> 8), byte(a >> 8)}
|
pix := []byte{byte(r >> 8), byte(g >> 8), byte(b >> 8), byte(a >> 8)}
|
||||||
if err := i.mipmap.ReplacePixels(pix, x, y, 1, 1); err != nil {
|
if err := i.mipmap.ReplacePixels(pix, x, y, 1, 1); err != nil {
|
||||||
theUIContext.setError(err)
|
ui.SetError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,7 +795,7 @@ func (i *Image) ReplacePixels(pixels []byte) {
|
|||||||
// * In internal/mipmap, pixels are copied when necessary.
|
// * In internal/mipmap, pixels are copied when necessary.
|
||||||
// * In internal/shareable, pixels are copied to make its paddings.
|
// * In internal/shareable, pixels are copied to make its paddings.
|
||||||
if err := i.mipmap.ReplacePixels(pixels, r.Min.X, r.Min.Y, r.Dx(), r.Dy()); err != nil {
|
if err := i.mipmap.ReplacePixels(pixels, r.Min.X, r.Min.Y, r.Dx(), r.Dy()); err != nil {
|
||||||
theUIContext.setError(err)
|
ui.SetError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
70
internal/ui/context.go
Normal file
70
internal/ui/context.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 2022 The Ebiten Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Context interface {
|
||||||
|
UpdateFrame() error
|
||||||
|
ForceUpdateFrame() error
|
||||||
|
Layout(outsideWidth, outsideHeight float64)
|
||||||
|
|
||||||
|
// AdjustPosition can be called from a different goroutine from Update's or Layout's.
|
||||||
|
AdjustPosition(x, y float64, deviceScaleFactor float64) (float64, float64)
|
||||||
|
}
|
||||||
|
|
||||||
|
type contextImpl struct {
|
||||||
|
context Context
|
||||||
|
|
||||||
|
err atomic.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *contextImpl) updateFrame() error {
|
||||||
|
if err, ok := c.err.Load().(error); ok && err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.context.UpdateFrame()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *contextImpl) forceUpdateFrame() error {
|
||||||
|
if err, ok := c.err.Load().(error); ok && err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.context.ForceUpdateFrame()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *contextImpl) layout(outsideWidth, outsideHeight float64) {
|
||||||
|
// The given outside size can be 0 e.g. just after restoring from the fullscreen mode on Windows (#1589)
|
||||||
|
// Just ignore such cases. Otherwise, creating a zero-sized framebuffer causes a panic.
|
||||||
|
if outsideWidth == 0 || outsideHeight == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.context.Layout(outsideWidth, outsideHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *contextImpl) adjustPosition(x, y float64, deviceScaleFactor float64) (float64, float64) {
|
||||||
|
return c.context.AdjustPosition(x, y, deviceScaleFactor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *contextImpl) setError(err error) {
|
||||||
|
c.err.Store(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetError(err error) {
|
||||||
|
Get().context.setError(err)
|
||||||
|
}
|
@ -31,7 +31,7 @@ type Input struct {
|
|||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Input) update(context Context) {
|
func (i *Input) update(context *contextImpl) {
|
||||||
i.m.Lock()
|
i.m.Lock()
|
||||||
defer i.m.Unlock()
|
defer i.m.Unlock()
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ func (i *Input) update(context Context) {
|
|||||||
i.touches = cbackend.AppendTouches(i.touches)
|
i.touches = cbackend.AppendTouches(i.touches)
|
||||||
|
|
||||||
for idx, t := range i.touches {
|
for idx, t := range i.touches {
|
||||||
x, y := context.AdjustPosition(float64(t.X), float64(t.Y), deviceScaleFactor)
|
x, y := context.adjustPosition(float64(t.X), float64(t.Y), deviceScaleFactor)
|
||||||
i.touches[idx].X = int(x)
|
i.touches[idx].X = int(x)
|
||||||
i.touches[idx].Y = int(y)
|
i.touches[idx].Y = int(y)
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ var glfwMouseButtonToMouseButton = map[glfw.MouseButton]MouseButton{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update must be called from the main thread.
|
// update must be called from the main thread.
|
||||||
func (i *Input) update(window *glfw.Window, context Context) error {
|
func (i *Input) update(window *glfw.Window, context *contextImpl) error {
|
||||||
i.ui.m.Lock()
|
i.ui.m.Lock()
|
||||||
defer i.ui.m.Unlock()
|
defer i.ui.m.Unlock()
|
||||||
|
|
||||||
@ -196,7 +196,7 @@ func (i *Input) update(window *glfw.Window, context Context) error {
|
|||||||
s := i.ui.deviceScaleFactor(m)
|
s := i.ui.deviceScaleFactor(m)
|
||||||
cx = i.ui.dipFromGLFWPixel(cx, m)
|
cx = i.ui.dipFromGLFWPixel(cx, m)
|
||||||
cy = i.ui.dipFromGLFWPixel(cy, m)
|
cy = i.ui.dipFromGLFWPixel(cy, m)
|
||||||
cx, cy = context.AdjustPosition(cx, cy, s)
|
cx, cy = context.adjustPosition(cx, cy, s)
|
||||||
|
|
||||||
// AdjustPosition can return NaN at the initialization.
|
// AdjustPosition can return NaN at the initialization.
|
||||||
if !math.IsNaN(cx) && !math.IsNaN(cy) {
|
if !math.IsNaN(cx) && !math.IsNaN(cy) {
|
||||||
|
@ -75,7 +75,7 @@ func (i *Input) CursorPosition() (x, y int) {
|
|||||||
if i.ui.context == nil {
|
if i.ui.context == nil {
|
||||||
return 0, 0
|
return 0, 0
|
||||||
}
|
}
|
||||||
xf, yf := i.ui.context.AdjustPosition(float64(i.cursorX), float64(i.cursorY), i.ui.DeviceScaleFactor())
|
xf, yf := i.ui.context.adjustPosition(float64(i.cursorX), float64(i.cursorY), i.ui.DeviceScaleFactor())
|
||||||
return int(xf), int(yf)
|
return int(xf), int(yf)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ func (i *Input) TouchPosition(id TouchID) (x, y int) {
|
|||||||
d := i.ui.DeviceScaleFactor()
|
d := i.ui.DeviceScaleFactor()
|
||||||
for tid, pos := range i.touches {
|
for tid, pos := range i.touches {
|
||||||
if id == tid {
|
if id == tid {
|
||||||
x, y := i.ui.context.AdjustPosition(float64(pos.X), float64(pos.Y), d)
|
x, y := i.ui.context.adjustPosition(float64(pos.X), float64(pos.Y), d)
|
||||||
return int(x), int(y)
|
return int(x), int(y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (u *UserInterface) Run(uicontext Context) error {
|
func (u *UserInterface) Run(uicontext Context) error {
|
||||||
u.context = uicontext
|
u.context = &contextImpl{
|
||||||
|
context: uicontext,
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the main thread first so the thread is available at u.run (#809).
|
// Initialize the main thread first so the thread is available at u.run (#809).
|
||||||
u.t = thread.NewOSThread()
|
u.t = thread.NewOSThread()
|
||||||
|
@ -23,7 +23,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (u *UserInterface) Run(uicontext Context) error {
|
func (u *UserInterface) Run(uicontext Context) error {
|
||||||
u.context = uicontext
|
u.context = &contextImpl{
|
||||||
|
context: uicontext,
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the main thread first so the thread is available at u.run (#809).
|
// Initialize the main thread first so the thread is available at u.run (#809).
|
||||||
u.t = thread.NewNoopThread()
|
u.t = thread.NewNoopThread()
|
||||||
|
@ -20,15 +20,6 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Context interface {
|
|
||||||
UpdateFrame() error
|
|
||||||
ForceUpdateFrame() error
|
|
||||||
Layout(outsideWidth, outsideHeight float64)
|
|
||||||
|
|
||||||
// AdjustPosition can be called from a different goroutine from Update's or Layout's.
|
|
||||||
AdjustPosition(x, y float64, deviceScaleFactor float64) (float64, float64)
|
|
||||||
}
|
|
||||||
|
|
||||||
type MouseButton int
|
type MouseButton int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -30,7 +30,8 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UserInterface struct {
|
type UserInterface struct {
|
||||||
input Input
|
context *contextImpl
|
||||||
|
input Input
|
||||||
}
|
}
|
||||||
|
|
||||||
var theUserInterface UserInterface
|
var theUserInterface UserInterface
|
||||||
@ -40,15 +41,18 @@ func Get() *UserInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) Run(context Context) error {
|
func (u *UserInterface) Run(context Context) error {
|
||||||
|
u.context = &contextImpl{
|
||||||
|
context: context,
|
||||||
|
}
|
||||||
cbackend.InitializeGame()
|
cbackend.InitializeGame()
|
||||||
for {
|
for {
|
||||||
w, h := cbackend.ScreenSize()
|
w, h := cbackend.ScreenSize()
|
||||||
context.Layout(float64(w), float64(h))
|
u.context.layout(float64(w), float64(h))
|
||||||
|
|
||||||
cbackend.BeginFrame()
|
cbackend.BeginFrame()
|
||||||
u.input.update(context)
|
u.input.update(u.context)
|
||||||
|
|
||||||
if err := context.UpdateFrame(); err != nil {
|
if err := u.context.updateFrame(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ func driverCursorModeToGLFWCursorMode(mode CursorMode) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UserInterface struct {
|
type UserInterface struct {
|
||||||
context Context
|
context *contextImpl
|
||||||
title string
|
title string
|
||||||
window *glfw.Window
|
window *glfw.Window
|
||||||
|
|
||||||
@ -731,8 +731,8 @@ func (u *UserInterface) registerWindowSetSizeCallback() {
|
|||||||
|
|
||||||
outsideWidth, outsideHeight = u.updateSize()
|
outsideWidth, outsideHeight = u.updateSize()
|
||||||
})
|
})
|
||||||
u.context.Layout(outsideWidth, outsideHeight)
|
u.context.layout(outsideWidth, outsideHeight)
|
||||||
if err := u.context.ForceUpdateFrame(); err != nil {
|
if err := u.context.forceUpdateFrame(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if graphics().IsGL() {
|
if graphics().IsGL() {
|
||||||
@ -1042,9 +1042,9 @@ func (u *UserInterface) loop() error {
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
u.context.Layout(outsideWidth, outsideHeight)
|
u.context.layout(outsideWidth, outsideHeight)
|
||||||
|
|
||||||
if err := u.context.UpdateFrame(); err != nil {
|
if err := u.context.updateFrame(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1365,7 +1365,7 @@ func (u *UserInterface) ResetForFrame() {
|
|||||||
u.t.Call(func() {
|
u.t.Call(func() {
|
||||||
w, h = u.updateSize()
|
w, h = u.updateSize()
|
||||||
})
|
})
|
||||||
u.context.Layout(w, h)
|
u.context.layout(w, h)
|
||||||
u.input.resetForFrame()
|
u.input.resetForFrame()
|
||||||
|
|
||||||
u.m.Lock()
|
u.m.Lock()
|
||||||
|
@ -61,7 +61,7 @@ type UserInterface struct {
|
|||||||
|
|
||||||
lastDeviceScaleFactor float64
|
lastDeviceScaleFactor float64
|
||||||
|
|
||||||
context Context
|
context *contextImpl
|
||||||
input Input
|
input Input
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,14 +240,14 @@ func (u *UserInterface) updateSize() {
|
|||||||
body := document.Get("body")
|
body := document.Get("body")
|
||||||
bw := body.Get("clientWidth").Float()
|
bw := body.Get("clientWidth").Float()
|
||||||
bh := body.Get("clientHeight").Float()
|
bh := body.Get("clientHeight").Float()
|
||||||
u.context.Layout(bw, bh)
|
u.context.layout(bw, bh)
|
||||||
case go2cpp.Truthy():
|
case go2cpp.Truthy():
|
||||||
w := go2cpp.Get("screenWidth").Float()
|
w := go2cpp.Get("screenWidth").Float()
|
||||||
h := go2cpp.Get("screenHeight").Float()
|
h := go2cpp.Get("screenHeight").Float()
|
||||||
u.context.Layout(w, h)
|
u.context.layout(w, h)
|
||||||
default:
|
default:
|
||||||
// Node.js
|
// Node.js
|
||||||
u.context.Layout(640, 480)
|
u.context.layout(640, 480)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -293,11 +293,11 @@ func (u *UserInterface) updateImpl(force bool) error {
|
|||||||
u.input.updateForGo2Cpp()
|
u.input.updateForGo2Cpp()
|
||||||
u.updateSize()
|
u.updateSize()
|
||||||
if force {
|
if force {
|
||||||
if err := u.context.ForceUpdateFrame(); err != nil {
|
if err := u.context.forceUpdateFrame(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := u.context.UpdateFrame(); err != nil {
|
if err := u.context.updateFrame(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -319,7 +319,9 @@ func (u *UserInterface) needsUpdate() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) loop(context Context) <-chan error {
|
func (u *UserInterface) loop(context Context) <-chan error {
|
||||||
u.context = context
|
u.context = &contextImpl{
|
||||||
|
context: context,
|
||||||
|
}
|
||||||
|
|
||||||
errCh := make(chan error, 1)
|
errCh := make(chan error, 1)
|
||||||
reqStopAudioCh := make(chan struct{})
|
reqStopAudioCh := make(chan struct{})
|
||||||
|
@ -109,7 +109,7 @@ type UserInterface struct {
|
|||||||
setGBuildSizeCh chan struct{}
|
setGBuildSizeCh chan struct{}
|
||||||
once sync.Once
|
once sync.Once
|
||||||
|
|
||||||
context Context
|
context *contextImpl
|
||||||
|
|
||||||
input Input
|
input Input
|
||||||
|
|
||||||
@ -273,7 +273,9 @@ func (u *UserInterface) run(context Context, mainloop bool) (err error) {
|
|||||||
u.sizeChanged = true
|
u.sizeChanged = true
|
||||||
u.m.Unlock()
|
u.m.Unlock()
|
||||||
|
|
||||||
u.context = context
|
u.context = &contextImpl{
|
||||||
|
context: context,
|
||||||
|
}
|
||||||
|
|
||||||
if mainloop {
|
if mainloop {
|
||||||
// When mainloop is true, gomobile-build is used. In this case, GL functions must be called via
|
// When mainloop is true, gomobile-build is used. In this case, GL functions must be called via
|
||||||
@ -320,7 +322,7 @@ func (u *UserInterface) layoutIfNeeded() {
|
|||||||
u.m.RUnlock()
|
u.m.RUnlock()
|
||||||
|
|
||||||
if sizeChanged {
|
if sizeChanged {
|
||||||
u.context.Layout(outsideWidth, outsideHeight)
|
u.context.layout(outsideWidth, outsideHeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +332,7 @@ func (u *UserInterface) update() error {
|
|||||||
renderEndCh <- struct{}{}
|
renderEndCh <- struct{}{}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err := u.context.UpdateFrame(); err != nil {
|
if err := u.context.updateFrame(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -368,7 +370,7 @@ func (u *UserInterface) setGBuildSize(widthPx, heightPx int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) adjustPosition(x, y int) (int, int) {
|
func (u *UserInterface) adjustPosition(x, y int) (int, int) {
|
||||||
xf, yf := u.context.AdjustPosition(float64(x), float64(y), deviceScale())
|
xf, yf := u.context.adjustPosition(float64(x), float64(y), deviceScale())
|
||||||
return int(xf), int(yf)
|
return int(xf), int(yf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
uicontext.go
16
uicontext.go
@ -18,7 +18,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/buffered"
|
"github.com/hajimehoshi/ebiten/v2/internal/buffered"
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/clock"
|
"github.com/hajimehoshi/ebiten/v2/internal/clock"
|
||||||
@ -39,8 +38,6 @@ type uiContext struct {
|
|||||||
outsideWidth float64
|
outsideWidth float64
|
||||||
outsideHeight float64
|
outsideHeight float64
|
||||||
|
|
||||||
err atomic.Value
|
|
||||||
|
|
||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,16 +49,7 @@ func (c *uiContext) set(game Game) {
|
|||||||
c.game = game
|
c.game = game
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *uiContext) setError(err error) {
|
|
||||||
c.err.Store(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *uiContext) Layout(outsideWidth, outsideHeight float64) {
|
func (c *uiContext) Layout(outsideWidth, outsideHeight float64) {
|
||||||
// The given outside size can be 0 e.g. just after restoring from the fullscreen mode on Windows (#1589)
|
|
||||||
// Just ignore such cases. Otherwise, creating a zero-sized framebuffer causes a panic.
|
|
||||||
if outsideWidth == 0 || outsideHeight == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.outsideWidth = outsideWidth
|
c.outsideWidth = outsideWidth
|
||||||
c.outsideHeight = outsideHeight
|
c.outsideHeight = outsideHeight
|
||||||
}
|
}
|
||||||
@ -149,10 +137,6 @@ func (c *uiContext) ForceUpdateFrame() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *uiContext) updateFrame(updateCount int) error {
|
func (c *uiContext) updateFrame(updateCount int) error {
|
||||||
if err, ok := c.err.Load().(error); ok && err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
debug.Logf("----\n")
|
debug.Logf("----\n")
|
||||||
|
|
||||||
if err := buffered.BeginFrame(); err != nil {
|
if err := buffered.BeginFrame(); err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user