packages feed

dx9d3d-0.1: DirectX9/D3D/Utility/Init.hs

module DirectX9.D3D.Utility.Init
where
import Graphics.Win32   ( WindowClosure, HWND, mkClassName, loadIcon
                        , loadCursor, createSolidBrush, rgb, registerClass
                        , showWindow, updateWindow, sendMessage, WPARAM
                        , LPARAM, LRESULT, WindowMessage, defWindowProc
                        , createWindow, getMessage, translateMessage
                        , dispatchMessage, allocaMessage
                        , iDI_APPLICATION, iDC_ARROW, cS_VREDRAW, cS_HREDRAW
                        , wS_OVERLAPPEDWINDOW, sW_SHOWNORMAL, wM_DESTROY
                        , wM_QUIT, wM_KEYDOWN, vK_ESCAPE )
import System.Win32.DLL ( getModuleHandle )
import Control.Concurrent   ( newEmptyMVar, putMVar, takeMVar, tryTakeMVar, forkIO )
-- import Control.Exception ( catch )
-- import Prelude hiding ( catch )

makeWindow :: Int -> Int -> String -> WindowClosure -> IO HWND
makeWindow width height name proc = do
    let winClass = mkClassName name
    icon         <- loadIcon   Nothing iDI_APPLICATION
    cursor       <- loadCursor Nothing iDC_ARROW
    bgBrush      <- createSolidBrush (rgb 0 0 255)
    instanc <- getModuleHandle Nothing
    let wclass = ( cS_VREDRAW + cS_HREDRAW, instanc, Just icon, Just cursor
                 , Just bgBrush, Nothing, winClass )
    registerClass wclass
    w <- createWindow
            winClass name
            wS_OVERLAPPEDWINDOW
            Nothing Nothing
            (Just width) (Just height)
            Nothing Nothing
            instanc proc
    showWindow w sW_SHOWNORMAL
    updateWindow w
    return w


basicWindowProc :: HWND -> WindowMessage -> WPARAM -> LPARAM -> IO LRESULT
basicWindowProc hwnd wmsg wParam lParam
    | wmsg==wM_DESTROY = do
        sendMessage hwnd wM_QUIT 1 0
        return 0
    | wmsg==wM_KEYDOWN && wParam==vK_ESCAPE =  do
        sendMessage hwnd wM_QUIT 1 0
        return 0    
    | otherwise =
        defWindowProc (Just hwnd) wmsg wParam lParam

messageAndRenderLoop :: HWND -> (Integer -> IO a) -> IO ()
messageAndRenderLoop hwnd proc = do
    signal  <- newEmptyMVar
    quit    <- newEmptyMVar
    forkIO $ catch
        (render signal quit 1)
        (\e -> do
            print e
            putMVar quit ())
    loop signal quit
    where
        -- todo: exceptions
        render signal quit frame = do
            proc frame
            s <- tryTakeMVar signal
            case s of
                Nothing -> render signal quit (frame+1)
                Just _  -> putMVar quit ()
        loop signal quit =  do
            more <- allocaMessage $ \msg ->
                catch
                    (do
                        more <- getMessage msg (Just hwnd)
                        translateMessage msg
                        dispatchMessage msg
                        return more)
                    (const $ return False)
            if more
                then loop signal quit
                else do
                    putMVar signal ()
                    takeMVar quit