{-# LANGUAGE RecordWildCards #-}

module Potato.Flow.Render (
  RenderCache(..)
  , RenderContext(..)
  , emptyRenderContext
  , emptyRenderCache
  , renderCache_clearAtKeys
  , renderCache_lookup
  , render -- TODO DELETE use render_new instead because it uses cache
  , render_new

  , RenderedCanvasRegion(..)
  , renderedCanvas_box
  , renderedCanvasRegion_nonEmptyCount
  , emptyRenderedCanvasRegion
  , printRenderedCanvasRegion
  , potatoRenderWithOwlTree
  , potatoRenderPFState
  , renderedCanvasToText
  , renderedCanvasRegionToText

  , renderWithBroadPhase
  , moveRenderedCanvasRegion
  , updateCanvas

  -- exposed for testing
  , moveRenderedCanvasRegionNoReRender
) where

import           Relude

import           Potato.Flow.RenderCache
import           Potato.Flow.BroadPhase
import           Potato.Flow.Math
import           Potato.Flow.SEltMethods
import           Potato.Flow.Methods.Types
import           Potato.Flow.SElts
import Potato.Flow.Types
import Potato.Flow.OwlState
import           Potato.Flow.OwlItem
import Potato.Flow.Owl
import           Potato.Flow.Controller.Types
import           Potato.Flow.Controller.OwlLayers
import           Potato.Flow.Methods.LineTypes


import qualified Data.IntMap             as IM
import qualified Data.Text               as T
import qualified Data.Text.IO as T
import qualified Data.Vector.Unboxed     as V
import qualified Data.Sequence as Seq
import Control.Exception (assert)

-- rather pointless abstraction but it's useful to have during refactors such that I don't ned to provide an explicit LayerMetaMap
class OwlRenderSet a where
  findSuperOwl :: a -> REltId -> Maybe (SuperOwl, Bool)
  sortForRendering :: a -> Seq.Seq SuperOwl -> Seq.Seq SuperOwl
  findSuperOwlForRendering :: a -> REltId -> Maybe SuperOwl
  findSuperOwlForRendering a
ors Int
rid = case forall a. OwlRenderSet a => a -> Int -> Maybe (SuperOwl, Bool)
findSuperOwl a
ors Int
rid of
    Maybe (SuperOwl, Bool)
Nothing -> forall a. Maybe a
Nothing
    Just (SuperOwl
sowl, Bool
b) -> if Bool
b then forall a. Maybe a
Nothing else forall a. a -> Maybe a
Just SuperOwl
sowl

instance OwlRenderSet OwlTree where
  findSuperOwl :: OwlTree -> Int -> Maybe (SuperOwl, Bool)
findSuperOwl OwlTree
ot = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (,Bool
False) forall b c a. (b -> c) -> (a -> b) -> a -> c
. OwlTree -> Int -> Maybe SuperOwl
owlTree_findSuperOwl OwlTree
ot
  sortForRendering :: OwlTree -> Seq SuperOwl -> Seq SuperOwl
sortForRendering OwlTree
a Seq SuperOwl
sowls = SuperOwlParliament -> Seq SuperOwl
unSuperOwlParliament forall a b. (a -> b) -> a -> b
$ OwlTree -> Seq SuperOwl -> SuperOwlParliament
makeSortedSuperOwlParliament OwlTree
a Seq SuperOwl
sowls

instance OwlRenderSet (OwlTree, LayerMetaMap) where
  findSuperOwl :: (OwlTree, LayerMetaMap) -> Int -> Maybe (SuperOwl, Bool)
findSuperOwl (OwlTree
ot,LayerMetaMap
lmm) Int
rid = Maybe (SuperOwl, Bool)
r where
    hidden :: Bool
hidden = OwlTree -> Int -> LayerMetaMap -> Bool
layerMetaMap_isInheritHidden OwlTree
ot Int
rid LayerMetaMap
lmm
    r :: Maybe (SuperOwl, Bool)
r = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (,Bool
hidden) forall a b. (a -> b) -> a -> b
$ OwlTree -> Int -> Maybe SuperOwl
owlTree_findSuperOwl OwlTree
ot Int
rid
  sortForRendering :: (OwlTree, LayerMetaMap) -> Seq SuperOwl -> Seq SuperOwl
sortForRendering (OwlTree
ot,LayerMetaMap
_) Seq SuperOwl
sowls = forall a. OwlRenderSet a => a -> Seq SuperOwl -> Seq SuperOwl
sortForRendering OwlTree
ot Seq SuperOwl
sowls

-- RenderContext is a helper container type that provides both read and write data for various render operations
data RenderContext = RenderContext {
  RenderContext -> RenderCache
_renderContext_cache :: RenderCache -- r/w
  , RenderContext -> OwlTree
_renderContext_owlTree :: OwlTree -- r
  , RenderContext -> LayerMetaMap
_renderContext_layerMetaMap :: LayerMetaMap -- r
  , RenderContext -> BroadPhaseState
_renderContext_broadPhase :: BroadPhaseState -- r
  , RenderContext -> RenderedCanvasRegion
_renderContext_renderedCanvasRegion :: RenderedCanvasRegion -- r/w
}

emptyRenderContext :: LBox -> RenderContext
emptyRenderContext :: LBox -> RenderContext
emptyRenderContext LBox
lbox = RenderContext {
    _renderContext_cache :: RenderCache
_renderContext_cache = RenderCache
emptyRenderCache
    , _renderContext_owlTree :: OwlTree
_renderContext_owlTree = OwlTree
emptyOwlTree
    , _renderContext_layerMetaMap :: LayerMetaMap
_renderContext_layerMetaMap = forall a. IntMap a
IM.empty
    , _renderContext_broadPhase :: BroadPhaseState
_renderContext_broadPhase = BroadPhaseState
emptyBroadPhaseState
    , _renderContext_renderedCanvasRegion :: RenderedCanvasRegion
_renderContext_renderedCanvasRegion = LBox -> RenderedCanvasRegion
emptyRenderedCanvasRegion LBox
lbox
  }


instance HasOwlTree RenderContext where
  hasOwlTree_owlTree :: RenderContext -> OwlTree
hasOwlTree_owlTree = forall o. HasOwlTree o => o -> OwlTree
hasOwlTree_owlTree forall b c a. (b -> c) -> (a -> b) -> a -> c
. RenderContext -> OwlTree
_renderContext_owlTree

instance OwlRenderSet RenderContext where
  findSuperOwl :: RenderContext -> Int -> Maybe (SuperOwl, Bool)
findSuperOwl RenderContext {LayerMetaMap
OwlTree
RenderCache
BroadPhaseState
RenderedCanvasRegion
_renderContext_renderedCanvasRegion :: RenderedCanvasRegion
_renderContext_broadPhase :: BroadPhaseState
_renderContext_layerMetaMap :: LayerMetaMap
_renderContext_owlTree :: OwlTree
_renderContext_cache :: RenderCache
_renderContext_renderedCanvasRegion :: RenderContext -> RenderedCanvasRegion
_renderContext_broadPhase :: RenderContext -> BroadPhaseState
_renderContext_layerMetaMap :: RenderContext -> LayerMetaMap
_renderContext_owlTree :: RenderContext -> OwlTree
_renderContext_cache :: RenderContext -> RenderCache
..} Int
rid = forall a. OwlRenderSet a => a -> Int -> Maybe (SuperOwl, Bool)
findSuperOwl (OwlTree
_renderContext_owlTree, LayerMetaMap
_renderContext_layerMetaMap) Int
rid
  sortForRendering :: RenderContext -> Seq SuperOwl -> Seq SuperOwl
sortForRendering RenderContext {LayerMetaMap
OwlTree
RenderCache
BroadPhaseState
RenderedCanvasRegion
_renderContext_renderedCanvasRegion :: RenderedCanvasRegion
_renderContext_broadPhase :: BroadPhaseState
_renderContext_layerMetaMap :: LayerMetaMap
_renderContext_owlTree :: OwlTree
_renderContext_cache :: RenderCache
_renderContext_renderedCanvasRegion :: RenderContext -> RenderedCanvasRegion
_renderContext_broadPhase :: RenderContext -> BroadPhaseState
_renderContext_layerMetaMap :: RenderContext -> LayerMetaMap
_renderContext_owlTree :: RenderContext -> OwlTree
_renderContext_cache :: RenderContext -> RenderCache
..} Seq SuperOwl
sowls = forall a. OwlRenderSet a => a -> Seq SuperOwl -> Seq SuperOwl
sortForRendering (OwlTree
_renderContext_owlTree, LayerMetaMap
_renderContext_layerMetaMap) Seq SuperOwl
sowls



emptyChar :: PChar
emptyChar :: Char
emptyChar = Char
' '


-- TODO for selection rendering you want to make it V.Vector (Maybe PChar) or maybe you can just use a map?
{-
class IsRenderedCanvasRegion rc where
  isRenderedCanvasRegion_area :: LBox
  isRenderedCanvasRegion_generateMaybe :: (Int, Int) -> ((Int, Int) -> Maybe PChar) -> rc
-}

-- A rendered region in Canvas space
data RenderedCanvasRegion = RenderedCanvasRegion {
  RenderedCanvasRegion -> LBox
_renderedCanvasRegion_box        :: LBox
  , RenderedCanvasRegion -> Vector MWidePChar
_renderedCanvasRegion_contents :: V.Vector MWidePChar -- ^ row major
} deriving (RenderedCanvasRegion -> RenderedCanvasRegion -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RenderedCanvasRegion -> RenderedCanvasRegion -> Bool
$c/= :: RenderedCanvasRegion -> RenderedCanvasRegion -> Bool
== :: RenderedCanvasRegion -> RenderedCanvasRegion -> Bool
$c== :: RenderedCanvasRegion -> RenderedCanvasRegion -> Bool
Eq, Int -> RenderedCanvasRegion -> ShowS
[RenderedCanvasRegion] -> ShowS
RenderedCanvasRegion -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RenderedCanvasRegion] -> ShowS
$cshowList :: [RenderedCanvasRegion] -> ShowS
show :: RenderedCanvasRegion -> String
$cshow :: RenderedCanvasRegion -> String
showsPrec :: Int -> RenderedCanvasRegion -> ShowS
$cshowsPrec :: Int -> RenderedCanvasRegion -> ShowS
Show)

