c++ - 类构造函数中的 OpenGL sigsegv 错误

标签 c++ opengl boost game-engine sdl-2

编辑* 我按照 much_a_chos 的建议重新排列了初始化列表,以便 Window 对象在 Game 对象之前初始化,确保首先初始化 glew。但是,这不起作用:

//Rearranged initialization list 
class TempCore
{
public:
    TempCore(Game* g) :
        win(new Window(800, 800, "EngineTry", false)), gamew(g) {}
    ~TempCore() { if(gamew) delete gamew; } 
...
};

下面是我在 Mesh 构造函数中更改的代码,当上面的代码不起作用时:

Mesh::Mesh( Vertex* vertices, unsigned int numVerts )
{
    m_drawCount = numVerts;

    glewExperimental = GL_TRUE;
    if(glewInit() != GLEW_OK){
        exit(-150);   //application stops and exits here with the code -150
    }

    glGenVertexArrays(1, &m_vertexArrayObject);
    glBindVertexArray(m_vertexArrayObject);

   ...
}

当我编译和运行时发生的事情令人惊讶。 程序在我从 Window 构造函数复制的 if(glewInit() != GLEW_OK) 处退出。出于某种原因,glew 在 Window 构造函数(之前调用)中正确初始化Game 构造函数),但在 Mesh 构造函数中第二次调用时无法初始化。我认为在一个程序中多次调用 glewInit() 是不好的做法,但我认为如果我真的这样做了,它应该不会失败。有人知道会发生什么吗?我是否在多次调用 glewInit() 时犯了错误?

*编辑结束

我一直在关注 3D Game Engine Development tutorial我在我的代码中遇到了一个奇怪的错误,我将在下面进行演示。我试图纯粹出于教育原因制作自己的游戏引擎。我使用 Code-blocks 13.12 作为我的 IDE,使用 mingw-w64 v4.0 作为我的编译器。我还使用 SDL2、glew、Assimp 和 boost 作为我的第三方库。

对于大量的代码摘录,我提前表示歉意,但我输入了我认为理解错误上下文所必需的内容。

我的游戏引擎有一个 Core 类,它包含主循环并相应地更新和渲染,调用 Gameupdate()render() 方法。 Game 类旨在作为游戏中所有 Assets 的持有者,并将成为使用该引擎制作的任何游戏的基类,因此,它包含网格、纹理和相机引用。 Game 类 update()render()input() 方法都是虚拟的,因为 Game 类意味着派生。

我的问题是:当我在 Core 类中初始化 Game 成员变量时,我在 Mesh 对象的构造函数中得到一个 SIGSEGV(即段错误)glGenVertexArrays 调用。 但是,当我将 Game 对象移出 Core 类并直接进入 main 方法时(因此我将它从类成员更改为main 方法),以及来自 Core 类的必要部分,然后它完美运行并呈现我的基本三角形示例。这是一个我从未遇到过的错误,我将非常感谢我能得到的任何帮助。

下面是我完美运行并呈现三角形的变形代码的摘录:

int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
    Window win(800, 800, "EngineTry", false); //Creates an SDL implemented window with a GL_context
    Game* gamew = new Game;
    const double frameTime = 1.0 / 500;  //500 = maximum fps

    double lastTime = FTime::getTime();  //gets current time in milliseconds
    double unprocessedTime = 0.0;
    int frames = 0;
    double frameCounter = 0;

    while(win.isRunning()){
        bool _render = false;

        double startTime = FTime::getTime();
        double passedTime = startTime - lastTime;
        lastTime = startTime;

        unprocessedTime += passedTime / (double)FTime::SECOND;
        frameCounter += passedTime;

        while(unprocessedTime > frameTime){
            if(!win.isRunning())
                exit(0);
            _render = true;

            unprocessedTime -= frameTime;
            FTime::delta = frameTime;

            gamew->input();
            Input::update();
            gamew->update();

            if(frameCounter >= FTime::SECOND)
            {
                std::cout << "FPS: " << frames << std::endl;
                frames = 0;
                frameCounter = 0;
            }
        }

        if(_render){
            RenderUtil::clearScreen(); //simple wrapper to the glClear function
            gamew->render();
            win.Update();
            frames++;
        }else{
            Sleep(1);
        }
    }

    delete gamew;
    return 0;
}

这是我修改后的 Core 类的摘录,它不起作用(在 Mesh 构造函数中抛出 sigsegv)

class TempCore
{
public:
    TempCore(Game* g) :
        gamew(g), win(800, 800, "EngineTry", false) {}
    ~TempCore() { if(gamew) delete gamew; }

    void start();

private:
    Window win;
    Game* gamew;
};


int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
    TempCore m_core(new Game());
    m_core.start();

    return 0;
}


