module Stage.Loader.UI ( Settings(..) , UI(..) , spawn , Observer(..) , newObserver , observe ) where import RIO import Control.Monad.Trans.Resource (ResourceT) import Control.Monad.Trans.Resource qualified as Resource import Geomancy (vec4) import Geomancy.Layout qualified as Layout import Geomancy.Layout.Alignment qualified as Alignment import Geomancy.Layout.Box qualified as Box import Geomancy.Transform qualified as Transform import Vulkan.Core10 qualified as Vk import Engine.Camera qualified as Camera import Engine.Types qualified as Engine import Engine.UI.Message qualified as Message import Engine.Vulkan.Types (HasVulkan, Queues) import Engine.Worker qualified as Worker import Geometry.Quad qualified as Quad import Render.Samplers qualified as Samplers import Render.Unlit.Textured.Model qualified as UnlitTextured import Resource.Buffer qualified as Buffer import Resource.Combined.Textures qualified as CombinedTextures import Resource.Font.EvanW qualified as EvanW import Resource.Model qualified as Model import Resource.Model.Observer qualified as Observer import Resource.Region qualified as Region import Resource.Texture (Texture, Flat) data Settings fonts textures = Settings { titleMessage :: Text , backgroundIx :: Int32 , spinnerIx :: Int32 , combined :: CombinedTextures.Collection textures fonts (Int32, Texture Flat) , fonts :: fonts EvanW.Container , smallFont :: forall a . fonts a -> a , largeFont :: forall a . fonts a -> a } data UI = UI { titleP :: Message.Process , subtitleP :: Message.Process , progressInput :: Worker.Var Message.Input , progressP :: Message.Process , backgroundP :: Worker.Merge UnlitTextured.Stores , spinnerP :: Worker.Merge UnlitTextured.Stores , quadUV :: UnlitTextured.Model 'Buffer.Staged } spawn :: Queues Vk.CommandPool -> Settings fonts textures -> Engine.StageRIO env (Resource.ReleaseKey, UI) spawn pools Settings{..} = Region.run do screenBoxP <- Camera.trackOrthoPixelsCentered screenPaddedP <- Worker.spawnMerge1 (Box.resize (-16)) screenBoxP -- Messages sectionsP <- Worker.spawnMerge1 ( \parent -> let (top, bottom) = Layout.vertical (Right 0.5) parent in ( top , Layout.vertical (Right 0.5) bottom ) ) screenPaddedP titleBoxP <- Worker.spawnMerge1 fst sectionsP titleP <- Worker.newVar title >>= Message.spawn titleBoxP lowerSectionP <- Worker.spawnMerge1 snd sectionsP subtitleBoxP <- Worker.spawnMerge1 fst lowerSectionP subtitleP <- Worker.newVar subtitle >>= Message.spawn subtitleBoxP progressInput <- Worker.newVar progress progressBoxP <- Worker.spawnMerge1 snd lowerSectionP progressP <- Message.spawn progressBoxP progressInput -- Splash backgroundBoxP <- Worker.spawnMerge1 (Layout.placeAspect Alignment.center 1) screenBoxP backgroundP <- Worker.spawnMerge1 ( \box -> UnlitTextured.stores1 (Samplers.linear Samplers.indices) backgroundIx [Box.mkTransform box] ) backgroundBoxP -- Spinner spinnerTransformTimeP <- Worker.spawnTimed_ True 100 mempty do t <- getMonotonicTime pure $ Transform.rotateZ (realToFrac t) spinnerTransformBoxP <- Worker.spawnMerge1 (Box.mkTransform) -- FIXME: . Layout.boxFitScale 64) subtitleBoxP spinnerP <- Worker.spawnMerge2 ( \place turn -> UnlitTextured.stores1 (Samplers.linear Samplers.indices) spinnerIx [turn, place] ) spinnerTransformBoxP spinnerTransformTimeP -- Models quadUV <- Model.createStagedL (Just "quadUV") pools (Quad.toVertices Quad.texturedQuad) Nothing Model.registerIndexed_ quadUV pure UI{..} where title = Message.Input { inputText = titleMessage , inputOrigin = Alignment.centerBottom , inputSize = 64 , inputColor = vec4 1 0.5 0.25 1 , inputFont = largeFont fonts , inputFontId = fst . largeFont $ CombinedTextures.fonts combined , inputOutline = vec4 0 0 0 1 , inputOutlineWidth = 4/16 , inputSmoothing = 1/16 } subtitle = Message.Input { inputText = "Loading..." , inputOrigin = Alignment.centerTop , inputSize = 32 , inputColor = vec4 0.5 1 0.25 1 , inputFont = smallFont fonts , inputFontId = fst . smallFont $ CombinedTextures.fonts combined , inputOutline = vec4 0 0 0 1 , inputOutlineWidth = 4/16 , inputSmoothing = 1/16 } progress = Message.Input { inputText = "" , inputOrigin = Alignment.centerBottom , inputSize = 16 , inputColor = vec4 0.25 0.5 1 1 , inputFont = smallFont fonts , inputFontId = fst . smallFont $ CombinedTextures.fonts combined , inputOutline = 0 , inputOutlineWidth = 0 , inputSmoothing = 1/16 } data Observer = Observer { messages :: [Message.Observer] , background :: UnlitTextured.ObserverCoherent , spinner :: UnlitTextured.ObserverCoherent } newObserver :: UI -> ResourceT (Engine.StageRIO st) Observer newObserver UI{..} = do -- XXX: Generic? messages <- traverse (const $ Message.newObserver 256) [ titleP , subtitleP , progressP ] background <- Observer.newCoherent 1 "background" spinner <- Observer.newCoherent 1 "spinner" pure Observer{..} observe :: ( HasVulkan env ) => UI -> Observer -> RIO env () observe UI{..} Observer{..} = do traverse_ (uncurry Message.observe) $ zip [titleP, subtitleP, progressP] messages Observer.observeCoherent backgroundP background Observer.observeCoherent spinnerP spinner