Рисование одновременно в нескольких окнах с помощью GLUT - PullRequest
2 голосов
/ 09 сентября 2011

Когда я создаю два окна и перерисовываю их в двух разных потоках (по одному на окно), кажется, что весь рисунок идет в первое созданное окно.Он постоянно переключается между тем, что должно отображаться в обоих окнах.А второй остается в основном черным.

Код работал хорошо только с одним окном, а затем я обновил его - вставил 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 голосов
/ 26 мая 2014

У меня была похожая проблема. Я работаю с потоком, который вычисляет итерации генетического алгоритма, и в каждой итерации я вызываю «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
...