Files
galaxy-game/client/world/renderer_schedule.go
T
2026-03-07 00:29:06 +03:00

71 lines
2.3 KiB
Go

// Pseudo-code / toolkit-agnostic example.
// Goal: never render more than one frame concurrently, and always render the latest params.
//
// Это не “асинхронная работа в фоне”, а чистый паттерн управления вызовами Render.
// Он работает в любом UI, где у тебя есть loop и возможность запускать отрисовку
// (например, через requestAnimationFrame-аналог или таски).
//
// Как это сочетается с CoalesceUpdates
// - Если params.Options.Incremental.CoalesceUpdates == true, UI использует этот scheduler.
// - Если false, UI может пытаться рендерить каждое событие (но это обычно хуже).
//
// # Важный момент
//
// Это не делает рендер асинхронным в смысле “рендерить в фоне” — в реальном UI ты должен
// выполнять w.Render строго в UI thread. Я показал go только как “планировщик”
// (в твоём GUI заменишь на invokeOnMainThread/PostTask/RunOnUI).
package world
import "sync"
type RenderScheduler struct {
w *World
drawer PrimitiveDrawer
// Protects fields below.
mu sync.Mutex
inFlight bool
pending bool
latest RenderParams
}
// RequestRender stores the latest params and schedules rendering.
// If a render is already in progress, it coalesces (drops intermediate requests).
func (s *RenderScheduler) RequestRender(params RenderParams) {
s.mu.Lock()
s.latest = params
if s.inFlight {
s.pending = true
s.mu.Unlock()
return
}
s.inFlight = true
s.mu.Unlock()
// Schedule on the UI thread/event loop. Replace this with your toolkit method.
go s.runOnUIThread()
}
// runOnUIThread should execute on the UI thread.
// Replace the body with actual UI scheduling primitives.
func (s *RenderScheduler) runOnUIThread() {
for {
s.mu.Lock()
params := s.latest
s.mu.Unlock()
_ = s.w.Render(s.drawer, params) // handle error in real code
s.mu.Lock()
if !s.pending {
s.inFlight = false
s.mu.Unlock()
return
}
// There was a newer request while we were rendering. Loop and render latest.
s.pending = false
s.mu.Unlock()
}
}