1
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include <stdio.h>
#include <OpenGL/gl.h>
#include <string.h>
using namespace std;


    //Screen dimension constants
    const int SCREEN_WIDTH = 640;
    const int SCREEN_HEIGHT = 480;


bool SetOpenGLAttributes()
{

    // SDL_GL_CONTEXT_CORE gives us only the newer version, deprecated functions are disabled
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);


    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    return true;
}



    int main( int argc, char* args[] )
    {

        SDL_Window* window = NULL;

        //Initialize SDL
        if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
        {
            printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
        }
        else
        {
            //Create window
            window = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL );
            if( window == NULL )
            {
                printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
            }
            else
            {



                //creating new context
                SDL_GL_CreateContext(window);

                SetOpenGLAttributes();
                SDL_GL_SetSwapInterval(1);

                //cube front
                glBegin(GL_POLYGON);
                glColor3f(1.0, 0.0, 0.0);
                glVertex3f(-.5, .5, -.5);
                glVertex3f(.5, .5, -.5);
                glVertex3f(.5, -.5, -.5);
                glVertex3f(-.5, -.5, -.5);
                glEnd();

                //cube top
                glBegin(GL_POLYGON);
                glColor3f(1.0,0.0,0.0);
                glVertex3f(-.5,.5,-.5);
                glVertex3f(.5, .5, -.5);
                glVertex3f(.5, .5, .5);
                glVertex3f(-.5, .5, .5);
                glEnd();

                //cube bottom
                glBegin(GL_POLYGON);
                glColor3f(1.0, 0.0, 0.0);
                glVertex3f(-.5,-.5,-.5);
                glVertex3f(.5, -.5, -.5);
                glVertex3f(.5, -.5, .5);
                glVertex3f(-.5, -.5, .5);
                glEnd();

                //cube right
                glBegin(GL_POLYGON);
                glColor3f(1.0, 0.0, 0.0);
                glVertex3f(.5, -.5, -.5);
                glVertex3f(.5, -.5, .5);
                glVertex3f(.5, .5, .5);
                glVertex3f(.5, .5, -.5);
                glEnd();

                //cube left
                glBegin(GL_POLYGON);
                glColor3f(1.0, 0.0, 0.0);
                glVertex3f(-.5, -.5, -.5);
                glVertex3f(-.5, .5, -.5);
                glVertex3f(-.5, .5, .5);
                glVertex3f(-.5, -.5, .5);
                glEnd();

                //cube back
                glBegin(GL_POLYGON);
                glColor3f(1.0, 0.0, 0.0);
                glVertex3f(-.5, .5, .5);
                glVertex3f(-.5, -.5, .5);
                glVertex3f(.5, -.5, .5);
                glVertex3f(.5, .5, .5);
                glEnd();

                glFlush();

                SDL_GL_SwapWindow(window);

                bool running = true;
                while(running){
                    glRotatef(1, 1, 0, 0);
                    glFlush();
                    SDL_GL_SwapWindow(window);
                    SDL_Delay(100);

                }


            }
        }


        //Destroy window
        //SDL_DestroyWindow( window );

        //Quit SDL subsystems
        //SDL_Quit();

        return 0;
}

I am in the process of learning openGL and SDL. I managed to get this "cube" to show up, but it just looks like a red rectangle. I want to rotate the cube to make sure that my code is in fact making a cube, however when I rotate and then swap windows, the cube only flickers. It seems that the second buffer window is just black, but when it switches again, it is always the same red rectangle. Why can't I rotate my cube and why is my second buffer window black?

genpfault
  • 51,148
  • 11
  • 85
  • 139
user2905256
  • 145
  • 2
  • 12

2 Answers2

3

You cannot just draw an image and then keep calling rotate after that and expect it to rotate everything you've previously rendered. That is not how it works. OpenGL could have been made to work that way, but it's not.

