{-# LANGUAGE DisambiguateRecordFields #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedRecordDot #-} -- | -- - Module : Game -- - Description : runs game -- - Copyright : 2025 Andromeda -- - License : BSD 3-clause -- - Maintainer : Matrix @Andromeda:tchncs.de -- - Stability : Experimental module Main ( main, ) where import Control.Lens ((^.)) import Data.IORef (newIORef) import Data.List (nub) import GHC.Float (double2Float) import Game.Internal import Game.Internal.Types import Graphics.Rendering.OpenGL (($=)) import qualified Graphics.Rendering.OpenGL as GL import qualified Graphics.UI.GLFW as GLFW import Linear (V3 (..), V4 (..), (*^), _w, _xyz, _y) import qualified Linear as L -- | Main function runs game main :: IO () main = do _ <- GLFW.init GLFW.defaultWindowHints -- OpenGL core >=3.3 GLFW.windowHint $ GLFW.WindowHint'ContextVersionMajor 3 GLFW.windowHint $ GLFW.WindowHint'ContextVersionMinor 3 GLFW.windowHint $ GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core -- MSAA GLFW.windowHint $ GLFW.WindowHint'Samples $ Just 8 -- alpha -- create window monitor <- GLFW.getPrimaryMonitor Just window <- GLFW.createWindow 256 256 "hs-game" monitor Nothing GLFW.makeContextCurrent $ Just window -- add callbacks GLFW.setWindowCloseCallback window $ Just shutdownWindow GLFW.setWindowSizeCallback window $ Just resizeWindow GLFW.setKeyCallback window $ Just (keyPressed Nothing) GLFW.setCursorInputMode window GLFW.CursorInputMode'Hidden GLFW.setCursorPosCallback window $ Just (cursorPosHandler Nothing) loop window 0 update view modelRef -------------------------------------------------------------------------------- -- Elm-like data structures -------------------------------------------------------------------------------- -- | update function update :: Float -> Model -> Model update dt model = model -- | views the model view :: GLFW.Window -> Model -> IO () view window model = do let camx = (\(V4 x _ _ _) -> x) model.camera.camPos camy = (\(V4 _ y _ _) -> y) model.camera.camPos camz = (\(V4 _ _ z _) -> z) model.camera.camPos camw = (\(V4 _ _ _ w) -> w) model.camera.camPos -- TODO optimise this inefficient pos let objarr = map (v3tov4 camw) $ sliceW camw $ initArr (obj, program) <- initResources objarr -- fit viewport to window (w, h) <- GLFW.getFramebufferSize window GL.viewport $= (GL.Position 0 0, GL.Size (fromIntegral w) (fromIntegral h)) -- clear screen GL.clearColor $= GL.Color4 1 0 1 1 GL.clear [GL.ColorBuffer, GL.DepthBuffer] -- depth GL.depthFunc $= Just GL.Less -- apply transforms let pitch = model.camera.camPitch yaw = model.camera.camYaw forward = V3 (cos pitch * sin yaw) (sin pitch) (cos pitch * cos yaw) viewMatrix = L.lookAt (model.camera.camPos ^. _xyz) ((model.camera.camPos ^. _xyz) - forward) model.wprop.up projectionMatrix = L.perspective 1.2 (fromIntegral w / fromIntegral h) 0.01 1000 viewGLMatrix <- GL.newMatrix GL.RowMajor $ toGLMatrix viewMatrix :: IO (GL.GLmatrix GL.GLfloat) -- load 3d view matrix viewLocation <- GL.get $ GL.uniformLocation program "u_view" GL.uniform viewLocation $= viewGLMatrix projectionGLMatrix <- GL.newMatrix GL.RowMajor $ toGLMatrix projectionMatrix :: IO (GL.GLmatrix GL.GLfloat) -- load 3d projection matrix projectionLocation <- GL.get $ GL.uniformLocation program "u_projection" GL.uniform projectionLocation $= projectionGLMatrix camWLocation <- GL.get $ GL.uniformLocation program "u_cam" GL.uniform camWLocation $= GL.Vector4 camx camy camz camw -- draw objects; returns IO [] _ <- drawObjects [obj] -- swap to current buffer GLFW.swapBuffers window -- check for interrupts GLFW.pollEvents