packages feed

roguestar-gl-0.6.0.0: src/Processes.hs

module Processes
    (sceneLoop,
     watchQuit,
     display)
    where

import Initialization
import Globals
import Control.Concurrent
import Control.Concurrent.STM
import System.Timeout
import Control.Monad
import Data.Maybe
import Statistics
import Animation
import System.IO
import System.Exit
import Graphics.Rendering.OpenGL.GL
import RSAGL.Scene
import PrintText
import Actions
import Keymaps.Keymaps

-- | Performs the listen-animate loop.  Should be called
-- exactly once per program instance.
sceneLoop :: Initialization -> IO ()
sceneLoop init_vars = liftM (const ()) $ forkIO $ forever $
    do dispatchKeyInput init_vars
       atomically $
           do b <- liftM isJust $ readTVar $ init_scene_var init_vars
              when b retry
       result <- timeout 20000000 $
           do scene <- runStatistics (init_scene_statistics init_vars) $
                  runRoguestarAnimationObject
                      (init_library init_vars)
                      (init_globals init_vars)
                      (init_driver_object init_vars)
                      (init_print_text_object init_vars)
                      (init_animation_object init_vars)
              atomically $ writeTVar (init_scene_var init_vars) $ Just scene
       if isNothing result
           then do hPutStrLn stderr "roguestar-gl: aborting due to stalled simulation run (timed out after 20 seconds)"
                   exitWith $ ExitFailure 1
           else return ()

-- | Update aspect ratio, when it changes.
reshape :: Size -> IO ()
reshape (Size width height) =
    do mat_mode <- get matrixMode
       matrixMode $= Projection
       loadIdentity
       viewport $= (Position 0 0,Size width height)
       matrixMode $= mat_mode

-- | Monitors the 'global_should_quit' variable,
-- and forcably terminates the application if
-- it is set.
--
-- Needs to be called from the main thread, or has
-- no effect.
watchQuit :: Initialization -> IO ()
watchQuit init_values =
    do q <- atomically $ readTVar $ global_should_quit $ init_globals init_values
       when q $ exitWith ExitSuccess

-- | Performs the display action.  This must
-- be executed in the event loop of the widget toolkit,
-- since OpenGL isn't thread safe.
display :: Size -> Initialization -> IO ()
display (Size width height) init_vars =
  do reshape (Size width height)
     scene <- atomically $
         do result <- maybe retry return =<< readTVar (init_scene_var init_vars)
            writeTVar (init_scene_var init_vars) Nothing
            return result
     result <- timeout 20000000 $
         do color (Color4 0 0 0 0 :: Color4 GLfloat)
            clear [ColorBuffer]
            runStatistics (init_display_statistics init_vars) $
                do sceneToOpenGL (fromIntegral width / fromIntegral height)
                                 (0.1,80.0)
                                 scene
                   renderText (Size width height) $
                              init_print_text_object init_vars
     if isNothing result
          then do hPutStrLn stderr "roguestar-gl: aborting due to stalled display callback (timed out after 20 seconds)"
                  exitWith $ ExitFailure 1
          else return ()

dispatchKeyInput :: Initialization -> IO ()
dispatchKeyInput init_vars =
    do result <- timeout 20000000 $
           do let action_input = ActionInput (init_globals init_vars)
                                             (init_driver_object init_vars)
                                             (init_print_text_object init_vars)
              pullInputBuffer (init_print_text_object init_vars)
              buffer_contents <- getInputBuffer (init_print_text_object init_vars)
              (id =<<) $ atomically $
                  do synced_with_engine <- liftM (not . null) $
                         getValidActions action_input Nothing
                     worked <- if synced_with_engine
                               then takeUserInputAction action_input =<<
                                        keysToActionNames action_input
                                                          (init_keymap init_vars)
                                                          buffer_contents
                               else return False
                     filtered <- filterKeySequence action_input
                                                   (init_keymap init_vars)
                                                   buffer_contents
                     return $ if worked
                              then clearInputBuffer (init_print_text_object init_vars)
                              else setInputBuffer (init_print_text_object init_vars)
                                                  filtered
       if isNothing result
           then do hPutStrLn stderr "roguestar-gl: aborting due to stalled timer callback (timed out after 20 seconds)"
                   exitWith $ ExitFailure 1
           else return ()