You need to call the transformation functions (rotation, scaling, translation) before you render the part that you are currently drawing; for multi-object scenes (think 2+ cubes all at different locations and moving/spinning independently of each other) you would reset-transform-draw-transform-draw-etc. Think of it as if you are moving the paintbrush, not the camera that you are taking the picture with.

So you should keep re-drawing that shape every frame (inside your loop), and generally you should keep resetting the view to the identity matrix each frame before you render (or push/pop matrices if you are comfortable with that).

main loop:
    reset view
    render
    swap buffers

As for the double-buffering...

Whenever you draw, you are drawing to a buffer. You don't draw to both buffers, you draw to one buffer at a time. If you are double (or more) buffering, you swap buffers after you are done rendering your image fully. The image you were drawing is swapped into the pipeline to be displayed on your monitor, and the one that was previously being displayed on your monitor is now your drawing space for your next frame of your image. Draw on that one now (probably erasing everything on it first before you draw, which is what glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); is for), and when you are done drawing that next frame you swap them again. That is what you are doing (or should be doing) with the loop. You are only ever drawing on 1 of the images at a time, but you keep drawing, swapping (to draw on the other), draw, swap, draw, swap, etc..

As for resetting your matrix, try glLoadIdentity();. Check out this question about glLoadIdentity and matrix modes here for further reading. In your specific instance here, just calling glLoadIdentity at the beginning of each loop should be sufficient, but if you plan on going further with this topic you should get a grasp on projection modes.

As far as using glLoadIdentity in your case, remember that I said you should keep rotating every instance of the loop, every frame? Remember that each iteration of the loop you are generally drawing the image how you want it to look in that frame of the animation. And between frames you are essentially resetting to draw a new picture, the next frame. Think of glLoadIdentity being like the artist bringing his hand back to himself to start again. If you keep doing a rotate every frame, it keeps rotating more and more. Same with scaling and translating. Now that I think about it, for your specific case you may actually want that, but in general you don't. For example, if you keep doing a translate to (1,2,0) and a rotate by (0.5,0.5,0), the "brush" will keep moving and rotating every single frame, and you rarely get the results you were expecting with that.

Another note on "resetting" things: sometimes you might need to "reset" while you're still in the middle of drawing a picture. For example, drawing two objects which have nothing to do with each other, you might glLoadIdentity to reset things after drawing the first object so you've "got your brush back in your hand in front of you" before drawing the second object on the same buffer. Or you might glClear to reset, say, the depth buffer if you need an effect where one object is always drawn on top of the other regardless of distance.

Check out this specific example of a rotating cube here.

Snippet from that example below - notice how it starts with some "reset view" type code (sometimes you will need more than that, depending on what you are doing), then transforming (including a couple of rotations), then rendering, then increasing a variable holding the angle to draw the cube at which is used in the rotate.

Note also that, in the example, the snippet is just the body of a function, but that could be a function called in your main loop, or the body of the function could be used directly as the body of a loop.

// Clear Screen And Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset The Current Modelview Matrix
glLoadIdentity();

