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
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
GLFW.init
GLFW.windowHint $ GLFW.WindowHint'Resizable True
GLFW.swapInterval 1
Just win <- GLFW.createWindow winWidth winHeight "" Nothing Nothing
GLFW.makeContextCurrent (Just win)
initGL
GLF.init
appDataRef <- newIORef $ AP.newAppData win gameData (LA.loadLevelsFrom args) (LA.saveLevelsTo args) editMode
initCallbacks appDataRef editMode
initRessources appDataRef
Just time <- GLFW.getTime
AP.runAppST (gameLoop time) appDataRef
return ()
gameLoop :: Double -> AP.AppST ()
gameLoop nextFrame = do
io GLFW.pollEvents
(nextFrame', nextFrameFraction) <- updateLoop nextFrame
clearGLState
render nextFrameFraction
win <- GR.gets AP.window
io $ GLFW.swapBuffers win
gameLoop nextFrame'
where
updateLoop = EG.mkUpdateLoop ticksPerSecond maxFrameSkip update
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
initCallbacks :: AP.AppDataRef -> AP.AppMode -> IO ()
initCallbacks appDataRef appMode = do
win <- getL AP.windowL
GLFW.setWindowSizeCallback win (Just resize)
GLFW.setWindowCloseCallback win (Just quit)
GLFW.setKeyCallback win (Just $ KC.newKeyCallback appDataRef)
GLFW.setMouseButtonCallback win (Just $ MC.newMouseButtonCallback appDataRef)
GLFW.setCursorPosCallback win (Just $ MM.newMouseMoveCallback appDataRef)
GLFW.setScrollCallback win (Just $ if appMode == AP.EditMode then updateOrthoScale else \_ _ _ -> return ())
where
resize _ width height = do
setL AP.windowSizeL (width, height)
modify U.updateBoundarySize
updateFrustum
updateCamera
quit win = GLFW.destroyWindow win >> GLFW.terminate >> exitSuccess
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 _ _ yoffset = do
modL AP.orthoScaleL (+ yoffset)
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}