SDL2 OpenGL3 How to initialize SDL inside a function
Asked Answered
T

2

8

I'm experimenting with the new SDL2 beta and an OpenGL3 context, and I'm having a weird problem:

If I run the SDL initialization code in my main() function, it works fine, but I want to have this code in a separete init_sdl() function.

If I put the initialization code in a separate init_sdl() function, and call this function from main(), the background color is never drawn, and the program starts to madly consume all my system's resources.

Could someone point me to a working example where SDL is initialized in a separate function? I can't seem to find one... Maybe this is not possible? I think I vaguely remember having a similar problem with SDL 1.2, but it's been a few years since I've used that, and I don't think I ever found a solution. In fact, this may be the reason I chose to switch to using SFML instead.

I really want to use SDL2 instead of SFML because it runs on more platforms, but not being able to separate things out into small functions is a deal breaker for me. This should be easy, am I missing something obvious?

Edit:

This works:

#include <iostream>
#include <GL/glew.h>
#include <SDL.h>
#define PROGRAM_NAME "SDL2 OpenGL3 Example"

int main(int argc, char** argv)
{
    SDL_Window* sdl2_window = 0;
    SDL_GLContext opengl3_context;

    SDL_Init(SDL_INIT_VIDEO);

    // set the opengl context version
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

    // turn on double buffering set the depth buffer to 24 bits
    // you may need to change this to 16 or 32 for your system
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

    // create the sdl2 window
    sdl2_window = SDL_CreateWindow(PROGRAM_NAME, SDL_WINDOWPOS_CENTERED,
            SDL_WINDOWPOS_CENTERED, 512, 512,
            SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);

    // create the opengl3 context
    opengl3_context = SDL_GL_CreateContext(sdl2_window);

    GLenum status = glewInit();
    if (status != GLEW_OK)
    {
        std::cerr << "GLEW Error: " << glewGetErrorString(status) << "\n";
        exit(1);
    }

    // sync buffer swap with monitor's vertical refresh rate
    SDL_GL_SetSwapInterval(1);

    // set background color
    glClearColor( 1.0, 0.0, 0.0, 1.0 );

    while (true)
    {
        int status = 0;

        glClear( GL_COLOR_BUFFER_BIT );

        SDL_GL_SwapWindow(sdl2_window);

        SDL_Event event;

        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
            case SDL_KEYDOWN:
                break;
            case SDL_KEYUP:
                // if escape is pressed, quit
                if (event.key.keysym.sym == SDLK_ESCAPE)
                    status = 1; // set status to 1 to exit main loop
                break;
            case SDL_QUIT:
                status = 1;
                break;
            }
        }

        if (status == 1) // if received instruction to quit
            break;
    }

    // delete opengl3 context, destroy sdl2 window, and shut down sdl subsystems
    SDL_GL_DeleteContext(opengl3_context);
    SDL_DestroyWindow(sdl2_window);
    SDL_Quit();

    return 0;
}

This doesn't work:

#include <iostream>
#include <GL/glew.h>
#include <SDL.h>
#define PROGRAM_NAME "SDL2 OpenGL3 Example"

void init_sdl(SDL_Window* sdl2_window, SDL_GLContext& opengl3_context)
{
    SDL_Init(SDL_INIT_VIDEO);

    // set the opengl context version
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

    // turn on double buffering set the depth buffer to 24 bits
    // you may need to change this to 16 or 32 for your system
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

    // create the sdl2 window
    sdl2_window = SDL_CreateWindow(PROGRAM_NAME, SDL_WINDOWPOS_CENTERED,
            SDL_WINDOWPOS_CENTERED, 512, 512,
            SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);

    // create the opengl3 context
    opengl3_context = SDL_GL_CreateContext(sdl2_window);
}

int main(int argc, char** argv)
{
    SDL_Window* sdl2_window = 0;
    SDL_GLContext opengl3_context;

    init_sdl(sdl2_window, opengl3_context);

    GLenum status = glewInit();
    if (status != GLEW_OK)
    {
        std::cerr << "GLEW Error: " << glewGetErrorString(status) << "\n";
        exit(1);
    }

    // sync buffer swap with monitor's vertical refresh rate
    SDL_GL_SetSwapInterval(1);

    // set background color
    glClearColor( 1.0, 0.0, 0.0, 1.0 );

    while (true)
    {
        int status = 0;

        glClear( GL_COLOR_BUFFER_BIT );

        SDL_GL_SwapWindow(sdl2_window);

        SDL_Event event;

        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
            case SDL_KEYDOWN:
                break;
            case SDL_KEYUP:
                // if escape is pressed, quit
                if (event.key.keysym.sym == SDLK_ESCAPE)
                    status = 1; // set status to 1 to exit main loop
                break;
            case SDL_QUIT:
                status = 1;
                break;
            }
        }

        if (status == 1) // if received instruction to quit
            break;
    }

    // delete opengl3 context, destroy sdl2 window, and shut down sdl subsystems
    SDL_GL_DeleteContext(opengl3_context);
    SDL_DestroyWindow(sdl2_window);
    SDL_Quit();

    return 0;
}
Thirza answered 11/12, 2012 at 18:22 Comment(1)
SSCCE time.Araujo
A
3
void init_sdl(SDL_Window* sdl2_window, SDL_GLContext& opengl3_context)

Your first argument should be a reference too. Otherwise when you get back to main() sdl2_window is still zero.

Araujo answered 11/12, 2012 at 18:50 Comment(5)
Thank you! So a pointer reference, eh? I didn't realize there was a difference between a pointer and a pointer reference.Thirza
No problem! This is why I like SSCCEs :)Araujo
@Defcronyke, when you send a variable (to a function) by value, you copy its content and the functions won't have any way to change that variable. If that variable happens to be a pointer, it's the same thing. You are passing the pointer "by-value" which means init_sdl has an address (which it can change where it points to), but can't change the original variable holding that address. That is why you need to send it by reference, so you can change the pointer itself.Alie
Thanks for the clarification Shahbaz. I had thought having the address to a piece of data was all you needed to write to the address, but if I understand what you're saying, a function being passed a pointer only has read access to the data found at that address.Thirza
What I just said doesn't seem right, it's explained very well here: markgodwin.blogspot.ca/2009/08/c-reference-to-pointer.html According to that blog post, when a pointer is passed to a function by value, you can modify the data found at the pointer's address, but you can't change the address it's pointing to, because you'd really only be changing the address that the local copy of the pointer is pointing to.Thirza
Z
0

Are you sure the context is no at fault:

int flags = SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_SHOWN;
win = SDL_CreateWindow("3Doodle", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1024, 768, flags);
SDL_assert(win != NULL);

context = SDL_GL_CreateContext(win);
SDL_assert(context != NULL);
Zach answered 11/1, 2014 at 0:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.