glTranslatef(0.0f, 0.0f,-7.0f); // Translate Into The Screen 7.0 Units
glRotatef(rotqube,0.0f,1.0f,0.0f);  // Rotate The cube around the Y axis
glRotatef(rotqube,1.0f,1.0f,1.0f);
glBegin(GL_QUADS);      // Draw The Cube Using quads
glColor3f(0.0f,1.0f,0.0f);  // Color Blue
glVertex3f( 1.0f, 1.0f,-1.0f);  // Top Right Of The Quad (Top)
glVertex3f(-1.0f, 1.0f,-1.0f);  // Top Left Of The Quad (Top)
glVertex3f(-1.0f, 1.0f, 1.0f);  // Bottom Left Of The Quad (Top)
glVertex3f( 1.0f, 1.0f, 1.0f);  // Bottom Right Of The Quad (Top)
glColor3f(1.0f,0.5f,0.0f);  // Color Orange
glVertex3f( 1.0f,-1.0f, 1.0f);  // Top Right Of The Quad (Bottom)
glVertex3f(-1.0f,-1.0f, 1.0f);  // Top Left Of The Quad (Bottom)
glVertex3f(-1.0f,-1.0f,-1.0f);  // Bottom Left Of The Quad (Bottom)
glVertex3f( 1.0f,-1.0f,-1.0f);  // Bottom Right Of The Quad (Bottom)
glColor3f(1.0f,0.0f,0.0f);  // Color Red    
glVertex3f( 1.0f, 1.0f, 1.0f);  // Top Right Of The Quad (Front)
glVertex3f(-1.0f, 1.0f, 1.0f);  // Top Left Of The Quad (Front)
glVertex3f(-1.0f,-1.0f, 1.0f);  // Bottom Left Of The Quad (Front)
glVertex3f( 1.0f,-1.0f, 1.0f);  // Bottom Right Of The Quad (Front)
glColor3f(1.0f,1.0f,0.0f);  // Color Yellow
glVertex3f( 1.0f,-1.0f,-1.0f);  // Top Right Of The Quad (Back)
glVertex3f(-1.0f,-1.0f,-1.0f);  // Top Left Of The Quad (Back)
glVertex3f(-1.0f, 1.0f,-1.0f);  // Bottom Left Of The Quad (Back)
glVertex3f( 1.0f, 1.0f,-1.0f);  // Bottom Right Of The Quad (Back)
glColor3f(0.0f,0.0f,1.0f);  // Color Blue
glVertex3f(-1.0f, 1.0f, 1.0f);  // Top Right Of The Quad (Left)
glVertex3f(-1.0f, 1.0f,-1.0f);  // Top Left Of The Quad (Left)
glVertex3f(-1.0f,-1.0f,-1.0f);  // Bottom Left Of The Quad (Left)
glVertex3f(-1.0f,-1.0f, 1.0f);  // Bottom Right Of The Quad (Left)
glColor3f(1.0f,0.0f,1.0f);  // Color Violet
glVertex3f( 1.0f, 1.0f,-1.0f);  // Top Right Of The Quad (Right)
glVertex3f( 1.0f, 1.0f, 1.0f);  // Top Left Of The Quad (Right)
glVertex3f( 1.0f,-1.0f, 1.0f);  // Bottom Left Of The Quad (Right)
glVertex3f( 1.0f,-1.0f,-1.0f);  // Bottom Right Of The Quad (Right)
glEnd();            // End Drawing The Cube

rotqube +=0.9f;         // Increase Angle
Community
  • 1
  • 1
Loduwijk
  • 1,950
  • 1
  • 16
  • 28
  • So how would I do this within SDL or openGL? If I rotate and then re draw the cube, will it automatically draw to the inactive buffer? What do you mean by resetting to the identity matrix? How would I do that? – user2905256 Jul 12 '16 at 16:51
  • @user2905256 I updated it to clarify better. No, you don't ever draw to the inactive buffer. You draw to the active one then swap them so that active becomes inactive and inactive becomes active. Though calling it "inactive" might be deceiving if you don't understand what's going on. It's still being used, just not for drawing; it's being displayed on the monitor. – Loduwijk Jul 12 '16 at 18:15
  • As far as SDL is concerned, I don't use that, or at least haven't recently, so I cannot comment much on the SDL aspect. However, I think your problem is more OpenGL related. – Loduwijk Jul 12 '16 at 18:30
  • Thanks for all the help! As soon as im off work Ill be trying again . Just for clarification, is the active buffer the one you are manupulating (the unseen one) or the one being displayed to the screen currently? – user2905256 Jul 12 '16 at 21:05
  • @user2905256 My point in my active/inactive comment was that those terms are very subjective. Neither of them are technically "inactive." I would not call either of them active or inactive. If you are reading a book or online tutorial which calls one of them active, it's probably referring to the one you are drawing on. But remember, the one you are drawing on *is not currently being displayed on the monitor*. You're drawing on one while the other is displayed on the monitor. That is why your drawing won't be displayed until you swap them. – Loduwijk Jul 13 '16 at 12:15
