module Engine.UI.Message
( Process
, Input(..)
, spawn
, spawnFromR
, mkAttrs
, Observer
, Buffer
, newObserver
, observe
) where
import RIO
import Control.Monad.Trans.Resource (ResourceT)
import Control.Monad.Trans.Resource qualified as Resource
import Data.Text qualified as Text
import Data.Vector.Storable qualified as Storable
import Geomancy (Vec4)
import Geomancy.Vec4 qualified as Vec4
import Vulkan.Core10 qualified as Vk
import Engine.Types qualified as Engine
import Engine.UI.Layout qualified as Layout
import Engine.Vulkan.Types (HasVulkan)
import Engine.Worker qualified as Worker
import Render.Font.EvanwSdf.Model qualified as EvanwSdf
import Render.Samplers qualified as Samplers
import Resource.Buffer qualified as Buffer
import Resource.Font.EvanW qualified as Font
type Process = Worker.Merge (Storable.Vector EvanwSdf.InstanceAttrs)
spawn
:: ( Worker.HasOutput box
, Worker.GetOutput box ~ Layout.Box
, Worker.HasOutput input
, Worker.GetOutput input ~ Input
) => box -> input -> RIO env Process
spawn = Worker.spawnMerge2 mkAttrs
spawnFromR
:: ( Resource.MonadResource (RIO env)
, Worker.HasOutput box
, Worker.GetOutput box ~ Layout.Box
, Worker.HasOutput source
)
=> box
-> source
-> (Worker.GetOutput source -> Input)
-> RIO env (Resource.ReleaseKey, Resource.ReleaseKey, Process)
spawnFromR parent inputProc mkMessage = do
inputP <- Worker.spawnMerge1 mkMessage inputProc
messageP <- spawn parent inputP
(,,messageP)
<$> Worker.register inputP
<*> Worker.register messageP
data Input = Input
{ inputText :: Text
, inputFontId :: Int32
, inputFont :: Font.Container
, inputOrigin :: Layout.Alignment
, inputSize :: Float
, inputColor :: Vec4
, inputOutline :: Vec4
, inputOutlineWidth :: Float
, inputSmoothing :: Float
}
mkAttrs :: Layout.Box -> Input -> Storable.Vector EvanwSdf.InstanceAttrs
mkAttrs Layout.Box{..} Input{..} =
if inputSize < 1 then mempty else Storable.fromList do
Font.PutChar{..} <- chars
pure EvanwSdf.InstanceAttrs
{ vertRect = Vec4.fromVec22 pcPos pcSize
, fragRect = Vec4.fromVec22 pcOffset pcScale
, color = inputColor
, outlineColor = inputOutline -- vec4 0 0.25 0 0.25
, textureId = inputFontId
, samplerId = samplerId
, smoothing = inputSmoothing -- 1/16
, outlineWidth = inputOutlineWidth -- 3/16
}
where
(scale, chars) = Font.putLine
boxSize
boxPosition
inputOrigin
inputSize
inputFont
(Text.unpack inputText)
samplerId =
if scale > 1 then
Samplers.linear Samplers.indices
else
Samplers.linear Samplers.indices
type Buffer = Buffer.Allocated 'Buffer.Coherent EvanwSdf.InstanceAttrs
type Observer = Worker.ObserverIO Buffer
newObserver :: Int -> ResourceT (Engine.StageRIO st) Observer
newObserver initialSize = do
context <- ask
messageData <- Buffer.createCoherent context Vk.BUFFER_USAGE_VERTEX_BUFFER_BIT initialSize mempty
observer <- Worker.newObserverIO messageData
void $! Resource.register do
vData <- readIORef observer
Buffer.destroyAll context vData
pure observer
observe
:: ( HasVulkan env
, Worker.HasOutput source
, Worker.GetOutput source ~ Storable.Vector EvanwSdf.InstanceAttrs
)
=> source
-> Observer -> RIO env ()
observe messageP observer = do
context <- ask
Worker.observeIO_ messageP observer $
Buffer.updateCoherentResize_ context