2012-04-16 38 views
3

我在使用OpenGl和Haskell編寫一個程序,該程序應該在單擊鼠標的時間和地點繪製一個矩形。但是,程序會在我點擊矩形之前立即關閉。Haskell圖形程序太早關閉

import Graphics.Rendering.OpenGL 
import Graphics.UI.GLUT 
import Graphics.UI.GLUT.Callbacks.Window 

main = do 
    (progname, _) <- getArgsAndInitialize 
    createWindow progname 
    keyboardMouseCallback $= Just myKeyboardMouseCallback 
    displayCallback $= display 
    mainLoop 

myKeyboardMouseCallback key keyState modifiers (Position x y) = 
    case (key, keyState) of 
    (MouseButton LeftButton, Down) -> do 
     clear[ColorBuffer] 
     let x = x :: GLfloat 
     let y = y :: GLfloat 
     renderPrimitive Quads $ do 
     color $ (Color3 (1.0::GLfloat) 0 0) 
     vertex $ (Vertex3 (x::GLfloat) y 0) 
     vertex $ (Vertex3 (x::GLfloat) (y+0.2) 0) 
     vertex $ (Vertex3 ((x+0.2)::GLfloat) (y+0.2) 0) 
     vertex $ (Vertex3 ((x+0.2)::GLfloat) y 0) 
     flush 
    _ -> return() 

display = do 
    clear [ColorBuffer] 
    renderPrimitive Lines $ do 
    flush 

有什麼導致程序中的一種方法提前終止,或者這只是告訴我的電腦的方式,我不能這樣做呢?

回答

5

你不能做你想做的事情。在OpenGL程序中,您只能在OpenGL上下文中發出繪圖命令。此上下文始終綁定到特定的線程,並且僅在GLUT中的displayCallback正文中處於活動狀態,因爲其他回調可能會從不同的線程運行。

但是,您可能會說:在許多/大多數平臺上,單獨的線程不是用於輸入GLUT的,這意味着您理論上可以在那裏發出繪圖命令。然而,還有很多其他的東西在你可以發出繪圖命令的時間和地點發揮作用;例如,當環境要求您使用雙緩衝輸出時,必須以非常特定的方式(例如,在X11中使用EGL或GLX時)刷新緩衝區。

簡而言之:您不應該發出displayCallback以外的繪圖命令。其存在的全部原因是讓您可以讓GLUT處理與本機幀緩衝區管理相關的特定於平臺的內容,並期望您能夠將代碼保存在正確的位置以使其工作。

你想要做的是創建一個可變變量(嘿,你使用的是OpenGL;可變狀態不應該是你的擔心),它表示是否繪製矩形和其中的位置。喜歡的東西(使用Data.IORef):

main = do 
    -- ... 

    -- Create a mutable variable that stores a Bool and a pair of floats 
    mouseStateRef <- newIORef (False, (0, 0)) 

    -- Pass a reference to the mutable variable to the callbacks 
    keyboardMouseCallback $= Just (myKeyboardMouseCallback mouseStateRef) 
    displayCallback $= (display mouseStateRef) 

myKeyboardMouseCallback mouseStateRef key keyState modifiers (Position x y) = 
    case key of 
    MouseButton LeftButton -> do 
     -- Store the current mouse pressed state and coords in the reference 
     writeIORef mouseStateRef (keyState == Pressed, (x, y)) 
    _ -> return() 

display mouseStateRef = do 
    clear [ColorBuffer] 

    -- Read the state stored in the mutable reference 
    (pressed, (x, y)) <- readIORef mouseStateRef 

    -- Draw the quad if the mouse button is pressed 
    when pressed . renderPrimitive Quads $ do 
    color $ (Color3 (1.0::GLfloat) 0 0) 
    vertex $ (Vertex3 (x::GLfloat) y 0) 
    vertex $ (Vertex3 (x::GLfloat) (y+0.2) 0) 
    vertex $ (Vertex3 ((x+0.2)::GLfloat) (y+0.2) 0) 
    vertex $ (Vertex3 ((x+0.2)::GLfloat) y 0) 
    flush 
+0

之類的很有道理,但是當我去試試我的iorefs被淘汰的範圍,另一個是關於keyState ==追問下,即在按下錯誤。 – lewdsterthumbs 2012-04-17 19:09:46

+0

我還沒有測試過這個代碼。我只是想給你一個總體思路。你必須導入'Data.IORef'和其他一些東西。我不會爲你做所有的工作。 – dflemstr 2012-04-17 20:26:05

+0

我知道,但我仍然有一些相同的問題。 MouseStateRef實際上持有一對整數。我需要花車。 – lewdsterthumbs 2012-04-24 19:21:19