renderedCanvas_box :: RenderedCanvasRegion -> LBox
renderedCanvas_box :: RenderedCanvasRegion -> LBox
renderedCanvas_box = RenderedCanvasRegion -> LBox
_renderedCanvasRegion_box

emptyRenderedCanvasRegion :: LBox -> RenderedCanvasRegion
emptyRenderedCanvasRegion :: LBox -> RenderedCanvasRegion
emptyRenderedCanvasRegion lb :: LBox
lb@(LBox XY
_ (V2 Int
w Int
h)) = RenderedCanvasRegion {
    _renderedCanvasRegion_box :: LBox
_renderedCanvasRegion_box = LBox
lb
    , _renderedCanvasRegion_contents :: Vector MWidePChar
_renderedCanvasRegion_contents = forall a. Unbox a => Int -> a -> Vector a
V.replicate (Int
wforall a. Num a => a -> a -> a
*Int
h) MWidePChar
emptyMWidePChar
  }

-- empty spaces due to wide chars to the left are not counted
renderedCanvasRegion_nonEmptyCount :: RenderedCanvasRegion -> Int
renderedCanvasRegion_nonEmptyCount :: RenderedCanvasRegion -> Int
renderedCanvasRegion_nonEmptyCount = forall a. Unbox a => Vector a -> Int
V.length forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Unbox a => (a -> Bool) -> Vector a -> Vector a
V.filter (\MWidePChar
x -> MWidePChar
x forall a. Eq a => a -> a -> Bool
/= MWidePChar
emptyMWidePChar) forall b c a. (b -> c) -> (a -> b) -> a -> c
. RenderedCanvasRegion -> Vector MWidePChar
_renderedCanvasRegion_contents

