質問

For anyone who has seen my previous questions, after working through the RedBook for Version 2.1, I am now moving on to Version 4.3. (Hoary you say, since many of you have been telling me to do this for ages.)

So, I am deep into Chapter 3, but still haven't got Chapter 1 's example program working.

I have two problems. (Actually 3.) Firstly, it doesn't compile. Okay so that's a problem, but kind of irrelevant considering the next two. Secondly, I don't exactly understand how it works or what it is trying to do, but we will get onto that.

Thirdly, it seems to me that the author of this code is a complete magician. I would suggest all sorts of tinkery-hackery are occurring here. This is most likely to be because of Problem Number 2, the fact that I don't understand what it is trying to do. The guys who wrote this book are, of course, not idiots, but bear with me, I will give an example.

Here is a section of code taken from the top of the main.cpp file. I will include the rest of the file later on, but for now:

enum VAO_IDs {
    Triangles,
    NumVAOs
};

If I understand correctly, this gives VAO_IDs::Triangles the value of 1, since enum's are zero based. (I hope I am correct here, or it will be embarrassing for me.)

A short while later, you can see this line:

GLuint VAOs[NumVAOs];

Which declares an array of GLuint's, containing 1 GLuint's due to the fact that NumVAOs is equal to 1. Now, firstly, shouldn't it be VAO_IDs::NumVAOs?

And secondly, why on earth has an enum been used in this way? I would never use an enum like that for obvious reasons - cannot have more than one data with the same value, values are not explicitly specified etc...

Am I barking up the right tree here? It just doesn't make sense to do this... VAOs should have been a global, like this, surely? GLuint NumVAOs = 1; This is just abusive to the enum!

In fact, below the statement const GLuint NumVertices = 6; appears. This makes sense, doesn't it, because we can change the value 6 if we wanted to, but we cannot change NumVAOs to 0 for example, because Triangles is already set to 0. (Why is it in an enum? Seriously?)

Anyway, forget the enum's... For now... Okay so I made a big deal out of that and that's the end of the problems... Any further comments I have are in the code now. You can ignore most of the glfw stuff, its essentially the same as glut.

// ----------------------------------------------------------------------------
//
// Triangles - First OpenGL 4.3 Program
//
// ----------------------------------------------------------------------------

#include <cstdlib>
#include <cstdint>
#include <cmath>

#include <stdio.h>
#include <iostream>

//#include <GL/gl.h>
//#include <GL/glu.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>


/// OpenGL specific
#include "vgl.h"
#include "LoadShaders.h" // These are essentially empty files with some background work going on, nothing declared or defined which is relevant here

enum VAO_IDs {
    Triangles,
    NumVAOs
};
// So Triangles = 0, NumVAOs = 1
// WHY DO THIS?!

enum Buffer_IDs {
    ArrayBuffer,
    NumBuffers
};

enum Attrib_IDs {
    vPosition = 0
}
// Please, please, please someone explain the enum thing to me, why are they using them instead of global -just- variables.
// (Yeah an enum is a variable, okay, but you know what I mean.)

GLuint VAOs[NumVAOs]; // Compile error: expected initializer before 'VAOs'
GLuint Buffers[NumBuffers]; // NumBuffers is hidden in an enum again, so it NumVAOs

const GLuint NumVertices = 6; // Why do something different here?

// ----------------------------------------------------------------------------
//
// Init
//
// ----------------------------------------------------------------------------

void init()
{
    glGenVertexArrays(NumVAOs, VAOs); // Error: VAOs was not declared in this scope
    glBindVertexArray(VAOs[Triangles]);

    GLfloat vertices[NumVertices][2] = {
        { -0.90, -0.90 },
        { +0.85, -0.90 },
        { -0.90, +0.85 },
        { +0.90, -0.85 },
        { +0.90, +0.90 },
        { -0.85, +0.90 }
    };

    glGenBuffers(NumBuffers, Buffers);
    glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    ShaderInfo shaders[] = {
        { GL_VERTEX_SHADER, "triangles.vert" },
        { GL_FRAGMENT_SHADER, "triangles.frag" },
        { GL_NONE, nullptr }
    };

    GLuint program = LoadShaders(shaders);
    glUseProgram(program);

    glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    glEnableVertexAttribArray(vPosition);
}

// ----------------------------------------------------------------------------
//
// Display
//
// ----------------------------------------------------------------------------

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);

    glBindVertexArray(VAOs[Triangles]);
    glDrawArrays(GL_TRIANGLES, 0, NumVertices); // Error VAOs not declared

    glFlush();
}

// ----------------------------------------------------------------------------
//
// Main
//
// ----------------------------------------------------------------------------

void error_handle(int error, const char* description)
{
    fputs(description, stderr);
}

void key_handle(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);

}


void handle_exit()
{

}


int main(int argc, char **argv)
{

    // Setup exit function
    atexit(handle_exit);


    // GLFW Window Pointer
    GLFWwindow* window;


    // Setup error callback
    glfwSetErrorCallback(error_handle);


    // Init
    if(!glfwInit())
    {
        exit(EXIT_FAILURE);
    }


    // Setup OpenGL
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);


    // Set GLFW window hints
    glfwWindowHint(GLFW_DEPTH_BITS, 32);
    glfwWindowHint(GLFW_RED_BITS, 8);
    glfwWindowHint(GLFW_GREEN_BITS, 8);
    glfwWindowHint(GLFW_BLUE_BITS, 8);
    glfwWindowHint(GLFW_ALPHA_BITS, 8);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 1);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);


    // Init GLEW
    if(glewInit())
    {
        printf("GLEW init failure!\n", stderr);
        exit(EXIT_FAILURE);
    }


    // Init OpenGL
    init();


    // Create Window
    window = glfwCreateWindow(800, 600, "Window Title", nullptr, nullptr);
    if(!window)
    {
        glfwTerminate();
        return EXIT_FAILURE;
    }

    // Make current
    glfwMakeContextCurrent(window);


    // Set key callback
    glfwSetKeyCallback(window, key_handle);


    // Check OpenGL Version
    char* version;
    version = (char*)glGetString(GL_VERSION);
    printf("OpenGL Application Running, Version: %s\n", version);


    // Enter main loop
    while(!glfwWindowShouldClose(window))
    {
        // Event polling
        glfwPollEvents();

        // OpenGL Rendering

        // Setup OpenGL viewport and clear screen
        float ratio;
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);
        ratio = width / height;

        glViewport(0, 0, width, height);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Setup projection
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45.0, ratio, 0.1, 10.0);

        // Render
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        // Swap Buffers
        glfwSwapBuffers(window);
    }


    // Free glfw memory allocated for window
    glfwDestroyWindow(window);


    // Exit
    glfwTerminate();
    exit(EXIT_SUCCESS);
}

A very verbose question I realize, but I thought it was important to explain why I think its crazy code rather than just saying "I don't get it" like it's easy to. Could someone please explain why these very clever people decided to do it this way and why there are errors. (I can find nothing about this online.)

役に立ちましたか?

解決

The author is using the automatic numbering property of enums to automatically update the definition for the NumVAOs and NumBuffers values. For example, when new VAO IDs are added to the enum the NumVAOs value will still be correct as long as it is listed last in the enum.

enum VAO_IDs {
    Triangles,
    Polygons,
    Circles,
    NumVAOs
};

Most likely your compiler does not support this trick.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top