mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 03:38:55 +01:00
ebiten: Add FPSModeType, FPSMode, SetFPSMode, and ScheduleFrame
This change adds these APIs: * type FPSModeType * func FPSMode * func SetFPSMode * func ScheduleFrame and deprecates these APIs: * func SetVsyncEnabled * func IsVsyncEnabled Closes #1556
This commit is contained in:
parent
cf8aa0a7b2
commit
1706d9436a
@ -164,7 +164,7 @@ const objcM = `// Code generated by ebitenmobile. DO NOT EDIT.
|
|||||||
|
|
||||||
#import "Ebitenmobileview.objc.h"
|
#import "Ebitenmobileview.objc.h"
|
||||||
|
|
||||||
@interface {{.PrefixUpper}}EbitenViewController : UIViewController
|
@interface {{.PrefixUpper}}EbitenViewController : UIViewController<EbitenmobileviewRenderRequester>
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation {{.PrefixUpper}}EbitenViewController {
|
@implementation {{.PrefixUpper}}EbitenViewController {
|
||||||
@ -173,6 +173,8 @@ const objcM = `// Code generated by ebitenmobile. DO NOT EDIT.
|
|||||||
bool started_;
|
bool started_;
|
||||||
bool active_;
|
bool active_;
|
||||||
bool error_;
|
bool error_;
|
||||||
|
CADisplayLink* displayLink_;
|
||||||
|
bool explicitRendering_;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIView*)metalView {
|
- (UIView*)metalView {
|
||||||
@ -214,8 +216,9 @@ const objcM = `// Code generated by ebitenmobile. DO NOT EDIT.
|
|||||||
[EAGLContext setCurrentContext:context];
|
[EAGLContext setCurrentContext:context];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawFrame)];
|
displayLink_ = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawFrame)];
|
||||||
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
[displayLink_ addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
||||||
|
EbitenmobileviewSetRenderRequester(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewWillLayoutSubviews {
|
- (void)viewWillLayoutSubviews {
|
||||||
@ -251,6 +254,10 @@ const objcM = `// Code generated by ebitenmobile. DO NOT EDIT.
|
|||||||
#else
|
#else
|
||||||
[[self glkView] setNeedsDisplay];
|
[[self glkView] setNeedsDisplay];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (explicitRendering_) {
|
||||||
|
[displayLink_ setPaused:YES];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,6 +343,25 @@ const objcM = `// Code generated by ebitenmobile. DO NOT EDIT.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setExplicitRenderingMode:(BOOL)explicitRendering {
|
||||||
|
@synchronized(self) {
|
||||||
|
explicitRendering_ = explicitRendering;
|
||||||
|
if (explicitRendering_) {
|
||||||
|
[displayLink_ setPaused:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)requestRenderIfNeeded {
|
||||||
|
@synchronized(self) {
|
||||||
|
if (explicitRendering_) {
|
||||||
|
// Resume the callback temporarily.
|
||||||
|
// This is paused again soon in drawFrame.
|
||||||
|
[displayLink_ setPaused:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
`
|
`
|
||||||
|
|
||||||
@ -745,9 +771,10 @@ import javax.microedition.khronos.egl.EGLConfig;
|
|||||||
import javax.microedition.khronos.opengles.GL10;
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
|
|
||||||
import {{.JavaPkg}}.ebitenmobileview.Ebitenmobileview;
|
import {{.JavaPkg}}.ebitenmobileview.Ebitenmobileview;
|
||||||
|
import {{.JavaPkg}}.ebitenmobileview.RenderRequester;
|
||||||
import {{.JavaPkg}}.{{.PrefixLower}}.EbitenView;
|
import {{.JavaPkg}}.{{.PrefixLower}}.EbitenView;
|
||||||
|
|
||||||
class EbitenSurfaceView extends GLSurfaceView {
|
class EbitenSurfaceView extends GLSurfaceView implements RenderRequester {
|
||||||
|
|
||||||
private class EbitenRenderer implements GLSurfaceView.Renderer {
|
private class EbitenRenderer implements GLSurfaceView.Renderer {
|
||||||
|
|
||||||
@ -795,10 +822,27 @@ class EbitenSurfaceView extends GLSurfaceView {
|
|||||||
setEGLContextClientVersion(2);
|
setEGLContextClientVersion(2);
|
||||||
setEGLConfigChooser(8, 8, 8, 8, 0, 0);
|
setEGLConfigChooser(8, 8, 8, 8, 0, 0);
|
||||||
setRenderer(new EbitenRenderer());
|
setRenderer(new EbitenRenderer());
|
||||||
|
Ebitenmobileview.setRenderRequester(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onErrorOnGameUpdate(Exception e) {
|
private void onErrorOnGameUpdate(Exception e) {
|
||||||
((EbitenView)getParent()).onErrorOnGameUpdate(e);
|
((EbitenView)getParent()).onErrorOnGameUpdate(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void setExplicitRenderingMode(boolean explictRendering) {
|
||||||
|
if (explictRendering) {
|
||||||
|
setRenderMode(RENDERMODE_WHEN_DIRTY);
|
||||||
|
} else {
|
||||||
|
setRenderMode(RENDERMODE_CONTINUOUSLY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void requestRenderIfNeeded() {
|
||||||
|
if (getRenderMode() == RENDERMODE_WHEN_DIRTY) {
|
||||||
|
requestRender();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
File diff suppressed because one or more lines are too long
@ -124,7 +124,7 @@ func (g *game) Update() error {
|
|||||||
fullscreen := ebiten.IsFullscreen()
|
fullscreen := ebiten.IsFullscreen()
|
||||||
runnableOnUnfocused := ebiten.IsRunnableOnUnfocused()
|
runnableOnUnfocused := ebiten.IsRunnableOnUnfocused()
|
||||||
cursorMode := ebiten.CursorMode()
|
cursorMode := ebiten.CursorMode()
|
||||||
vsyncEnabled := ebiten.IsVsyncEnabled()
|
fpsMode := ebiten.FPSMode()
|
||||||
tps := ebiten.MaxTPS()
|
tps := ebiten.MaxTPS()
|
||||||
decorated := ebiten.IsWindowDecorated()
|
decorated := ebiten.IsWindowDecorated()
|
||||||
positionX, positionY := ebiten.WindowPosition()
|
positionX, positionY := ebiten.WindowPosition()
|
||||||
@ -205,7 +205,14 @@ func (g *game) Update() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if inpututil.IsKeyJustPressed(ebiten.KeyV) {
|
if inpututil.IsKeyJustPressed(ebiten.KeyV) {
|
||||||
vsyncEnabled = !vsyncEnabled
|
switch fpsMode {
|
||||||
|
case ebiten.FPSModeVsyncOn:
|
||||||
|
fpsMode = ebiten.FPSModeVsyncOffMaximum
|
||||||
|
case ebiten.FPSModeVsyncOffMaximum:
|
||||||
|
fpsMode = ebiten.FPSModeVsyncOffMinimum
|
||||||
|
case ebiten.FPSModeVsyncOffMinimum:
|
||||||
|
fpsMode = ebiten.FPSModeVsyncOn
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if inpututil.IsKeyJustPressed(ebiten.KeyT) {
|
if inpututil.IsKeyJustPressed(ebiten.KeyT) {
|
||||||
switch tps {
|
switch tps {
|
||||||
@ -249,10 +256,10 @@ func (g *game) Update() error {
|
|||||||
ebiten.SetRunnableOnUnfocused(runnableOnUnfocused)
|
ebiten.SetRunnableOnUnfocused(runnableOnUnfocused)
|
||||||
ebiten.SetCursorMode(cursorMode)
|
ebiten.SetCursorMode(cursorMode)
|
||||||
|
|
||||||
// Set vsync enabled only when this is needed.
|
// Set FPS mode enabled only when this is needed.
|
||||||
// This makes a bug around vsync initialization more explicit (#1364).
|
// This makes a bug around FPS mode initialization more explicit (#1364).
|
||||||
if vsyncEnabled != ebiten.IsVsyncEnabled() {
|
if fpsMode != ebiten.FPSMode() {
|
||||||
ebiten.SetVsyncEnabled(vsyncEnabled)
|
ebiten.SetFPSMode(fpsMode)
|
||||||
}
|
}
|
||||||
ebiten.SetMaxTPS(tps)
|
ebiten.SetMaxTPS(tps)
|
||||||
ebiten.SetWindowDecorated(decorated)
|
ebiten.SetWindowDecorated(decorated)
|
||||||
@ -323,7 +330,7 @@ func (g *game) Draw(screen *ebiten.Image) {
|
|||||||
[U] Switch the runnable-on-unfocused state
|
[U] Switch the runnable-on-unfocused state
|
||||||
[C] Switch the cursor mode (visible, hidden, or captured)
|
[C] Switch the cursor mode (visible, hidden, or captured)
|
||||||
[I] Change the window icon (only for desktops)
|
[I] Change the window icon (only for desktops)
|
||||||
[V] Switch vsync
|
[V] Switch the FPS mode
|
||||||
[T] Switch TPS (ticks per second)
|
[T] Switch TPS (ticks per second)
|
||||||
[D] Switch the window decoration (only for desktops)
|
[D] Switch the window decoration (only for desktops)
|
||||||
[L] Switch the window floating state (only for desktops)
|
[L] Switch the window floating state (only for desktops)
|
||||||
@ -403,7 +410,9 @@ func main() {
|
|||||||
ebiten.SetWindowResizable(true)
|
ebiten.SetWindowResizable(true)
|
||||||
ebiten.MaximizeWindow()
|
ebiten.MaximizeWindow()
|
||||||
}
|
}
|
||||||
ebiten.SetVsyncEnabled(*flagVsync)
|
if !*flagVsync {
|
||||||
|
ebiten.SetFPSMode(ebiten.FPSModeVsyncOffMaximum)
|
||||||
|
}
|
||||||
if *flagAutoAdjusting {
|
if *flagAutoAdjusting {
|
||||||
ebiten.SetWindowResizable(true)
|
ebiten.SetWindowResizable(true)
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,7 @@ type UI interface {
|
|||||||
|
|
||||||
FPSMode() FPSMode
|
FPSMode() FPSMode
|
||||||
SetFPSMode(mode FPSMode)
|
SetFPSMode(mode FPSMode)
|
||||||
|
ScheduleFrame()
|
||||||
|
|
||||||
IsScreenTransparent() bool
|
IsScreenTransparent() bool
|
||||||
SetScreenTransparent(transparent bool)
|
SetScreenTransparent(transparent bool)
|
||||||
@ -104,4 +105,5 @@ type FPSMode int
|
|||||||
const (
|
const (
|
||||||
FPSModeVsyncOn FPSMode = iota
|
FPSModeVsyncOn FPSMode = iota
|
||||||
FPSModeVsyncOffMaximum
|
FPSModeVsyncOffMaximum
|
||||||
|
FPSModeVsyncOffMinimum
|
||||||
)
|
)
|
||||||
|
@ -334,6 +334,10 @@ func PollEvents() {
|
|||||||
glfw.PollEvents()
|
glfw.PollEvents()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PostEmptyEvent() {
|
||||||
|
glfw.PostEmptyEvent()
|
||||||
|
}
|
||||||
|
|
||||||
func SetMonitorCallback(cbfun func(monitor *Monitor, event PeripheralEvent)) {
|
func SetMonitorCallback(cbfun func(monitor *Monitor, event PeripheralEvent)) {
|
||||||
var gcb func(monitor *glfw.Monitor, event glfw.PeripheralEvent)
|
var gcb func(monitor *glfw.Monitor, event glfw.PeripheralEvent)
|
||||||
if cbfun != nil {
|
if cbfun != nil {
|
||||||
@ -360,6 +364,10 @@ func UpdateGamepadMappings(mapping string) bool {
|
|||||||
return glfw.UpdateGamepadMappings(mapping)
|
return glfw.UpdateGamepadMappings(mapping)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WaitEvents() {
|
||||||
|
glfw.WaitEvents()
|
||||||
|
}
|
||||||
|
|
||||||
func WindowHint(target Hint, hint int) {
|
func WindowHint(target Hint, hint int) {
|
||||||
glfw.WindowHint(glfw.Hint(target), hint)
|
glfw.WindowHint(glfw.Hint(target), hint)
|
||||||
}
|
}
|
||||||
|
@ -517,6 +517,11 @@ func PollEvents() {
|
|||||||
panicErrorExceptForInvalidValue()
|
panicErrorExceptForInvalidValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PostEmptyEvent() {
|
||||||
|
glfwDLL.call("glfwPostEmptyEvent")
|
||||||
|
panicError()
|
||||||
|
}
|
||||||
|
|
||||||
func SetMonitorCallback(cbfun func(monitor *Monitor, event PeripheralEvent)) {
|
func SetMonitorCallback(cbfun func(monitor *Monitor, event PeripheralEvent)) {
|
||||||
var gcb uintptr
|
var gcb uintptr
|
||||||
if cbfun != nil {
|
if cbfun != nil {
|
||||||
@ -554,6 +559,11 @@ func UpdateGamepadMappings(mapping string) bool {
|
|||||||
return r == True
|
return r == True
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WaitEvents() {
|
||||||
|
glfwDLL.call("glfwWaitEvents")
|
||||||
|
panicError()
|
||||||
|
}
|
||||||
|
|
||||||
func WindowHint(target Hint, hint int) {
|
func WindowHint(target Hint, hint int) {
|
||||||
glfwDLL.call("glfwWindowHint", uintptr(target), uintptr(hint))
|
glfwDLL.call("glfwWindowHint", uintptr(target), uintptr(hint))
|
||||||
panicError()
|
panicError()
|
||||||
|
@ -639,6 +639,15 @@ func (u *UserInterface) FPSMode() driver.FPSMode {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) ScheduleFrame() {
|
||||||
|
if !u.isRunning() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// As the main thread can be blocked, do not check the current FPS mode.
|
||||||
|
// PostEmptyEvent is concurrent safe.
|
||||||
|
glfw.PostEmptyEvent()
|
||||||
|
}
|
||||||
|
|
||||||
func (u *UserInterface) CursorMode() driver.CursorMode {
|
func (u *UserInterface) CursorMode() driver.CursorMode {
|
||||||
if !u.isRunning() {
|
if !u.isRunning() {
|
||||||
return u.getInitCursorMode()
|
return u.getInitCursorMode()
|
||||||
@ -964,8 +973,12 @@ func (u *UserInterface) update() (float64, float64, bool, error) {
|
|||||||
|
|
||||||
outsideWidth, outsideHeight, outsideSizeChanged := u.updateSize()
|
outsideWidth, outsideHeight, outsideSizeChanged := u.updateSize()
|
||||||
|
|
||||||
|
if u.fpsMode != driver.FPSModeVsyncOffMinimum {
|
||||||
// TODO: Updating the input can be skipped when clock.Update returns 0 (#1367).
|
// TODO: Updating the input can be skipped when clock.Update returns 0 (#1367).
|
||||||
glfw.PollEvents()
|
glfw.PollEvents()
|
||||||
|
} else {
|
||||||
|
glfw.WaitEvents()
|
||||||
|
}
|
||||||
u.input.update(u.window, u.context)
|
u.input.update(u.window, u.context)
|
||||||
|
|
||||||
for !u.isRunnableOnUnfocused() && u.window.GetAttrib(glfw.Focused) == 0 && !u.window.ShouldClose() {
|
for !u.isRunnableOnUnfocused() && u.window.GetAttrib(glfw.Focused) == 0 && !u.window.ShouldClose() {
|
||||||
|
@ -403,6 +403,8 @@ func (i *Input) updateFromEvent(e js.Value) {
|
|||||||
case t.Equal(stringTouchstart) || t.Equal(stringTouchend) || t.Equal(stringTouchmove):
|
case t.Equal(stringTouchstart) || t.Equal(stringTouchend) || t.Equal(stringTouchmove):
|
||||||
i.updateTouchesFromEvent(e)
|
i.updateTouchesFromEvent(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i.ui.forceUpdateOnMinimumFPSMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Input) setMouseCursorFromEvent(e js.Value) {
|
func (i *Input) setMouseCursorFromEvent(e js.Value) {
|
||||||
|
@ -50,11 +50,13 @@ func driverCursorShapeToCSSCursor(cursor driver.CursorShape) string {
|
|||||||
type UserInterface struct {
|
type UserInterface struct {
|
||||||
runnableOnUnfocused bool
|
runnableOnUnfocused bool
|
||||||
fpsMode driver.FPSMode
|
fpsMode driver.FPSMode
|
||||||
|
renderingScheduled bool
|
||||||
running bool
|
running bool
|
||||||
initFocused bool
|
initFocused bool
|
||||||
cursorMode driver.CursorMode
|
cursorMode driver.CursorMode
|
||||||
cursorPrevMode driver.CursorMode
|
cursorPrevMode driver.CursorMode
|
||||||
cursorShape driver.CursorShape
|
cursorShape driver.CursorShape
|
||||||
|
onceUpdateCalled bool
|
||||||
|
|
||||||
sizeChanged bool
|
sizeChanged bool
|
||||||
|
|
||||||
@ -146,6 +148,10 @@ func (u *UserInterface) FPSMode() driver.FPSMode {
|
|||||||
return u.fpsMode
|
return u.fpsMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) ScheduleFrame() {
|
||||||
|
u.renderingScheduled = true
|
||||||
|
}
|
||||||
|
|
||||||
func (u *UserInterface) CursorMode() driver.CursorMode {
|
func (u *UserInterface) CursorMode() driver.CursorMode {
|
||||||
if !canvas.Truthy() {
|
if !canvas.Truthy() {
|
||||||
return driver.CursorModeHidden
|
return driver.CursorModeHidden
|
||||||
@ -281,6 +287,20 @@ func (u *UserInterface) updateImpl(force bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) needsUpdate() bool {
|
||||||
|
if u.fpsMode != driver.FPSModeVsyncOffMinimum {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !u.onceUpdateCalled {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if u.renderingScheduled {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// TODO: Watch the gamepad state?
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (u *UserInterface) loop(context driver.UIContext) <-chan error {
|
func (u *UserInterface) loop(context driver.UIContext) <-chan error {
|
||||||
u.context = context
|
u.context = context
|
||||||
|
|
||||||
@ -290,6 +310,9 @@ func (u *UserInterface) loop(context driver.UIContext) <-chan error {
|
|||||||
|
|
||||||
var cf js.Func
|
var cf js.Func
|
||||||
f := func() {
|
f := func() {
|
||||||
|
if u.needsUpdate() {
|
||||||
|
u.onceUpdateCalled = true
|
||||||
|
u.renderingScheduled = false
|
||||||
if err := u.update(); err != nil {
|
if err := u.update(); err != nil {
|
||||||
close(reqStopAudioCh)
|
close(reqStopAudioCh)
|
||||||
<-resStopAudioCh
|
<-resStopAudioCh
|
||||||
@ -297,10 +320,14 @@ func (u *UserInterface) loop(context driver.UIContext) <-chan error {
|
|||||||
errCh <- err
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if u.fpsMode == driver.FPSModeVsyncOn {
|
}
|
||||||
|
switch u.fpsMode {
|
||||||
|
case driver.FPSModeVsyncOn:
|
||||||
requestAnimationFrame.Invoke(cf)
|
requestAnimationFrame.Invoke(cf)
|
||||||
} else {
|
case driver.FPSModeVsyncOffMaximum:
|
||||||
setTimeout.Invoke(cf, 0)
|
setTimeout.Invoke(cf, 0)
|
||||||
|
case driver.FPSModeVsyncOffMinimum:
|
||||||
|
requestAnimationFrame.Invoke(cf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,6 +567,13 @@ func setCanvasEventHandlers(v js.Value) {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) forceUpdateOnMinimumFPSMode() {
|
||||||
|
if u.fpsMode != driver.FPSModeVsyncOffMinimum {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u.updateImpl(true)
|
||||||
|
}
|
||||||
|
|
||||||
func (u *UserInterface) Run(context driver.UIContext) error {
|
func (u *UserInterface) Run(context driver.UIContext) error {
|
||||||
if u.initFocused && window.Truthy() {
|
if u.initFocused && window.Truthy() {
|
||||||
// Do not focus the canvas when the current document is in an iframe.
|
// Do not focus the canvas when the current document is in an iframe.
|
||||||
|
@ -112,6 +112,9 @@ type UserInterface struct {
|
|||||||
|
|
||||||
input Input
|
input Input
|
||||||
|
|
||||||
|
fpsMode driver.FPSMode
|
||||||
|
renderRequester RenderRequester
|
||||||
|
|
||||||
t *thread.OSThread
|
t *thread.OSThread
|
||||||
|
|
||||||
m sync.RWMutex
|
m sync.RWMutex
|
||||||
@ -405,11 +408,19 @@ func (u *UserInterface) SetRunnableOnUnfocused(runnableOnUnfocused bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) FPSMode() driver.FPSMode {
|
func (u *UserInterface) FPSMode() driver.FPSMode {
|
||||||
return driver.FPSModeVsyncOn
|
return u.fpsMode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) SetFPSMode(mode driver.FPSMode) {
|
func (u *UserInterface) SetFPSMode(mode driver.FPSMode) {
|
||||||
// Do nothing
|
u.fpsMode = mode
|
||||||
|
u.updateExplicitRenderingModeIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) updateExplicitRenderingModeIfNeeded() {
|
||||||
|
if u.renderRequester == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u.renderRequester.SetExplicitRenderingMode(u.fpsMode == driver.FPSModeVsyncOffMinimum)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) DeviceScaleFactor() float64 {
|
func (u *UserInterface) DeviceScaleFactor() float64 {
|
||||||
@ -459,4 +470,23 @@ type Gamepad struct {
|
|||||||
|
|
||||||
func (u *UserInterface) UpdateInput(keys map[driver.Key]struct{}, runes []rune, touches []*Touch, gamepads []Gamepad) {
|
func (u *UserInterface) UpdateInput(keys map[driver.Key]struct{}, runes []rune, touches []*Touch, gamepads []Gamepad) {
|
||||||
u.input.update(keys, runes, touches, gamepads)
|
u.input.update(keys, runes, touches, gamepads)
|
||||||
|
if u.fpsMode == driver.FPSModeVsyncOffMinimum {
|
||||||
|
u.renderRequester.RequestRenderIfNeeded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RenderRequester interface {
|
||||||
|
SetExplicitRenderingMode(explicitRendering bool)
|
||||||
|
RequestRenderIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) SetRenderRequester(renderRequester RenderRequester) {
|
||||||
|
u.renderRequester = renderRequester
|
||||||
|
u.updateExplicitRenderingModeIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) ScheduleFrame() {
|
||||||
|
if u.renderRequester != nil && u.fpsMode == driver.FPSModeVsyncOffMinimum {
|
||||||
|
u.renderRequester.RequestRenderIfNeeded()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,3 +90,12 @@ func OnContextLost() {
|
|||||||
func DeviceScale() float64 {
|
func DeviceScale() float64 {
|
||||||
return devicescale.GetAt(0, 0)
|
return devicescale.GetAt(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RenderRequester interface {
|
||||||
|
SetExplicitRenderingMode(explicitRendering bool)
|
||||||
|
RequestRenderIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetRenderRequester(renderRequester RenderRequester) {
|
||||||
|
mobile.Get().SetRenderRequester(renderRequester)
|
||||||
|
}
|
||||||
|
67
run.go
67
run.go
@ -312,7 +312,7 @@ func DeviceScaleFactor() float64 {
|
|||||||
// IsVsyncEnabled returns a boolean value indicating whether
|
// IsVsyncEnabled returns a boolean value indicating whether
|
||||||
// the game uses the display's vsync.
|
// the game uses the display's vsync.
|
||||||
//
|
//
|
||||||
// IsVsyncEnabled is concurrent-safe.
|
// Deprecated: as of v2.2. Use FPSMode instead.
|
||||||
func IsVsyncEnabled() bool {
|
func IsVsyncEnabled() bool {
|
||||||
return uiDriver().FPSMode() == driver.FPSModeVsyncOn
|
return uiDriver().FPSMode() == driver.FPSModeVsyncOn
|
||||||
}
|
}
|
||||||
@ -320,17 +320,7 @@ func IsVsyncEnabled() bool {
|
|||||||
// SetVsyncEnabled sets a boolean value indicating whether
|
// SetVsyncEnabled sets a boolean value indicating whether
|
||||||
// the game uses the display's vsync.
|
// the game uses the display's vsync.
|
||||||
//
|
//
|
||||||
// If the given value is true, the game tries to sync the display's refresh rate.
|
// Deprecated: as of v2.2. Use SetFPSMode instead.
|
||||||
// If false, the game ignores the display's refresh rate.
|
|
||||||
// The initial value is true.
|
|
||||||
// By disabling vsync, the game works more efficiently but consumes more CPU.
|
|
||||||
//
|
|
||||||
// Note that the state doesn't affect TPS (ticks per second, i.e. how many the run function is
|
|
||||||
// updated per second).
|
|
||||||
//
|
|
||||||
// SetVsyncEnabled does nothing on mobiles so far.
|
|
||||||
//
|
|
||||||
// SetVsyncEnabled is concurrent-safe.
|
|
||||||
func SetVsyncEnabled(enabled bool) {
|
func SetVsyncEnabled(enabled bool) {
|
||||||
if enabled {
|
if enabled {
|
||||||
uiDriver().SetFPSMode(driver.FPSModeVsyncOn)
|
uiDriver().SetFPSMode(driver.FPSModeVsyncOn)
|
||||||
@ -339,10 +329,63 @@ func SetVsyncEnabled(enabled bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FPSModeType is a type of FPS modes.
|
||||||
|
type FPSModeType = driver.FPSMode
|
||||||
|
|
||||||
|
const (
|
||||||
|
// FPSModeVsyncOn indicates that the game tries to sync the display's refresh rate.
|
||||||
|
// FPSModeVsyncOn is the default mode.
|
||||||
|
FPSModeVsyncOn FPSModeType = driver.FPSModeVsyncOn
|
||||||
|
|
||||||
|
// FPSModeVsyncOffMaximum indicates that the game doesn't sync with vsycn, and
|
||||||
|
// the game is updated whenever possible.
|
||||||
|
//
|
||||||
|
// Be careful that FPSModeVsyncOffMaximum might consume a lot of battery power.
|
||||||
|
//
|
||||||
|
// In FPSModeVsyncOffMaximum, the game's Draw is called almost without sleeping.
|
||||||
|
// The game's Update is called based on the specified TPS.
|
||||||
|
FPSModeVsyncOffMaximum FPSModeType = driver.FPSModeVsyncOffMaximum
|
||||||
|
|
||||||
|
// FPSModeVsyncOffMinimum indicates that the game doesn't sync with vsycn, and
|
||||||
|
// the game is updated only when necessary.
|
||||||
|
//
|
||||||
|
// FPSModeVsyncOffMinimum is useful for relatively static applications to save battery power.
|
||||||
|
//
|
||||||
|
// In FPSModeVsyncOffMinimum, the game's Update and Draw are called only when
|
||||||
|
// 1) new inputting is detected, or 2) ScheduleFrame is called.
|
||||||
|
// In FPSModeVsyncOffMinimum, TPS is SyncWithFPS no matter what TPS is specified at SetMaxTPS.
|
||||||
|
FPSModeVsyncOffMinimum FPSModeType = driver.FPSModeVsyncOffMinimum
|
||||||
|
)
|
||||||
|
|
||||||
|
// FPSMode returns the current FPS mode.
|
||||||
|
//
|
||||||
|
// FPSMode is concurrent-safe.
|
||||||
|
func FPSMode() FPSModeType {
|
||||||
|
return uiDriver().FPSMode()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFPSMode sets the FPS mode.
|
||||||
|
// The default FPS mode is FPSModeVsycnOn.
|
||||||
|
//
|
||||||
|
// SetFPSMode is concurrent-safe.
|
||||||
|
func SetFPSMode(mode FPSModeType) {
|
||||||
|
uiDriver().SetFPSMode(mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScheduleFrame schedules a next frame when the current FPS mode is FPSModeVsyncOffMinimum.
|
||||||
|
//
|
||||||
|
// ScheduleFrame is concurrent-safe.
|
||||||
|
func ScheduleFrame() {
|
||||||
|
uiDriver().ScheduleFrame()
|
||||||
|
}
|
||||||
|
|
||||||
// MaxTPS returns the current maximum TPS.
|
// MaxTPS returns the current maximum TPS.
|
||||||
//
|
//
|
||||||
// MaxTPS is concurrent-safe.
|
// MaxTPS is concurrent-safe.
|
||||||
func MaxTPS() int {
|
func MaxTPS() int {
|
||||||
|
if FPSMode() == FPSModeVsyncOffMinimum {
|
||||||
|
return SyncWithFPS
|
||||||
|
}
|
||||||
return int(atomic.LoadInt32(¤tMaxTPS))
|
return int(atomic.LoadInt32(¤tMaxTPS))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user