-- | brute force renders a RenderedCanvasRegion (ignores broadphase)
potatoRenderWithOwlTree :: OwlTree -> [OwlSubItem] -> RenderedCanvasRegion -> RenderedCanvasRegion
potatoRenderWithOwlTree :: OwlTree
-> [OwlSubItem] -> RenderedCanvasRegion -> RenderedCanvasRegion
potatoRenderWithOwlTree OwlTree
ot [OwlSubItem]
osubitems RenderedCanvasRegion
prevrcr = RenderedCanvasRegion
r where
  drawerswithcache :: [(SEltDrawer, Maybe OwlItemCache)]
drawerswithcache = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\OwlSubItem
osubitem -> (OwlSubItem -> Maybe OwlItemCache -> SEltDrawer
getDrawerWithCache OwlSubItem
osubitem forall a. Maybe a
Nothing, forall a. Maybe a
Nothing)) [OwlSubItem]
osubitems 
  llbx :: LBox
llbx = RenderedCanvasRegion -> LBox
_renderedCanvasRegion_box RenderedCanvasRegion
prevrcr
  r :: RenderedCanvasRegion
r = forall a.
HasOwlTree a =>
a
-> LBox
-> [(SEltDrawer, Maybe OwlItemCache)]
-> RenderedCanvasRegion
-> RenderedCanvasRegion
render_withCache OwlTree
ot LBox
llbx [(SEltDrawer, Maybe OwlItemCache)]
drawerswithcache RenderedCanvasRegion
prevrcr

potatoRenderPFState :: OwlPFState -> RenderedCanvasRegion
potatoRenderPFState :: OwlPFState -> RenderedCanvasRegion
potatoRenderPFState OwlPFState {SCanvas
OwlTree
_owlPFState_canvas :: OwlPFState -> SCanvas
_owlPFState_owlTree :: OwlPFState -> OwlTree
_owlPFState_canvas :: SCanvas
_owlPFState_owlTree :: OwlTree
..} = OwlTree
-> [OwlSubItem] -> RenderedCanvasRegion -> RenderedCanvasRegion
potatoRenderWithOwlTree OwlTree
_owlPFState_owlTree (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap OwlItem -> OwlSubItem
_owlItem_subItem forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> [a]
toList forall b c a. (b -> c) -> (a -> b) -> a -> c
. OwlTree -> OwlMapping
_owlTree_mapping forall a b. (a -> b) -> a -> b
$ OwlTree
_owlPFState_owlTree) (LBox -> RenderedCanvasRegion
emptyRenderedCanvasRegion (SCanvas -> LBox
_sCanvas_box SCanvas
_owlPFState_canvas))


render_withCache :: (HasOwlTree a) => a -> LBox -> [(SEltDrawer, Maybe OwlItemCache)] -> RenderedCanvasRegion -> RenderedCanvasRegion
render_withCache :: forall a.
HasOwlTree a =>
a
-> LBox
-> [(SEltDrawer, Maybe OwlItemCache)]
-> RenderedCanvasRegion
-> RenderedCanvasRegion
render_withCache a
ot LBox
llbx [(SEltDrawer, Maybe OwlItemCache)]
drawerswithcache RenderedCanvasRegion
prevrcr = RenderedCanvasRegion
r where

  genfn :: Int -> (Int, MWidePChar)
genfn Int
i = (Int, MWidePChar)
newc' where
    -- construct parent point and index
    pt :: XY
pt = LBox -> Int -> XY
toPoint LBox
llbx Int
i
    pindex :: Int
pindex = LBox -> XY -> Int
toIndex (RenderedCanvasRegion -> LBox
_renderedCanvasRegion_box RenderedCanvasRegion
prevrcr) XY
pt

    -- go through drawers in reverse order until you find a match
    --mdrawn = join . find isJust $ (fmap (\d -> _sEltDrawer_renderFn d _renderContext_owlTree pt) drawers)
    -- go through caches (they should have all been updated in the previous step) until you find a match
    drawfn :: (SEltDrawer, Maybe OwlItemCache) -> Maybe MWidePChar
drawfn (SEltDrawer
drawer, Maybe OwlItemCache
mcache) = case Maybe OwlItemCache
mcache of
      Maybe OwlItemCache
Nothing -> Maybe MWidePChar
drawnocache
      --Just _ -> drawnocache
      Just OwlItemCache
cache -> case OwlItemCache -> Maybe PreRender
owlItemCache_preRender OwlItemCache
cache of
        Maybe PreRender
Nothing -> Maybe MWidePChar
drawnocache
        Just PreRender
pr -> case HasCallStack => PreRender -> XY -> MWidePChar
preRender_lookup PreRender
pr XY
pt of
          (-1, Char
_) -> forall a. Maybe a
Nothing
          MWidePChar
x       -> forall a. a -> Maybe a
Just MWidePChar
x
      where
        drawnocache :: Maybe MWidePChar
