我正在使用 OpenGl 和 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
是否有什么原因导致程序在其中一种方法中提前终止,或者这只是计算机告诉我不能这样做的方式?
最佳答案
你无法做你想做的事。在 OpenGL 程序中,您只能在OpenGL 上下文中发出绘制命令。此上下文始终绑定(bind)到特定线程,并且仅在 GLUT 中的 displayCallback
主体中处于事件状态,因为其他回调可能会从不同的线程运行。
但是,您可能会说:在许多/大多数平台上,单独的线程不用于 GLUT 中的输入,这意味着理论上您可以在那里发出绘图命令。然而,还有许多其他因素会影响您何时何地发出绘图命令;例如,当环境要求您使用双缓冲输出时,必须以非常特定的方式刷新缓冲区(例如,当对 X11 使用 EGL 或 GLX 时)。
简而言之:您不应在 displayCallback
之外发出绘图命令。它存在的全部原因是,您可以让 GLUT 处理与 native 帧缓冲区管理相关的特定于平台的内容,并且它希望您将代码保存在正确的位置以使其工作。
您想要做的是创建一个可变变量(嘿,您正在使用 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
关于opengl - Haskell 图形程序关闭过早,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10182173/