3

我正在使用 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

是否有什么东西导致程序在其中一种方法中提前终止,或者这只是计算机告诉我我不能这样做的方式?

4

1 回答 1

5

你不能做你想做的事。在 OpenGL 程序中,您只能在OpenGL 上下文中发出绘图命令。此上下文始终绑定到特定线程,并且仅displayCallback在 GLUT 的主体中处于活动状态,因为其他回调可能会从不同的线程运行。

但是,您可能会说:在许多/大多数平台上,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
于 2012-04-17T00:51:24.347 回答