1
  • Clear the framebuffer & re-draw the cube every time through the while(running) loop. Right now you're just alternating between the framebuffer with your cube in it and a blank one.
  • OpenGL isn't a scenegraph, etc.
  • Don't request a Core context if you're going to use removed functionality like glBegin(). Isn't going to work.
  • Pump the event loop using SDL_PollEvent()/SDL_WaitEvent() to keep the OS happy

All together:

#include <cstdio>
#include <cstdlib>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>

//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

int main( int argc, char* args[] )
{
    SDL_Window* window = NULL;

    //Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
        return EXIT_FAILURE;
    }

    //Create window
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    window = SDL_CreateWindow
        (
        "SDL Tutorial",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        SCREEN_WIDTH, SCREEN_HEIGHT,
        SDL_WINDOW_OPENGL
        );
    if( window == NULL )
    {
        printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
        return EXIT_FAILURE;
    }

    //creating new context
    SDL_GLContext ctx = SDL_GL_CreateContext(window);
    SDL_GL_SetSwapInterval(1);

    bool running = true;
    while( running )
    {
        SDL_Event ev;
        while( SDL_PollEvent( &ev ) )
        {
            if( ( SDL_QUIT == ev.type ) ||
                ( SDL_KEYDOWN == ev.type && SDLK_ESCAPE == ev.key.keysym.sym ) )
            {
                running = false;
                break;
            }
        }

        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();

        glMatrixMode( GL_MODELVIEW );
        glLoadIdentity();

        static float angle = 0.0f;
        angle += 1;
        glRotatef( angle, 0.2, 0.3, 0.1 );

        //cube front
        glBegin(GL_POLYGON);
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(-.5, .5, -.5);
        glVertex3f(.5, .5, -.5);
        glVertex3f(.5, -.5, -.5);
        glVertex3f(-.5, -.5, -.5);
        glEnd();

        //cube top
        glBegin(GL_POLYGON);
        glColor3f(1.0,0.0,0.0);
        glVertex3f(-.5,.5,-.5);
        glVertex3f(.5, .5, -.5);
        glVertex3f(.5, .5, .5);
        glVertex3f(-.5, .5, .5);
        glEnd();

        //cube bottom
        glBegin(GL_POLYGON);
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(-.5,-.5,-.5);
        glVertex3f(.5, -.5, -.5);
        glVertex3f(.5, -.5, .5);
        glVertex3f(-.5, -.5, .5);
        glEnd();

        //cube right
        glBegin(GL_POLYGON);
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(.5, -.5, -.5);
        glVertex3f(.5, -.5, .5);
        glVertex3f(.5, .5, .5);
        glVertex3f(.5, .5, -.5);
        glEnd();

        //cube left
        glBegin(GL_POLYGON);
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(-.5, -.5, -.5);
        glVertex3f(-.5, .5, -.5);
        glVertex3f(-.5, .5, .5);
        glVertex3f(-.5, -.5, .5);
        glEnd();

        //cube back
        glBegin(GL_POLYGON);
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(-.5, .5, .5);
        glVertex3f(-.5, -.5, .5);
        glVertex3f(.5, -.5, .5);
        glVertex3f(.5, .5, .5);
        glEnd();

        SDL_GL_SwapWindow(window);
        SDL_Delay( 16 );
    }

    SDL_GL_DeleteContext(ctx);
    SDL_DestroyWindow( window );
    SDL_Quit();

    return 0;
}
Community
  • 1
  • 1
genpfault
  • 51,148
  • 11
  • 85
  • 139