drawnocache = case SEltDrawer -> SEltDrawerRenderFn
_sEltDrawer_renderFn SEltDrawer
drawer a
ot XY
pt of
          Maybe Char
Nothing -> forall a. Maybe a
Nothing
          Just Char
x  -> forall a. a -> Maybe a
Just (Int8
0, Char
x)
    mdrawn :: Maybe MWidePChar
mdrawn = forall (m :: * -> *) a. Monad m => m (m a) -> m a
join forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find forall a. Maybe a -> Bool
isJust forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (SEltDrawer, Maybe OwlItemCache) -> Maybe MWidePChar
drawfn [(SEltDrawer, Maybe OwlItemCache)]
drawerswithcache

    -- render what we found or empty otherwise
    newc' :: (Int, MWidePChar)
newc' = case Maybe MWidePChar
mdrawn of
      Just MWidePChar
c  -> (Int
pindex, MWidePChar
c)
      Maybe MWidePChar
Nothing -> (Int
pindex, MWidePChar
emptyMWidePChar)

  -- go through each point in target LBox and render it
  newc :: Vector (Int, MWidePChar)
newc = forall a. Unbox a => Int -> (Int -> a) -> Vector a
V.generate (LBox -> Int
lBox_area LBox
llbx) Int -> (Int, MWidePChar)
genfn
  r :: RenderedCanvasRegion
r = RenderedCanvasRegion
prevrcr {
      _renderedCanvasRegion_contents :: Vector MWidePChar
_renderedCanvasRegion_contents = forall a. Unbox a => Vector a -> Vector (Int, a) -> Vector a
V.update (RenderedCanvasRegion -> Vector MWidePChar
_renderedCanvasRegion_contents RenderedCanvasRegion
prevrcr) Vector (Int, MWidePChar)
newc
    }


-- TODO DELETE use render_new instead
-- | renders just a portion of the RenderedCanvasRegion
-- caller is expected to provide all SElts that intersect the rendered LBox (broadphase is ignored)
-- SElts are rendered in ORDER
render :: LBox -> [OwlSubItem] -> RenderContext -> RenderContext
render :: LBox -> [OwlSubItem] -> RenderContext -> RenderContext
render LBox
llbx [OwlSubItem]
osubitems rctx :: RenderContext
rctx@RenderContext {LayerMetaMap
OwlTree
RenderCache
BroadPhaseState
RenderedCanvasRegion
_renderContext_renderedCanvasRegion :: RenderedCanvasRegion
_renderContext_broadPhase :: BroadPhaseState
_renderContext_layerMetaMap :: LayerMetaMap
_renderContext_owlTree :: OwlTree
_renderContext_cache :: RenderCache
_renderContext_renderedCanvasRegion :: RenderContext -> RenderedCanvasRegion
_renderContext_broadPhase :: RenderContext -> BroadPhaseState
_renderContext_layerMetaMap :: RenderContext -> LayerMetaMap
_renderContext_owlTree :: RenderContext -> OwlTree
_renderContext_cache :: RenderContext -> RenderCache
..} = RenderContext
r where
  drawerswithcache :: [(SEltDrawer, Maybe OwlItemCache)]
drawerswithcache = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\OwlSubItem
osubitem -> (OwlSubItem -> Maybe OwlItemCache -> SEltDrawer
getDrawerWithCache OwlSubItem
osubitem forall a. Maybe a
Nothing, forall a. Maybe a
Nothing)) [OwlSubItem]
osubitems 
  prevrcr :: RenderedCanvasRegion
prevrcr = RenderedCanvasRegion
_renderContext_renderedCanvasRegion
  r :: RenderContext
r = RenderContext
rctx {
      _renderContext_renderedCanvasRegion :: RenderedCanvasRegion
_renderContext_renderedCanvasRegion = forall a.
HasOwlTree a =>
a
-> LBox
-> [(SEltDrawer, Maybe OwlItemCache)]
-> RenderedCanvasRegion
-> RenderedCanvasRegion
render_withCache OwlTree
_renderContext_owlTree LBox
llbx [(SEltDrawer, Maybe OwlItemCache)]
drawerswithcache RenderedCanvasRegion
prevrcr
    }

mapREltIdToCaches :: OwlTree -> [REltId] -> RenderCache -> (RenderCache, [(OwlSubItem, Maybe OwlItemCache)])
mapREltIdToCaches :: OwlTree
-> [Int]
-> RenderCache
-> (RenderCache, [(OwlSubItem, Maybe OwlItemCache)])
mapREltIdToCaches OwlTree
ot [Int]
rids RenderCache
rcache = (RenderCache, [(OwlSubItem, Maybe OwlItemCache)])
r where

  mapaccumlfn :: IntMap OwlItemCache
-> Int -> (IntMap OwlItemCache, (OwlSubItem, Maybe OwlItemCache))
mapaccumlfn IntMap OwlItemCache
cacheacc Int
rid = (IntMap OwlItemCache, (OwlSubItem, Maybe OwlItemCache))
r where
    -- see if it was in the previous cache
    mprevcache :: Maybe OwlItemCache
mprevcache = forall a. Int -> IntMap a -> Maybe a
IM.lookup Int
rid (RenderCache -> IntMap OwlItemCache
unRenderCache RenderCache
rcache)
    sowl :: SuperOwl
sowl = HasCallStack => OwlTree -> Int -> SuperOwl
owlTree_mustFindSuperOwl OwlTree
ot Int
rid
    OwlItem OwlInfo
_ OwlSubItem
osubitem = SuperOwl -> OwlItem
_superOwl_elt SuperOwl
sowl
    mupdatedcache :: Maybe OwlItemCache
