-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
304 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#!/bin/bash -xe | ||
|
||
cd $(git rev-parse --show-toplevel) | ||
|
||
SCENARIO_PATH=${1?"Usage: $0 SCENARIO_PATH"} | ||
|
||
IMG_WIDTH=200 | ||
IMG_HEIGHT=150 | ||
|
||
DOT_OUTPUT_PATH=structures.dot | ||
|
||
EXECUTABLE_NAME=swarm-scene | ||
|
||
cabal build -j -O0 $EXECUTABLE_NAME | ||
|
||
OUTPUT_DIR=blarg | ||
|
||
mkdir -p $OUTPUT_DIR | ||
cabal run $EXECUTABLE_NAME -- \ | ||
$SCENARIO_PATH structures \ | ||
--fail-blank \ | ||
--dest $OUTPUT_DIR/$DOT_OUTPUT_PATH \ | ||
--png \ | ||
--width $IMG_WIDTH \ | ||
--height $IMG_HEIGHT | ||
|
||
cd $OUTPUT_DIR | ||
dot -Tpng -o structures.png $DOT_OUTPUT_PATH | ||
dot -Tsvg -o structures.svg $DOT_OUTPUT_PATH |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
-- | | ||
-- SPDX-License-Identifier: BSD-3-Clause | ||
module Swarm.Render.Image ( | ||
TransparencyHandling (..), | ||
ImgRendering (..), | ||
mkStructurePng, | ||
defaultImageRendering, | ||
) where | ||
|
||
import Codec.Picture | ||
import Data.ByteString.Lazy qualified as LBS | ||
import Data.Either.Utils (forceEither) | ||
import Data.Function (on) | ||
import Data.Map (Map) | ||
import Swarm.Game.Scenario.Topography.Navigation.Waypoint ( | ||
Parentage (Root), | ||
) | ||
import Swarm.Game.Scenario.Topography.Rasterize | ||
import Swarm.Game.Scenario.Topography.Structure | ||
import Swarm.Game.Scenario.Topography.Structure.Assembly | ||
import Swarm.Game.Scenario.Topography.Structure.Named (NamedArea, StructureName) | ||
import Swarm.Game.Scenario.Topography.Structure.Overlay | ||
import Swarm.Util (applyWhen) | ||
|
||
data TransparencyHandling | ||
= Transparent | ||
| DiagonalIndicators | ||
|
||
data ImgRendering = ImgRendering | ||
{ scaleNum :: Int | ||
, transparencyHandling :: TransparencyHandling | ||
} | ||
|
||
defaultImageRendering :: ImgRendering | ||
defaultImageRendering = ImgRendering 1 Transparent | ||
|
||
mkStructurePng :: | ||
ToPixel a => | ||
ImgRendering -> | ||
Map StructureName (NamedArea (PStructure (Maybe a))) -> | ||
PStructure (Maybe a) -> | ||
LBS.ByteString | ||
mkStructurePng (ImgRendering scaleFactor transparencyMode) sMap parentStruct = | ||
encodePng . imgPipeline . makeImage $ gridContent overlayArea | ||
where | ||
imgPipeline = illustrateTransparency transparencyMode . scalePixelImage scaleFactor | ||
overlayArea = forceMerge sMap parentStruct | ||
|
||
illustrateTransparency :: TransparencyHandling -> Image PixelRGBA8 -> Image PixelRGBA8 | ||
illustrateTransparency mode img@(Image w h _) = case mode of | ||
Transparent -> img | ||
DiagonalIndicators -> mkNewImage img | ||
where | ||
mkNewImage s = generateImage (f s) w h | ||
f s x y = | ||
if pixelOpacity px == 0 | ||
then checkerColor | ||
else px | ||
where | ||
px = pixelAt s x y | ||
checkerOpacity = | ||
if even $ (x `div` 2) + (y `div` 2) | ||
then maxBound `div` 4 | ||
else maxBound `div` 2 | ||
checkerColor = PixelRGBA8 (gradientPixel x w) 128 128 checkerOpacity | ||
gradientPixel i d = fromIntegral $ (i * 255) `div` d | ||
|
||
-- | Integral-factor scaling by nearest neighbor. | ||
-- Preserves sharp definition for pixel art. | ||
scaleImage :: Pixel a => Int -> Image a -> Image a | ||
scaleImage scaleFactor = | ||
applyWhen (scaleFactor > 1) mkNewImage | ||
where | ||
mkNewImage s@(Image w h _) = (generateImage (f s) `on` (* scaleFactor)) w h | ||
f s = pixelAt s `on` (`div` scaleFactor) | ||
|
||
scalePixelImage :: Int -> Image PixelRGBA8 -> Image PixelRGBA8 | ||
scalePixelImage rawScaleFactor = | ||
applyWhen (rawScaleFactor > 1) mkNewImage | ||
where | ||
scaleFactor = rawScaleFactor + 1 | ||
mkNewImage s@(Image w h _) = (generateImage (f s) `on` (* scaleFactor)) w h | ||
f s x y = | ||
if x `mod` scaleFactor == 0 || y `mod` scaleFactor == 0 | ||
then PixelRGBA8 minBound minBound minBound maxBound | ||
else (pixelAt s `on` (`div` scaleFactor)) x y | ||
|
||
forceMerge :: | ||
Map StructureName (NamedArea (PStructure (Maybe a))) -> | ||
PStructure (Maybe a) -> | ||
PositionedGrid (Maybe a) | ||
forceMerge sMap parentStruct = | ||
overlayArea | ||
where | ||
MergedStructure overlayArea _ _ = forceEither $ mergeStructures sMap Root parentStruct |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
{-# LANGUAGE OverloadedStrings #-} | ||
|
||
-- | | ||
-- SPDX-License-Identifier: BSD-3-Clause | ||
module Swarm.Render.Structures where | ||
|
||
import Control.Carrier.Throw.Either | ||
import Control.Effect.Lift | ||
import Control.Lens ((^.)) | ||
import Control.Monad (forM_) | ||
import Data.ByteString.Lazy qualified as LBS | ||
import Data.Map (Map) | ||
import Data.Map qualified as M | ||
import Data.Text qualified as T | ||
import Swarm.Failure (SystemFailure) | ||
import Swarm.Game.Entity.Cosmetic | ||
import Swarm.Game.Scenario | ||
import Swarm.Game.Scenario.Topography.Cell (Cell) | ||
import Swarm.Game.Scenario.Topography.Structure | ||
import Swarm.Game.Scenario.Topography.Structure.Assembly | ||
import Swarm.Game.Scenario.Topography.Structure.Named | ||
import Swarm.Game.Scenario.Topography.WorldPalette | ||
import Swarm.Render.Image | ||
import Swarm.Util.Content (getTerrainEntityColor) | ||
import System.FilePath | ||
import Text.Dot | ||
|
||
renderStructuresGraph :: | ||
M.Map k (NamedStructure a) -> | ||
Dot () | ||
renderStructuresGraph sMap = | ||
nlg | ||
where | ||
gEdges = makeGraphEdges $ M.elems sMap | ||
|
||
edgeLookup = M.fromList $ map (\x@(_, b, _) -> (b, x)) gEdges | ||
nlg = | ||
netlistGraph | ||
(\k -> maybe mempty mkAttrs $ M.lookup k edgeLookup) | ||
(\k -> maybe mempty (\(_, _, c) -> c) $ M.lookup k edgeLookup) | ||
([(a, a) | (_, a, _) <- gEdges]) | ||
|
||
mkAttrs (_, b, _) = | ||
[ ("label", sname) | ||
, ("height", "1") | ||
, ("image", imgPath) | ||
, ("shape", "box") | ||
, ("style", "filled") | ||
, ("penwidth", "0") | ||
, ("fillcolor", "#b0b0b0:#f0f0f0") | ||
, ("imagepos", "tc") | ||
, ("labelloc", "b") | ||
] | ||
where | ||
imgPath = sname <.> "png" | ||
sname = T.unpack $ getStructureName b | ||
|
||
renderImages :: | ||
ImgRendering -> | ||
FilePath -> | ||
Map WorldAttr PreservableColor -> | ||
Map StructureName (NamedArea (PStructure (Maybe Cell))) -> | ||
IO () | ||
renderImages imgRendering outputFolder aMap sMap = do | ||
forM_ (M.toList modifiedMap) $ \(StructureName n, parentStruct) -> do | ||
let fp = outputFolder </> T.unpack n <.> "png" | ||
encodedImgBytestring = mkStructurePng imgRendering modifiedMap $ structure parentStruct | ||
LBS.writeFile fp encodedImgBytestring | ||
where | ||
modifiedMap = M.map ((fmap . fmap . fmap) (getTerrainEntityColor aMap . toCellPaintDisplay)) sMap | ||
|
||
doRenderStructures :: | ||
(Has (Throw SystemFailure) sig m, Has (Lift IO) sig m) => | ||
FilePath -> | ||
FilePath -> | ||
m () | ||
doRenderStructures scenarioFilepath outputFilepath = do | ||
(myScenario, _gsi) <- loadStandaloneScenario scenarioFilepath | ||
-- sendIO $ print $ myScenario ^. scenarioMetadata . scenarioName | ||
|
||
let sMap = myScenario ^. scenarioDiagnostic . scenarioStructureMap | ||
aMap = myScenario ^. scenarioLandscape . scenarioCosmetics | ||
imgOutputFolder = "blarg" | ||
|
||
sGraph = do | ||
renderStructuresGraph sMap | ||
|
||
-- attribute ("imagepath", imgOutputFolder) | ||
|
||
sendIO $ do | ||
renderImages (ImgRendering 8 DiagonalIndicators) imgOutputFolder aMap sMap | ||
writeFile outputFilepath $ showDot sGraph |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.