调用OpenGL函数时程序崩溃

问题描述:

我正在尝试设置一个游戏引擎项目。我的视觉工作室项目的设置是为了让我的'引擎'项目与我的'游戏'项目分开。然后将引擎项目编译为一个dll供游戏项目使用。我已经下载并设置了glfw和glew开始使用openGL。我的问题是,当我打我的第一个openGL函数时,程序崩溃。我知道这与glewinit有关,即使glew成功初始化(没有控制台错误)。在我的发动机项目,我有一个窗口类,其中,在窗口建设,GLEW应设置:调用OpenGL函数时程序崩溃

在window.h

#pragma once 
#include "GL\glew.h" 
#include "GLFW\glfw3.h" 

#if (_DEBUG) 
#define LOG(x) printf(x) 
#else 
#define LOG(x) 
#endif 

namespace BlazeGraphics 
{ 

    class __declspec(dllexport) Window 
    { 
    public: 
     Window(short width, short height, const char* title); 
     ~Window(); 

     void Update(); 
     void Clear() const; 
     bool Closed() const; 

    private: 
     int m_height; 
     int m_width; 
     const char* m_title; 
     GLFWwindow* m_window; 

    private: 
     Window(const Window& copy) {} 
     void operator=(const Window& copy) {} 
    }; 

} 

Window.cpp(其中glewinit()被调用)

#include "Window.h" 
#include <cstdio> 

namespace BlazeGraphics 
{ 

    //Needed to define outside of the window class (not sure exactly why yet) 
    void WindowResize(GLFWwindow* window, int width, int height); 

    Window::Window(short width, short height, const char* title) : 
     m_width(width), 
     m_height(height), 
     m_title(title) 
    { 
     //InitializeWindow 
     { 
      if (!glfwInit()) 
      { 
       LOG("Failed to initialize glfw!"); 
       return; 
      }; 

      m_window = glfwCreateWindow(m_width, m_height, m_title, NULL, NULL); 
      if (!m_window) 
      { 
       LOG("Failed to initialize glfw window!"); 
       glfwTerminate(); 
       return; 
      }; 

      glfwMakeContextCurrent(m_window); 
      glfwSetWindowSizeCallback(m_window, WindowResize); 
     } 

     //IntializeGl 
     { 
      //This needs to be after two functions above (makecontextcurrent and setwindowresizecallback) or else glew will not initialize 
      **if (glewInit() != GLEW_OK) 
      { 
       LOG("Failed to initialize glew!"); 
      }** 
     } 
    } 


    Window::~Window() 
    { 
     glfwTerminate(); 
    } 

    void Window::Update() 
    { 
     glfwPollEvents(); 
     glfwSwapBuffers(m_window); 
    } 

    void Window::Clear() const 
    { 
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    } 

    //Returns a bool because glfwwindowShouldClose returns a nonzero number or zero 
    bool Window::Closed() const 
    { 
     //Made it equal to 1 to take away warning involving converting an int to bool 
     return glfwWindowShouldClose(m_window) == 1; 
    } 

    //Not part of window class so defined above 
    void WindowResize(GLFWwindow* window, int width, int height) 
    { 
     glViewport(0, 0, width, height); 
    } 

} 

这是这是我的游戏项目,我现在有我的OpenGL功能在全局函数(只是现在)内发现了我的main.cpp文件:

的main.cpp

#include <iostream> 
#include <array> 
#include <fstream> 
#include "GL\glew.h" 
#include "GLFW\glfw3.h" 
#include "../Engine/Source/Graphics/Window.h" 

void initializeGLBuffers() 
{ 
    GLfloat triangle[] = 
    { 
     +0.0f, +0.1f, -0.0f, 
     0.0f, 1.0f, 0.0f, 

     -0.1f, -0.1f, 0.0f, //1 
     0.0f, 1.0f, 0.0f, 

     +0.1f, -0.1f, 0.0f, //2 
     0.0f, 1.0f, 0.0f, 
    }; 

    GLuint bufferID; 
    glGenBuffers(1, &bufferID); 
    glBindBuffer(GL_ARRAY_BUFFER, bufferID); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle), triangle, GL_STATIC_DRAW); 
    glEnableVertexAttribArray(0); 
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, (sizeof(GLfloat)) * 6, nullptr); 
    glEnableVertexAttribArray(1); 
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, (sizeof(GLfloat)) * 6, (char*)((sizeof(GLfloat)) * 3)); 

    GLushort indices[] = 
    { 
     0,1,2 
    }; 

    GLuint indexBufferID; 
    glGenBuffers(1, &indexBufferID); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); 
}; 


