I am just started haskell gloss. I learnt a little about it functions. I am trying to draw a chess board in haskell. The main problem is that everything is being drawn in the center. If I used the function translate the board is being draw at random position. That's probably because translate moves from moves the distance given from current position not to the exact point which is given.
Is there a way in gloss haskell so that we can move to a specific point like setTransform or translateTo. Or is there any function which tells coordinates of current point at which we are at.
module Main where
import Graphics.Gloss
import Lib (someFunc)
blockSize :: Float
blockSize = 50
board :: [[Int]]
board = replicate 8 (replicate 8 0)
drawTile :: Float -> Float -> Color -> Picture
drawTile a b col = translate a b $ color col $ rectangleSolid blockSize blockSize
-- drawRow :: Int -> Pictur
-- drawRow =
toInt :: Float -> Integer
toInt = round
getColor :: Float -> Float -> Color
getColor i j = if even $ toInt ((i * 8) + j) then red else blue
screenHeight = 700
screenWidth = 1000
drawing :: Picture
drawing = pictures [drawTile (row * blockSize) (e * blockSize) (getColor row e) | row <- [0 .. 8], e <- [0 .. 8]]
-- moveToStart = viewPortTranslate
main :: IO ()
main = display (InWindow (show board) (screenWidth, screenHeight) (10, 10)) white (translate 0 0 drawing)
Edit: I don't want to fix this specific problem by using some math tricks. What I want to know is that how can I translate to a specfic position. Like when I do someFunc 0 0 the position should go to 0 0 top right corner.
If its not possible please tell the way to get the current transform point.
There is no existing Gloss function that will take an arbitrary picture and move it so its top-left corner is in the top-left corner of the screen. All existing transformation functions in Gloss are relative, so there's no way to make an "absolute" move to a specific point.
The best you can probably do is arrange to draw your picture so its origin matches its top-left corner, and then translate it up and left by half the screen height and width.
import Graphics.Gloss
-- chess board with top-left corner at (0,0), one unit in width and height
chess = scale (1/8) (1/8) $ pictures [square x y | x <- [0..7], y <- [0..8]]
where square x y =
Color (if even (x+y) then red else black) $
translate (fromIntegral x+0.5) (-fromIntegral y -0.5) $ rectangleSolid 1 1
main = display (InWindow "Layout" (1000,700) (10,10)) white $
-- scale to a 700x700 square (with origin still at top-level corner)
-- then translate origin from default position at center of window
-- to top-left corner, by moving half the window width and height
translate (-500) 350 $ scale 700 700 chess
I'm using two textures on two different objects that each have their own shader program. However, the second object renders with both textures applied and with some strange distortion.
I will focus on the second object's code as the first object and texture renders correctly.
The first texture is loaded like this:
-- Icosahedron texture
dice_textureP <- malloc
glGenTextures 1 dice_textureP
diceText <- peek dice_textureP
glBindTexture GL_TEXTURE_2D diceText
glEnable GL_BLEND
glBlendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
glGenerateMipmap GL_TEXTURE_2D
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER GL_LINEAR
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER GL_LINEAR
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S GL_REPEAT
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T GL_REPEAT
eErrDI0 <- readImage "app/numbers.png"
dyImage0 <- case eErrDI0 of
Left e -> do
putStrLn e
return $ ImageRGBA8 $ generateImage (\x y ->
let x' = fromIntegral x in (PixelRGBA8 x' x' x' x')) 500 400
Right di -> return di
let ipixelrgba80 = convertRGBA8 dyImage0
iWidth0 = fromIntegral $ imageWidth ipixelrgba80
iHeight0 = fromIntegral $ imageHeight ipixelrgba80
iData0 = imageData ipixelrgba80
VS.unsafeWith iData0 $ \dataP ->
glTexImage2D GL_TEXTURE_2D 0 GL_RGBA iWidth0 iHeight0 0 GL_RGBA GL_UNSIGNED_BYTE (castPtr dataP)
glGenerateMipmap GL_TEXTURE_2D
glBindTexture GL_TEXTURE_2D 0
The second texture is loaded like this:
card_oneP <- malloc
glGenTextures 1 card_oneP
card_oneTexture <- peek card_oneP
glBindTexture GL_TEXTURE_2D card_oneTexture
glDisable GL_BLEND
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER GL_NEAREST_MIPMAP_NEAREST
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER GL_NEAREST_MIPMAP_NEAREST
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S GL_CLAMP_TO_EDGE
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T GL_CLAMP_TO_EDGE
eErrDI1 <- readImage "app/card_one.jpg"
dyImage1 <- case eErrDI1 of
Left e -> do
putStrLn e
return $ ImageRGBA8 $ generateImage (\x y ->
let x' = fromIntegral x in (PixelRGBA8 x' x' x' x')) 312 445
Right di -> return di
let ipixelrgb81 = convertRGBA8 dyImage1
iWidth1 = fromIntegral $ imageWidth ipixelrgb81
iHeight1 = fromIntegral $ imageHeight ipixelrgb81
iData1 = imageData ipixelrgb81
VS.unsafeWith iData1 $ \dataP ->
glTexImage2D GL_TEXTURE_2D 0 GL_RGBA iWidth0 iHeight0 0 GL_RGBA GL_UNSIGNED_BYTE (castPtr dataP)
glGenerateMipmap GL_TEXTURE_2D
glBindTexture GL_TEXTURE_2D 0
I bind the first texture before drawing the first object like this:
-- first vao and shader program
glUseProgram ico_shaderProgram
glBindVertexArray ico_vao
-- bind first texture
glActiveTexture GL_TEXTURE0
glBindTexture GL_TEXTURE_2D diceText
diceTextureLocation <- glGetUniformLocation ico_shaderProgram diceTexture
glUniform1i diceTextureLocation 0
After calling glDrawArrays on the first object, I unbind the first texture using glBindTexture_2D 0.
The second texture is bound in a similar fashion:
-- second vao and shader
glUseProgram card_shaderProgram
glBindVertexArray card_vao
-- bind second texture
glActiveTexture GL_TEXTURE0
glBindTexture GL_TEXTURE_2D card_oneTexture
cardTextureLocation <- glGetUniformLocation card_shaderProgram cardTexture
glUniform1i cardTextureLocation 0
I call glBindTexture_2D 0 after the draw before re-entering the render loop.
The result looks like this:
As you can see, the object on the right has a few artifacts... The second texture is rendering on top of the first texture (which should only be on the first object). Moreover, the second texture is all distorted.
The verticies and uv coords for the second object can be found here (gist).
The shader used for this object is here (gist).
The attributes for the second object are set up like so:
-- second object attribs
glVertexAttribPointer 0 3 GL_FLOAT GL_FALSE (5*floatSize) nullPtr
glEnableVertexAttribArray 0
let threeFloatOffset = castPtr $ plusPtr nullPtr (fromIntegral $ 3*floatSize)
glVertexAttribPointer 1 2 GL_FLOAT GL_FALSE (5*floatSize) threeFloatOffset
glEnableVertexAttribArray 1
glBindVertexArray 0
I've tried to include the most relevant code. I would be very grateful if someone can spot my error. I am 100% willing to post more code if needed.
UPDATE:
Someone in the comments kindly pointed out that my code was using incorrect width and height values for the second texture. I am using this function to load in images now:
loadImageTexture :: [Char] -> Int -> Int -> IO (Image PixelRGBA8)
loadImageTexture filePath w h = do
errorOrDyImage <- readImage filePath
dyImage <- case errorOrDyImage of
Left e -> do
putStrLn e
return $ ImageRGBA8 $ generateImage (\x y ->
let x' = fromIntegral x in (PixelRGBA8 x' x' x' x')) w h
Right di -> return di
return $ convertRGBA8 dyImage
As someone pointed out in the comments, iWidth0 and iHeight0 (width and height for the first texture) are incorrectly called for the second texture:
glTexImage2D GL_TEXTURE_2D 0 GL_RGBA iWidth0 iHeight0 0 GL_RGBA GL_UNSIGNED_BYTE (castPtr dataP)
It should be:
glTexImage2D GL_TEXTURE_2D 0 GL_RGBA iWidth1 iHeight1 0 GL_RGBA GL_UNSIGNED_BYTE (castPtr dataP)
Creating a function to handle loading textures would have avoided this problem from the start.
Simplifying the reality, my OpenGL program has the following structure:
At the beginning, there's a function f : (Double,Double,Double) -> Double.
Then there is a function triangulize :: ((Double,Double,Double) -> Double) -> [Triangle] such that triangulize f calculates a triangular mesh of the surface f(x,y,z)=0.
Then there is the displayCallback, a function display :: IORef Float -> DisplayCallBack which displays the graphics (that is to say it displays the triangular mesh). The first argument IORef Float is here to rotate the graphics, and its value (the angle of the rotation) changes when the user presses a key on the keyboard, thanks to the keyboardCallback defined later. Don't forget that the display function calls triangulize f.
Then the problem is the following one. When the user presses the key to rotate the graphic, the display function is triggered. And then triangulize f is re-evaluated, whereas it doesn't need to be re-evaluated: rotating the graphics does not change the triangular mesh (i.e. the result of triangulize f is the same as before).
So, is there a way to rotate the graphics by pressing a key without triggering triangulize f ? In other words, to "freeze" triangulize f so that it is evaluated only once and is never re-evaluated, which is time-consuming but useless since anyway the result is always the same.
I believe this is a standard way to rotate a graphics in Haskell OpenGL (I viewed that way in some tutos), so I don't think it is necessary to post my code. But of course I can post it if needed.
The reality is more complicated since there are other IORef's to control some parameters of the surface. But I would like to firstly know some solutions for this simplified situation.
EDIT: more details and some code
Simplified code
So, if I follow the simplified description above, my program looks like
fBretzel5 :: (Double,Double,Double) -> Double
fBretzel5 (x,y,z) = ((x*x+y*y/4-1)*(x*x/4+y*y-1))^2 + z*z
triangles :: [Triangle] -- Triangle: triplet of 3 vertices
triangles =
triangulize fBretzel5 ((-2.5,2.5),(-2.5,2.5),(-0.5,0.5))
-- "triangulize f (xbounds, ybounds, zbounds)"
-- calculates a triangular mesh of the surface f(x,y,z)=0
display :: IORef Float -> DisplayCallback
display rot = do
clear [ColorBuffer, DepthBuffer]
rot' <- get rot
loadIdentity
rotate rot $ Vector3 1 0 0
renderPrimitive Triangles $ do
materialDiffuse FrontAndBack $= red
mapM_ drawTriangle triangles
swapBuffers
where
drawTriangle (v1,v2,v3) = do
triangleNormal (v1,v2,v3) -- the normal of the triangle
vertex v1
vertex v2
vertex v3
keyboard :: IORef Float -- rotation angle
-> KeyboardCallback
keyboard rot c _ = do
case c of
'e' -> rot $~! subtract 2
'r' -> rot $~! (+ 2)
'q' -> leaveMainLoop
_ -> return ()
postRedisplay Nothing
This causes the issue described above. Each time the key 'e' or 'r' is pressed, the triangulize function runs while its output remains the same.
True code (almost)
Now, here is a version of my program closest to the reality. In fact, it calculates a triangular mesh for a surface f(x,y,z)=l, where the "isolevel" l can be changed with the keyboard.
voxel :: IO Voxel
voxel = makeVoxel fBretzel5 ((-2.5,2.5),(-2.5,2.5),(-0.5,0.5))
-- the voxel is a 3D-array of points; each entry of the array is
-- the value of the function at this point
-- !! the voxel should never changes throughout the program !!
trianglesBretz :: Double -> IO [Triangle]
trianglesBretz level = do
vxl <- voxel
computeContour3d vxl level
-- "computeContour3d vxl level" calculates a triangular mesh
-- of the surface f(x,y,z)=level
display :: IORef Float -> IORef Float -> DisplayCallback
display rot level = do
clear [ColorBuffer, DepthBuffer]
rot' <- get rot
level' <- get level
triangles <- trianglesBretz level'
loadIdentity
rotate rot $ Vector3 1 0 0
renderPrimitive Triangles $ do
materialDiffuse FrontAndBack $= red
mapM_ drawTriangle triangles
swapBuffers
where
drawTriangle (v1,v2,v3) = do
triangleNormal (v1,v2,v3) -- the normal of the triangle
vertex v1
vertex v2
vertex v3
keyboard :: IORef Float -- rotation angle
-> IORef Double -- isolevel
-> KeyboardCallback
keyboard rot level c _ = do
case c of
'e' -> rot $~! subtract 2
'r' -> rot $~! (+ 2)
'h' -> level $~! (+ 0.1)
'n' -> level $~! subtract 0.1
'q' -> leaveMainLoop
_ -> return ()
postRedisplay Nothing
A part of a solution
In fact, I have found a solution in order to "freeze" the voxel:
voxel :: Voxel
{-# NOINLINE voxel #-}
voxel = unsafePerformIO $ makeVoxel fBretzel5 ((-2.5,2.5),(-2.5,2.5),(-0.5,0.5))
trianglesBretz :: Double -> IO [Triangle]
trianglesBretz level =
computeContour3d voxel level
In this way, I think the voxel is never re-evaluated.
But there is still a problem. When the IORef rot changes, to rotate the graphics, then there's no reason to re-evaluate trianglesBretz: the triangular mesh of f(x,y,z)=level is always the same whatever the rotation.
So, how can I say to the display function: "hey! when rot changes, do not re-evaluate trianglesBretz, since you will find the same result" ?
I don't know how to use NOINLINE for trianglesBretz, as I did for voxel. Something which would "freezes" trianglesBretz level unless level changes.
And here is the 5-holes bretzel:
EDIT: solution based on #Petr Pudlák's answer.
After #Petr Pudlák's very good answer I came to the following code. I give this solution here in order to place the answer more in the context of OpenGL.
data Context = Context
{
contextRotation :: IORef Float
, contextTriangles :: IORef [Triangle]
}
red :: Color4 GLfloat
red = Color4 1 0 0 1
fBretz :: XYZ -> Double
fBretz (x,y,z) = ((x2+y2/4-1)*(x2/4+y2-1))^2 + z*z
where
x2 = x*x
y2 = y*y
voxel :: Voxel
{-# NOINLINE voxel #-}
voxel = unsafePerformIO $ makeVoxel fBretz ((-2.5,2.5),(-2.5,2.5),(-1,1))
trianglesBretz :: Double -> IO [Triangle]
trianglesBretz level = computeContour3d voxel level
display :: Context -> DisplayCallback
display context = do
clear [ColorBuffer, DepthBuffer]
rot <- get (contextRotation context)
triangles <- get (contextTriangles context)
loadIdentity
rotate rot $ Vector3 1 0 0
renderPrimitive Triangles $ do
materialDiffuse FrontAndBack $= red
mapM_ drawTriangle triangles
swapBuffers
where
drawTriangle (v1,v2,v3) = do
triangleNormal (v1,v2,v3) -- the normal of the triangle
vertex v1
vertex v2
vertex v3
keyboard :: IORef Float -- rotation angle
-> IORef Double -- isolevel
-> IORef [Triangle] -- triangular mesh
-> KeyboardCallback
keyboard rot level trianglesRef c _ = do
case c of
'e' -> rot $~! subtract 2
'r' -> rot $~! (+ 2)
'h' -> do
l $~! (+ 0.1)
l' <- get l
triangles <- trianglesBretz l'
writeIORef trianglesRef triangles
'n' -> do
l $~! (- 0.1)
l' <- get l
triangles <- trianglesBretz l'
writeIORef trianglesRef triangles
'q' -> leaveMainLoop
_ -> return ()
postRedisplay Nothing
main :: IO ()
main = do
_ <- getArgsAndInitialize
_ <- createWindow "Bretzel"
windowSize $= Size 500 500
initialDisplayMode $= [RGBAMode, DoubleBuffered, WithDepthBuffer]
clearColor $= white
materialAmbient FrontAndBack $= black
lighting $= Enabled
lightModelTwoSide $= Enabled
light (Light 0) $= Enabled
position (Light 0) $= Vertex4 0 0 (-100) 1
ambient (Light 0) $= black
diffuse (Light 0) $= white
specular (Light 0) $= white
depthFunc $= Just Less
shadeModel $= Smooth
rot <- newIORef 0.0
level <- newIORef 0.1
triangles <- trianglesBretz 0.1
trianglesRef <- newIORef triangles
displayCallback $= display Context {contextRotation = rot,
contextTriangles = trianglesRef}
reshapeCallback $= Just yourReshapeCallback
keyboardCallback $= Just (keyboard rot level trianglesRef)
idleCallback $= Nothing
putStrLn "*** Bretzel ***\n\
\ To quit, press q.\n\
\ Scene rotation:\n\
\ e, r, t, y, u, i\n\
\ Increase/Decrease level: h, n\n\
\"
mainLoop
And now my bretzel can be rotated without performing useless calculations.
I'm not very familiar with OpenGL, so I have some difficulty understanding the code in detail - please correct me if I misunderstood something.
I'd try to abstain from using unsafe functions or relying on INLINE as much as possible. This usually makes code brittle and obscures more natural solutions.
In the simplest case, if you don't need to re-evaluate triangularize, we could just replace it with its output. So we'd have
data Context = Context
{ contextRotation :: IORef Float,
, contextTriangles :: [Triangle]
}
and then
display :: Context -> DisplayCallback
which won't reevaluate triangles at all, they'll be computed only once when Context is created.
Now if there are two parameters, rotation and level, and triangles depend on the level, but not on rotation: The trick here would be to manage dependencies properly. Now we expose the storage for parameters explicitly (IORef Float), and as a consequence, we can't monitor when the value inside changes. But the caller doesn't need to know the representation of how the parameters are stored. It just needs to store them somehow. So instead, let's have
data Context = Context
{ contextRotation :: IORef Float,
, contextTriangles :: IORef [Triangle]
}
and
setLevel :: Context -> Float -> IO ()
That is, we expose a function to store the parameter, but we hide the internals. Now we can implement it as:
setLevel (Context _ trianglesRef) level = do
let newTriangles = ... -- compute the new triangles
writeIORef trianglesRef newTriangles
And as triangles don't depend on the rotation parameter, we can have just:
setRotation :: Context -> Float -> IO ()
setRoration (Context rotationRef _) = writeIORef rotationRef
Now the dependencies are hidden for callers. They can set the level or the rotation, without knowing what depends on them. At the same time, triangles are updated when needed (level changes), and only then. And Haskell's lazy evaluation gives a nice bonus: If the level changes multiple times before the triangles are needed, they are not evaluated. The [Triangle] thunk inside the IORef will be only evaluated when requested by display.
I am currently trying to write a graphical application in haskell using OpenGL and GLFW-b. I am rather new to OpenGL, and I am having some problems displaying the TextureObjects. I have tried two ways of doing it.
The first way I tried was to store the textures as an TextureObject, and then simply using it as an input argument to the render function (see below). However, this doesn't work, as
the texture objects simply appear as white squares.
I will also note that it probably took several second for the program to start, presumably because it loaded all the graphics.
The second thing I tried was to store the textures as an IO TextureObject. This worked
, but it is very slow. It slows down to a few frames per second. I suspect this is because the textures need to be reloaded every time they are drawn. In order to test this, I renamed the textures while the program are running, and indeed the program crashed, confirming that it needs to reload the textures every iteration.
The texture is loaded with the function
loadTexture' :: FilePath -> IO TextureObject
loadTexture' f = do
tex <- either error id <$> readTexture f
textureFilter Texture2D $= ((Linear', Nothing), Linear')
return tex
and rendered with
renderTexture :: Area -> Area -> TextureObject -> IO()
renderTexture window area tex =
let (x,x') = xRangeToGL window $ getXRange area
(y,y') = yRangeToGL window $ getYRange area
in do textureBinding Texture2D $= Just tex
renderPrimitive Quads $ do
col
txc 1 1 >> ver x' y'
txc 1 0 >> ver x' y
txc 0 0 >> ver x y
txc 0 1 >> ver x y'
where col = color (Color3 1.0 1.0 1.0 :: Color3 GLfloat)
ver x y = vertex (Vertex2 x y :: Vertex2 GLfloat)
txc u v = texCoord (TexCoord2 u v :: TexCoord2 GLfloat)
The OpenGL settings are
clearColor $= Color4 r g b 1.0
depthFunc $= Just Lequal
blendFunc $= (SrcAlpha, OneMinusSrcAlpha)
normalize $= Enabled
texture Texture2D $= Enabled
shadeModel $= Smooth
This is my first post, so please tell me if I have missed something, and thank you for your kind assistance!
Bad practice solution:
I have come up with a solution, I have added it as an edit, rather than a solution, because I'm not certain that it is good practice --- it is not the type of answer I would like to have to this post, but it can still be of use to those who wish to answer.
Calling loadTexture using unsafeCoerce,
unsafePerformIO $ loadTexture "foo/bar.png"
works. However, rewriting the loadTexture' function as
loadTexture' :: FilePath -> IO TextureObject
loadTexture' f = do
let tex = unsafePerformIO $ either error id <$> readTexture f
textureFilter Texture2D $= ((Linear', Nothing), Linear')
return tex
does not work.
When I create two windows and redraw them in two different threads (one per window), it seems like all drawing goes to first created window. It constantly switches between what should be displayed in both windows. And second one remains mostly black.
The code was working well with only one window, and then I updated it - inserted currentWindow $= Just glWindow in the beginning of the functions which set callbacks and call rendering methods.
What do you think is the cause of the problems?
EDIT:
Code skeleton:
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
...
BTW, when I commented the line which sets reshapeCallback (and window is reshaped at the beginning) and launched charting with only one window, I got exactly the same effect as in multi-window launch. I mean, the (only) window was mostly empty as if it was secondly created.
I had a similar problem. I work with a thread that calculates the iterations of a genetic algorithm and in each iteration I call to "GL.postRedisplay (Just window)" but it didn't draw anything.
I solved my problem by calling "GL.postRedisplay (Just window)" from the idle function:
idle window = CC.threadDelay (1000*500) >> GL.postRedisplay (Just window)
Don't forget to setup your idle callback function like this:
GL.idleCallback GL.$= Just (idle window) >>
CC and GL mean:
import qualified Control.Concurrent as CC
import qualified Graphics.UI.GLUT as GL