少し趣を変えてGLSLを使って書いたシェーダーを使う方法です。
シェーダーを使うには、頂点シェーダーとフラグメントシェーダーをコンパイルしてから、プログラムオブジェクトにアタッチし、そのプログラムオブジェクトをリンクして使います。実際に描く時には、vertexAttribPointerで頂点の属性を設定して頂点シェーダに情報を渡します。頂点の属性は、StorableArrayを使って配列へのポインタにして渡します。
以下の例では、フラグメントシェーダーは赤を返すように固定してあります。
import Control.Monad import Data.Array.Storable import Foreign.Ptr import Graphics.Rendering.OpenGL import Graphics.UI.GLUT main = do (progName, _) <- getArgsAndInitialize initialDisplayMode $= [RGBAMode] window <- createWindow "Window" clearColor $= Color4 1.0 1.0 1.0 0.0 program <- join $ liftM2 createProgram (createShader vertexShaderSource) (createShader fragmentShaderSource) displayCallback $= display program mainLoop display program = do clear [ColorBuffer] currentProgram $= Just program loc <- get $ attribLocation program "a_position" positions <- newListArray (0, 5) ([0.0, 0.9, -0.9, -0.9, 0.9, -0.9] :: [GLfloat]) withStorableArray positions $ \ptr -> do vertexAttribPointer loc $= (ToFloat, VertexArrayDescriptor 2 Float 0 ptr) vertexAttribArray loc $= Enabled drawArrays Triangles 0 3 flush vertexShaderSource = "attribute vec4 a_position; \ \void main() { \ \ gl_Position = a_position; \ \}" fragmentShaderSource = "void main() { \ \ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); \ \}" createShader source = do [shader] <- genObjectNames 1 shaderSource shader $= [source] compileShader shader return shader createProgram vertexShader fragmentShader = do [program] <- genObjectNames 1 attachedShaders program $= ([vertexShader], [fragmentShader]) linkProgram program return program