2016-11-05 184 views
0

我正在嘗試設置一個遊戲引擎項目。我的視覺工作室項目的設置是爲了讓我的'引擎'項目與我的'遊戲'項目分開。然後將引擎項目編譯爲一個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

回答

3

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