mupdatedcache = forall a. HasOwlTree a => a -> OwlSubItem -> Maybe OwlItemCache
updateOwlSubItemCache OwlTree
ot OwlSubItem
osubitem
    r :: (IntMap OwlItemCache, (OwlSubItem, Maybe OwlItemCache))
r = case Maybe OwlItemCache
mprevcache of
      Just OwlItemCache
c -> (IntMap OwlItemCache
cacheacc, (OwlSubItem
osubitem, forall a. a -> Maybe a
Just OwlItemCache
c))
      Maybe OwlItemCache
Nothing -> case Maybe OwlItemCache
mupdatedcache of
        Just OwlItemCache
c  -> (forall a. Int -> a -> IntMap a -> IntMap a
IM.insert Int
rid OwlItemCache
c IntMap OwlItemCache
cacheacc, (OwlSubItem
osubitem, forall a. a -> Maybe a
Just OwlItemCache
c))
        Maybe OwlItemCache
Nothing -> (IntMap OwlItemCache
cacheacc, (OwlSubItem
osubitem, forall a. Maybe a
Nothing))
  (IntMap OwlItemCache
newcache, [(OwlSubItem, Maybe OwlItemCache)]
owlswithcache) = forall (t :: * -> *) s a b.
Traversable t =>
(s -> a -> (s, b)) -> s -> t a -> (s, t b)
mapAccumL IntMap OwlItemCache
-> Int -> (IntMap OwlItemCache, (OwlSubItem, Maybe OwlItemCache))
mapaccumlfn (RenderCache -> IntMap OwlItemCache
unRenderCache RenderCache
rcache) [Int]
rids
  r :: (RenderCache, [(OwlSubItem, Maybe OwlItemCache)])
r = (IntMap OwlItemCache -> RenderCache
RenderCache IntMap OwlItemCache
newcache, [(OwlSubItem, Maybe OwlItemCache)]
owlswithcache)



-- | renders just a portion of the RenderedCanvasRegion
-- updates cache as appropriate
-- caller is expected to provide all REltIds that intersect the rendered LBox (broadphase is ignored)
-- REltIds are rendered in ORDER
render_new :: LBox -> [REltId] -> RenderContext -> RenderContext
render_new :: LBox -> [Int] -> RenderContext -> RenderContext
render_new LBox
llbx [Int]
rids rctx :: RenderContext
rctx@RenderContext {LayerMetaMap
OwlTree
RenderCache
BroadPhaseState
RenderedCanvasRegion
_renderContext_renderedCanvasRegion :: RenderedCanvasRegion
_renderContext_broadPhase :: BroadPhaseState
_renderContext_layerMetaMap :: LayerMetaMap
_renderContext_owlTree :: OwlTree
_renderContext_cache :: RenderCache
_renderContext_renderedCanvasRegion :: RenderContext -> RenderedCanvasRegion
_renderContext_broadPhase :: RenderContext -> BroadPhaseState
_renderContext_layerMetaMap :: RenderContext -> LayerMetaMap
_renderContext_owlTree :: RenderContext -> OwlTree
_renderContext_cache :: RenderContext -> RenderCache
..} = RenderContext
rctxout where
  (RenderCache
newcache, [(OwlSubItem, Maybe OwlItemCache)]
owlswithcache) = OwlTree
-> [Int]
-> RenderCache
-> (RenderCache, [(OwlSubItem, Maybe OwlItemCache)])
mapREltIdToCaches OwlTree
_renderContext_owlTree [Int]
rids RenderCache
_renderContext_cache
  drawerswithcache :: [(SEltDrawer, Maybe OwlItemCache)]
drawerswithcache = forall a b. (a -> b) -> [a] -> [b]
map (\(OwlSubItem
x, Maybe OwlItemCache
c)-> (OwlSubItem -> Maybe OwlItemCache -> SEltDrawer
getDrawerWithCache OwlSubItem
x Maybe OwlItemCache
c, Maybe OwlItemCache
c)) [(OwlSubItem, Maybe OwlItemCache)]
owlswithcache 
  rctxout :: RenderContext
rctxout = RenderContext
rctx {
      _renderContext_cache :: RenderCache
_renderContext_cache = RenderCache
newcache
      , _renderContext_renderedCanvasRegion :: RenderedCanvasRegion
_renderContext_renderedCanvasRegion = forall a.
HasOwlTree a =>
a
-> LBox
-> [(SEltDrawer, Maybe OwlItemCache)]
-> RenderedCanvasRegion
-> RenderedCanvasRegion
render_withCache OwlTree
_renderContext_owlTree LBox
llbx [(SEltDrawer, Maybe OwlItemCache)]
drawerswithcache RenderedCanvasRegion
_renderContext_renderedCanvasRegion
    }


renderedCanvasToText :: RenderedCanvasRegion -> Text
renderedCanvasToText :: RenderedCanvasRegion -> Text
renderedCanvasToText RenderedCanvasRegion
rcr = LBox -> RenderedCanvasRegion -> Text
renderedCanvasRegionToText (RenderedCanvasRegion -> LBox
_renderedCanvasRegion_box RenderedCanvasRegion
rcr) RenderedCanvasRegion
rcr


-- TODO this does not handle wide chars at all fack
-- | assumes region LBox is strictly contained in _renderedCanvasRegion_box
renderedCanvasRegionToText :: LBox -> RenderedCanvasRegion -> Text
renderedCanvasRegionToText :: LBox -> RenderedCanvasRegion -> Text
renderedCanvasRegionToText LBox
lbx RenderedCanvasRegion {Vector MWidePChar
LBox
_renderedCanvasRegion_contents :: Vector MWidePChar
_renderedCanvasRegion_box :: LBox
_renderedCanvasRegion_contents :: RenderedCanvasRegion -> Vector MWidePChar
_renderedCanvasRegion_box :: RenderedCanvasRegion -> LBox
..} = if Bool -> Bool
not Bool
validBoxes 
  then forall a t. (HasCallStack, IsText t) => t -> a
error (Text
"render region outside canvas:\n" forall a. Semigroup a => a -> a -> a
<> forall b a. (Show a, IsString b) => a -> b
show LBox
lbx forall a. Semigroup a => a -> a -> a
<> Text
"\n" forall a. Semigroup a => a -> a -> a
<> forall b a. (Show a, IsString b) => a -> b
show LBox
_renderedCanvasRegion_box)
  else Text
r 
  where
    validBoxes :: Bool
validBoxes = LBox -> LBox -> Maybe LBox
intersect_lBox_include_zero_area LBox
lbx LBox
_renderedCanvasRegion_box forall a. Eq a => a -> a -> Bool
== forall a. a -> Maybe a
Just LBox
lbx
    -- TODO preloop and include widechars

    l :: Int
l = LBox -> Int
lBox_area LBox
lbx
    (LBox XY
_ (V2 Int
lw Int
_)) = LBox
lbx
    unfoldfn :: (Int, Bool, Bool) -> Maybe (Maybe Char, (Int, Bool, Bool))
unfoldfn (Int
i, Bool
eol, Bool
waseol) = if Int
i forall a. Eq a => a -> a -> Bool
== Int
l
      then forall a. Maybe a
Nothing
      else if Bool
eol
        -- use -2 to indicate eol
        then forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ (Maybe Char
eolchar, (Int
i, Bool
False, Bool
newwaseol))
        else forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ (Maybe Char
regchar, (Int
iforall a. Num a => a -> a -> a
+Int
1, Bool
neweol, Bool
newwaseol))
        where
          neweol :: Bool
neweol = (Int
iforall a. Num a => a -> a -> a
+Int
1) forall a. Integral a => a -> a -> a
`mod` Int
lw forall a. Eq a => a -> a -> Bool
== Int
0
          -- maintain waseol status if there is offset
          newwaseol :: Bool
newwaseol = Bool
eol Bool -> Bool -> Bool
|| (Bool
waseol Bool -> Bool -> Bool
&& Int8
ofs forall a. Ord a => a -> a -> Bool
> Int8
0)
          (Int8
ofs, Char
pch) = Vector MWidePChar
_renderedCanvasRegion_contents forall a. Unbox a => Vector a -> Int -> a
V.! Int
pindex
          eolchar :: Maybe Char
eolchar = forall a. a -> Maybe a
Just Char
'\n'
          regchar :: Maybe Char
regchar = if Bool
waseol Bool -> Bool -> Bool
&& Int8
ofs forall a. Ord a => a -> a -> Bool
> Int8
0
            -- TODO is this what we want? Will this overwrite the previous wide char? Also this should never happen as broadphase should have included the widechar at bol
            -- if we were at eol and there is offset then use ' ' padding character
            then forall a. a -> Maybe a
Just Char
' '
            else if Int8
ofs forall a. Ord a => a -> a -> Bool
> Int8
0
              -- if there is offset, skip the character
              then forall a. Maybe a
Nothing
              else forall a. a -> Maybe a
Just Char
pch
          pt :: XY
pt = LBox -> Int -> XY
toPoint LBox
lbx Int
i
          pindex :: Int
pindex = LBox -> XY -> Int
toIndex LBox
_renderedCanvasRegion_box XY
pt
    
    -- TODO use something more efficient than a string
    r' :: [Maybe Char]
r' = forall b a. (b -> Maybe (a, b)) -> b -> [a]
unfoldr (Int, Bool, Bool) -> Maybe (Maybe Char, (Int, Bool, Bool))
unfoldfn (Int
0, Bool
False, Bool
True)
    r :: Text
r = String -> Text
T.pack forall a b. (a -> b) -> a -> b
$ forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe forall a. a -> a
id [Maybe Char]
r' 
  

printRenderedCanvasRegion :: RenderedCanvasRegion -> IO ()
printRenderedCanvasRegion :: RenderedCanvasRegion -> IO ()
printRenderedCanvasRegion rc :: RenderedCanvasRegion
rc@RenderedCanvasRegion {Vector MWidePChar
LBox
_renderedCanvasRegion_contents :: Vector MWidePChar
_renderedCanvasRegion_box :: LBox
_renderedCanvasRegion_contents :: RenderedCanvasRegion -> Vector MWidePChar
_renderedCanvasRegion_box :: RenderedCanvasRegion -> LBox
..} = Text -> IO ()
T.putStrLn forall a b. (a -> b) -> a -> b
$ LBox -> RenderedCanvasRegion -> Text
renderedCanvasRegionToText LBox
_renderedCanvasRegion_box RenderedCanvasRegion
rc

renderWithBroadPhase :: LBox -> RenderContext -> RenderContext
renderWithBroadPhase :: LBox -> RenderContext -> RenderContext
renderWithBroadPhase  LBox
lbx rctx :: RenderContext
rctx@RenderContext {LayerMetaMap
OwlTree
RenderCache
BroadPhaseState
RenderedCanvasRegion
_renderContext_renderedCanvasRegion :: RenderedCanvasRegion
_renderContext_broadPhase :: BroadPhaseState
_renderContext_layerMetaMap :: LayerMetaMap
_renderContext_owlTree :: OwlTree
_renderContext_cache :: RenderCache
_renderContext_renderedCanvasRegion :: RenderContext -> RenderedCanvasRegion
_renderContext_broadPhase :: RenderContext -> BroadPhaseState
_renderContext_layerMetaMap :: RenderContext -> LayerMetaMap
_renderContext_owlTree :: RenderContext -> OwlTree
_renderContext_cache :: RenderContext -> RenderCache
..} = RenderContext
r where
  bpt :: BPTree
