2016-05-09 8 views
1

Mein Computer läuft Ubuntu 16.04 mit einer Intel-Grafikkarte. Ich verwende Mesa 11.2 für mein OpenGL-Profil.OpenGL: Umschalten Polygon-Modus verursacht segfault

Mein bescheidenes OpenGL-Programm zeigt ein einfaches Quadrat in einem Fenster an. Ich wollte die Programmumschaltung in und aus Drahtgitter-Modus machen, wenn ich eine bestimmte Taste gedrückt, so definierte ich die folgende Callback-Funktion:

void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mode) { 
    if (key == GLFW_KEY_ESCAPE and action == GLFW_PRESS) { 
     glfwSetWindowShouldClose(window, GL_TRUE); 
    } 
    if (key == GLFW_KEY_M and action == GLFW_PRESS) { 
     // Find the rasterizing mode. 
     GLint rastMode; 
     glGetIntegerv(GL_POLYGON_MODE, &rastMode); 

     // Switch modes depending on current rasterizing mode. 
     if (rastMode == GL_FILL) { 
      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 
     } 
     else { 
      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 
     } 
    } 
} 

Leider drückte m, während mein Programm wird dazu führen, läuft einen segfault. Seltsamerweise, auf meinem anderen Computer (Ubuntu 16.04 aber mit einer Nvidia GPU laufen) habe ich kein solches Problem und das Programm funktioniert wie erwartet.

Das Problem ist nicht mit glPolygonMode: Ich kann das innerhalb meiner main Funktion platzieren und das Programm wird erfolgreich Modi wechseln. Die Probleme scheinen mit glGetIntegerv zu liegen. Wenn ich diese Funktion innerhalb meiner main Funktion (sagen wir, direkt vor der Spielschleife) anrufe, wird mein Quadrat nicht erscheinen (obwohl es keinen segfault gibt).

Hier ist der komplette Code:

#include <array> 
#include <fstream> 
#include <iostream> 
#include <sstream> 
#include <string> 
#include <GL/glew.h> 
#include <GLFW/glfw3.h> 

// Vertex and fragment shader source files. 
constexpr char VERTEX_SHADER_SOURCE_FILE[] = "simple_vertex.shader"; 
constexpr char FRAGMENT_SHADER_SOURCE_FILE[] = "simple_fragment.shader"; 

// Window properties. 
constexpr int WINDOW_WIDTH = 800; 
constexpr int WINDOW_HEIGHT = 800; 
constexpr char WINDOW_TITLE[] = "Triangle"; 

// Background colour. 
constexpr std::array<GLfloat, 4> bgColour { 0.3f, 0.1f, 0.3f, 1.0f }; 

/* 
* Instructs GLFW to close window if escape key is pressed and to toggle between rasterizing modes 
* if m is pressed. 
*/ 
void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mode); 

