module Main where #include "Utils.cpp" import Control.Applicative ((<$>)) import Data.IORef (newIORef, readIORef, modifyIORef) import qualified Data.List as L import System.Exit (exitSuccess) import qualified Control.Monad.State as ST import Control.Monad (when, void) import qualified Graphics.UI.GLFW as GLFW import qualified Graphics.Rendering.OpenGL.Raw as GL import Gamgine.Control ((?)) import qualified Gamgine.Engine as EG import qualified Gamgine.Lens.IORef as GR import qualified Ressources as RES import qualified Gamgine.State.RenderState as RS import qualified Gamgine.Gfx as G import Gamgine.Gfx ((<<<)) import qualified Gamgine.Font.GLF as GLF import Defaults as DF import qualified Utils as U import qualified FileData.Data2 as FD import qualified Convert.ToGameData as TGD import qualified AppData as AP import qualified Callback.Key as KC import qualified Callback.MouseButton as MC import qualified Callback.MouseMove as MM import qualified Rendering.Ressources as RR import qualified LayersArgs as LA import qualified GameData.Data as GD IMPORT_LENS_AS_LE updateLoop = EG.mkUpdateLoop ticksPerSecond maxFrameSkip update io = ST.liftIO main :: IO () main = do args <- LA.getLayersArgs file <- readFile . LA.loadLevelsFrom $ args let fileData = read file :: FD.Data gameData = TGD.toGameData fileData editMode = LA.editMode args ? AP.EditMode $ AP.GameMode appDataRef <- newIORef $ AP.newAppData gameData (LA.loadLevelsFrom args) (LA.saveLevelsTo args) editMode initGL initGLFW appDataRef editMode GLF.init initRessources appDataRef time <- GLFW.getTime AP.runAppST (gameLoop time) appDataRef return () gameLoop :: Double -> AP.AppST () gameLoop nextFrame = do (nextFrame', nextFrameFraction) <- updateLoop nextFrame clearGLState render nextFrameFraction io GLFW.swapBuffers gameLoop nextFrame' update :: AP.AppST () update = do GR.modify AP.update appMode <- GR.gets AP.appMode when (appMode == AP.GameMode) $ do gdata <- GR.getsL AP.gameDataL when (GD.levelFinished gdata) $ do GR.modifyL AP.gameDataL GD.toNextLevel render :: Double -> AP.AppST () render nextFrameFraction = do gdata <- GR.getsL AP.gameDataL if GD.gameFinished gdata then renderEndScreen else do app <- GR.get io $ GL.glTranslatef <<< U.levelScrolling nextFrameFraction app app' <- io $ AP.render nextFrameFraction app GR.put app' renderEndScreen :: AP.AppST () renderEndScreen = do font <- RR.fontId RR.Crystal <$> GR.gets AP.renderRessources (fx, fy) <- GR.gets AP.frustumSize io $ do GLF.setCurrentFont font GLF.Bounds (minx, miny) (maxx, maxy) <- GLF.getStringBounds endMsg GL.glTranslatef <<< G.xyz (fx / 2 - ((minx + maxx) * 2)) (fy / 2) 0 GL.glScalef <<< G.xyz 3.75 3 3 GLF.drawSolidString endMsg where endMsg = "END" clearGLState :: AP.AppST () clearGLState = io $ do GL.glClear (fromIntegral GL.gl_COLOR_BUFFER_BIT) GL.glMatrixMode GL.gl_MODELVIEW GL.glLoadIdentity initGLFW :: AP.AppDataRef -> AP.AppMode -> IO () initGLFW appDataRef appMode = do GLFW.initialize GLFW.openWindow GLFW.defaultDisplayOptions { GLFW.displayOptions_width = winWidth, GLFW.displayOptions_height = winHeight, GLFW.displayOptions_windowIsResizable = True } GLFW.setWindowBufferSwapInterval 1 GLFW.setWindowSizeCallback resize GLFW.setWindowCloseCallback quit GLFW.setKeyCallback $ KC.newKeyCallback appDataRef GLFW.setMouseButtonCallback $ MC.newMouseButtonCallback appDataRef GLFW.setMousePositionCallback $ MM.newMouseMoveCallback appDataRef GLFW.setMouseWheelCallback $ if appMode == AP.EditMode then updateOrthoScale else \_ -> return () where resize width height = do setL AP.windowSizeL (width, height) modify U.updateBoundarySize updateFrustum updateCamera updateFrustum = do modify (\app -> let (width, height) = AP.windowSize app orthoScale = AP.orthoScale app top = orthoScale * (fromIntegral height / fromIntegral width) right = orthoScale in app {AP.frustumSize = (right, top)}) updateCamera = do (w, h) <- getL AP.windowSizeL (r, t) <- getL AP.frustumSizeL GL.glViewport 0 0 (fromIntegral w) (fromIntegral h) GL.glMatrixMode GL.gl_PROJECTION GL.glLoadIdentity GL.glOrtho 0 (G.floatToFloat r) 0 (G.floatToFloat t) (-1) 1 updateOrthoScale mouseWheelPos = do setL AP.orthoScaleL (DF.orthoScale + fromIntegral mouseWheelPos) modify U.updateBoundarySize updateFrustum updateCamera getL = GR.getL appDataRef setL = GR.setL appDataRef modL = GR.modL appDataRef read = readIORef appDataRef modify = modifyIORef appDataRef initGL :: IO () initGL = do GL.glClearColor 0 0 0 0 initRessources :: AP.AppDataRef -> IO () initRessources appDataRef = do res <- RR.newRessources modifyIORef appDataRef $ \app -> app {AP.renderRessources = res} quit :: IO Bool quit = GLFW.closeWindow >> GLFW.terminate >> exitSuccess