mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
driver: Let UI have Graphics
Now UIs own the implementation of Graphics. Updates #1026
This commit is contained in:
parent
e66f1fb71e
commit
982b7d6ddc
@ -31,8 +31,8 @@ type UIContext interface {
|
|||||||
var RegularTermination = errors.New("regular termination")
|
var RegularTermination = errors.New("regular termination")
|
||||||
|
|
||||||
type UI interface {
|
type UI interface {
|
||||||
Run(context UIContext, graphics Graphics) error
|
Run(context UIContext) error
|
||||||
RunWithoutMainLoop(width, height int, scale float64, title string, context UIContext, graphics Graphics) <-chan error
|
RunWithoutMainLoop(width, height int, scale float64, title string, context UIContext) <-chan error
|
||||||
|
|
||||||
DeviceScaleFactor() float64
|
DeviceScaleFactor() float64
|
||||||
CursorMode() CursorMode
|
CursorMode() CursorMode
|
||||||
@ -51,6 +51,7 @@ type UI interface {
|
|||||||
|
|
||||||
Input() Input
|
Input() Input
|
||||||
Window() Window
|
Window() Window
|
||||||
|
Graphics() Graphics
|
||||||
}
|
}
|
||||||
|
|
||||||
type Window interface {
|
type Window interface {
|
||||||
|
@ -12,11 +12,11 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// +build darwin,!ios
|
// +build darwin
|
||||||
// +build !js
|
// +build !js
|
||||||
// +build !ebitengl
|
// +build !ebitengl
|
||||||
|
|
||||||
package ebiten
|
package glfw
|
||||||
|
|
||||||
// #cgo CFLAGS: -x objective-c
|
// #cgo CFLAGS: -x objective-c
|
||||||
// #cgo LDFLAGS: -framework Foundation
|
// #cgo LDFLAGS: -framework Foundation
|
||||||
@ -48,7 +48,7 @@ var (
|
|||||||
isMetalSupportedOnce sync.Once
|
isMetalSupportedOnce sync.Once
|
||||||
)
|
)
|
||||||
|
|
||||||
func graphicsDriver() driver.Graphics {
|
func (*UserInterface) Graphics() driver.Graphics {
|
||||||
isMetalSupportedOnce.Do(func() {
|
isMetalSupportedOnce.Do(func() {
|
||||||
// On old mac devices like iMac 2011, Metal is not supported (#779).
|
// On old mac devices like iMac 2011, Metal is not supported (#779).
|
||||||
if _, err := mtl.CreateSystemDefaultDevice(); err != nil {
|
if _, err := mtl.CreateSystemDefaultDevice(); err != nil {
|
@ -12,15 +12,15 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// +build android darwin,ios,386 darwin,ios,amd64 freebsd js linux windows ebitengl
|
// +build freebsd js linux windows ebitengl
|
||||||
|
|
||||||
package ebiten
|
package glfw
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hajimehoshi/ebiten/internal/driver"
|
"github.com/hajimehoshi/ebiten/internal/driver"
|
||||||
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl"
|
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl"
|
||||||
)
|
)
|
||||||
|
|
||||||
func graphicsDriver() driver.Graphics {
|
func (*UserInterface) Graphics() driver.Graphics {
|
||||||
return opengl.Get()
|
return opengl.Get()
|
||||||
}
|
}
|
@ -72,7 +72,6 @@ type UserInterface struct {
|
|||||||
reqWidth int
|
reqWidth int
|
||||||
reqHeight int
|
reqHeight int
|
||||||
|
|
||||||
graphics driver.Graphics
|
|
||||||
input Input
|
input Input
|
||||||
iwindow window
|
iwindow window
|
||||||
|
|
||||||
@ -509,11 +508,10 @@ func init() {
|
|||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) Run(uicontext driver.UIContext, graphics driver.Graphics) error {
|
func (u *UserInterface) Run(uicontext driver.UIContext) error {
|
||||||
// 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.New()
|
u.t = thread.New()
|
||||||
u.graphics = graphics
|
u.Graphics().SetThread(u.t)
|
||||||
u.graphics.SetThread(u.t)
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
@ -532,7 +530,7 @@ func (u *UserInterface) Run(uicontext driver.UIContext, graphics driver.Graphics
|
|||||||
return <-ch
|
return <-ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext, graphics driver.Graphics) <-chan error {
|
func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext) <-chan error {
|
||||||
panic("glfw: RunWithoutMainLoop is not implemented")
|
panic("glfw: RunWithoutMainLoop is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,7 +551,7 @@ func (u *UserInterface) createWindow() error {
|
|||||||
}
|
}
|
||||||
u.window = window
|
u.window = window
|
||||||
|
|
||||||
if u.graphics.IsGL() {
|
if u.Graphics().IsGL() {
|
||||||
u.window.MakeContextCurrent()
|
u.window.MakeContextCurrent()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,7 +589,7 @@ func (u *UserInterface) run(context driver.UIContext) error {
|
|||||||
u.window.Destroy()
|
u.window.Destroy()
|
||||||
u.window = nil
|
u.window = nil
|
||||||
|
|
||||||
if u.graphics.IsGL() {
|
if u.Graphics().IsGL() {
|
||||||
glfw.WindowHint(glfw.ContextVersionMajor, 2)
|
glfw.WindowHint(glfw.ContextVersionMajor, 2)
|
||||||
glfw.WindowHint(glfw.ContextVersionMinor, 1)
|
glfw.WindowHint(glfw.ContextVersionMinor, 1)
|
||||||
} else {
|
} else {
|
||||||
@ -609,7 +607,7 @@ func (u *UserInterface) run(context driver.UIContext) error {
|
|||||||
transparent = glfw.True
|
transparent = glfw.True
|
||||||
}
|
}
|
||||||
glfw.WindowHint(glfw.TransparentFramebuffer, transparent)
|
glfw.WindowHint(glfw.TransparentFramebuffer, transparent)
|
||||||
u.graphics.SetTransparent(u.isInitScreenTransparent())
|
u.Graphics().SetTransparent(u.isInitScreenTransparent())
|
||||||
|
|
||||||
resizable := glfw.False
|
resizable := glfw.False
|
||||||
if u.isInitWindowResizable() {
|
if u.isInitWindowResizable() {
|
||||||
@ -652,7 +650,7 @@ func (u *UserInterface) run(context driver.UIContext) error {
|
|||||||
w = u.nativeWindow()
|
w = u.nativeWindow()
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
u.graphics.SetWindow(w)
|
u.Graphics().SetWindow(w)
|
||||||
return u.loop(context)
|
return u.loop(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -807,7 +805,7 @@ func (u *UserInterface) loop(context driver.UIContext) error {
|
|||||||
|
|
||||||
// swapBuffers must be called from the main thread.
|
// swapBuffers must be called from the main thread.
|
||||||
func (u *UserInterface) swapBuffers() {
|
func (u *UserInterface) swapBuffers() {
|
||||||
if u.graphics.IsGL() {
|
if u.Graphics().IsGL() {
|
||||||
u.window.SwapBuffers()
|
u.window.SwapBuffers()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -844,13 +842,13 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool, vsync
|
|||||||
|
|
||||||
// Swapping buffer is necesary to prevent the image lag (#1004).
|
// Swapping buffer is necesary to prevent the image lag (#1004).
|
||||||
// TODO: This might not work when vsync is disabled.
|
// TODO: This might not work when vsync is disabled.
|
||||||
if u.graphics.IsGL() {
|
if u.Graphics().IsGL() {
|
||||||
glfw.PollEvents()
|
glfw.PollEvents()
|
||||||
u.swapBuffers()
|
u.swapBuffers()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if u.window.GetMonitor() != nil {
|
if u.window.GetMonitor() != nil {
|
||||||
if u.graphics.IsGL() {
|
if u.Graphics().IsGL() {
|
||||||
// When OpenGL is used, swapping buffer is enough to solve the image-lag
|
// When OpenGL is used, swapping buffer is enough to solve the image-lag
|
||||||
// issue (#1004). Rather, recreating window destroys GPU resources.
|
// issue (#1004). Rather, recreating window destroys GPU resources.
|
||||||
// TODO: This might not work when vsync is disabled.
|
// TODO: This might not work when vsync is disabled.
|
||||||
@ -929,7 +927,7 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool, vsync
|
|||||||
u.windowWidth = width
|
u.windowWidth = width
|
||||||
u.windowHeight = height
|
u.windowHeight = height
|
||||||
|
|
||||||
if u.graphics.IsGL() {
|
if u.Graphics().IsGL() {
|
||||||
// SwapInterval is affected by the current monitor of the window.
|
// SwapInterval is affected by the current monitor of the window.
|
||||||
// This needs to be called at least after SetMonitor.
|
// This needs to be called at least after SetMonitor.
|
||||||
// Without SwapInterval after SetMonitor, vsynch doesn't work (#375).
|
// Without SwapInterval after SetMonitor, vsynch doesn't work (#375).
|
||||||
@ -943,14 +941,14 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool, vsync
|
|||||||
glfw.SwapInterval(0)
|
glfw.SwapInterval(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
u.graphics.SetVsyncEnabled(vsync)
|
u.Graphics().SetVsyncEnabled(vsync)
|
||||||
|
|
||||||
u.toChangeSize = true
|
u.toChangeSize = true
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if windowRecreated {
|
if windowRecreated {
|
||||||
u.graphics.SetWindow(u.nativeWindow())
|
u.Graphics().SetWindow(u.nativeWindow())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/internal/devicescale"
|
"github.com/hajimehoshi/ebiten/internal/devicescale"
|
||||||
"github.com/hajimehoshi/ebiten/internal/driver"
|
"github.com/hajimehoshi/ebiten/internal/driver"
|
||||||
|
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl"
|
||||||
"github.com/hajimehoshi/ebiten/internal/hooks"
|
"github.com/hajimehoshi/ebiten/internal/hooks"
|
||||||
"github.com/hajimehoshi/ebiten/internal/jsutil"
|
"github.com/hajimehoshi/ebiten/internal/jsutil"
|
||||||
)
|
)
|
||||||
@ -371,7 +372,7 @@ func init() {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) Run(context driver.UIContext, graphics driver.Graphics) error {
|
func (u *UserInterface) Run(context driver.UIContext) error {
|
||||||
canvas.Call("focus")
|
canvas.Call("focus")
|
||||||
u.running = true
|
u.running = true
|
||||||
ch := u.loop(context)
|
ch := u.loop(context)
|
||||||
@ -392,7 +393,7 @@ func (u *UserInterface) Run(context driver.UIContext, graphics driver.Graphics)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext, graphics driver.Graphics) <-chan error {
|
func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext) <-chan error {
|
||||||
panic("js: RunWithoutMainLoop is not implemented")
|
panic("js: RunWithoutMainLoop is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,3 +435,7 @@ func (u *UserInterface) Input() driver.Input {
|
|||||||
func (u *UserInterface) Window() driver.Window {
|
func (u *UserInterface) Window() driver.Window {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (*UserInterface) Graphics() driver.Graphics {
|
||||||
|
return opengl.Get()
|
||||||
|
}
|
||||||
|
@ -12,10 +12,10 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// +build darwin,ios,arm darwin,ios,arm64
|
// +build ios,arm ios,arm64
|
||||||
// +build !ebitengl
|
// +build !ebitengl
|
||||||
|
|
||||||
package ebiten
|
package mobile
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -25,7 +25,7 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/metal/mtl"
|
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/metal/mtl"
|
||||||
)
|
)
|
||||||
|
|
||||||
func graphicsDriver() driver.Graphics {
|
func (*UserInterface) Graphics() driver.Graphics {
|
||||||
if _, err := mtl.CreateSystemDefaultDevice(); err != nil {
|
if _, err := mtl.CreateSystemDefaultDevice(); err != nil {
|
||||||
panic(fmt.Sprintf("ebiten: mtl.CreateSystemDefaultDevice failed on iOS: %v", err))
|
panic(fmt.Sprintf("ebiten: mtl.CreateSystemDefaultDevice failed on iOS: %v", err))
|
||||||
}
|
}
|
26
internal/uidriver/mobile/graphics_opengl.go
Normal file
26
internal/uidriver/mobile/graphics_opengl.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
// +build android ios,386 ios,amd64 ebitengl
|
||||||
|
|
||||||
|
package mobile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hajimehoshi/ebiten/internal/driver"
|
||||||
|
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (*UserInterface) Graphics() driver.Graphics {
|
||||||
|
return opengl.Get()
|
||||||
|
}
|
@ -72,7 +72,7 @@ func (u *UserInterface) Update() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if u.graphics.IsGL() {
|
if u.Graphics().IsGL() {
|
||||||
if u.glWorker == nil {
|
if u.glWorker == nil {
|
||||||
panic("mobile: glWorker must be initialized but not")
|
panic("mobile: glWorker must be initialized but not")
|
||||||
}
|
}
|
||||||
@ -106,7 +106,6 @@ type UserInterface struct {
|
|||||||
setGBuildSizeCh chan struct{}
|
setGBuildSizeCh chan struct{}
|
||||||
|
|
||||||
context driver.UIContext
|
context driver.UIContext
|
||||||
graphics driver.Graphics
|
|
||||||
|
|
||||||
input Input
|
input Input
|
||||||
|
|
||||||
@ -182,12 +181,12 @@ func (u *UserInterface) appMain(a app.App) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) Run(context driver.UIContext, graphics driver.Graphics) error {
|
func (u *UserInterface) Run(context driver.UIContext) error {
|
||||||
// TODO: Remove width/height/scale arguments. They are not used from gomobile-build.
|
// TODO: Remove width/height/scale arguments. They are not used from gomobile-build.
|
||||||
|
|
||||||
u.setGBuildSizeCh = make(chan struct{})
|
u.setGBuildSizeCh = make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
if err := u.run(16, 16, 1, context, graphics, true); err != nil {
|
if err := u.run(16, 16, 1, context, true); err != nil {
|
||||||
// As mobile apps never ends, Loop can't return. Just panic here.
|
// As mobile apps never ends, Loop can't return. Just panic here.
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -196,12 +195,12 @@ func (u *UserInterface) Run(context driver.UIContext, graphics driver.Graphics)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext, graphics driver.Graphics) <-chan error {
|
func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext) <-chan error {
|
||||||
ch := make(chan error)
|
ch := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
defer close(ch)
|
defer close(ch)
|
||||||
// title is ignored?
|
// title is ignored?
|
||||||
if err := u.run(width, height, scale, context, graphics, false); err != nil {
|
if err := u.run(width, height, scale, context, false); err != nil {
|
||||||
ch <- err
|
ch <- err
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -209,7 +208,7 @@ func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, tit
|
|||||||
return ch
|
return ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) run(width, height int, scale float64, context driver.UIContext, graphics driver.Graphics, mainloop bool) (err error) {
|
func (u *UserInterface) run(width, height int, scale float64, context driver.UIContext, mainloop bool) (err error) {
|
||||||
// Convert the panic to a regular error so that Java/Objective-C layer can treat this easily e.g., for
|
// Convert the panic to a regular error so that Java/Objective-C layer can treat this easily e.g., for
|
||||||
// Crashlytics. A panic is treated as SIGABRT, and there is no way to handle this on Java/Objective-C layer
|
// Crashlytics. A panic is treated as SIGABRT, and there is no way to handle this on Java/Objective-C layer
|
||||||
// unfortunately.
|
// unfortunately.
|
||||||
@ -226,20 +225,19 @@ func (u *UserInterface) run(width, height int, scale float64, context driver.UIC
|
|||||||
u.scale = scale
|
u.scale = scale
|
||||||
u.sizeChanged = true
|
u.sizeChanged = true
|
||||||
u.context = context
|
u.context = context
|
||||||
u.graphics = graphics
|
|
||||||
u.m.Unlock()
|
u.m.Unlock()
|
||||||
|
|
||||||
if graphics.IsGL() {
|
if u.Graphics().IsGL() {
|
||||||
var ctx gl.Context
|
var ctx gl.Context
|
||||||
if mainloop {
|
if mainloop {
|
||||||
ctx = <-glContextCh
|
ctx = <-glContextCh
|
||||||
} else {
|
} else {
|
||||||
ctx, u.glWorker = gl.NewContext()
|
ctx, u.glWorker = gl.NewContext()
|
||||||
}
|
}
|
||||||
graphics.(*opengl.Driver).SetMobileGLContext(ctx)
|
u.Graphics().(*opengl.Driver).SetMobileGLContext(ctx)
|
||||||
} else {
|
} else {
|
||||||
u.t = thread.New()
|
u.t = thread.New()
|
||||||
graphics.SetThread(u.t)
|
u.Graphics().SetThread(u.t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If gomobile-build is used, wait for the outside size fixed.
|
// If gomobile-build is used, wait for the outside size fixed.
|
||||||
|
4
run.go
4
run.go
@ -215,7 +215,7 @@ func RunGame(game Game) error {
|
|||||||
|
|
||||||
func runGame(game Game, scale float64) error {
|
func runGame(game Game, scale float64) error {
|
||||||
theUIContext.set(game, scale)
|
theUIContext.set(game, scale)
|
||||||
if err := uiDriver().Run(theUIContext, graphicsDriver()); err != nil {
|
if err := uiDriver().Run(theUIContext); err != nil {
|
||||||
if err == driver.RegularTermination {
|
if err == driver.RegularTermination {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -236,7 +236,7 @@ func RunWithoutMainLoop(f func(*Image) error, width, height int, scale float64,
|
|||||||
height: height,
|
height: height,
|
||||||
}
|
}
|
||||||
theUIContext.set(game, scale)
|
theUIContext.set(game, scale)
|
||||||
return uiDriver().RunWithoutMainLoop(width, height, scale, title, theUIContext, graphicsDriver())
|
return uiDriver().RunWithoutMainLoop(width, height, scale, title, theUIContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScreenSizeInFullscreen is deprecated as of 1.11.0-alpha.
|
// ScreenSizeInFullscreen is deprecated as of 1.11.0-alpha.
|
||||||
|
@ -28,8 +28,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
shareable.SetGraphicsDriver(graphicsDriver())
|
shareable.SetGraphicsDriver(uiDriver().Graphics())
|
||||||
graphicscommand.SetGraphicsDriver(graphicsDriver())
|
graphicscommand.SetGraphicsDriver(uiDriver().Graphics())
|
||||||
}
|
}
|
||||||
|
|
||||||
type defaultGame struct {
|
type defaultGame struct {
|
||||||
@ -275,7 +275,7 @@ func (c *uiContext) update(afterFrameUpdate func()) error {
|
|||||||
op := &DrawImageOptions{}
|
op := &DrawImageOptions{}
|
||||||
|
|
||||||
s := c.screenScale()
|
s := c.screenScale()
|
||||||
switch vd := graphicsDriver().VDirection(); vd {
|
switch vd := uiDriver().Graphics().VDirection(); vd {
|
||||||
case driver.VDownward:
|
case driver.VDownward:
|
||||||
// c.screen is special: its Y axis is down to up,
|
// c.screen is special: its Y axis is down to up,
|
||||||
// and the origin point is lower left.
|
// and the origin point is lower left.
|
||||||
|
Loading…
Reference in New Issue
Block a user