packages feed

sdl2-sprite (empty) → 0.0.0

raw patch · 6 files changed

+283/−0 lines, 6 filesdep +basedep +optparse-simpledep +sdl2setup-changed

Dependencies added: base, optparse-simple, sdl2, sdl2-image, sdl2-sprite, split, text

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Chris Done (c) 2018++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Chris Done nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,71 @@+# sdl2-sprite++Create a horizontal sprite like this:++![](img/blue-fish-sprite.png)++The size of the intended result image is 220x130, so provide that:++    sdl2-sprite blue-fish.png 220x130 --fps 15++This will open a window animating that sprite:++![](img/blue-fish.gif)++(Note: this is a screenflow recording of the animation manually edited+to repeat, so it's not as smooth as in reality.)++The animation repeats indefinitely at the desired framerate.++## Using Haskell API++Use `load` to load in a sprite for a `Renderer`:++``` haskell+load :: MonadIO m => Renderer -> FilePath -> V2 CInt -> m Sprite+```++To render the sprite at a given position use `render`:++``` haskell+render :: MonadIO m => Sprite -> V2 CInt -> m ()+```++To advance the sprite's frame to the next frame (or loop), use+`animate`:++``` haskell+animate :: Sprite -> Sprite+```++This is a pure function, so you can use it in a loop. See the source+in `app/Main.hs` of this repository for an example.+++## How to make sprites in Inkscape++Choose the size of your intended result e.g. 220x130 and then setup+the grid in Inkscape to show that size (see the Spacing X/Spacing Y+fields):++![](img/inkscape-doc-properties.png)++It'll look like this, which is handy:++![](img/inkscape-grid.png)++When you want to make a new frame, use `Ctrl-D` to duplicate the+selection and use the Transform tool to move it exactly 220 pixels to+the right and hit Apply.++![](img/inkscape-transform.png)++Make sure that your document dimensions are your width x your frame+count.++Finally, export your image with the right "Image size" - make sure the+size is 130 so that the width scales right:++![](img/inkscape-export.png)++Now you're good to go! Hit Export.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ app/Main.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE ViewPatterns #-}+-- |++module Main where++import           Control.Concurrent+import           Control.Monad+import           Data.List.Split+import           Data.Monoid+import qualified Data.Text as T+import           Options.Applicative.Simple+import           SDL+import qualified SDL.Sprite+import           Text.Read++main :: IO ()+main = do+  ((fp, dim, ms), ()) <-+    simpleOptions+      "0.0.0"+      "sdl2-sprite"+      "Animate sprites with sdl2"+      ((,,) <$> argument str (metavar "FILE") <*>+       argument+         (eitherReader+            (\i ->+               case splitOn "x" i of+                 [w, h] -> V2 <$> readEither w <*> readEither h+                 _ -> Left "invalid WIDTHxHEIGHT specification"))+         (metavar "WIDTHxHEIGHT") <*>+       (fmap+          (\fps -> 1000 / fps)+          (option+             auto+             (long "fps" <> value (15 :: Double) <> help "Frames per second")) <|>+        option+          auto+          (long "delay" <> value (50 :: Double) <>+           help "Delay between frames in ms")))+      empty+  initializeAll+  window <-+    createWindow+      (T.pack fp)+      defaultWindow {windowInitialSize = dim, windowHighDPI = True}+  renderer <- createRenderer window (-1) defaultRenderer+  -- Resize the window (smaller) if in high DPI (retina) mode.+  do Just (Rectangle _ (V2 w h)) <- SDL.get (SDL.rendererViewport renderer)+     let scale =+           let (V2 w0 h0) = dim+           in (V2+                 (fromIntegral w / fromIntegral w0 :: Double)+                 (fromIntegral h / fromIntegral h0 :: Double))+     windowSize window $= (fmap round (fmap fromIntegral dim / scale))+  -- Load up the sprite.+  sprite0 <- SDL.Sprite.load renderer fp dim+  -- Render the sprite on a timer.+  let loop (!sprite) = do+        events <- pollEvents+        let eventQuit event =+              case eventPayload event of+                KeyboardEvent keyboardEvent ->+                  keyboardEventKeyMotion keyboardEvent == Pressed &&+                  keysymKeycode (keyboardEventKeysym keyboardEvent) == KeycodeQ+                WindowClosedEvent {} -> True+                _ -> False+        clear renderer+        SDL.Sprite.render sprite (V2 0 0)+        present renderer+        threadDelay (round (1000 * ms))+        unless (any eventQuit events) (loop (SDL.Sprite.animate sprite))+  loop sprite0
+ sdl2-sprite.cabal view
@@ -0,0 +1,36 @@+name:                sdl2-sprite+version:             0.0.0+synopsis:            Sprite previewer/animator+description:         View your sprites in an animated way with SDL2+homepage:            https://github.com/chrisdone/sdl2-sprite#readme+license:             BSD3+license-file:        LICENSE+author:              Chris Done+maintainer:          chrisdone@gmail.com+copyright:           2015 Chris Done+category:            Web+build-type:          Simple+extra-source-files:  README.md+cabal-version:       >=1.10++library+  hs-source-dirs:      src+  ghc-options:         -Wall+  exposed-modules:     SDL.Sprite+  build-depends:       base >= 4.7 && < 5,+                       sdl2+                     , sdl2-image+  default-language:    Haskell2010++executable sdl2-sprite+  hs-source-dirs:      app+  main-is:             Main.hs+  ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N+  build-depends:       base+                     , sdl2-sprite+                     , sdl2+                     , sdl2-image+                     , optparse-simple+                     , text+                     , split+  default-language:    Haskell2010
+ src/SDL/Sprite.hs view
@@ -0,0 +1,71 @@+-- | Handle sprites in a simple way.++module SDL.Sprite+  ( load+  , animate+  , render+  , Sprite+  ) where++import Control.Exception+import Control.Monad.IO.Class+import Foreign.C.Types+import qualified SDL.Image+import SDL.Vect+import SDL.Video.Renderer++-- | A loaded sprite.+data Sprite = Sprite+  { spriteDimensions :: !(V2 CInt)+    -- ^ Render dimensions.+  , spriteTexture :: !Texture+    -- ^ The texture to render from.+  , spriteFrame :: !CInt+    -- ^ The current frame index.+  , spriteTextureInfo :: !TextureInfo+    -- ^ Info about the sprite texture.+  , spriteRenderer :: !Renderer+    -- ^ The renderer.+  }++-- | Get the current source rectangle of the sprite's frame.+spriteRectangle :: Sprite -> Rectangle CInt+spriteRectangle s = Rectangle (P (V2 x 0)) (V2 w h)+  where (V2 w h) = spriteDimensions s+        x = spriteFrame s * w++-- | Load a sprite from file.+load :: MonadIO m => Renderer -> FilePath -> V2 CInt -> m Sprite+load ren fp dimensions =+  liftIO+    (do texture <- SDL.Image.loadTexture ren fp+        textInfo <- queryTexture texture+        evaluate+          (Sprite+           { spriteDimensions = dimensions+           , spriteTexture = texture+           , spriteFrame = 0+           , spriteTextureInfo = textInfo+           , spriteRenderer = ren+           }))++-- | Advance sprite to the next frame.+animate :: Sprite -> Sprite+animate s =+  s+  { spriteFrame =+      if (spriteFrame s + 1) * w < textureWidth (spriteTextureInfo s)+        then spriteFrame s + 1+        else 0+  }+  where+    (V2 w _) = spriteDimensions s++-- | Render the sprite at the given coordinates.+render :: MonadIO m => Sprite -> V2 CInt -> m ()+render s xy =+  copy+    (spriteRenderer s)+    (spriteTexture s)+    (Just (spriteRectangle s))+    (Just (Rectangle (P xy) (spriteDimensions s)))