packages feed

nano-ui-0.1.0.0: test/integration/Cases/Atlas.hs

module Cases.Atlas (runAtlasGrowthTest) where

import Control.Monad (forM_)
import Data.ByteString qualified as BS
import Data.IORef (IORef)
import Foreign.ForeignPtr (withForeignPtr)
import Foreign.Marshal.Array (peekArray)
import Foreign.Ptr (plusPtr)
import NanoUI (ImageId (..))
import NanoUI.Context (lookupImageUv)
import NanoUI.Testing (Context, atlasSnapshot, newContext, registerImage)
import NanoUI.Testing.Assert (assert, assertEq)

runAtlasGrowthTest :: Context -> IORef Int -> IO ()
runAtlasGrowthTest ctx failed = do
  let
    red = BS.pack [255, 0, 0, 255]
    blue = BS.pack [0, 0, 255, 255]
    pixels w h color = BS.concat (replicate (w * h) color)
    insert tid w h color = registerImage ctx (ImageId tid) w h (pixels w h color)
    checkPixel tid expected = do
      snapshot <- atlasSnapshot ctx >>= maybe (fail "missing atlas snapshot") pure
      uv <- lookupImageUv ctx (ImageId tid) >>= maybe (fail "missing image UV") pure
      let
        (w, h, fp, _) = snapshot
        (u0, v0, u1, v1) = uv
        xs = [round (u0 * fromIntegral w), round (u1 * fromIntegral w) - 1]
        ys = [round (v0 * fromIntegral h), round (v1 * fromIntegral h) - 1]
      forM_ [(x, y) | x <- xs, y <- ys] $ \(x, y) -> do
        actual <- withForeignPtr fp $ \ptr -> BS.pack <$> peekArray 4 (ptr `plusPtr` ((y * w + x) * 4))
        assertEq failed actual expected
  insert 1 2 2 red >>= assert failed
  initialUv <- lookupImageUv ctx (ImageId 1)
  -- A wider image grows the atlas; wrapping another image starts a new shelf.
  insert 2 300 3 blue >>= assert failed
  insert 3 400 1 red >>= assert failed
  grownUv <- lookupImageUv ctx (ImageId 1)
  assert failed (initialUv /= grownUv)
  checkPixel 1 red
  checkPixel 2 blue
  checkPixel 3 red
  -- Same-size updates retain their location and change only their pixels.
  insert 1 2 2 blue >>= assert failed
  lookupImageUv ctx (ImageId 1) >>= assertEq failed grownUv
  checkPixel 1 blue
  checkPixel 2 blue
  before <- atlasSnapshot ctx
  insert 1 3 2 red >>= assert failed . not
  atlasSnapshot ctx >>= assertEq failed before

  -- Width growth cannot rescue this insertion: neither the current shelf nor
  -- a new shelf can accommodate it within the atlas's maximum dimensions.
  full <- newContext
  registerImage full (ImageId 1) 1 3000 (BS.replicate (3000 * 4) 255)
    >>= assert failed
  fullBefore <- atlasSnapshot full
  registerImage full (ImageId 2) 4094 1100 (BS.replicate (4094 * 1100 * 4) 0)
    >>= assert failed . not
  atlasSnapshot full >>= assertEq failed fullBefore
  lookupImageUv full (ImageId 2) >>= assertEq failed Nothing