void TempCore::start()
{
    const double frameTime = 1.0 / 500;

    double lastTime = FTime::getTime();
    double unprocessedTime = 0.0;
    int frames = 0;
    double frameCounter = 0;

    while(win.isRunning()){
        bool _render = false;

        double startTime = FTime::getTime();
        double passedTime = startTime - lastTime;
        lastTime = startTime;

        unprocessedTime += passedTime / (double)FTime::SECOND;
        frameCounter += passedTime;

        while(unprocessedTime > frameTime){
            if(!win.isRunning())
                exit(0);
            _render = true;

            unprocessedTime -= frameTime;
            FTime::delta = frameTime;

            gamew->input();
            Input::update();
            gamew->update();

            if(frameCounter >= FTime::SECOND){
                //double totalTime = ((1000.0 * frameCounter)/((double)frames));
                //double totalMeasuredTime = 0.0;

                std::cout << "Frames: " << frames << std::endl;
                //m_frames_per_second = frames;
                frames = 0;
                frameCounter = 0;
            }
        }

        if(_render){
            RenderUtil::clearScreen();
            gamew->render();
            win.Update();
            frames++;
        }else{
            Sleep(1);
        }
    }
}

上述TestCore实现中出现sigsegv的Mesh构造函数:

Mesh::Mesh( Vertex* vertices, unsigned int numVerts )
{
    m_drawCount = numVerts;

    glGenVertexArrays(1, &m_vertexArrayObject); //sigsegv occurs here
    glBindVertexArray(m_vertexArrayObject);

        std::vector<glm::vec3> positions;
        std::vector<glm::vec2> texCoords;
        positions.reserve(numVerts);
        texCoords.reserve(numVerts);

        for(unsigned i = 0; i < numVerts; i++){
            positions.push_back(vertices[i].pos);
            texCoords.push_back(vertices[i].texCoord);
        }

        glGenBuffers(NUM_BUFFERS, m_vertexArrayBuffers);
        glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[POSITION_VB]); 
        glBufferData(GL_ARRAY_BUFFER, numVerts*sizeof(positions[0]), &positions[0], GL_STATIC_DRAW); 

        glEnableVertexAttribArray(0); 
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);


        glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[TEXCOORD_VB]); 
        glBufferData(GL_ARRAY_BUFFER, numVerts*sizeof(texCoords[0]), &texCoords[0], GL_STATIC_DRAW);

        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);

    glBindVertexArray(0);
}

初始化Mesh对象的Game构造函数:

Vertex vertices[] = {   Vertex(-0.5f, -0.5f, 0, 0, 0),
                        Vertex(0, 0.5f, 0, 0.5f, 1.0f),
                        Vertex(0.5f, -0.5f, 0, 1.0f, 0)};
//Vertex is basically a struct with a glm::vec3 for position and a glm::vec2 for texture coordinate

Game::Game() :
    m_mesh(vertices, sizeof(vertices)/sizeof(vertices[0])),
    m_shader("res\\shaders\\basic_shader"),
    m_texture("res\\textures\\mist_tree.jpg")
{
}

初始化glewWindow类构造函数:

Window::Window(int width, int height, const std::string& title, bool full_screen) :
    m_fullscreen(full_screen)
{
    SDL_Init(SDL_INIT_EVERYTHING);

        SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    //SDL_Window* in private of class declaration 
    m_window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    //SDL_GLContext in private of class declaration 
    m_glContext = SDL_GL_CreateContext(m_window);

    std::cout << "GL Version: " << glGetString(GL_VERSION) << std::endl;
    glewExperimental = GL_TRUE;
    if(glewInit() != GLEW_OK || !glVersionAbove(3.0)){
        std::cerr << "Glew failed to initialize...\n";
        exit(-150);
    }
}

最佳答案

这里不太可能,因为给定的信息量非常大。我搜索了类似的问题,例如 this onethis one ,但他们中的每一个都已经用你在 Window 类构造函数中所做的技巧来回答,必须在你的游戏构造函数之前调用。正如我在您的 TempCore 构造函数中看到的那样,您构建游戏对象(并调用 glGenVertexArrays)构建 Window 对象之前

...

TempCore(Game* g) :
    gamew(g), win(800, 800, "EngineTry", false) {}

...

因此,在使用 SDL_GL_CreateContext(m_window) 调用创建 OpenGL 上下文之前和 glewExperimental = GL_TRUE; 之前glewInit();。然后你说按这个顺序放到main里就解决了问题...

...
Window win(800, 800, "EngineTry", false); //Creates an SDL implemented window with a GL_context
Game* gamew = new Game;
...

也许像这样在构造函数中重新排序初始化列表可以解决您的问题?

class TempCore
{
public:
    TempCore(Game* g) :
        win(800, 800, "EngineTry", false), gamew(g) {}
    ~TempCore() { if(gamew) delete gamew; }

...
};

更新

我错了,如评论中所述,初始化列表顺序无关紧要。重要的是定义顺序,这里是正确的...

关于c++ - 类构造函数中的 OpenGL sigsegv 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36184231/

相关文章:

c++ - 存储只读数据混合程序集和 C++

c++ - 为什么 C++ 容器不实现接口(interface)

c# - 无法从 VS 2010 SP1 中的 C# 访问 C++ 类/命名空间

opengl - 将 HD 3000 与 OpenGL 结合使用?

c++ - 如何继承类型列表,然后调用继承成员列表中的成员?

c++ - 使用 operator== 时 std::set 中 unique_ptr 的深度比较

c++ - OpenGL ping pong 一次通过,而不是两次

c++ - 如何使用gl_polygon绘制3d圆柱体

c++ - 启用_if : case of templated method of a template base inherited several times

c++ - 如何像普通 C 函数一样使用正确的 'this' 指针调用 C++ 类成员函数? (指向类成员函数的指针)