Skip to content

Instantly share code, notes, and snippets.

@patrl
Last active February 16, 2023 10:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save patrl/559eb3db9f8b97e436257a0e87279c29 to your computer and use it in GitHub Desktop.
Save patrl/559eb3db9f8b97e436257a0e87279c29 to your computer and use it in GitHub Desktop.
Simple program for decoding .xp files (REXPaint)
{-# LANGUAGE TemplateHaskell #-}
-- Xp format specification: https://steveasleep.com/rexpaint_manual.html#appendix-b:-.xp-format-specification-(and-import-libraries)
module Data.Xp where
import Data.Colour.RGBSpace
import qualified Codec.Compression.GZip as GZip
import qualified Data.ByteString.Lazy as BL
import Data.Binary.Get
import Data.Word
import qualified Data.Vector as V
import Data.Vector (Vector())
import Lens.Micro.Platform
data Tile = Tile {_asciiCode :: Word32, _fg :: RGB Word8, _bg :: RGB Word8 } deriving Show
makeLenses ''Tile
data ImgLayer = ImgLayer { _width :: Int, _height :: Int, _tiles :: Vector Tile } deriving Show
makeLenses ''ImgLayer
data Img = Img { _layerNum :: Int, _layers :: Vector ImgLayer }
makeLenses ''Img
load :: FilePath -> IO Img
load f = do
contents <- GZip.decompress <$> (BL.readFile f)
return $ (runGet decode) contents
decode :: Get Img
decode = do
_ <- getWord32le -- decode and discard header
ln <- getWord32le -- get number of layers
ls <- V.replicateM (fromIntegral ln) decodeLayer
return $ Img (fromIntegral ln) ls
decodeLayer :: Get ImgLayer
decodeLayer = do
w <- getWord32le
h <- getWord32le
ts <- V.replicateM (fromIntegral $ w * h) decodeCell
return $ ImgLayer (fromIntegral w) (fromIntegral h) ts
decodeCell :: Get Tile
decodeCell = do
asciiCode <- getWord32le
fgr <- getWord8
fgg <- getWord8
fgb <- getWord8
bgr <- getWord8
bgg <- getWord8
bgb <- getWord8
return $ Tile asciiCode (RGB fgr fgg fgb) (RGB bgr bgg bgb)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment