add example

This commit is contained in:
andromeda
2026-02-27 22:27:15 +01:00
parent d9d14bdc94
commit f09e348de8
4 changed files with 187 additions and 75 deletions

View File

@@ -10,52 +10,6 @@
self, self,
... ...
}: let }: let
version = "0.1.0";
package = {
# nix stuff
mkDerivation,
lib,
# haskell deps
base,
c-expr-runtime,
hs-bindgen-runtime,
# pkgconfig deps
libGL,
libX11,
libXcursor,
libXi,
xrandr,
# shell deps
clang,
hs-bindgen-cli,
tree,
}:
mkDerivation {
pname = "hs-rgfw";
inherit version;
src = ./.;
libraryHaskellDepends = [
base
c-expr-runtime
hs-bindgen-runtime
];
libraryPkgconfigDepends = [
libGL
libX11
libXcursor
libXi
xrandr
];
preConfigure = ''
set -x
export PATH=${clang}/bin:${hs-bindgen-cli}/bin:${tree}/bin:$PATH
./generate.sh
set +x
'';
homepage = "https://git.mtgmonkey.net/Andromeda/hs-rgfw";
license = lib.licenses.gpl3Only;
platforms = ["x86_64-linux"];
};
system = "x86_64-linux"; system = "x86_64-linux";
pkgs = import nixpkgs { pkgs = import nixpkgs {
inherit system; inherit system;
@@ -69,6 +23,8 @@
default = pkgs.mkShell { default = pkgs.mkShell {
stdenv = pkgs.clangStdenv; stdenv = pkgs.clangStdenv;
packages = [ packages = [
pkgs.haskellPackages.ghcide
pkgs.haskellPackages.ormolu
pkgs.clang pkgs.clang
pkgs.cabal-install pkgs.cabal-install
pkgs.hs-bindgen-cli pkgs.hs-bindgen-cli
@@ -80,7 +36,18 @@
}; };
}; };
packages.${system} = { packages.${system} = {
default = pkgs.haskellPackages.callPackage package {}; default =
(pkgs.haskell.packages.ghc912.callCabal2nix "hs-rgfw" ./. {
xi = pkgs.libxi;
gl = pkgs.libGL;
xcursor = pkgs.libxcursor;
xrandr = pkgs.xrandr;
}).overrideAttrs {
preConfigure = ''
export PATH=${pkgs.clang}/bin:${pkgs.hs-bindgen-cli}/bin:${pkgs.tree}/bin:$PATH
./generate.sh
'';
};
}; };
}; };
} }

View File

@@ -40,9 +40,11 @@ executable hs-rgfw
main-is: Main.hs main-is: Main.hs
build-depends: build-depends:
, base , base
, hs-rgfw , bytestring
, c-expr-runtime , c-expr-runtime
, hs-bindgen-runtime , hs-bindgen-runtime
, hs-rgfw
, OpenGL
pkgconfig-depends: pkgconfig-depends:
, gl , gl
, x11 , x11

91
src/LoadShaders.hs Normal file
View File

@@ -0,0 +1,91 @@
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- |
-- Module : LoadShaders
-- Copyright : (c) Sven Panne 2013
-- License : BSD3
--
-- Maintainer : Sven Panne <svenpanne@gmail.com>
-- Stability : stable
-- Portability : portable
--
-- Utilities for shader handling, adapted from LoadShaders.cpp which is (c) The
-- Red Book Authors.
module LoadShaders
( ShaderSource (..),
ShaderInfo (..),
loadShaders,
)
where
import Control.Exception
import Control.Monad
import qualified Data.ByteString as B
import Graphics.Rendering.OpenGL
--------------------------------------------------------------------------------
-- | The source of the shader source code.
data ShaderSource
= -- | The shader source code is directly given as a 'B.ByteString'.
ByteStringSource B.ByteString
| -- | The shader source code is directly given as a 'String'.
StringSource String
| -- | The shader source code is located in the file at the given 'FilePath'.
FileSource FilePath
deriving (Eq, Ord, Show)
getSource :: ShaderSource -> IO B.ByteString
getSource (ByteStringSource bs) = return bs
getSource (StringSource str) = return $ packUtf8 str
getSource (FileSource path) = B.readFile path
--------------------------------------------------------------------------------
-- | A description of a shader: The type of the shader plus its source code.
data ShaderInfo
= ShaderInfo ShaderType ShaderSource
deriving (Eq, Ord, Show)
--------------------------------------------------------------------------------
-- | Create a new program object from the given shaders, throwing an
-- 'IOException' if something goes wrong.
loadShaders :: [ShaderInfo] -> IO Program
loadShaders infos =
createProgram `bracketOnError` deleteObjectName $ \program -> do
loadCompileAttach program infos
linkAndCheck program
return program
linkAndCheck :: Program -> IO ()
linkAndCheck = checked linkProgram linkStatus programInfoLog "link"
loadCompileAttach :: Program -> [ShaderInfo] -> IO ()
loadCompileAttach _ [] = return ()
loadCompileAttach program (ShaderInfo shType source : infos) =
createShader shType `bracketOnError` deleteObjectName $ \shader -> do
src <- getSource source
shaderSourceBS shader $= src
compileAndCheck shader
attachShader program shader
loadCompileAttach program infos
compileAndCheck :: Shader -> IO ()
compileAndCheck = checked compileShader compileStatus shaderInfoLog "compile"
checked ::
(t -> IO ()) ->
(t -> GettableStateVar Bool) ->
(t -> GettableStateVar String) ->
String ->
t ->
IO ()
checked action getStatus getInfoLog message object = do
action object
ok <- get (getStatus object)
unless ok $ do
infoLog <- get (getInfoLog object)
fail (message ++ " log: " ++ infoLog)

