Haskell graphics program closing too early - opengl

I'm writing a program using OpenGl and Haskell that should draw a rectangle when and where the mouse is clicked. However, the program closes as soon as I click and before the rectangle is drawn.
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
Is there something causing the program to terminate early in one of the methods, or is this just the the computers way of telling me I can't do this?

You can't do what you are trying to do. In an OpenGL program, you are only allowed to issue draw commands in the OpenGL context. This context is always bound to a specific thread, and is only active in the body of the displayCallback in GLUT, because the other callbacks might potentially run from different threads.
However, you might say: On many/most platforms, a separate thread isn't used for input in GLUT, which means that you theoretically could issue drawing commands there. There are, however, many other things that play a role in where and when you can issue drawing commands; for example when the environment requires you to use double-buffered output where the buffers have to be flushed in very specific ways (e.g. when using EGL or GLX for X11).
In short: you should not issue drawing commands outside of the displayCallback. The whole reason for its existence is so that you can let GLUT handle the platform-specific stuff related to native frame buffer management, and it expects you to keep your code in the right places for it to work.
What you want to do instead is to create a mutable variable (Hey, you're using OpenGL; mutable state shouldn't be a worry to you) that indicates whether to draw the rectangle and where. Something like (Using 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

Related

glReadPixels doesnt work for the first left click

I am working on a MFC app which is a MDI. One of the child frame uses OpenGL(mixed with fixed function and modern version) called 3d view and another child frame uses GDI called plan view. Both of the views use the same doc.
The 3d view has a function to detect if the mouse cursor is over rendered 3d model by reading pixels and check its depth value.
The function is used for WM_MOUSEMOVE and WM_LBUTTONDOWN events. Most time it works pretty well. But it failed when I move my cursor from the plan view(currently active) to the 3d view and left mouse click. The depth values read from the pixels(called from onLButtonDown) are always all zeros though it is over a model. There is no OpenGL error reported. It only fails on the first mouse click when the 3d view is not activated. Afterwards, everything works well again.
The issue doesn't happen on all machines. And it happens to me but not to another guy with the same hardware machine with me. Is that possible hardware related or a code bug?
Things tried:
I tried to increase the pixel block size much bigger but depths are still all zero.
If I click on the title bar of the 3d view to activate it first, then works.
I tried to set the 3d view active and foreground in the onLButtonDown method before reading pixels. But still failed.(btw, the 3d view should be active already before the OnLButtonDown handler via other message handler fired by the left button down).
I tried to invalidate rect before reading pixels, failed too.
The code is as below:
BOOL CMy3DView::IsOverModel(int x0, int y0, int &xM, int &yM, GLfloat &zWin, int width0 , int height0 )
{
int width = max(1,width0);
int height= max(1,height0);
CRect RectView;
GetClientRect(&RectView);
GLint realy = RectView.Height() - 1 - (GLint)y0 ; /* OpenGL y coordinate position */
std::vector<GLfloat> z(width*height);
//Read the window z co-ordinates the z value of the points in a rectangle of width*height )
xM = max(0, x0-(width-1)/2);
yM = max(0, realy-(height-1)/2);
glReadPixels(xM, yM, (GLsizei)width, (GLsizei)height, GL_DEPTH_COMPONENT, GL_FLOAT, &z[0]); OutputGlError(_T("glReadPixels")) ;
/* check pixels along concentric, nested boxes around the central point */
for (int k=0; k<=(min(height,width)-1)/2; ++k){
for (int i=-k;i<=k;++i){
xM = x0+i;
for (int j=-k;j<=k;++j){
if (abs(i)==k || abs(j)==k) {
yM = realy+j;
zWin=z[(i+(width-1)/2)+width*(j+(height-1)/2)];
if (zWin<1.0-FLT_EPSILON) break;
}
}
if (zWin<1.0-FLT_EPSILON) break;
}
if (zWin<1.0-FLT_EPSILON) break;
}
yM = RectView.Height() - 1 - yM;
if (zWin>1.0-FLT_EPSILON || zWin<FLT_EPSILON) {// z is the depth, between 0 and 1, i.e. between Near and Far plans.
xM=x0; yM=y0;
return FALSE;
}
return TRUE;
}
Just found a solution for that: I called render(GetDC) before any processing in OnLButtonDown. somehow it fixed the issue though I don't think it's necessary.
InvalideRect wont fix the issue since it will update the view for the next WM_PAINT.
Weird, since it works for some machines without the fix. Still curious about the reason.

How to draw a triangle with OCaml and GLFW?

I tried to draw a triangle with OCaml using glfw-ocaml and lablgl libraries. The program only shows a black window and I didn't manage to draw something in.
I've tried to use shader and the result is the same. I succeed to draw a simple triangle with GLUT. But how to do it with GLFW?
Here's my code (without shader):
let of_float_array_static arr ~kind =
let raw = Raw.create_static kind ~len:(Array.length arr) in
Raw.sets_float raw ~pos:0 arr;
raw
let () =
(* Initialize the library *)
GLFW.init ();
GLFW.windowHint ~hint:Samples ~value:(Some 4);
GLFW.windowHint ~hint:ContextVersionMajor ~value:3;
GLFW.windowHint ~hint:ContextVersionMinor ~value:3;
GLFW.windowHint ~hint:OpenGLForwardCompat ~value:true;
GLFW.windowHint ~hint:OpenGLProfile ~value:CoreProfile;
(* Create a windowed mode window and its OpenGL context *)
let window = GLFW.createWindow ~width:1024 ~height:768 ~title:"Triangle" () in
(* Make the window's context current *)
GLFW.makeContextCurrent ~window:(Some window);
(* Ensure we can capture the escape key being pressed below *)
GLFW.setInputMode ~window:window ~mode:StickyKeys ~value:true;
(* Dark blue background *)
GlClear.color (0., 0., 0.4);
let raw = of_float_array_static [|-1.; -1.; 0.; 1.; -1.; 0.; 0.; 1.; 0.|] ~kind:`float in
GlArray.vertex `three raw;
while (not ((GLFW.getKey ~window:window ~key:Escape) || (GLFW.windowShouldClose ~window:window))) do
(* Render here *)
(* Clear the screen *)
GlClear.clear [`color; `depth];
(* Draw triangle... *)
GlArray.enable `vertex;
GlArray.draw_arrays `triangles ~first:0 ~count:3;
GlArray.disable `vertex;
(* Swap front and back buffers *)
GLFW.swapBuffers ~window:window;
(* Poll for and process events *)
GLFW.pollEvents ()
done;
GLFW.terminate ()
I suppose I didn't succeed to draw in the right buffer, but I didn't find any function allowing to draw in a specific buffer. Moreover, the program (except the shaders) works when I use glut.

gluLookAt() not looking where it should

I don't understand what the glLookAt() function does exactly.
I have an object at position x,y,z . I want to place the camera at position x+20,y+20,z+20 while the object is moving, so that it should look like stationary. However, this is not the case : when I do the following code, I see a cross which is slowly moving to the right and even goes out of the window !
while (keystate[SDLK_ESCAPE] == false) {
SDL_PollEvent(&event);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
n+=0.1;
float x = 10;
float y = 10+n*n;
float z = 10;
// drawing an object at x,y,z (here a cross)
glBegin(GL_LINES);
glColor3ub(200,0,0);
glVertex3f(x-2,y,z);
glVertex3f(x+2,y,z);
glVertex3f(x,y-2,z);
glVertex3f(x,y+2,z);
glEnd();
// looking at the object
glMatrixMode( GL_MODELVIEW );
glLoadIdentity( );
gluLookAt(x+20,y+20,z+20,x,y,z,0,0,1);
glFlush();
SDL_GL_SwapBuffers();
}
If the camera were correctly looking at x,y,z , the cross should always appear at the center ?
If I put y = 10 + n , the object looks stationary.
With y = 10 + n * n , the object moves at constant speed, and with y = 10 + n * n * n, the object moves and accelerates.
I also did
gluPerspective(70,(double)640/480,1,1000);
at the beginning of my code.
Thank you in advance ! :S
OpenGL is a state machine, not a scene graph library. It does not remember the objects you have drawn. With your code, you first draw the object (with whatever matrices are current), and after that, set the new view matrix. This will have no effect on the object already drawn during this frame.
When the above code is executed in a loop, this will have the effect that the camera always looks at the object's position from last frame, and as faster your object is moving, the more away from the camera it will get.
Set the matrices before you draw the object.

How do I move an object in c++/opengl to a new place and erase the old object

I'm making Pacman game in opengl and I want to move my pacman in the game represented by a matrix.
The matrix have 16x16 and i put 4's when I whant to draw the walls, 3 for the small spheres and 2 for the pacman.
In the main class of my project I read a key from keyboard and i send the information to the class I defined the game. In that class I have this function:
void boardGame::refreshPacman(int n, int m)
{
int x, y;
(* pacman).movePacman(n, m); // This is working, it send information to class Pacman. In there I store the n (x axe) and m(y axe), and i get the next coordinates where pacman should translate.
x = (* pacman).getPacX(); // get coordinate of the old pacman
y = (* pacman).getPacY(); // get coordinate of the old pacman
board[x][y] = 0; // delete old information of pacman in matrix
x += n; // set the coordinates of x axis for new pacman
y += m; // set the coordinates of y axis for new pacman
wall[x][y] = 2; // insert the information of new pacman in matrix
pac->redraw (x, y, 0.5); // construct the new pacman
}
Pacman It's not beeing erased. Can you tell me what do I need to do next, and waht am I doing wrong?
Pacman It's not beeing erased. Can you tell me what do I need to do next, and waht am I doing wrong?
OpenGL is not a scenegraph (this is becomming the one statement I'm apparently make in almost every answer). It's a drawing API, which allows you to draw dancy points, lines and triangles. There's no concept of "geometric objects".
If you change something: Clear the old picture and draw a new one!
Use the -> operator with class pointers.
(* pacman).movePacman(n, m);
Should be:
pacman->movePacman(n,m);
To erase the earlier pacman, try redrawing the screen before adding the new one. Also, does the pacman destructor internally also end the rendering of the pacman image/sprite?

convert window coordinates to 3D world coordinates with glut function glutMouseFunc()

I am trying to get the 3D coordinates of a mouse click C++/OpengGL with the glut function glutMouseFunc(). So I created a function like this:
void mouse(int button, int state, int x, int y){
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
mouse_x=x;
mouse_y=y;
}
}
The function gets the window coordinates of the click of the mouse and i use it with the glut function glutMouseFunc() like this:
glutMouseFunc(mouse);
My question is how would I modify the coordinates given by the mouse function so I could use them in a 3D world. My exact purpose would be the following: to be able to see if I have clicked on a 3D shape drawn in the world.
[EDIT] Would it be easier to transform the coordinates of the 3D object to 2D window coordinates and then compare it to the coordinates of the mouse click?
Mouse click does not correspond to a point in 3d space, but to a ray.
In any case, you use gluUnProject.
If you know scene "depth" under cursor, then you can get 3d position of a click - by passing depth via winZ parameter.
If you don't know depth, pass 0.0 in winZ parameter, to get start of the ray, and 1.0 to get the "end". You'll have to calculate yourself if this ray hits anything.