bpt = (BroadPhaseState -> BPTree
_broadPhaseState_bPTree BroadPhaseState
_renderContext_broadPhase)
  rids :: [Int]
rids = LBox -> BPTree -> [Int]
broadPhase_cull LBox
lbx BPTree
bpt

  -- TODO I THINK THIS IS INCORRECT DELETE, specifically, broadPhase_cull will give hidden elements that we can't find with findSuperOwlForRendering
  {-sowls' = flip fmap rids $ \rid -> case findSuperOwlForRendering ot rid of
      Nothing -> error "this should never happen, because broadPhase_cull should only give existing seltls"
      Just sowl -> sowl-}

  sowls' :: [SuperOwl]
sowls' = forall a. [Maybe a] -> [a]
catMaybes forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Int
rid -> forall a. OwlRenderSet a => a -> Int -> Maybe SuperOwl
findSuperOwlForRendering OwlTree
_renderContext_owlTree Int
rid) [Int]
rids

  sowls :: Seq SuperOwl
sowls = forall a. OwlRenderSet a => a -> Seq SuperOwl -> Seq SuperOwl
sortForRendering OwlTree
_renderContext_owlTree forall a b. (a -> b) -> a -> b
$ forall a. [a] -> Seq a
Seq.fromList [SuperOwl]
sowls'
  sortedrids :: [Int]
sortedrids = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap SuperOwl -> Int
_superOwl_id forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Seq SuperOwl
sowls

  r :: RenderContext
r = LBox -> [Int] -> RenderContext -> RenderContext
render_new LBox
lbx [Int]
sortedrids RenderContext
rctx

moveRenderedCanvasRegionNoReRender :: LBox -> RenderedCanvasRegion -> RenderedCanvasRegion
moveRenderedCanvasRegionNoReRender :: LBox -> RenderedCanvasRegion -> RenderedCanvasRegion
moveRenderedCanvasRegionNoReRender LBox
lbx RenderedCanvasRegion {Vector MWidePChar
LBox
_renderedCanvasRegion_contents :: Vector MWidePChar
_renderedCanvasRegion_box :: LBox
_renderedCanvasRegion_contents :: RenderedCanvasRegion -> Vector MWidePChar
_renderedCanvasRegion_box :: RenderedCanvasRegion -> LBox
..} = forall a. HasCallStack => Bool -> a -> a
assert (Int
area forall a. Ord a => a -> a -> Bool
>= Int
0) RenderedCanvasRegion
outrcr where
  -- unnecessary to init with empty vector as moveRenderedCanvasRegion will re-render those areas
  -- but it's still nice to do and makes testing easier
  area :: Int
area = LBox -> Int
lBox_area LBox
lbx
  emptyv :: Vector MWidePChar
emptyv = forall a. Unbox a => Int -> a -> Vector a
V.replicate Int
area MWidePChar
emptyMWidePChar
  newv :: Vector MWidePChar
newv = case LBox -> LBox -> Maybe LBox
intersect_lBox LBox
lbx LBox
_renderedCanvasRegion_box of
    Just LBox
intersectlbx -> Vector MWidePChar
copiedv where
      (Int
l,Int
r,Int
t,Int
b) = LBox -> (Int, Int, Int, Int)
lBox_to_axis LBox
intersectlbx
      -- [(newIndex, oldIndex)]
      indices' :: [Maybe (Int, Int)]
indices' = [LBox -> XY -> Maybe Int
toIndexSafe LBox
_renderedCanvasRegion_box (forall a. a -> a -> V2 a
V2 Int
x Int
y) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. (LBox -> XY -> Int
toIndex LBox
lbx (forall a. a -> a -> V2 a
V2 Int
x Int
y),) | Int
x <- [Int
l..(Int
rforall a. Num a => a -> a -> a
-Int
1)], Int
y <- [Int
t..(Int
bforall a. Num a => a -> a -> a
-Int
1)]]
      indices :: [(Int, Int)]
indices = forall a. [Maybe a] -> [a]
catMaybes [Maybe (Int, Int)]
indices'
      indexedValues :: [(Int, MWidePChar)]
indexedValues = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(Int
idx, Int
oldidx) -> (Int
idx, Vector MWidePChar
_renderedCanvasRegion_contents forall a. Unbox a => Vector a -> Int -> a
V.! Int
oldidx)) [(Int, Int)]
indices
      copiedv :: Vector MWidePChar