View File

@@ -1,37 +1,89 @@
{-# LANGUAGE MultilineStrings #-}
module Main where module Main where
import RGFW.Generated
import Foreign.C.Types (CChar)
import Foreign.C.String (newCString)
import Foreign.C.ConstPtr
import Data.Bits ((.|.)) import Data.Bits ((.|.))
import Foreign.C.ConstPtr
import Foreign.C.String (newCString)
import Foreign.C.Types (CChar)
import Foreign.Ptr (Ptr)
import Graphics.Rendering.OpenGL (($=))
import qualified Graphics.Rendering.OpenGL as GL
import LoadShaders
import RGFW.Generated
main :: IO () main :: IO ()
main = do main = do
putStrInfo "creating window"
-- disable wayland, can't be bothered -- string not freed; window remains open
_ <- rGFW_useWayland_safe $ RGFW_bool 0
-- create window. This string does not need to be freed, the window stays open
windowTitle_cstr <- newCString "window" windowTitle_cstr <- newCString "window"
let let windowTitle_ptr = ConstPtr windowTitle_cstr
windowTitle_ptr = ConstPtr windowTitle_cstr windowFlags = RGFW_windowFlags $ fromIntegral $ RGFW_windowCenter .|. RGFW_windowNoResize .|. RGFW_windowOpenGL
windowFlags = RGFW_windowFlags $ fromIntegral $ RGFW_windowCenter .|. RGFW_windowNoResize .|. RGFW_windowOpenGL
window_ptr <- rGFW_createWindow_safe window <-
windowTitle_ptr -- name rGFW_createWindow_safe
100 -- x windowTitle_ptr -- name
100 -- y 0 -- x
100 -- w 0 -- y
100 -- h 300 -- w
windowFlags -- flags 300 -- h
putDebug $ "windowFlags: " ++ (show $ unwrapU32 $ unwrapRGFW_windowFlags windowFlags) windowFlags -- flags
putDebug $ "window_ptr: " ++ (show $ window_ptr) putStrDebug $ "windowFlags: " ++ (show $ unwrapU32 $ unwrapRGFW_windowFlags windowFlags)
putDebug "created window" putStrDebug $ "window: " ++ (show $ window)
loop 0 putStrInfo "initialising shaders"
_ <- initResources
putStrInfo "entering loop"
loop window 0
loop :: Int -> IO () loop :: Ptr RGFW_window -> Int -> IO ()
loop i = loop $ i + 1 loop window i = do
view
rGFW_window_swapBuffers_OpenGL_safe window
loop window $ i + 1
putDebug :: String -> IO () putStrDebug :: String -> IO ()
putDebug a = putStrLn $ "[debug] " ++ a putStrDebug a = putStrLn $ "[debug]:" ++ a
putStrInfo :: String -> IO ()
putStrInfo a = putStrLn $ "[info]:" ++ a
initResources :: IO GL.Program
initResources = do
program <-
loadShaders
[ ShaderInfo GL.VertexShader $ StringSource vertShader,
ShaderInfo GL.FragmentShader $ StringSource fragShader
]
GL.currentProgram $= Just program
return program
where
vertShader =
"""
#version 330 core
layout (location = 0) in vec3 aPos;
out vec4 vertexColor;
void main()
{
gl_Position = vec4(aPos, 1.0);
vertexColor = vec4(0.5, 0.0, 0.0, 1.0);
}
"""
fragShader =
"""
#version 330 core
out vec4 FragColor;
in vec4 vertexColor;
void main()
{
FragColor = vertexColor;
}
"""
view :: IO ()
view = do
GL.clearColor $= GL.Color4 1 0 1 1
GL.clear [GL.ColorBuffer, GL.DepthBuffer]