HaskellでOpenGL

昨日までOpenGLのおの字も知らなかったのだが、
気が向いたのでやってみることにした。
なんというか、思いのほか簡単である。
もっと初期化とかめんどくさいと思っていた。

とりあえず、初期化のコード

main = do
  True <- sdlInit [VIDEO]

  glSetAttribute GL_RED_SIZE   5
  glSetAttribute GL_GREEN_SIZE 5
  glSetAttribute GL_BLUE_SIZE  5
  glSetAttribute GL_DEPTH_SIZE 16
  glSetAttribute GL_DOUBLEBUFFER 1

  setCaption "OpenGL" ""
  sur <- setVideoMode 640 480 16 [OPENGL]

  loop
  sdlQuit

loop = do
  quit <- checkEvent
  when (not quit) $ do
    threadDelay 16666
    loop

あとは普通にOpenGLを呼び出すだけなので、
http://www.wakayama-u.ac.jp/~tokoi/opengl/libglut.html
この辺を読んで勉強してみた。
で、最後まで読んで出来上がったのがこれ。

import Graphics.UI.SDL as SDL hiding (color)
import Graphics.Rendering.OpenGL as GL
import Graphics.Rendering.OpenGL.GLU
import Control.Concurrent
import Control.Monad
import Data.IORef

                                                      • -
initialize = do clearColor $= Color4 0.0 0.0 0.0 1.0 depthFunc $= Just Less lighting $= Enabled light (Light 0) $= Enabled light (Light 1) $= Enabled initVar = 0.0 setupMat = do viewport $= (Position 0 0,GL.Size 640 480) matrixMode $= Projection loadIdentity perspective 30.0 (640.0/480.0) 1.0 100.0 matrixMode $= Modelview 0 loadIdentity translate $ Vector3 0.0 0.0 (-5.0 :: GLdouble) lookAt (Vertex3 3.0 4.0 5.0) (Vertex3 0.0 0.0 0.0) (Vector3 0.0 1.0 0.0) setupLight = do position (Light 0) $= Vertex4 0.0 3.0 5.0 1.0 position (Light 1) $= Vertex4 5.0 3.0 0.0 1.0 diffuse (Light 1) $= Color4 0.0 1.0 0.0 1.0 specular (Light 1) $= Color4 0.0 1.0 0.0 1.0 cube = do renderPrimitive Quads $ mapM_ (\(n,v) -> do normal $ uncurry3 Normal3 n mapM_ (\n -> vertex $ Vertex3 (vert!!n!!0) (vert!!n!!1) (vert!!n!!2)) v ) $ zip norm face where vert :: GLdouble vert = [[0.0,0.0,0.0] ,[1.0,0.0,0.0] ,[1.0,1.0,0.0] ,[0.0,1.0,0.0] ,[0.0,0.0,1.0] ,[1.0,0.0,1.0] ,[1.0,1.0,1.0] ,[0.0,1.0,1.0]] edge = [(0,1),(1,2),(2,3),(3,0) ,(4,5),(5,6),(6,7),(7,4) ,(0,4),(1,5),(2,6),(3,7)] face = [[0,1,2,3] ,[1,5,6,2] ,[5,4,7,6] ,[4,0,3,7] ,[4,5,1,0] ,[3,2,6,7]] col :: [(GLdouble,GLdouble,GLdouble)] col = [(1.0,0.0,0.0) ,(0.0,1.0,0.0) ,(0.0,0.0,1.0) ,(1.0,1.0,0.0) ,(1.0,0.0,1.0) ,(0.0,1.0,1.0)] norm :: [(GLdouble,GLdouble,GLdouble)] norm = [( 0.0, 0.0,-1.0) ,( 1.0, 0.0, 0.0) ,( 0.0, 0.0, 1.0) ,(-1.0, 0.0, 0.0) ,( 0.0,-1.0, 0.0) ,( 0.0, 1.0, 0.0)] fromInt = fromInteger . toInteger uncurry3 f (a,b,c) = f a b c render var = do r <- readIORef var modifyIORef var (+1) clear [ColorBuffer,DepthBuffer] setupMat setupLight preservingMatrix $ do rotate r $ Vector3 0.0 1.0 (0.0 :: GLdouble) materialDiffuse FrontAndBack $= Color4 0.8 0.2 0.2 1.0 cube preservingMatrix $ do translate $ Vector3 2.0 0.0 (0.0 :: GLdouble) rotate (r*2) $ Vector3 0.0 1.0 (0.0 :: GLdouble) materialDiffuse FrontAndBack $= Color4 0.0 0.8 0.2 1.0 cube glSwapBuffers
                                                      • -
main = do True <- sdlInit [VIDEO] glSetAttribute GL_RED_SIZE 5 glSetAttribute GL_GREEN_SIZE 5 glSetAttribute GL_BLUE_SIZE 5 glSetAttribute GL_DEPTH_SIZE 16 glSetAttribute GL_DOUBLEBUFFER 1 setCaption "OpenGL" "" sur <- setVideoMode 640 480 16 [OPENGL] var <- newIORef initVar initialize loop $ render var sdlQuit loop f = do quit <- checkEvent when (not quit) $ do f threadDelay 16666 loop f checkEvent = do ev <- pollEvent case ev of Just QuitEvent -> return True Nothing -> return False _ -> checkEvent

テクスチャ周りが何も書いてなかった…