I am starting to learn OpenGL. So far I am doing alright, the only problem is that I don't know exactly which is the "best" way to organize the program. For example, a lot of tutorials construct all of the code sequentially on the main() function, which I don't think is very nice. Others will build functions like render(), init(), and call them on the main() function.
Right now I am trying to mix things, I built a class to wrap GLFW and GLEW libraries, and I call them on the main(). Also I have init() and render() functions. The problem I am getting into is that I have to declare (GLuint program) as a global variable, which is not advisable. This is the only way I can get the render function to use also the variable.
Here is the code:
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "GLWrapper.h"
#include "GLShader.h"
#include <iostream>
#include <ctime>
using namespace std;
GLuint program;
void renderer() {
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
float time = float(clock()) / float(CLOCKS_PER_SEC);
GLint uniColor = glGetUniformLocation(program, "triangleColor");
glUniform3f(uniColor, (sin(time * 4.0f) + 1.0f) / 2.0f, cos(time*2), 0.0f);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
void init() {
float vertices[] = {
0.0f, 0.5f, // Vertex 1 (X, Y)
0.5f, -0.5f, // Vertex 2 (X, Y)
-0.5f, -0.5f // Vertex 3 (X, Y)
};
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo;
glGenBuffers(1, &vbo); // Generate 1 buffer
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
program = LoadShader("Shader.vert", "Shader.frag");
glUseProgram(program);
}
int main() {
GLWrapper *glw = new GLWrapper(800, 600, "Ola Mundo!");
glw->setRenderer(renderer);
init();
GLint posAttrib = glGetAttribLocation(program, "position");
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(posAttrib);
glw->glMainLoop();
delete(glw);
return 0;
}
So, I want to know If there is a better way of organizing this code (building a class perhaps?), because since I will be building bigger and bigger codes, I want them to be as organized as possible.
Hope I made myself clear.
Related
This question already has an answer here:
Why is the sprite not rendering in OpenGL?
(1 answer)
Closed 2 years ago.
I'm trying to render a square using two triangles, and then applying some transformations, but for whatever reason it isn't showing up. Here is the code:
#include <iostream>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
#define WINDOW_TITLE "Modern OpenGL 3D Cube"
#ifndef GLSL
#define GLSL(Version, Source) "#version " #Version "\n" #Source
#endif
GLint shaderProgram, windowWidth = 800, windowHeight = 600;
GLuint VBO, VAO, EBO, texture;
void UResizeWindow(int, int);
void URenderGraphics(void);
void UCreateShader(void);
void UCreateBuffers(void);
const GLchar* vertexShaderSource = GLSL(330,
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 color;
out vec3 mobileColor;
uniform mat4 shaderTransform;
void main() {
gl_Position = shaderTransform * vec4(position, 1.0f);
mobileColor = color;
});
const GLchar* fragmentShaderSource = GLSL(330,
in vec3 mobileColor;
out vec4 gpuColor;
void main() {
gpuColor = vec4(mobileColor, 1.0);
});
//main program
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(windowWidth, windowHeight);
glutCreateWindow(WINDOW_TITLE);
glutReshapeFunc(UResizeWindow);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
cout << "Failed to initialize GLEW" << endl;
return -1;
}
UCreateShader();
UCreateBuffers();
glUseProgram(shaderProgram);
glClearColor(0, 0, 0, 1);
glutDisplayFunc(URenderGraphics);
glutMainLoop();
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
return 0;
}
void UResizeWindow(int w, int h) {
windowWidth = w;
windowHeight = h;
glViewport(0, 0, windowWidth, windowHeight);
}
void URenderGraphics(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(VAO);
glm::mat4 currentTransform;
currentTransform = glm::translate(currentTransform, glm::vec3(0.0f, 0.5f, 0.0f));
currentTransform = glm::rotate(currentTransform, 45.0f, glm::vec3(0.0f, 0.0f, 1.0f));
currentTransform = glm::scale(currentTransform, glm::vec3(0.5f, 0.5f, 0.5f));
GLuint transformLocation = glGetUniformLocation(shaderProgram, "shaderTransform");
glUniformMatrix4fv(transformLocation, 1, GL_FALSE, glm::value_ptr(currentTransform));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glutSwapBuffers();
}
void UCreateShader() {
GLint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
GLint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
void UCreateBuffers() {
GLfloat vertices[] = {
0.5f, 0.5f, 0.0f, 1, 0, 0, //top right vertex 0
0.5f, -0.5f, 0.0f, 0, 1, 0, //bottom right vertex 1
-0.5f, -0.5f, 0.0f, 0, 0, 1, //bottom left vertex 2
-0.5f, 0.5f, 0.0f, 1, 0, 1 //top left vertex 3
};
GLuint indices[] = {
0, 1, 3, //triangle 1
1, 2, 3 //triangle 2
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
}
It compiles and runs just fine, but it only opens a blank window. No graphics are shown on that window like it normally would. The output is supposed to look like a slightly rotated square rotated about its z-axis, but nothing appears at all. All help appreciated.
Some common things I check, when I get the infamous blank screen:
forgetting to call glUseProgram(shaderID) before you start passing uniforms (done)
pass the model matrix as an identity matrix.
double checking if the VBO/EBO are laid out in memory correctly (also, simplifying them during this step, ie. removing the color attribute, just pass position, and hard code the color in the fragment shader)
doing some error checking to see if there is a problem with the shader compilation using glGetShaderInfoLog and glGetProgramInfoLog.
The model matrix variable glm::mat4 currentTransform has to be initialized by the Identity matrix.
The OpenGL Mathematics (GLM) API documentation is based on OpenGL Shading Language (GLSL) and refers to The OpenGL Shading Language specification.
5.4.2 Vector and Matrix Constructors
[...] If there is a single scalar parameter to a matrix constructor, it is used to initialize all the components on the matrix's diagonal, with the remaining components initialized to 0.0.
An Identity matrix can be initialized by the single parameter 1.0:
glm::mat4 currentTransform;
glm::mat4 currentTransform(1.0f);
I'm trying to encapsulate OpenGL rendering in a renderer class.
I'm pretty sure my window class works fine (I've checked for errors) but I think the error is in my sprite class but I have no idea what it is.
This is my sprite class:
sprite_renderer.hpp
#ifndef SPRITE_RENDERER_H
#define SPRITE_RENDERER_H
#include <GL/glew.h>
#include "shader.hpp"
class SpriteRenderer
{
public:
SpriteRenderer(Shader &shader);
~SpriteRenderer();
void DrawSprite();
private:
Shader shader;
GLuint quadVAO;
void initRenderData();
};
#endif
sprite_renderer.cpp
#include "sprite_renderer.hpp"
SpriteRenderer::SpriteRenderer(Shader &shader)
{
this->shader = shader;
this->initRenderData();
}
SpriteRenderer::~SpriteRenderer()
{
glDeleteVertexArrays(1, &this->quadVAO);
}
void SpriteRenderer::DrawSprite()
{
this->shader.Use();
glBindVertexArray(this->quadVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
}
void SpriteRenderer::initRenderData()
{
GLuint VBO;
GLfloat vertices[] = {
// Pos
0.0f, 1.0f,
1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
};
glGenVertexArrays(1, &this->quadVAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(this->quadVAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
I'm using it like this in my main.cpp:
int main()
{
Window window = Window();
Shader shader = ResourceManager::LoadShader("./assets/shaders/sprite.vert", "./assets/shaders/sprite.frag", "sprite");
SpriteRenderer* renderer = new SpriteRenderer(shader);
while (window.IsOpen())
{
window.BeginDraw();
renderer->DrawSprite();
window.EndDraw();
}
glfwTerminate();
return 0;
}
Where window.BeginDraw() and window.EndDraw() are just:
void Window::BeginDraw()
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
void Window::EndDraw()
{
glfwSwapBuffers(window);
glfwPollEvents();
}
Just to rule out the obvious, try sticking a print statement in the destructor of your Shader class. Judging by the design of your Shader class, you should find it extremely easy to end up calling glDeleteProgram prior to actually using the shader.
In general, if you have a wrapper around a GLSL shader or program, you probably want to delete the copy constructor and assignment operator (or implement a ref counting system).
\edit to delete the copy ctor & assignment operator....
Shader(const Shader&) = delete;
Shader& operator = (const Shader&) = delete;
You probably want to manage these shaders somewhere (possibly ref counted), and only store pointers to them within your SpriteRenderer.
I can't see any other problem with the code you've posted above, so the issue may be within your shader, or how you are passing any uniform variables you're using.
I have been fiddling around with making a game/rendering engine, and I have found that I can have a class for a shader object, but if I wrap a VAO in a class, it won't render.
The shaders return no errors, and the VAO and shaders are valid OpenGL objects.
UPDATE
The problem is this line:
glBufferData(GL_ARRAY_BUFFER, sizeof(arrFVertex), arrFVertex, GL_STATIC_DRAW);
As #BDL suggested in the comments, I thought about it and I realized, it should be:
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * intNumVertex * 3, arrFVertex, GL_STATIC_DRAW);
UPDATE 2
In response to being put on hold, here is a Minimum Complete and Verifiable Example:
#include <OpenGL/gl3.h>
#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
SDL_Window *window = NULL;
SDL_GLContext openGLRenderer;
bool bolRunning = true;
int intGLVersionMajor, intGLVersionMinor;
GLfloat arrFVertex[] = {
0.5f, 0.5f, 0.0f, // Top Right
0.5f, -0.5f, 0.0f, // Bottom Right
-0.5f, 0.5f, 0.0f, // Top Left
0.5f, -0.5f, 0.0f, // Bottom Right
-0.5f, -0.5f, 0.0f, // Bottom Left
-0.5f, 0.5f, 0.0f // Top Left
};
GLuint intVAO;
GLuint intVBO;
GLuint intShaderAttribPosition;
GLuint intShaderProgram;
GLuint intNumVertex = 6;
void loadShaders(const char *strVertexShaderSource, const char *strFragmentShaderSource) {
intShaderProgram = glCreateProgram();
GLuint intVertexShader;
intVertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(intVertexShader, 1, &strVertexShaderSource, NULL);
glCompileShader(intVertexShader);
GLuint intFragmentShader;
intFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(intFragmentShader, 1, &strFragmentShaderSource, NULL);
glCompileShader(intFragmentShader);
glAttachShader(intShaderProgram, intVertexShader);
glAttachShader(intShaderProgram, intFragmentShader);
glLinkProgram(intShaderProgram);
glDeleteShader(intVertexShader);
glDeleteShader(intFragmentShader);
}
void buildVAO(GLfloat *arrFVertex) {
intShaderAttribPosition = glGetAttribLocation(intShaderProgram, "f3Position");
glGenVertexArrays(1, &intVAO);
glBindVertexArray(intVAO);
glGenBuffers(1, &intVBO);
glBindBuffer(GL_ARRAY_BUFFER, intVBO);
glVertexAttribPointer(intShaderAttribPosition, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid *)0);
glEnableVertexAttribArray(intShaderAttribPosition);
glBufferData(GL_ARRAY_BUFFER, sizeof(arrFVertex), arrFVertex, GL_STATIC_DRAW);
glBindVertexArray(0);
}
int main(int argc, char **argv) {
SDL_Init(SDL_INIT_EVERYTHING);
window = SDL_CreateWindow("GSEngine",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
640, 480,
SDL_WINDOW_OPENGL);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
if (window == NULL) {
printf("Could not create window: %s\n", SDL_GetError());
exit(1);
}
openGLRenderer = SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, openGLRenderer);
glViewport(0, 0, 640, 480);
loadShaders("#version 330 core\n\
in vec3 f3Position;\n\
void main() {\n\
gl_Position = vec4(f3Position, 1.0);\n\
}", "#version 330 core\n\
out vec4 f4Color;\n\
void main() {\n\
f4Color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n\
}");
buildVAO(arrFVertex);
while (bolRunning) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
bolRunning = false;
}
}
SDL_GL_MakeCurrent(window, openGLRenderer);
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(intShaderProgram);
glDrawArrays(GL_TRIANGLES, 0, intNumVertex);
SDL_GL_SwapWindow(window);
}
glDeleteBuffers(1, &intVBO);
glDeleteVertexArrays(1, &intVAO);
glDeleteShader(intShaderProgram);
SDL_GL_DeleteContext(openGLRenderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
The problem has nothing to do with the VAO, but with the VBO. Since you pass a pointer to the constructor:
void GSMesh::build(GLfloat *arrFVertex, GSShader *shader, int _intNumVertex)
{
glBufferData(GL_ARRAY_BUFFER, sizeof(arrFVertex), arrFVertex, GL_STATIC_DRAW);
}
sizeof(arrFVertex) = sizeof(GLfloat*) which is the size of the pointer, not the size of the array pointed to. The correct code will look like this:
glBufferData(GL_ARRAY_BUFFER,
sizeof(GLfloat) * _intNumVertex * 3, arrFVertex,
GL_STATIC_DRAW);
In general I have to add, that this is not the way how questions should be asked on SO. It would have been good if you would have included at least the relevant parts of the code in your question.
Despite what the spec says, with some drivers you must enable the shader before you can get the location of an attribute or uniform. This may be what is causing your problems.
In your code that would mean in your GSMesh::build method adding:
shader->use();
Before:
intShaderAttribPosition = glGetAttribLocation(shader->intShaderProgram, "f3Position");
Personally if the version of OpenGL that you are using has support for Vertex Attribute Indexes I'd use them instead.
In the vertex shader you could have something like:
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 tex_coords;
And then in your mesh class all you need is:
struct Vertex
{
glm::vec3 position;
glm::vec2 tex_coords;
};
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, position);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, tex_coords));
I began to learn OpenGL about a week ago and I now want to create a mesh class. The code I'm about to show gives me a black screen (that's the color I fill it with).
I basically stripped the code from my main function and placed it inside a class, it worked inside main.
mesh.cpp
#include "mesh.h"
mesh::mesh(std::vector<GLfloat> vertices, std::vector<GLuint> indices)
{
this->vertices = vertices;
this->indices = indices;
glGenVertexArrays(1, &vertexArrayObject);
glGenBuffers(1, &vertexBuffer);
glGenBuffers(1, &triangleBuffer);
glBindVertexArray(vertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(GLfloat), this->vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangleBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(GLuint), this->indices.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
}
mesh::~mesh()
{
glDeleteBuffers(1, &triangleBuffer);
glDeleteBuffers(1, &vertexBuffer);
glDeleteVertexArrays(1, &vertexArrayObject);
}
void mesh::update(){
glBindVertexArray(vertexArrayObject);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
mesh.h
#ifndef MESH_H
#define MESH_H
#include <iostream>
#include <vector>
#include <GL/glew.h>
#include <glm/glm.hpp>
class mesh
{
public:
mesh(std::vector<GLfloat> vertices, std::vector<GLuint> triangles);
~mesh();
void update();
protected:
private:
GLuint vertexArrayObject, vertexBuffer, triangleBuffer;
std::vector<GLfloat> vertices;
std::vector<GLuint> indices;
};
#endif // MESH_H
According to this, this should be the correct way to do it (?).
BTW, all this code is a mashup from this and open.gl sites, here are the variables I pass into the constructor.
For the vertices:
std::vector<GLfloat> vertices = {
// Position Color Texcoords
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // Top-left
0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // Top-right
0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // Bottom-right
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f // Bottom-left
};
and the indices:
std::vector<GLuint> elements = {
0, 1, 2,
2, 3, 0
};
Also please note that I changed the code snippets according to Anton's suggestions, that didn't seem to work
You have two problems that immediately come to mind:
this->triangles.size() * sizeof(GLfloat)
This problem will not affect anything because GLfloat has the same size as GLuint, but if that was not a typo, it indicates to me you may be thinking about the index buffer wrong.
Make this triangles.size () * sizeof (GLuint) for consistency.
glDrawElements(GL_TRIANGLES, this->vertices.size(), GL_UNSIGNED_INT, 0);
You have two separate lists in your class, vertices and triangles, and this call only cares about the size of one of those.
triangles is an array of indices that makes a list of triangles (3 indices per-triangle).
When you draw your elements array, you pass the number of elements in that list, not the number of vertices in your mesh.
While not technically a problem, I think you use this-> a little bit too much when you write your code.
It is useful when you have variables at one scope that have the same name as members in your class (which one could argue builds a case for inadequately descriptive names), but completely unnecessary in functions like mesh::~mesh(). It makes your code harder to read (for me anyway) because the lines are much longer.
Following the theme of inadequately descriptive names, by calling your index array "triangles" you have inadvertently limited this mesh class to drawing triangles. That might be a good variable name for a specialized constructor that builds a triangle mesh, but not so much for a class member. If you use indices instead, that gets rid of the name collision and the need to qualify everything using this->.
I am trying to display a simple triangle with OpenGL (I am using freeglut3-dev and libglew1.6 on Ubuntu 12.04 and coding in NetBeans 7.2). The code compiles and links with no problems, but displays only a blank screen (with initialized colour) but only a single white point at the origin (instead of 3 points for each of the triangle vertices). My code is below:
#include <stdio.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include "math_3d.h"
GLuint VBO;
static void RenderSceneCB()
{
glClear(GL_COLOR_BUFFER_BIT);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glutSwapBuffers();
}
static void InitializeGlutCallbacks()
{
glutDisplayFunc(RenderSceneCB);
}
static void CreateVertexBuffer()
{
Vector3f Vertices[3];
Vertices[0] = Vector3f(-1.0f, -1.0f, 0.0f);
Vertices[1] = Vector3f(1.0f, -1.0f, 0.0f);
Vertices[2] = Vector3f(0.0f, 1.0f, 0.0f);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA);
glutInitWindowSize(1024, 768);
glutInitWindowPosition(100, 100);
glutCreateWindow("Tutorial 03");
InitializeGlutCallbacks();
// Must be done after glut is initialized!
GLenum res = glewInit();
if (res != GLEW_OK) {
fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res));
return 1;
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
CreateVertexBuffer();
glutMainLoop();
return 0;
}
Here is a screenshot of what I see:
Here is a picture of what it should look like:
I am following this tutorial. Vector3f is just a structure with three data members: x, y, z.
Read the next chapter of the tutorial, it explains it all.
A vertex is simply a set of attributes, which are referenced by their number (0 in your case). This number however doesn't tell the GL what the data are, and thus how to use them. With the old API you had specific vertex specification functions for each attribute; glVertexPointer() was used to provide position attributes, glTexCoordPointer() texture coordinates, etc. Today it is up to you to use the attributes the way you want, through shaders, which are explained in the next chapter of your tutorial.