int main() { 
    // Initialize GLFW. 
    if (not glfwInit()) { 
     std::cerr << "ERROR: Failed to start GLFW.\n"; 
     return 1; 
    } 

    // Set required OpenGL version. 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 

    // Create a window object and bind it to the current context. 
    GLFWwindow *window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE, nullptr, 
              nullptr); 
    if (not window) { 
     std::cerr << "ERROR: Failed to create GLFW window.\n"; 
     glfwTerminate(); 
     return 1; 
    } 
    glfwMakeContextCurrent(window); 

    // Set callback functions. 
    glfwSetKeyCallback(window, keyCallback); 

    // Initialize GLEW with experimental features enabled. 
    glewExperimental = GL_TRUE; 
    if (glewInit() != GLEW_OK) { 
     std::cerr << "ERROR: Failed to start GLEW.\n"; 
     glfwTerminate(); 
     return 1; 
    } 

    // Display information on the current GL connection. 
    std::cout << "Renderer: " << glGetString(GL_RENDERER) << std::endl; 
    std::cout << "Version: " << glGetString(GL_VERSION) << std::endl; 
    std::cout << "Shading Language: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; 

    // Define the viewport dimensions. 
    int width, height; 
    glfwGetFramebufferSize(window, &width, &height); 
    glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height)); 

    // Create a vertex shader object. 
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); 

    // Load the vertex shader source code. 
    std::string vertexShaderSource; 
    std::ifstream vsfs(VERTEX_SHADER_SOURCE_FILE); 
    if (vsfs.is_open()) { 
     std::stringstream ss; 
     ss << vsfs.rdbuf(); 
     vertexShaderSource = ss.str(); 
    } 
    else { 
     std::cerr << "ERROR: File " << VERTEX_SHADER_SOURCE_FILE << " could not be found.\n"; 
     glfwTerminate(); 
     return 1; 
    } 

    // Attach the shader source code to the vertex shader object and compile. 
    const char *vertexShaderSource_cstr = vertexShaderSource.c_str(); 
    glShaderSource(vertexShader, 1, &vertexShaderSource_cstr, nullptr); 
    glCompileShader(vertexShader); 

    // Check if compilation was successful. 
    GLint success; 
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); 
    if (not success) { 
     std::cerr << "ERROR: Vertex shader compilation failed.\n"; 
     glfwTerminate(); 
     return 1; 
    } 

    // Create a fragment shader object. 
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 

    // Load the fragment shader source code. 
    std::string fragmentShaderSource; 
    std::ifstream fsfs(FRAGMENT_SHADER_SOURCE_FILE); 
    if (fsfs.is_open()) { 
     std::stringstream ss; 
     ss << fsfs.rdbuf(); 
     fragmentShaderSource = ss.str(); 
    } 
    else { 
     std::cerr << "ERROR: File " << FRAGMENT_SHADER_SOURCE_FILE << " could not be found.\n"; 
     glfwTerminate(); 
     return 1; 
    } 

    // Attach the shader source code to the fragment shader object and compile. 
    const char *fragmentShaderSource_cstr = fragmentShaderSource.c_str(); 
    glShaderSource(fragmentShader, 1, &fragmentShaderSource_cstr, nullptr); 
    glCompileShader(fragmentShader); 

    // Check if compilation was successful. 
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); 
    if (not success) { 
     std::cerr << "ERROR: Fragment shader compilation failed.\n"; 
     glfwTerminate(); 
     return 1; 
    } 

    // Link the vertex and fragment shaders into a shader program. 
    GLuint shaderProgram = glCreateProgram(); 
    glAttachShader(shaderProgram, vertexShader); 
    glAttachShader(shaderProgram, fragmentShader); 
    glLinkProgram(shaderProgram); 

    // Check that shader program was successfully linked. 
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); 
    if (not success) { 
     std::cerr << "ERROR: Shader program linking failed.\n"; 
     glfwTerminate(); 
     return 1; 
    } 

    // Delete shader objects. 
    glDeleteShader(vertexShader); 
    glDeleteShader(fragmentShader); 

    // Coordinates of square's vertices. 
    std::array<GLfloat, 12> vertices { 
     0.5f, 0.5f, 0.0f, 
     0.5f, -0.5f, 0.0f, 
     -0.5f, -0.5f, 0.0f, 
     -0.5f, 0.5f, 0.0f 
    }; 

    // Indices to draw. 
    std::array<GLuint, 6> indices { 
     0, 1, 3, 
     1, 2, 3 
    }; 

    // Create a vertex array object. 
    GLuint vao; 
    glGenVertexArrays(1, &vao); 
    glBindVertexArray(vao); 

    // Create a vertex buffer object. 
    GLuint vbo; 
    glGenBuffers(1, &vbo); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo); 

    // Create an element buffer object. 
    GLuint ebo; 
    glGenBuffers(1, &ebo); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 

    // Pass vertex data into currently bound vertex buffer object. 
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(), GL_STATIC_DRAW); 

    // Pass index data into currently bound element buffer object. 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices.data(), GL_STATIC_DRAW); 

    // Create and enable a vertex attribute. 
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), static_cast<GLvoid*>(0)); 
    glEnableVertexAttribArray(0); 

    // It is good practice to unbind the vertex array object, vertex buffer object, and element 
    // buffer object. 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
    glBindVertexArray(0); 

    // Set background colour. 
    glClearColor(bgColour[0], bgColour[1], bgColour[2], bgColour[3]); 

    // Main loop. 
    while (not glfwWindowShouldClose(window)) { 
     // Clear the screen of colours and poll for events. 
     glClear(GL_COLOR_BUFFER_BIT); 
     glfwPollEvents(); 

     // Inform OpenGL to use the shader program created above. 
     glUseProgram(shaderProgram); 

     // Bind the vertex array object and element buffer object. 
     glBindVertexArray(vao); 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 

     // Draw the triangle using glDrawElements. The first argument gives the OpenGL primitive to 
     // render, the second argument gives the number of vertices to draw, the third gives type 
     // used to represent an index, and finally the last argument gives a possible offset in the 
     // EBO. 
     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, static_cast<GLvoid*>(0)); 

     // Unbind the vertex array object (good practice). 
     glBindVertexArray(0); 

     // Swap buffers. 
     glfwSwapBuffers(window); 
    } 

    // Clean up. 
    glDeleteVertexArrays(1, &vao); 
    glDeleteBuffers(1, &vbo); 
    glDeleteProgram(shaderProgram); 
    glfwDestroyWindow(window); 
    glfwTerminate(); 
    return 0; 
} 

void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mode) { 
    if (key == GLFW_KEY_ESCAPE and action == GLFW_PRESS) { 
     glfwSetWindowShouldClose(window, GL_TRUE); 
    } 
    if (key == GLFW_KEY_M and action == GLFW_PRESS) { 
     // Find the rasterizing mode. 
     GLint rastMode; 
     glGetIntegerv(GL_POLYGON_MODE, &rastMode); 

     // Switch modes depending on current rasterizing mode. 
     if (rastMode == GL_FILL) { 
      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 
     } 
     else { 
      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 
     } 
    } 
} 
+3

Während die Dokumentation das nicht sagt. Es kann ratsam sein, einen Zeiger an einen größeren Speicherplatz zu übergeben, sagen wir GLint [2] für GL_FRONT und für GL_BACK. – mrVoid

+0

Die Dokumentation * sagt * Folgendes: "* params * gibt zwei Werte zurück: symbolische Konstanten, die angeben, ob nach vorn und nach hinten gerichtete Polygone als Punkte, Linien oder gefüllte Polygone gerastert werden". – Wyzard

+0

@mrVoid Ihr Vorschlag hat funktioniert. Wenn Sie es als Antwort aufschreiben, akzeptiere ich es. –

Antwort

2

Dokumentation heißt es:

params liefert zwei Werte: symbolische Konstanten angibt, ob nach vorn gerichtete und hinten gerichtete Polygone als Punkte gerastert werden, Linien oder gefüllte Vielecke

Wrapping @Wyzard und meine Kommentare: glGetIntegerv(GL_POLYGON_MODE, &rastMode); benötigt zwei Ganzzahlen von Speicher, auf die geschrieben werden soll. Der Segfault war aufgrund des Schreibens nach rastMode int

Die Lösung besteht darin, einen Puffer aus zwei ganzen Zahlen zu übergeben.

Verwandte Themen