OpenGL doesn't draw triangle

Started by
8 comments, last by Gooey 10 years ago

I have done a lot of programming in OpenGL before, but somehow I am now unable to draw a triangle...

Here's the code (this is a one-file program). I have no idea which part of the code is failing so I'm posting all of it. All help appreaciated.

This code displays a blank, black window.


#include <MaddCompute.h>
#include <SDL2/SDL.h>
#include <iostream>
#include <GL/glew.h>
#include <string>
#include <fstream>
#include <stdlib.h>

using namespace std;

struct Vertex
{
	float pos[2];
	float color[3];
};

Vertex vertices[3] = {
	{{0.0, -1.0}, {1.0, 0.0, 0.0}},
	{{-1.0, 1.0}, {0.0, 1.0, 0.0}},
	{{1.0, 1.0}, {0.0, 0.0, 1.0}}
};

GLuint CompileShader(GLuint type, string filename)
{
	string code = "";
	ifstream ifs(filename.c_str());
	string line;
	while (getline(ifs, line))
	{
		code += line + '\n';
	};
	ifs.close();

	//cout << code << endl;
	//exit(1);

	GLuint shader = glCreateShader(type);
	char *str = (char*) code.c_str();
	glShaderSource(shader, 1, (const GLchar**)&str, NULL);
	glCompileShader(shader);

#if 0
	int len, ignore;
	glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
	char *buffer = new char[len+1];
	glGetShaderInfoLog(shader, len, &ignore, buffer);
	string log = buffer;
	delete buffer;

	ofstream ofs((filename + ".log").c_str());
	ofs << log << endl;
	ofs.close();
#endif

	return shader;
};

int main()
{
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		cerr << "SDL_Init: " << SDL_GetError() << endl;
		return 1;
	};

	SDL_Window *win = SDL_CreateWindow("MaddCompute OpenGL Shared Context",
						SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
						640, 480,
						SDL_WINDOW_OPENGL);
	if (win == NULL)
	{
		cerr << "SDL_CreateWindow: " << SDL_GetError() << endl;
		return 1;
	};

	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);

	SDL_GLContext glcontext = SDL_GL_CreateContext(win);
	if (glcontext == NULL)
	{
		cerr << "SDL_GL_CreateContext: " << SDL_GetError() << endl;
		return 1;
	};

	if (glewInit() != GLEW_OK)
	{
		cerr << "glewInit fail" << endl;
		return 1;
	};
	if (!glewIsSupported("GL_VERSION_3_0"))
	{
		cerr << "OpenGL 3.0 not supported!" << endl;
		return 1;
	};

	while (glGetError() != GL_NO_ERROR);

	GLuint vshader = CompileShader(GL_VERTEX_SHADER, "vertex.glsl");
	GLuint fshader = CompileShader(GL_FRAGMENT_SHADER, "fragment.glsl");
	
	GLuint prog = glCreateProgram();
	glAttachShader(prog, vshader);
	glAttachShader(prog, fshader);
	glLinkProgram(prog);

#if 0
	int len, ignore;
	glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len);
	char *buffer = new char[len+1];
	glGetProgramInfoLog(prog, len, &ignore, buffer);
	string log = buffer;
	delete buffer;

	ofstream ofs("link.log");
	ofs << log << endl;
	ofs.close();
#endif

	glUseProgram(prog);

	if (glGetError() != GL_NO_ERROR)
	{
		cerr << "Something went wrong in shader compilation." << endl;
		return 1;
	};

	GLint attrPos = glGetAttribLocation(prog, "pos");
	if (attrPos == -1)
	{
		cerr << "couldn't find 'pos' !" << endl;
		return 1;
	};
	GLint attrColor = glGetAttribLocation(prog, "color");
	if (attrColor == -1)
	{
		cerr << "couldn't find 'color' !" << endl;
		return 1;
	};

	GLuint vbo;
	glEnableVertexAttribArray(attrPos);
	glEnableVertexAttribArray(attrColor);

	glGenBuffers(1, &vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, 3*sizeof(Vertex), vertices, GL_STATIC_DRAW);
	glVertexAttribPointer(attrPos, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) 0);
	glVertexAttribPointer(attrColor, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, color));

	MC::Context *context = NULL;
	try
	{
		context = new MC::Context(MC::Context::OPENGL);
	}
	catch (MC::Error e)
	{
		cerr << "MC::Error: " << e.what() << endl;
		return 1;
	};

	bool quit = false;
	unsigned long time = SDL_GetTicks();
	while (!quit)
	{
		SDL_Event ev;
		while (SDL_PollEvent(&ev))
		{
			if (ev.type == SDL_QUIT)
			{
				quit = true;
			};
		};

		if ((SDL_GetTicks()-time) >= 33)
		{
			time = SDL_GetTicks();

			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			glDrawArrays(GL_TRIANGLES, 0, 3);

			SDL_GL_SwapWindow(win);
		};
	};

	delete context;
	SDL_GL_DeleteContext(glcontext);
	SDL_DestroyWindow(win);
	SDL_Quit();

	return 0;
};
Advertisement

Lack of a vertex array bound before setting up attributes? (glGenVertexArrays / glBindVertexArray)

New C/C++ Build Tool 'Stir' (doesn't just generate Makefiles, it does the build): https://github.com/space222/stir

Yes, looks like it's because of the missing VAO. I had the same problem a few days ago with OpenGL 3.0. glDrawArray requires a VAO and not a VBO.

I ran into the same VAO problem when I first got into OpenGL 3+.

Everything would render fine on my PC, but not on a friends. Turns out that nVidia cards require a VAO bound at all times while ATI/AMD cards don't care either way.

I believe nVidia's way is correct.

Thanks for the replies. I don't fully understand this though. If I create a VAO, and set up the vertex attributes with glVertexAttribPointer(), it tkaes the data from the currently-bound VBO, right? And before I call glDrawArrays(), do I have to bind into the VAO, or the VBO as well? And if I update the VBO, using glBufferData() or OpenCL, do those changes automatically affect the VAO, or do I have to create the VAO again?

The vao saves the state whereas the vbo holds the data. The vao will hold how to read your vbo.

Thank you, that answers everything smile.png

EDIT: Do I have to bind both the VBO and VAO before calling glDrawArray()? Or do I just need to bind the VAO?

I generally gen/bind a vao early in my program then only unbind/bind programs and vbos(array, element, texture ect) until the end then unbind and cleanup my vao with the vbos and programs. There are alot of arguments online about best practices for vaos some of which i believe are on this very site i would link a couple but im on my phone. The vbos you are going to use on that draw call will need to be the bound buffers.
The vao stores in info to read the vbos.
glVertexAttribPointer(index, size, type, normalized, stride, pointer);

EDIT: Do I have to bind both the VBO and VAO before calling glDrawArray()? Or do I just need to bind the VAO?

Binding the VAO should be sufficient.


Binding the VAO should be sufficient.

As long as the last time you called glVertexAttribPointer the correct objects VBO was bound otherwise you will have either a seg fault or the wrong object displayed

This topic is closed to new replies.

Advertisement