Raincat-1.1.1: src/Nxt/Graphics.hs
module Nxt.Graphics
(begin,
end,
initWindow,
initGraphics,
toGLdouble,
fromGLdouble,
loadTexture,
freeTexture,
drawTexture,
drawTextureFlip,
drawString,
drawRect,
drawPoly,
worldTransform,
cycleTextures,
cycleTextures2,
repeatTexturesN) where
import Control.Monad
import Graphics.UI.GLUT as GLUT hiding (windowSize, windowTitle)
import Graphics.Rendering.OpenGL as GL
import Graphics.UI.SDL.Image as SDLImage
import Graphics.UI.SDL.Types
import Graphics.UI.SDL.Video
import Nxt.Types hiding (rectX, rectY, rectWidth, rectHeight)
import Unsafe.Coerce
-- initWindow
initWindow :: Size -> String -> IO ()
initWindow windowSize windowTitle = do
_ <- getArgsAndInitialize
initialWindowSize $= windowSize
initialDisplayMode $= [DoubleBuffered]
_ <- createWindow windowTitle
return ()
-- initGraphics
initGraphics :: GLdouble -> GLdouble -> IO ()
initGraphics screenResWidth screenResHeight = do
blend $= Enabled
blendFunc $= (GL.SrcAlpha, OneMinusSrcAlpha)
shadeModel $= Flat
matrixMode $= Projection
loadIdentity
ortho 0.0 screenResWidth 0.0 screenResHeight (-1.0) 0.0
matrixMode $= Modelview 0
return ()
-- begin
begin :: IO ()
begin =
clear [ColorBuffer, DepthBuffer]
-- end
end :: IO ()
end = do
swapBuffers
flush
-- toGLdouble
toGLdouble :: a -> GLdouble
toGLdouble = unsafeCoerce
-- fromGLdouble
fromGLdouble :: a -> Double
fromGLdouble = unsafeCoerce
-- loadTexture (only specified to load PNGs)
loadTexture :: String -> IO Nxt.Types.Texture
loadTexture textureFilePath = do
surface <- SDLImage.loadTyped textureFilePath SDLImage.PNG
let width = fromIntegral (surfaceGetWidth surface)
let height = fromIntegral (surfaceGetHeight surface)
let surfaceSize = TextureSize2D width height
textureObj <- liftM head (genObjectNames 1)
textureBinding Texture2D $= Just textureObj
textureWrapMode Texture2D S $= (Repeated, Repeat)
textureWrapMode Texture2D T $= (Repeated, Repeat)
textureFilter Texture2D $= ((Nearest, Nothing), Nearest)
surfacePixels <- surfaceGetPixels surface
let pixelData = PixelData RGBA UnsignedByte surfacePixels
texImage2D Nothing NoProxy 0 RGBA' surfaceSize 0 pixelData
freeSurface surface
return (Nxt.Types.Texture width height textureObj)
-- freeTexture
freeTexture :: Nxt.Types.Texture -> IO ()
freeTexture tex =
deleteObjectNames [textureObject tex]
-- drawTexture
drawTexture :: Double -> Double -> Nxt.Types.Texture -> GLdouble -> IO ()
drawTexture x y tex alpha =
drawTextureFlip x y tex alpha False
-- drawTextureFlip
drawTextureFlip :: Double -> Double -> Nxt.Types.Texture -> GLdouble -> Bool -> IO ()
drawTextureFlip x y tex alpha fliped = do
texture Texture2D $= Enabled
textureBinding Texture2D $= Just (textureObject tex)
let texWidth = fromIntegral $ textureWidth tex
texHeight = fromIntegral $ textureHeight tex
let texCoord2f = texCoord :: TexCoord2 GLdouble -> IO ()
vertex3f = vertex :: Vertex3 GLdouble -> IO ()
color4f = color :: Color4 GLdouble -> IO ()
col = color4f (Color4 (1.0::GLdouble) (1.0::GLdouble) (1.0::GLdouble) alpha)
let texCoordX = if fliped then (-1) else 1
x' = toGLdouble x
y' = toGLdouble y
renderPrimitive Quads $ do
texCoord2f (TexCoord2 0 1); vertex3f (Vertex3 x' y' 0.0); col
texCoord2f (TexCoord2 0 0); vertex3f (Vertex3 x' (y' + texHeight) 0.0); col
texCoord2f (TexCoord2 texCoordX 0); vertex3f (Vertex3 (x' + texWidth) (y' + texHeight) 0.0); col
texCoord2f (TexCoord2 texCoordX 1); vertex3f (Vertex3 (x' + texWidth) y' 0.0); col
texture Texture2D $= Disabled
-- drawString (using Helvetica 12pt font)
drawString :: GLfloat -> GLfloat -> String -> Color4 GLfloat -> IO ()
drawString x y string col = do
color col
currentRasterPosition $= Vertex4 x y (0.0::GLfloat) (1.0::GLfloat)
renderString Helvetica12 string
-- drawRect
drawRect :: Nxt.Types.Rect -> Color4 GLdouble -> IO ()
drawRect (Rect rectX rectY rectWidth rectHeight) rectColor = do
let rX = toGLdouble rectX
rY = toGLdouble rectY
rW = toGLdouble rectWidth
rH = toGLdouble rectHeight
rectVertices = [Vertex3 rX rY 0.0,
Vertex3 (rX + rW) rY 0.0,
Vertex3 (rX + rW) (rY + rH) 0.0,
Vertex3 rX (rY + rH) 0.0]
renderPrimitive Quads $ do
mapM_ color [rectColor]
mapM_ vertex rectVertices
-- drawPoly
drawPoly :: Nxt.Types.Poly -> Color4 GLdouble -> IO ()
drawPoly (Poly _ points) polyColor = do
let polyVerts = map (\(x,y) -> Vertex3 (toGLdouble x) (toGLdouble y) (0.0::GLdouble)) points
renderPrimitive Polygon $ do
mapM_ color [polyColor]
mapM_ vertex polyVerts
-- worldTransform
worldTransform :: Double -> Double -> IO ()
worldTransform worldX worldY = do
loadIdentity
translate (Vector3 (toGLdouble worldX) (toGLdouble worldY) 0.0)
-- cycleTextures
cycleTextures :: String -> Int -> Int -> IO [Nxt.Types.Texture]
cycleTextures filePath frames frameTime = do
texLists <- mapM (\n -> Nxt.Graphics.loadTexture (filePath ++ show n ++ ".png")) [1..frames]
let textures = cycle $ foldr ((++) . replicate frameTime) [] texLists
return textures
-- cycleTextures2
cycleTextures2 :: String -> Int -> Int -> Int -> IO [Nxt.Types.Texture]
cycleTextures2 filePath frames lastFrame frameTime = do
texLists <- mapM (\n -> Nxt.Graphics.loadTexture (filePath ++ show n ++ ".png")) [1..frames]
texLists2 <- Nxt.Graphics.loadTexture (filePath ++ show lastFrame ++ ".png");
let textures = foldr ((++) . replicate frameTime) (repeat texLists2) texLists
return textures
-- repeatTexturesN
repeatTexturesN :: String -> Int -> Int -> Int -> Int -> Int -> Int -> IO [Nxt.Types.Texture]
repeatTexturesN filePath frames startRepeat endRepeat nRepeats lastFrame frameTime = do
texLists <- mapM (\n -> Nxt.Graphics.loadTexture (filePath ++ show n ++ ".png")) [1..frames]
repeatTexLists <- mapM (\n -> Nxt.Graphics.loadTexture (filePath ++ show n ++ ".png")) [startRepeat..endRepeat]
endTexLists <- mapM (\n -> Nxt.Graphics.loadTexture (filePath ++ show n ++ ".png")) [(endRepeat + 1)..lastFrame]
let textures = replicate 60 (last endTexLists)
++
foldr ((++) . replicate frameTime) [] texLists
++
take (nRepeats * frameTime * (endRepeat - startRepeat)) (cycle $ foldr ((++) . replicate frameTime) [] repeatTexLists)
++
foldr ((++) . replicate frameTime) (repeat $ last endTexLists) endTexLists
return textures