i'm continue my dialog with openGL and c++ and for a now i want to make "scenes", that will change each other. for example screen with button "go next", i push button and then begin game.
What is the best approach with openGL in c++ for this ? The main question is what make with glut initialization commands like :
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(screenWidth, screenHeight);
glutInitWindowPosition(0,0);
glutCreateWindow("Puzzle quest!");
// Registration
glutDisplayFunc(Draw);
glutIdleFunc(Draw);
Is i need to implement this method in both classes, or only in one, and then only "show start button/ hide game functionality, hide start button/ show game functionality+start timer" ?
I do not mess with screen settings during scene/mode changes. Screen setings is changed on resize of the OpenGL window not on some button event...
You have to write your visualization and UI logic stuff dependent on some variables for example:
enum _game_screens_enum
{
_game_screen_main_menu=0,
_game_screen_game,
_game_screen_game_over,
_game_screen_help,
_game_screen_intro,
_game_screen_redefine_keys,
_game_screen_high_score,
_game_screen_exit,
};
int screen=_game_screen_main_menu;
Now in draw,update and UI handling functions just add appropriate ifs for example:
void draw()
{
if (screen==_game_screen_main_menu)
{
// draw main menu ...
}
else if (screen==_game_screen_game)
{
// draw in game screen stuff...
}
else ...
}
And that is it ...
Are you looking for a fade effect or some sort of transition where they are blended? Fade effect should be easy if using alpha channel... enable blend... draw black quad in front of everything as its alpha value increases from 0 to 1 over whatever time frame you want the fade to occur. The fade in would be the opposite. Not sure about the blending scenes effect... maybe accum buffer, or read pixels and then draw pixels if you can change alpha values.
Otherwise, glutDisplayFunc is the correct way to switch between scenes/drawing functions.
Try just fading effect, it could be of great help.
You should only initialize glut once.
Normally, the display and idle callbacks would do different things depending on what state you're in.
On a high level:
void idle()
{
if (showingMenu)
menu.idle();
else
currentScene.idle();
}
You could do it by switching functions, but I think that makes debugging more difficult.
(You should probably not use the same function for drawing and idling, though.)
Related
I'm stumped. I have a widget inside the mainwindow on a QT 4.6 application which has been configured as a openGL widget. It draws just fine except I am unable to clear the background between frames. I get a black background when he window opens and it never clears after that, so I get a jumbled mess of rendered objects as time goes along. I'm also having to call swapBuffers() at the end of the paintGL() function to get the widget to show the most recent frame which has me puzzled as I was under the impression that swapBuffers() was called automatically. I am set up for double buffering and the widget is not shared. Here is the relevant code:
void GLWidget::paintGL ( )
{
m_Input.Draw();
QGLWidget::swapBuffers();
}
void GLWidget::initializeGL ( )
{
qglClearColor(QColor(0,0,255,128));
glClear(GL_COLOR_BUFFER_BIT);
}
It does seem there's something not right with the double buffering. Clearing the screen to a background color is pretty basic. But it's driving me nuts as to why it's not working. The remainder of the drawing code is working fine. Any ideas? (This is on a Linux system.)
glClear is a drawing operation. It doesn't belong into initializeGL but into paintGL. The clearing color should be set right before calling glClear as well, so move that [q]glClearColor along.
Update
The paintGL method should look like this:
void GLWidget::paintGL()
{
qglClearColor(QColor(0,0,255,128));
glClear(GL_COLOR_BUFFER_BIT);
// you probably also want to clear the depth and stencil buffers
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
m_Input.Draw();
QGLWidget::swapBuffers();
}
Of course you must make sure that m_Input.Draw() doesn't mess things up again. You didn't show the code for that, so I'm in the blind here.
I am trying to rotate a 3d object but it doesnt update when applying transforms in a for loop.
The object jumps to the last position.
How does one update a 3d object's position in a sequence of updates if it wont update in a for loop?
Just calling glTranslate, glRotate or such won't change things on the screen. Why? Because OpenGL is a plain drawing API, not a scene graph. All it knows about are points, lines and triangles that draws to a pixel framebuffer. That's it. You want to change something on the screen, you must redraw it, i.e. clear the picture, and draw it again, with the changes.
BTW: You should not use a dedicated loop to implement animations (neither for, nor while, nor do while). Instead perform animation in the idle handler and issue a redraw event.
I reckon you have a wrong understanding what OpenGL does for you.
I'll try to outline:
- Send vertex data to the GPU (once)
(this does only specify the (standard) shape of the object)
- Create matrices to rotate, translate or transform the object (per update)
- Send the matrices to the shader (per update)
(The shader then calculates the screen position using the original
vertex position and the transformation matrix)
- Tell OpenGL to draw the bound vertices (per update)
Imagine programming with OpenGL like being a web client - only specifying the request (changing the matrix and binding stuff) is not enough, you need to explicitly send the request (send the transformation data and tell OpenGL to draw) to receive the answer (having objects on the screen.)
It is possible to draw an animation from a loop.
for ( ...) {
edit_transformation();
draw();
glFlush(); // maybe glutSwapBuffers() if you use GLUT
usleep(100); // not standard C, bad
}
You draw, you flush/swap to make sure that what you just drew is sent to the screen, and you sleep.
However, it is not recommended to do this in an interactive application. The main reason is that while you are in this loop, nothing else can run. Your application will be unresponsive.
That's why window systems are event-based. Every few miliseconds, the window system pings your app so you can update your state, for example do animation. This is the idle function. When the state of your program changed, you tell the window system that you would like to draw again. It is then up the the window system to call your display function. You do your OpenGL calls when the system tells you to.
If you use GLUT for communicating with the window system, this looks like the code below. Other libraries like GLFW have equivalent functions.
int main() {
... // Create window, set everything up.
glutIdleFunc(update); // Register idle function
glutDisplayFunc(display); // Register display function
glutMainLoop(); // The window system is in charge from here on.
}
void update() {
edit_transformation(); // Update your models
glutPostRedisplay(); // Tell the window system that something changed.
}
void display() {
draw(); // Your OpenGL code here.
glFlush(); // or glutSwapBuffers();
}
I have the following code:
paintGL()
{
if(mouse_was_clicked)
{
... do the color picking with openGL to identify a clicked element
... !!! now I need to call again paintGL() to switch the selected element from the
old one to the new one but I can't create a recursive cycle!
}
else
{
... normal code to draw the scene and the selected element in red ...
}
}
As the lines suggest, I need a way to call once more the paint event.. is there any way to accomplish this without creating a potential livelock? Something like deferring a new paint event?
If the control flow within your paintGL() is that simple, just make sure that the contens currently being in the else block are executed in every case:
void MyWidget::paintGL()
{
if(mouse_was_clicked)
{
... do the color picking with openGL to identify a clicked element
}
... normal code to draw the scene and the selected element in red ...
}
It's a bit hard to tell exactly what you're doing here.
If you're trying to setup a display widget (a color picker) when paintGL detects a mouse button has been clicked, you've mixed up your events. You should make a separate action for handling a mouseclick, which sets up flags/variables and triggers a repaint. IE, move the mouse-event handling out of the repaint callback.
I could easily have misunderstood your problem here, however... if so I apologize.
As a general rule, though, if you find yourself needing a recursive repaint in QT, you're probably working against, rather than with, the system.
I have a main window which has both a glut UI in the top 10% of the screen, and the openGL world in the bottom 90% of the screen. Every time my cursor starts hovering over the GLUT portion, openGL rendering will freeze. It resumes only when the cursor exits the GLUT area.
This is because as long as the cursor is hovering over the GLUT area, presumably glutIdleFunc is never called because glut is not "idle", so openGL stuff is not rendered.
I already tried making a new unrelated thread that just calls the display code and/or glutPostRedisplay but I got a framerate of whopping 20 fps as opposed to the 100+ fps the normal way. I don't know exactly why. (In this test I also disabled glutIdleFunc so there is no idle func, just the separate thread calling the display)
Ways to get around this (other than "stop using glut" which I might do in the future but for now I would like a temporary solution)?
I know this is an old question, but I was having a similar issue and wanted to share how I solved it.
Basically, in your idle function, you should manually set the window to your normal window ID. Thanks to Joel Davis' HexPlanet code ( https://github.com/joeld42/hexplanet/ ) for demonstrating this:
void glut_Idle( void )
{
// According to the GLUT specification, the current window is
// undefined during an idle callback. So we need to explicitly change
// it if necessary
if ( glutGetWindow() != g_glutMainWin )
{
glutSetWindow(g_glutMainWin);
}
...
}
Create a callback for passive motion func:
void passiveMouseFunc(int,int){
glutPostRedisplay();
}
And register it using:
glutPassiveMotionFunc(passiveMouseFunc);
I have drawn a picture with openGL on my windows. Now whenever I hold the mouse button on the windows and move it, my picture always got distorted. I don't know what function in openGL that can help me redraw the picture while the windows is moved. Anybody could help?
I tried this but seems not work:
void myDisplay()
{
.....
}
void reshape(int x, int y)
{
glutPostRedisplay();
}
int main()
{
.....
glutDisplayFunc(myDisplay);
glutReshapeFunc(reshape);
}
The first (and usually only) necessary step is to to quit using glut. glut is oriented primarily toward producing a static display, so it attempts to accumulate changes and then redraw only when the state has "stabilized" again, such as when you're done resizing the window. That made sense at one time, but mostly doesn't anymore.
Given that it's been around 10 years since glut was last updated, out of date design goals are hardly a surprise. That doesn't change the fact that it's carefully written to prevent what you want from happening. If you wanted to, you could probably rewrite it to fit your expectations better, but it'll almost certainly be quite a bit simpler to use something else that's designed to do what you want (or at least something closer to what you want).
Add glutIdleFunc function
int main()
{
.....
glutDisplayFunc(myDisplay);
glutIdleFunc(myDisplay);
glutReshapeFunc(reshape);
}
Solution that worked for me was to skip the execution of InvalidateRect/RedrawWindow functions after calling MoveWindow on WM_MOUSEMOVE (I'm not using glut). Because usually it makes sense to execute InvalidateRect(wnd,0,0) after all mouse/keyboard events, but apprently calling it after MoveWindow causes the window contents to "stay behind" dragging.