Starting a new project

Copy-paste/checklist for getting things rolling.

Stack environment

# Check for a recent one at https://gitlab.com/keid/meta/-/tree/main/resolvers
resolver: https://gitlab.com/keid/meta/-/raw/main/resolvers/keid-engine-2022-08-20.yaml

packages:
- . # this one

extra-deps: {}
# hacking time!
# - ../../engine/core
# - ../../engine/render-basic

# let the ghcup in
system-ghc: true

# your users will thank you later
ghc-options:
  "$everything": -split-sections -j2
  "$locals": -split-sections -j8

Entry point

app/Main.hs

module Main (main) where

-- Prelude used with Keid, from `rio` package
import RIO -- rio

-- From `rio-app` package
import Engine.App (engineMain)

-- Initial stage, from project library or executable
import Stage.Example (stackStage)

main :: IO ()
main = engineMain stackStage

Global

Render

A bunch of keid-render-basic types for now. The aliases are shared with downstream stage components.

module Global.Render where

import Engine.Stage.Component qualified as Stage
import Engine.Types qualified as Engine
import Render.Basic qualified as Basic

type Frame = Engine.Frame RenderPasses Pipelines
type Stage = Engine.Stage RenderPasses Pipelines
type StageFrameRIO fr rs = Engine.StageFrameRIO RenderPasses Pipelines fr rs
type StageResources fr rs = Stage.Resources RenderPasses Pipelines fr rs
type StageScene fr rs = Stage.Scene RenderPasses Pipelines fr rs

type RenderPasses = Basic.RenderPasses

type Pipelines = Basic.Pipelines

component :: Basic.Rendering st
component = Basic.rendering_

Assets

TBD

Stage

Setup

app/Stage/<StageName>.hs:

module Stage.StageName where

-- the prelude
import RIO

import Engine.Stage.Component qualified as Stage
import Engine.Types (StackStage(..))

import Global.Render qualified as Render
import Stage.StageName.Resources qualified as Resources
import Stage.StageName.Scene qualified as Scene
import Stage.StageName.Types (Stage)

stackStage :: StackStage
stackStage = StackStage stage

stage :: Workbench.Stage
stage =
  Stage.assemble
    "Main"
    Render.component
    Resources.component
    (Just Scene.component)

Types

module Stage.Workbench.Types where

import RIO

import Vulkan.Core10 qualified as Vk

import Global.Render qualified as Render

type Stage = Render.Stage FrameResources RunState
type Frame = Render.Frame FrameResources
type Scene = Render.StageScene RunState FrameResources
type RecordCommands a = Vk.CommandBuffer -> FrameResources -> Word32 -> Render.StageFrameRIO FrameResources RunState a

-- Double-buffered resources used in rendering
data FrameResources = FrameResources
  {
  }

-- Inter-frame persistent resources
data RunState = RunState
  {
  }

Resources

module Stage.Workbench.Resources where

import RIO

import Control.Monad.Trans.Resource (ResourceT)
import Engine.Stage.Component qualified as Stage
import Engine.Types (StageRIO, StageSetupRIO)
import Engine.Vulkan.Types (Queues)
import Resource.Region (ReleaseKey)
import Resource.Region qualified as Region
import Vulkan.Core10 qualified as Vk

import Global.Render qualified
import Stage.Workbench.Types qualified as Workbench

component :: Workbench.Resources
component = Stage.Resources
  { rInitialRS = initialRunState
  , rInitialRR = initialRecycledResources
  }

initialRunState :: StageSetupRIO (ReleaseKey, Workbench.RunState)
initialRunState = Region.run do
  pure Workbench.RunState{}

initialRecycledResources
  :: Queues Vk.CommandPool
  -> Global.Render.RenderPasses
  -> Global.Render.Pipelines
  -> ResourceT (StageRIO Workbench.RunState) Workbench.FrameResources
initialRecycledResources _pools _renderpasses _pipelines = do
  pure Workbench.FrameResources{}

Scene

module Stage.Workbench.Scene where

import RIO

import Engine.Stage.Component qualified as Stage
import Engine.Types qualified as Engine
import Engine.Vulkan.Swapchain qualified as Swapchain
import Render.Basic qualified as Basic
import Render.Pass (usePass)

import  Stage.Workbench.Types qualified as Workbench

component :: Workbench.Scene
component = Stage.Scene
  { scBeforeLoop = pure ()
  , scUpdateBuffers = updateBuffers
  , scRecordCommands = recordCommands
  }

updateBuffers :: Workbench.UpdateBuffers ()
updateBuffers Workbench.RunState{} Workbench.FrameResources{} = do
  pure ()

recordCommands :: Workbench.RecordCommands ()
recordCommands cb Workbench.FrameResources{} imageIndex = do
  Engine.Frame{fRenderpass, fSwapchainResources, fPipelines} <- asks snd
  usePass (Basic.rpForwardMsaa fRenderpass) imageIndex cb do
    Swapchain.setDynamicFullscreen cb fSwapchainResources