void installShaders() 
{ 
    //Create Shader 
    GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER); 
    GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); 

    //Add source or text file to shader object 
    std::string temp = readShaderCode("VertexShaderCode.glsl"); 
    const GLchar* adapter[1]; 

    adapter[0] = temp.c_str(); 
    glShaderSource(vertexShaderID, 1, adapter, 0); 
    temp = readShaderCode("FragmentShaderCode.glsl").c_str(); 
    adapter[0] = temp.c_str(); 
    glShaderSource(FragmentShaderID, 1, adapter, 0); 

    //Compile Shadaer 
    glCompileShader(vertexShaderID); 
    glCompileShader(FragmentShaderID); 

    if (!checkShaderStatus(vertexShaderID) || !checkShaderStatus(FragmentShaderID)) 
     return; 

    //Create Program 
    GLuint programID = glCreateProgram(); 
    glAttachShader(programID, vertexShaderID); 
    glAttachShader(programID, FragmentShaderID); 

    //Link Program 
    glLinkProgram(programID); 

    if (!checkProgramStatus(programID)) 
    { 
     std::cout << "Failed to link program"; 
     return; 
    } 

    //Use program 
    glUseProgram(programID); 
} 

int main() 
{ 

    BlazeGraphics::Window window(1280, 720, "MyGame"); 

    initializeGLBuffers(); 
    installShaders(); 

    while (!window.Closed()) 
    { 
     window.Clear(); 

     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0); 

     window.Update(); 
    }; 

    return 0; 
} 

现在,如果我是在我的main.cpp这里移动glewinit()代码:

int main() 
{ 

    BlazeGraphics::Window window(1280, 720, "MyGame"); 

    if (glewInit() != GLEW_OK) 
      { 
       LOG("Failed to initialize glew!"); 
      } 

    initializeGLBuffers(); 
    installShaders(); 

    while (!window.Closed()) 
    { 
     window.Clear(); 

     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0); 

     window.Update(); 
    }; 

    return 0; 
} 

然后我的程序编译罚款。为什么试图在engine.dll中初始化glew导致程序崩溃?谢谢你的帮助。

+0

桌面。我不小心添加了opengl-es标记,现在删除它 – Jason

+0

只有当你的OpenGL上下文已经创建时,你才可以调用'glewInit',否则你会碰壁...我没有看到任何OpenGL初始化...可能是隐藏的在BlazeGraphics :: Window窗口内(1280,720,“MyGame”);'。此外''glewInit'和所有OpenGL的东西应该从同一个线程调用... – Spektre

GLEW通过为每个OpenGL函数定义一个函数指针全局变量来工作。让我们来看看glBindBuffer为例:

#define GLEW_FUN_EXPORT GLEWAPI 

typedef void (GLAPIENTRY * PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); 
GLEW_FUN_EXPORT PFNGLBINDBUFFERPROC __glewBindBuffer; 

所以我们只是有一个__glewBindBuffer函数指针,这将是glewInit被设置为正确的地址,从你的OpenGL实现。

居然能写出glBindBuffer,GLEW简单地定义预处理器宏映射GL功能,这些函数指针变量:

#define glBindBuffer GLEW_GET_FUN(__glewBindBuffer); 

为什么试图内engine.dll导致程序崩溃GLEW初始化?

因为你的engine.dll和你的主应用程序每个都有一个单独的所有这些全局变量的集合。您必须从您的引擎DLL中导出所有__glew*变量,以便能够访问您在engine.dll中呼叫的glewInit呼叫的结果。

+0

谢谢你的一些澄清。确保导出游戏项目中使用的所有glew变量的最佳方法是什么?动态链接glew而不是静态链接到引擎中会有诀窍吗? – Jason

+2

@Jason:老实说:你可能不应该那样做,因为函数指针在上下文之间可能会有所不同。从技术上讲,每次切换上下文时都必须调用'glewInit'。正确的解决方案是拥有一个结构或类,它包含所有的函数指针,并通过它完成调用。然后你可以在DLL之间传递一个指向该结构的指针。 - 当然,大多数OpenGL加载程序的设计不允许它轻松地完成此操作。我建议你在每个需要它的模块中调用'glewInit'。 – datenwolf

+0

哇真的吗?这很有趣。我永远不会认为这是事实。感谢datenwolf的领导 – Jason