使用GLUT在多个窗口中同时绘图

时间:2011-09-09 18:41:25

标签: haskell glut freeglut

当我创建两个窗口并在两个不同的线程(每个窗口一个)中重绘它们时,似乎所有绘图都转到第一个创建的窗口。它不断在两个窗口中显示的内容之间切换。第二个仍然是黑色。

代码只用了一个窗口,然后我更新了它 - 在设置回调和调用渲染方法的函数的开头插入currentWindow $= Just glWindow

您认为问题的原因是什么?

编辑:

代码框架:

module Chart.Window where

import Graphics.UI.GLUT hiding (Window, postRedisplay, <etc>)
import qualified Graphics.UI.GLUT as GLUT
import qualified Graphics.Rendering.OpenGL as GL

data Window = Window
  { glWindow :: GLUT.Window
  , viewListRef :: IORef [Line]
  }

main = do
  forkOS start <params1>
  forkOS start <params2>

start <params> = do
  win <- new <params>
  run win
  mainLoop

new :: Strict -> (Int, Int) -> (Int, Int) -> IO Window
new name (posx, posy) (w, h) = do
  initGLUT
  glWindow <- createWindow name
  currentWindow $= Just glWindow
  windowSize $= Size (fromIntegral w) (fromIntegral h)
  windowPosition $= Position (fromIntegral posx) (fromIntegral posy)
  return Window {..}

initGLUT :: IO ()
initGLUT = do
  beenInit <- get initState
  unless beenInit $ void getArgsAndInitialize 
  initialDisplayMode $= [WithDepthBuffer, DoubleBuffered, RGBAMode]
  initialWindowSize $= Size 100 100
  initialWindowPosition $= Position 100 100
  actionOnWindowClose $= ContinueExectuion

run :: Window -> IO ()
run win@Window{..} = do
  -- this will fork (with forkIO) threads 
  -- which will call "repaint" when chart needs to be updated
  initListeners repaint 
  initCallbacks win
  where
  repaint :: [Line] -> IO ()
  repaint viewList = do
    writeIORef viewListRef viewList
    postRedisplay win

postRedisplay Window{..} = GLUT.postRedisplay $ Just glWindow

initCallbacks win@Window{..} = do
  currentWindow $= Just glWindow
  GLUT.displayCallback $= display win
  GLUT.idleCallback $= Just (postRedisplay win)

display Window{..} = do
  currentWindow $= Just glWindow
  Size w h <- get windowSize
  viewList <- readIORef viewListRef
  drawChart viewList otherOptions

reshapeCallback :: Window -> GLUT.ReshapeCallback
reshapeCallback win@Window{..} size@(Size w h) = do
  currentWindow $= Just glWindow
  GL.viewport $= (Position 0 0, size)
  GL.matrixMode $= GL.Projection
  GL.loadIdentity
  GL.ortho2D 0 (fromIntegral w) 0 (fromIntegral h)
  GL.matrixMode $= GL.Modelview 0
  GL.loadIdentity
  ... -- send command for listener thread to change internal state and postRedisplay

drawChart viewList otherOptions = do
  ...
  -- chart consists of several horizontal panels. Call this for each panel:
  glViewport 0 panelYPosition width winHeight
  glScissor 0 panelYPosition (fromIntegral width) (fromIntegral panelHeight)
  GL.clear [GL.ColorBuffer]
  ...
  -- and then for each line=(Vertex2 v1 v2) from viewList
  GL.renderPrimitive GL.Lines $ do
    GL.vertex v1
    GL.vertex v2
  ...
顺便说一下,当我评论设置reshapeCallback的行(并且窗口在开头重新整形)并仅使用一个窗口启动图表时,我得到了与多窗口启动完全相同的效果。我的意思是,(唯一)窗口大部分都是空的,好像它是第二次创建的那样。

1 个答案:

答案 0 :(得分:0)

我有类似的问题。我使用一个计算遗传算法迭代的线程,并在每次迭代中调用“GL.postRedisplay(Just window)”,但它没有绘制任何东西。

我通过从空闲功能调用“GL.postRedisplay(Just window)”解决了我的问题:

idle window = CC.threadDelay (1000*500) >> GL.postRedisplay (Just window)

不要忘记设置这样的空闲回调函数:

GL.idleCallback GL.$= Just (idle window) >>

CC和GL意味着:

import qualified Control.Concurrent as CC
import qualified Graphics.UI.GLUT as GL