Two Triangles (garish)

This commit is contained in:
mtgmonkey
2025-11-27 17:50:45 +01:00
parent d4d9cab0e8
commit 4af0a1c4c2
8 changed files with 243 additions and 72 deletions

View File

@@ -9,13 +9,5 @@
packages.${system} = { packages.${system} = {
default = pkgs.callPackage ./package.nix {}; default = pkgs.callPackage ./package.nix {};
}; };
devShells.${system} = {
default = pkgs.mkShell {
nativeBuildInputs = [
];
shellHook = ''
'';
};
};
}; };
} }

8
frag.glsl Normal file
View File

@@ -0,0 +1,8 @@
#version 450 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}

View File

@@ -7,8 +7,10 @@
}: let }: let
ghcExeOptions = "-Wall -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N"; ghcExeOptions = "-Wall -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N";
ghcPackages = p: [ ghcPackages = p: [
p.OpenGL p.bytestring
p.data-default
p.GLFW-b p.GLFW-b
p.OpenGL
p.relude p.relude
]; ];
in in

171
src/IO.hs Normal file
View File

@@ -0,0 +1,171 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module IO (Descriptor, openWindow, shutdownWindow, view) where
-- IMPORTS --
import qualified Data.ByteString as BS
import qualified Graphics.Rendering.OpenGL as GL
import Graphics.Rendering.OpenGL (($=))
import qualified Graphics.UI.GLFW as GLFW
import Control.Exception
import Control.Monad
import Foreign.Ptr
import Foreign.Marshal.Array
import Foreign.Storable
import Relude
import Model
-- VIEW --
view :: GLFW.Window -> Descriptor -> Model -> IO ()
view window descriptor@(Descriptor vertices firstIndex numVertices) model = do
GL.clearColor $= GL.Color4 1 0 1 1
GL.clear [GL.ColorBuffer]
GL.bindVertexArrayObject $= Just vertices
GL.drawArrays GL.Triangles firstIndex numVertices
GLFW.swapBuffers window
GLFW.pollEvents
-- SHADER DATA STRUCTURES --
data Descriptor
= Descriptor
{ vertexArray :: GL.VertexArrayObject
, firstindex :: GL.ArrayIndex
, numArrayIndicies :: GL.NumArrayIndices
}
data ShaderInfo
= ShaderInfo
GL.ShaderType
ShaderSource
deriving (Eq, Ord, Show)
data ShaderSource
= ByteStringSource BS.ByteString
| StringSource String
| FileSource FilePath
deriving (Eq, Ord, Show)
-- INIT RENDERER --
bufferOffset :: Integral a => a -> Ptr b
bufferOffset integral = plusPtr nullPtr $ fromIntegral integral
initResources :: IO Descriptor
initResources = do
verticesGLArray <- GL.genObjectName
GL.bindVertexArrayObject $= Just verticesGLArray
let
verticesArray =
[ GL.Vertex2 0.9 0.9
, GL.Vertex2 0.9 (-0.85)
, GL.Vertex2 (-0.85) 0.9
, GL.Vertex2 (-0.9) (-0.9)
, GL.Vertex2 (-0.9) 0.85
, GL.Vertex2 0.85 (-0.9)
] :: [GL.Vertex2 GL.GLfloat]
numVertices = length verticesArray
arrayBuffer <- GL.genObjectName
GL.bindBuffer GL.ArrayBuffer $= Just arrayBuffer
withArray verticesArray $ \ptr -> do
let
size
= fromIntegral
$ (*)
numVertices
$ sizeOf
$ case viaNonEmpty head verticesArray of
Nothing -> (GL.Vertex2 0 0) :: (GL.Vertex2 GL.GLfloat)
Just a -> a
GL.bufferData GL.ArrayBuffer $= (size, ptr, GL.StaticDraw)
program <- loadShaders
[ ShaderInfo GL.VertexShader (FileSource "vert.glsl")
, ShaderInfo GL.FragmentShader (FileSource "frag.glsl")
]
GL.currentProgram $= Just program
let
firstIndex = 0
vPosition = GL.AttribLocation 0
GL.vertexAttribPointer vPosition $=
(GL.ToFloat, GL.VertexArrayDescriptor 2 GL.Float 0 (bufferOffset firstIndex))
GL.vertexAttribArray vPosition $= GL.Enabled
return $ Descriptor verticesGLArray firstIndex $ fromIntegral numVertices
-- LOAD SHADERS --
getSource :: ShaderSource -> IO BS.ByteString
getSource (ByteStringSource bs) = return bs
getSource (StringSource str) = return $ GL.packUtf8 str
getSource (FileSource path) = BS.readFile path
loadShaders :: [ShaderInfo] -> IO GL.Program
loadShaders infos =
GL.createProgram `bracketOnError` GL.deleteObjectName $ \program -> do
loadCompileAttach program infos
GL.linkProgram program
return program
loadCompileAttach :: GL.Program -> [ShaderInfo] -> IO ()
loadCompileAttach _ [] = return ()
loadCompileAttach program (ShaderInfo shType source : infos) =
GL.createShader shType `bracketOnError` GL.deleteObjectName $ \shader -> do
src <- getSource source
GL.shaderSourceBS shader $= src
GL.compileShader shader
GL.attachShader program shader
loadCompileAttach program infos
-- INPUT --
keyPressed :: GLFW.KeyCallback
keyPressed window GLFW.Key'Escape _ GLFW.KeyState'Pressed _ = shutdownWindow window
keyPressed _ _ _ _ _ = return ()
-- WINDOW --
openWindow :: String -> IO (GLFW.Window, Descriptor)
openWindow
title
= do
GLFW.init
GLFW.defaultWindowHints
GLFW.windowHint (GLFW.WindowHint'ContextVersionMajor 4)
GLFW.windowHint (GLFW.WindowHint'ContextVersionMinor 5)
GLFW.windowHint (GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core)
monitor <- GLFW.getPrimaryMonitor
-- get an error n ur cooked. TODO graceful failure here
Just window <- GLFW.createWindow 256 256 title monitor Nothing
GLFW.makeContextCurrent (Just window)
GLFW.setWindowCloseCallback window (Just shutdownWindow)
GLFW.setWindowSizeCallback window (Just resizeWindow)
GLFW.setKeyCallback window (Just keyPressed)
descriptor <- initResources
return (window, descriptor)
shutdownWindow :: GLFW.WindowCloseCallback
shutdownWindow window =
do
closeWindow window
_ <- exitSuccess
return ()
resizeWindow :: GLFW.WindowSizeCallback
resizeWindow _ w h =
do
GL.viewport $= (GL.Position 0 0, GL.Size (fromIntegral w) (fromIntegral h))
GL.matrixMode $= GL.Projection
GL.loadIdentity
GL.ortho2D 0 (realToFrac w) (realToFrac h) 0
closeWindow :: GLFW.Window -> IO ()
closeWindow window =
do
GLFW.destroyWindow window
GLFW.terminate

View File

@@ -1,79 +1,35 @@
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Main (main) where module Main (main) where
-- IMPORTS -- -- IMPORTS --
import Graphics.Rendering.OpenGL as GL import Graphics.UI.GLFW (Window)
import Graphics.UI.GLFW as GLFW import IO (Descriptor, openWindow, view)
import Model (Model, model)
import Relude import Relude
import Relude.Monad (forever) import Relude.Monad (forever)
import Update (update)
-- MAIN -- -- MAIN --
main :: IO () main :: IO ()
main = do main =
putStrLn "haskengl 2025 Andromeda; WTFPL"
window <- openWindow "window :)"
onPaint window
closeWindow window
return ()
-- EVENTS --
keyPressed :: GLFW.KeyCallback
keyPressed window GLFW.Key'Escape _ GLFW.KeyState'Pressed _ = shutdownWindow window
keyPressed _ _ _ _ _ = return ()
-- PAINT --
onPaint :: GLFW.Window -> IO ()
onPaint window =
do do
GL.clearColor $= Color4 1 0 1 1 (window, descriptor) <- openWindow "window :)"
GL.clear [ColorBuffer] putTextLn "has window"
GLFW.swapBuffers window _ <- loop window descriptor update view model
forever $ do
GLFW.pollEvents
onPaint window
-- WINDOW --
openWindow :: String -> IO GLFW.Window
openWindow
title
= do
GLFW.init
GLFW.defaultWindowHints
GLFW.windowHint (GLFW.WindowHint'ContextVersionMajor 4)
GLFW.windowHint (GLFW.WindowHint'ContextVersionMinor 5)
GLFW.windowHint (GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core)
monitor <- GLFW.getPrimaryMonitor
Just window <- GLFW.createWindow 256 256 title monitor Nothing -- get an error n ur cooked. TODO graceful failure here
GLFW.makeContextCurrent (Just window)
GLFW.maximizeWindow window
GLFW.setWindowCloseCallback window (Just shutdownWindow)
GLFW.setWindowSizeCallback window (Just resizeWindow)
GLFW.setKeyCallback window (Just keyPressed)
return window
shutdownWindow :: GLFW.WindowCloseCallback
shutdownWindow window =
do
closeWindow window
_ <- exitSuccess
return () return ()
resizeWindow :: GLFW.WindowSizeCallback loop
resizeWindow _ w h = :: Window
-> Descriptor
-> (Model -> Model)
-> (Window -> Descriptor -> Model -> IO ())
-> Model -> IO Model
loop window descriptor update view model =
do do
GL.viewport $= (GL.Position 0 0, GL.Size (fromIntegral w) (fromIntegral h)) let model = update model
GL.matrixMode $= GL.Projection view window descriptor model
GL.loadIdentity loop window descriptor update view model
GL.ortho2D 0 (realToFrac w) (realToFrac h) 0
closeWindow :: GLFW.Window -> IO ()
closeWindow window =
do
GLFW.destroyWindow window
GLFW.terminate

19
src/Model.hs Normal file
View File

@@ -0,0 +1,19 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Model (Model, model) where
-- IMPORTS --
import Relude
-- TYPES --
data Model = Model
{ counter :: Integer
}
-- DEFAULTS --
model = Model
{ counter = 0
}

15
src/Update.hs Normal file
View File

@@ -0,0 +1,15 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Update (update) where
-- IMPORTS --
import Model
import Relude
-- UPDATE --
update :: Model -> Model
update model =
model

8
vert.glsl Normal file
View File

@@ -0,0 +1,8 @@
#version 450 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}