twitchapon-anim

Basic Twitchapon Receiver/Visuals
git clone git://bsandro.tech/twitchapon-anim
Log | Files | Refs | README | LICENSE

run.go (13911B)


      1 // Copyright 2014 Hajime Hoshi
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package ebiten
     16 
     17 import (
     18 	"sync/atomic"
     19 
     20 	"github.com/hajimehoshi/ebiten/v2/internal/clock"
     21 	"github.com/hajimehoshi/ebiten/v2/internal/driver"
     22 )
     23 
     24 // Game defines necessary functions for a game.
     25 type Game interface {
     26 	// Update updates a game by one tick. The given argument represents a screen image.
     27 	//
     28 	// Update updates only the game logic and Draw draws the screen.
     29 	//
     30 	// In the first frame, it is ensured that Update is called at least once before Draw. You can use Update
     31 	// to initialize the game state.
     32 	//
     33 	// After the first frame, Update might not be called or might be called once
     34 	// or more for one frame. The frequency is determined by the current TPS (tick-per-second).
     35 	Update() error
     36 
     37 	// Draw draws the game screen by one frame.
     38 	//
     39 	// The give argument represents a screen image. The updated content is adopted as the game screen.
     40 	Draw(screen *Image)
     41 
     42 	// Layout accepts a native outside size in device-independent pixels and returns the game's logical screen
     43 	// size.
     44 	//
     45 	// On desktops, the outside is a window or a monitor (fullscreen mode). On browsers, the outside is a body
     46 	// element. On mobiles, the outside is the view's size.
     47 	//
     48 	// Even though the outside size and the screen size differ, the rendering scale is automatically adjusted to
     49 	// fit with the outside.
     50 	//
     51 	// Layout is called almost every frame.
     52 	//
     53 	// If Layout returns non-positive numbers, the caller can panic.
     54 	//
     55 	// You can return a fixed screen size if you don't care, or you can also return a calculated screen size
     56 	// adjusted with the given outside size.
     57 	Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int)
     58 }
     59 
     60 // DefaultTPS represents a default ticks per second, that represents how many times game updating happens in a second.
     61 const DefaultTPS = 60
     62 
     63 // CurrentFPS returns the current number of FPS (frames per second), that represents
     64 // how many swapping buffer happens per second.
     65 //
     66 // On some environments, CurrentFPS doesn't return a reliable value since vsync doesn't work well there.
     67 // If you want to measure the application's speed, Use CurrentTPS.
     68 //
     69 // CurrentFPS is concurrent-safe.
     70 func CurrentFPS() float64 {
     71 	return clock.CurrentFPS()
     72 }
     73 
     74 var (
     75 	isScreenClearedEveryFrame = int32(1)
     76 	currentMaxTPS             = int32(DefaultTPS)
     77 )
     78 
     79 // SetScreenClearedEveryFrame enables or disables the clearing of the screen at the beginning of each frame.
     80 // The default value is false and the screen is cleared each frame by default.
     81 //
     82 // SetScreenClearedEveryFrame is concurrent-safe.
     83 func SetScreenClearedEveryFrame(cleared bool) {
     84 	v := int32(0)
     85 	if cleared {
     86 		v = 1
     87 	}
     88 	atomic.StoreInt32(&isScreenClearedEveryFrame, v)
     89 	theUIContext.setScreenClearedEveryFrame(cleared)
     90 }
     91 
     92 // IsScreenClearedEveryFrame returns true if the frame isn't cleared at the beginning.
     93 //
     94 // IsScreenClearedEveryFrame is concurrent-safe.
     95 func IsScreenClearedEveryFrame() bool {
     96 	return atomic.LoadInt32(&isScreenClearedEveryFrame) != 0
     97 }
     98 
     99 type imageDumperGameWithDraw struct {
    100 	game Game
    101 	d    *imageDumper
    102 	err  error
    103 }
    104 
    105 func (i *imageDumperGameWithDraw) Update() error {
    106 	if i.err != nil {
    107 		return i.err
    108 	}
    109 	if i.d == nil {
    110 		i.d = &imageDumper{g: i.game}
    111 	}
    112 	return i.d.update()
    113 }
    114 
    115 func (i *imageDumperGameWithDraw) Draw(screen *Image) {
    116 	if i.err != nil {
    117 		return
    118 	}
    119 
    120 	i.game.Draw(screen)
    121 	i.err = i.d.dump(screen)
    122 }
    123 
    124 func (i *imageDumperGameWithDraw) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
    125 	return i.game.Layout(outsideWidth, outsideHeight)
    126 }
    127 
    128 // RunGame starts the main loop and runs the game.
    129 // game's Update function is called every tick to update the game logic.
    130 // game's Draw function is, if it exists, called every frame to draw the screen.
    131 // game's Layout function is called when necessary, and you can specify the logical screen size by the function.
    132 //
    133 // game must implement Game interface.
    134 // Game's Draw function is optional, but it is recommended to implement Draw to seperate updating the logic and
    135 // rendering.
    136 //
    137 // RunGame is a more flexibile form of Run due to game's Layout function.
    138 // You can make a resizable window if you use RunGame, while you cannot if you use Run.
    139 // RunGame is more sophisticated way than Run and hides the notion of 'scale'.
    140 //
    141 // While Run specifies the window size, RunGame does not.
    142 // You need to call SetWindowSize before RunGame if you want.
    143 // Otherwise, a default window size is adopted.
    144 //
    145 // Some functions (ScreenScale, SetScreenScale, SetScreenSize) are not available with RunGame.
    146 //
    147 // On browsers, it is strongly recommended to use iframe if you embed an Ebiten application in your website.
    148 //
    149 // RunGame must be called on the main thread.
    150 // Note that Ebiten bounds the main goroutine to the main OS thread by runtime.LockOSThread.
    151 //
    152 // Ebiten tries to call game's Update function 60 times a second by default. In other words,
    153 // TPS (ticks per second) is 60 by default.
    154 // This is not related to framerate (display's refresh rate).
    155 //
    156 // RunGame returns error when 1) OpenGL error happens, 2) audio error happens or
    157 // 3) f returns error. In the case of 3), RunGame returns the same error.
    158 //
    159 // The size unit is device-independent pixel.
    160 //
    161 // Don't call RunGame twice or more in one process.
    162 func RunGame(game Game) error {
    163 	fixWindowPosition(WindowSize())
    164 	return runGame(&imageDumperGameWithDraw{
    165 		game: game,
    166 	}, 0)
    167 }
    168 
    169 func runGame(game Game, scale float64) error {
    170 	theUIContext.set(game, scale)
    171 	if err := uiDriver().Run(theUIContext); err != nil {
    172 		if err == driver.RegularTermination {
    173 			return nil
    174 		}
    175 		return err
    176 	}
    177 	return nil
    178 }
    179 
    180 // RunGameWithoutMainLoop runs the game, but don't call the loop on the main (UI) thread.
    181 // Different from Run, RunGameWithoutMainLoop returns immediately.
    182 //
    183 // Ebiten users should NOT call RunGameWithoutMainLoop.
    184 // Instead, functions in github.com/hajimehoshi/ebiten/v2/mobile package calls this.
    185 func RunGameWithoutMainLoop(game Game) {
    186 	fixWindowPosition(WindowSize())
    187 	game = &imageDumperGameWithDraw{
    188 		game: game,
    189 	}
    190 	theUIContext.set(game, 0)
    191 	uiDriver().RunWithoutMainLoop(theUIContext)
    192 }
    193 
    194 // ScreenSizeInFullscreen returns the size in device-independent pixels when the game is fullscreen.
    195 // The adopted monitor is the 'current' monitor which the window belongs to.
    196 // The returned value can be given to Run or SetSize function if the perfectly fit fullscreen is needed.
    197 //
    198 // On browsers, ScreenSizeInFullscreen returns the 'window' (global object) size, not 'screen' size since an Ebiten
    199 // game should not know the outside of the window object. For more details, see SetFullscreen API comment.
    200 //
    201 // On mobiles, ScreenSizeInFullscreen returns (0, 0) so far.
    202 //
    203 // ScreenSizeInFullscreen's use cases are limited. If you are making a fullscreen application, you can use RunGame and
    204 // the Game interface's Layout function instead. If you are making a not-fullscreen application but the application's
    205 // behavior depends on the monitor size, ScreenSizeInFullscreen is useful.
    206 //
    207 // ScreenSizeInFullscreen must be called on the main thread before ebiten.Run, and is concurrent-safe after
    208 // ebiten.Run.
    209 func ScreenSizeInFullscreen() (int, int) {
    210 	return uiDriver().ScreenSizeInFullscreen()
    211 }
    212 
    213 // CursorMode returns the current cursor mode.
    214 //
    215 // On browsers, only CursorModeVisible and CursorModeHidden are supported.
    216 //
    217 // CursorMode returns CursorModeHidden on mobiles.
    218 //
    219 // CursorMode is concurrent-safe.
    220 func CursorMode() CursorModeType {
    221 	return CursorModeType(uiDriver().CursorMode())
    222 }
    223 
    224 // SetCursorMode sets the render and capture mode of the mouse cursor.
    225 // CursorModeVisible sets the cursor to always be visible.
    226 // CursorModeHidden hides the system cursor when over the window.
    227 // CursorModeCaptured hides the system cursor and locks it to the window.
    228 //
    229 // On browsers, only CursorModeVisible and CursorModeHidden are supported.
    230 //
    231 // SetCursorMode does nothing on mobiles.
    232 //
    233 // SetCursorMode is concurrent-safe.
    234 func SetCursorMode(mode CursorModeType) {
    235 	uiDriver().SetCursorMode(driver.CursorMode(mode))
    236 }
    237 
    238 // IsFullscreen reports whether the current mode is fullscreen or not.
    239 //
    240 // IsFullscreen always returns false on browsers or mobiles.
    241 //
    242 // IsFullscreen is concurrent-safe.
    243 func IsFullscreen() bool {
    244 	return uiDriver().IsFullscreen()
    245 }
    246 
    247 // SetFullscreen changes the current mode to fullscreen or not on desktops.
    248 //
    249 // On fullscreen mode, the game screen is automatically enlarged
    250 // to fit with the monitor. The current scale value is ignored.
    251 //
    252 // On desktops, Ebiten uses 'windowed' fullscreen mode, which doesn't change
    253 // your monitor's resolution.
    254 //
    255 // SetFullscreen does nothing on browsers or mobiles.
    256 //
    257 // SetFullscreen is concurrent-safe.
    258 func SetFullscreen(fullscreen bool) {
    259 	uiDriver().SetFullscreen(fullscreen)
    260 }
    261 
    262 // IsFocused returns a boolean value indicating whether
    263 // the game is in focus or in the foreground.
    264 //
    265 // IsFocused will only return true if IsRunnableOnUnfocused is false.
    266 //
    267 // IsFocused is concurrent-safe.
    268 func IsFocused() bool {
    269 	return uiDriver().IsFocused()
    270 }
    271 
    272 // IsRunnableOnUnfocused returns a boolean value indicating whether
    273 // the game runs even in background.
    274 //
    275 // IsRunnableOnUnfocused is concurrent-safe.
    276 func IsRunnableOnUnfocused() bool {
    277 	return uiDriver().IsRunnableOnUnfocused()
    278 }
    279 
    280 // SetRunnableOnUnfocused sets the state if the game runs even in background.
    281 //
    282 // If the given value is true, the game runs even in background e.g. when losing focus.
    283 // The initial state is true.
    284 //
    285 // Known issue: On browsers, even if the state is on, the game doesn't run in background tabs.
    286 // This is because browsers throttles background tabs not to often update.
    287 //
    288 // SetRunnableOnUnfocused does nothing on mobiles so far.
    289 //
    290 // SetRunnableOnUnfocused is concurrent-safe.
    291 func SetRunnableOnUnfocused(runnableOnUnfocused bool) {
    292 	uiDriver().SetRunnableOnUnfocused(runnableOnUnfocused)
    293 }
    294 
    295 // DeviceScaleFactor returns a device scale factor value of the current monitor which the window belongs to.
    296 //
    297 // DeviceScaleFactor returns a meaningful value on high-DPI display environment,
    298 // otherwise DeviceScaleFactor returns 1.
    299 //
    300 // DeviceScaleFactor might panic on init function on some devices like Android.
    301 // Then, it is not recommended to call DeviceScaleFactor from init functions.
    302 //
    303 // DeviceScaleFactor must be called on the main thread before the main loop, and is concurrent-safe after the main loop.
    304 func DeviceScaleFactor() float64 {
    305 	return uiDriver().DeviceScaleFactor()
    306 }
    307 
    308 // IsVsyncEnabled returns a boolean value indicating whether
    309 // the game uses the display's vsync.
    310 //
    311 // IsVsyncEnabled is concurrent-safe.
    312 func IsVsyncEnabled() bool {
    313 	return uiDriver().IsVsyncEnabled()
    314 }
    315 
    316 // SetVsyncEnabled sets a boolean value indicating whether
    317 // the game uses the display's vsync.
    318 //
    319 // If the given value is true, the game tries to sync the display's refresh rate.
    320 // If false, the game ignores the display's refresh rate.
    321 // The initial value is true.
    322 // By disabling vsync, the game works more efficiently but consumes more CPU.
    323 //
    324 // Note that the state doesn't affect TPS (ticks per second, i.e. how many the run function is
    325 // updated per second).
    326 //
    327 // SetVsyncEnabled does nothing on mobiles so far.
    328 //
    329 // SetVsyncEnabled is concurrent-safe.
    330 func SetVsyncEnabled(enabled bool) {
    331 	uiDriver().SetVsyncEnabled(enabled)
    332 }
    333 
    334 // MaxTPS returns the current maximum TPS.
    335 //
    336 // MaxTPS is concurrent-safe.
    337 func MaxTPS() int {
    338 	return int(atomic.LoadInt32(&currentMaxTPS))
    339 }
    340 
    341 // CurrentTPS returns the current TPS (ticks per second),
    342 // that represents how many update function is called in a second.
    343 //
    344 // CurrentTPS is concurrent-safe.
    345 func CurrentTPS() float64 {
    346 	return clock.CurrentTPS()
    347 }
    348 
    349 // UncappedTPS is a special TPS value that means the game doesn't have limitation on TPS.
    350 const UncappedTPS = clock.UncappedTPS
    351 
    352 // SetMaxTPS sets the maximum TPS (ticks per second),
    353 // that represents how many updating function is called per second.
    354 // The initial value is 60.
    355 //
    356 // If tps is UncappedTPS, TPS is uncapped and the game is updated per frame.
    357 // If tps is negative but not UncappedTPS, SetMaxTPS panics.
    358 //
    359 // SetMaxTPS is concurrent-safe.
    360 func SetMaxTPS(tps int) {
    361 	if tps < 0 && tps != UncappedTPS {
    362 		panic("ebiten: tps must be >= 0 or UncappedTPS")
    363 	}
    364 	atomic.StoreInt32(&currentMaxTPS, int32(tps))
    365 }
    366 
    367 // IsScreenTransparent reports whether the window is transparent.
    368 //
    369 // IsScreenTransparent is concurrent-safe.
    370 func IsScreenTransparent() bool {
    371 	return uiDriver().IsScreenTransparent()
    372 }
    373 
    374 // SetScreenTransparent sets the state if the window is transparent.
    375 //
    376 // SetScreenTransparent panics if SetScreenTransparent is called after the main loop.
    377 //
    378 // SetScreenTransparent does nothing on mobiles.
    379 //
    380 // SetScreenTransparent is concurrent-safe.
    381 func SetScreenTransparent(transparent bool) {
    382 	uiDriver().SetScreenTransparent(transparent)
    383 }
    384 
    385 // SetInitFocused sets whether the application is focused on show.
    386 // The default value is true, i.e., the application is focused.
    387 // Note that the application does not proceed if this is not focused by default.
    388 // This behavior can be changed by SetRunnableInBackground.
    389 //
    390 // SetInitFocused does nothing on mobile.
    391 //
    392 // SetInitFocused panics if this is called after the main loop.
    393 //
    394 // SetInitFocused is cuncurrent-safe.
    395 func SetInitFocused(focused bool) {
    396 	uiDriver().SetInitFocused(focused)
    397 }