copiedv = forall a. Unbox a => Vector a -> [(Int, a)] -> Vector a
(V.//) Vector MWidePChar
emptyv [(Int, MWidePChar)]
indexedValues
    Maybe LBox
Nothing -> Vector MWidePChar
emptyv

  outrcr :: RenderedCanvasRegion
outrcr = RenderedCanvasRegion {
      _renderedCanvasRegion_box :: LBox
_renderedCanvasRegion_box = LBox
lbx
      , _renderedCanvasRegion_contents :: Vector MWidePChar
_renderedCanvasRegion_contents = Vector MWidePChar
newv
    }

moveRenderedCanvasRegion ::  LBox -> RenderContext -> RenderContext
moveRenderedCanvasRegion :: LBox -> RenderContext -> RenderContext
moveRenderedCanvasRegion LBox
lbx rctx :: RenderContext
rctx@RenderContext {LayerMetaMap
OwlTree
RenderCache
BroadPhaseState
RenderedCanvasRegion
_renderContext_renderedCanvasRegion :: RenderedCanvasRegion
_renderContext_broadPhase :: BroadPhaseState
_renderContext_layerMetaMap :: LayerMetaMap
_renderContext_owlTree :: OwlTree
_renderContext_cache :: RenderCache
_renderContext_renderedCanvasRegion :: RenderContext -> RenderedCanvasRegion
_renderContext_broadPhase :: RenderContext -> BroadPhaseState
_renderContext_layerMetaMap :: RenderContext -> LayerMetaMap
_renderContext_owlTree :: RenderContext -> OwlTree
_renderContext_cache :: RenderContext -> RenderCache
..} = RenderContext
r where
  prevrc :: RenderedCanvasRegion
prevrc = RenderedCanvasRegion
_renderContext_renderedCanvasRegion
  rctx1 :: RenderContext
rctx1 = RenderContext
rctx {
      _renderContext_renderedCanvasRegion :: RenderedCanvasRegion
_renderContext_renderedCanvasRegion = LBox -> RenderedCanvasRegion -> RenderedCanvasRegion
moveRenderedCanvasRegionNoReRender LBox
lbx RenderedCanvasRegion
prevrc
    }
  r :: RenderContext
r = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr LBox -> RenderContext -> RenderContext
renderWithBroadPhase RenderContext
rctx1 (LBox -> LBox -> [LBox]
substract_lBox LBox
lbx (RenderedCanvasRegion -> LBox
_renderedCanvasRegion_box RenderedCanvasRegion
prevrc))

updateCanvas :: SuperOwlChanges -> NeedsUpdateSet -> RenderContext -> RenderContext
updateCanvas :: SuperOwlChanges -> [LBox] -> RenderContext -> RenderContext
updateCanvas SuperOwlChanges
cslmap [LBox]
needsupdateaabbs rctx :: RenderContext
rctx@RenderContext {LayerMetaMap
OwlTree
RenderCache
BroadPhaseState
RenderedCanvasRegion
_renderContext_renderedCanvasRegion :: RenderedCanvasRegion
_renderContext_broadPhase :: BroadPhaseState
_renderContext_layerMetaMap :: LayerMetaMap
_renderContext_owlTree :: OwlTree
_renderContext_cache :: RenderCache
_renderContext_renderedCanvasRegion :: RenderContext -> RenderedCanvasRegion
_renderContext_broadPhase :: RenderContext -> BroadPhaseState
_renderContext_layerMetaMap :: RenderContext -> LayerMetaMap
_renderContext_owlTree :: RenderContext -> OwlTree
_renderContext_cache :: RenderContext -> RenderCache
..} = case [LBox]
needsupdateaabbs of
  [] -> RenderContext
rctx
  -- TODO create disjoint union of all boxes and render than one at a time instead union_lBoxing them all
  --aoeu@(b:bs) -> trace "UPDATE CANVAS" $ traceShow aoeu $ case intersect_lBox (renderedCanvas_box _renderContext_renderedCanvasRegion) (foldl' union_lBox b bs) of
  (LBox
b:[LBox]
bs) -> case LBox -> LBox -> Maybe LBox
intersect_lBox (RenderedCanvasRegion -> LBox
renderedCanvas_box RenderedCanvasRegion
_renderContext_renderedCanvasRegion) (forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' LBox -> LBox -> LBox
union_lBox LBox
b [LBox]
bs) of
    Maybe LBox
Nothing -> RenderContext
rctx
    Just LBox
aabb -> RenderContext
r where
      rids :: [Int]
rids = LBox -> BPTree -> [Int]
broadPhase_cull LBox
aabb (BroadPhaseState -> BPTree
_broadPhaseState_bPTree BroadPhaseState
_renderContext_broadPhase)

      msowls :: [Maybe SuperOwl]
msowls = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Int]
rids forall a b. (a -> b) -> a -> b
$ \Int
rid -> case forall a. Int -> IntMap a -> Maybe a
IM.lookup Int
rid SuperOwlChanges
cslmap of
        Maybe (Maybe SuperOwl)
Nothing -> case forall a. OwlRenderSet a => a -> Int -> Maybe (SuperOwl, Bool)
findSuperOwl OwlTree
_renderContext_owlTree Int
rid of
          Maybe (SuperOwl, Bool)
Nothing -> forall a t. (HasCallStack, IsText t) => t -> a
error Text
"this should never happen, because broadPhase_cull should only give existing seltls"
          -- changes could indicate hidden, if that's the case, give a dummy object to render
          Just (SuperOwl
sowl, Bool
hidden) -> if Bool
hidden then forall a. Maybe a
Nothing else forall a. a -> Maybe a
Just SuperOwl
sowl
        Just Maybe SuperOwl
msowl -> case Maybe SuperOwl
msowl of
          Maybe SuperOwl
Nothing -> forall a t. (HasCallStack, IsText t) => t -> a
error Text
"this should never happen, because deleted seltl would have been culled in broadPhase_cull"
          Just SuperOwl
sowl -> forall a. a -> Maybe a
Just SuperOwl
sowl
      sowls :: Seq SuperOwl
sowls = forall a. OwlRenderSet a => a -> Seq SuperOwl -> Seq SuperOwl
sortForRendering OwlTree
_renderContext_owlTree forall a b. (a -> b) -> a -> b
$ forall a. [a] -> Seq a
Seq.fromList (forall a. [Maybe a] -> [a]
catMaybes [Maybe SuperOwl]
msowls)
      sortedrids :: [Int]
sortedrids = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap SuperOwl -> Int
_superOwl_id forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Seq SuperOwl
sowls
      r :: RenderContext
r = LBox -> [Int] -> RenderContext -> RenderContext
render_new LBox
aabb [Int]
sortedrids RenderContext
rctx