Stuck on a basic OpenGL program - c++

I'm trying to create a sample program that can be used as a test harness for OpenGL. The one I have so far seems to work, but it seems that the MVP matrix passed via the uniform variable MVPMatrix is ignored. When I added code to read the uniform back and check that it was actually updating properly, I get an invalid operation error when doing so and I can't see why - what's going on?
#include "stdafx.h"
#include <iostream>
#include <memory>
#include <sdl/SDL.h>
#include <assimp/Importer.hpp>
#include <assimp/mesh.h>
#include <assimp/scene.h>
#include <sdl/SDL_image.h>
#include <glm/glm.hpp>
#include <Windows.h>
#include <GL/glew.h>
#include <GL/GL.h>
#include <gl/GLU.h>
#include <vector>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <assimp/Importer.hpp>
#include <assimp/mesh.h>
#include <assimp/postprocess.h>
#include <assimp/vector3.h>
using namespace std;
void checkGLShaderStatus(GLuint id, GLuint thingToCheck, bool shader) {
GLint ret;
if (shader) glGetShaderiv(id, thingToCheck, &ret); else glGetProgramiv(id, thingToCheck, &ret);
// If there was an error
if (ret == GL_FALSE) {
// Print it out, then halt
GLint maxLength = 0;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &maxLength);
GLchar *shaderErrorLog = (GLchar*)malloc(sizeof(GLchar)*(maxLength + 1));
glGetShaderInfoLog(id, maxLength, &maxLength, shaderErrorLog);
shaderErrorLog[maxLength] = '\0';
cout << shaderErrorLog;
free(shaderErrorLog);
int junk;
cin >> junk;
exit(EXIT_FAILURE);
}
}
GLuint buildShader(const GLchar **source, GLuint length, GLenum type) {
// Create the shader
GLuint shaderId = glCreateShader(type);
// Upload source code
glShaderSource(shaderId, length, source, NULL);
// Compile the shader
glCompileShader(shaderId);
// See how the compilation went
checkGLShaderStatus(shaderId, GL_COMPILE_STATUS, true);
return shaderId;
}
void checkGL(string stage) {
GLuint error = glGetError();
if (error != GL_NO_ERROR) {
cout << "OpenGL broke..";
switch (error) {
case GL_INVALID_ENUM:
cout << "Invalid Enum";
break;
case GL_INVALID_VALUE:
cout << "Value out of range";
break;
case GL_INVALID_OPERATION:
cout << "Invalid operation";
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
cout << "Incomplete framebuffer";
break;
case GL_OUT_OF_MEMORY:
cout << "Out of memory";
break;
default:
cout << "Oh boy, did it break..";
}
cout << " (" << stage << ")" << endl;
int junk;
cin >> junk;
exit(EXIT_FAILURE);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
if (SDL_Init(SDL_INIT_EVERYTHING) == -1) exit(EXIT_FAILURE);
if (IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG) == -1) exit(EXIT_FAILURE);
Assimp::Importer importer;
const aiScene *importedScene = importer.ReadFile("Table.3ds",aiProcess_Triangulate);
if (importedScene == nullptr) exit(EXIT_FAILURE);
aiMesh *theMesh = importedScene->mMeshes[0];
if (theMesh == nullptr) exit(EXIT_FAILURE);
cout << "I imported a mesh with " << theMesh->mNumVertices << " vertices and " << theMesh->mNumFaces << " faces! " << endl;
SDL_Window *win = nullptr;
win = SDL_CreateWindow("My even more awesome SDL/OGL program", 100, 100, 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
if (win == nullptr) exit(EXIT_FAILURE);
SDL_Renderer *ren = nullptr;
ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (ren == nullptr) exit(EXIT_FAILURE);
SDL_GLContext context = SDL_GL_CreateContext(win);
if (context == nullptr) exit(EXIT_FAILURE);
glewInit();
int attrib_vPosition = 0;
const GLchar *vertexShaderSource = { "#version 430 core\n"
"layout (location=0) in vec4 vPosition;"
"uniform mat4 MVPMatrix;"
"void main() {"
" gl_Position = MVPMatrix * vPosition;"
"}"};
GLuint vertexShader = buildShader(&vertexShaderSource, 1, GL_VERTEX_SHADER);
checkGL("compiling vertex shader");
const GLchar *fragShaderSource = { "#version 430 core\n"
"out vec4 fColor;"
"void main() {"
" fColor = vec4(0.0, 0.0, 1.0, 1.0);"
"}"
};
GLuint fragmentShader = buildShader(&fragShaderSource, 1, GL_FRAGMENT_SHADER);
checkGL("compiling fragment shader");
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
checkGLShaderStatus(shaderProgram, GL_LINK_STATUS, false);
checkGL("Linking shader");
glUseProgram(shaderProgram);
//glDeleteShader(fragmentShader);
//glDeleteShader(vertexShader);
checkGL("Running shader");
GLint MVPlocation = glGetUniformLocation(shaderProgram, "MVPMatrix");
checkGL("Getting uniform location");
glm::mat4 mvpMatrix(0.1f);
glUniformMatrix4fv(MVPlocation, 1, GL_FALSE, glm::value_ptr(mvpMatrix));
checkGL("Setting uniform");
GLint testLocation = glGetUniformLocation(shaderProgram, "MVPMatrix[0][0]");
checkGL("Getting uninform test cell location");
GLfloat testfloat;
glGetUniformfv(shaderProgram, testLocation, &testfloat);
checkGL("Reading uniform");
if (testfloat != mvpMatrix[0][0]) {
cout << "Uniform setting did not sink in..";
}
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
checkGL("Creating VAO");
GLfloat vertices[3][3] = { { -0.9f, -0.9f, 0.f }, { 0.85f, -0.9f, 0.f }, { -0.9f, 0.85f, 0.f } };
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
int vertexDataSize = 9;
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, ((void *)(0)));
glEnableVertexAttribArray(0);
checkGL("creating VBO");
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, vertexDataSize);
glFlush();
SDL_GL_SwapWindow(win);
SDL_Event event;
bool quit = false;
while (!quit) {
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
quit = true;
}
}
}
glDeleteProgram(shaderProgram);
glDeleteBuffers(1, &buffer);
glDeleteVertexArrays(1, &VAO);
SDL_GL_DeleteContext(context);
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
IMG_Quit();
SDL_Quit();
return 0;
}

You shouldn't use glGetUniformfv(... glGetUniformLocation(... "MVPMatrix[0][0]")). The documentation says
glGetUniformLocation returns an integer that represents the location of a specific uniform variable within a program object. name must be a null terminated string that contains no white space. name must be an active uniform variable name in program that is not a structure, an array of structures, or a subcomponent of a vector or a matrix.
And
glGetUniform returns in params the value(s) of the specified uniform variable. The type of the uniform variable specified by location determines the number of values returned. If the uniform variable is defined in the shader as a boolean, int, or float, a single value will be returned. If it is defined as a vec2, ivec2, or bvec2, two values will be returned. If it is defined as a vec3, ivec3, or bvec3, three values will be returned, and so on. To query values stored in uniform variables declared as arrays, call glGetUniform for each element of the array. To query values stored in uniform variables declared as structures, call glGetUniform for each field in the structure. The values for uniform variables declared as a matrix will be returned in column major order.
Your uniform variable uniform mat4 MVPMatrix; is declared as a matrix type, not an array and you will retrieve the entire 4x4 matrix at once (just like you set it in a single operation). Try
GLfloat testfloat[16];
glGetUniformfv(shaderProgram, MVPLocation, testfloat);
Another problem is here:
GLfloat vertices[3][3] = { { -0.9f, -0.9f, 0.f }, { 0.85f, -0.9f, 0.f }, { -0.9f, 0.85f, 0.f } };
int vertexDataSize = 9;
glDrawArrays(GL_TRIANGLES, 0, vertexDataSize);
You don't have 9 vertices, only 3.

Related

Modern OpenGL 3.3 with glfw window not displaying anything

I just get an empty window without any c++ or opengl errors. And the vao method dosen't work. Im also on a 8 year old laptop, so this also may be the cause.
Here's the code:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
// shader stuff (do not understand lol)
static unsigned int compile_shader(unsigned int type, const std::string& source) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
// ERRORS
int resoult;
glGetShaderiv(id, GL_COMPILE_STATUS, &resoult);
if (resoult == GL_FALSE) {
int lenght;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &lenght);
char* message = (char*)_malloca(lenght * sizeof(char));
glGetShaderInfoLog(id, lenght, &lenght, message);
std::cout << "ERROR !!! Failded to compile shader !!! ERROR" << (type ==
GL_VERTEX_SHADER ? "vertex" : "fragment") << std::endl;
std::cout << message << std::endl;
glDeleteShader(id);
return 0;
}
return id;
}
static unsigned int create_shader(const std::string& vertex_shader, const std::string&
fragment_shader) {
unsigned int program = glCreateProgram();
unsigned int vs = compile_shader(GL_VERTEX_SHADER, vertex_shader);
unsigned int fs = compile_shader(GL_FRAGMENT_SHADER, fragment_shader);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(800, 600, "test", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
std::cout << glGetString(GL_VERSION) << std::endl;
// Initializing GLEW
if (glewInit() != GLEW_OK)
std::cout << "Error with glew :((((((" << std::endl;
// buffer for the triangle
float positions[6] = {
-0.5f, -0.5f,
0.0f, -0.5f,
0.5f, -0.5f
};
unsigned int vao;
glGenVertexArrays(1, &vao);
unsigned int buffer;
glGenBuffers(1, &buffer);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), positions, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, (void*)0);
std::string vertex =
"#version 330 core \n"
"layout(location = 0 ) in vec4 position;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = position;\n"
"}\n";
std::string fragment =
"#version 330 core \n"
"layout(location = 0 ) out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
" color = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
unsigned int shader = create_shader(vertex, fragment);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
// making a triangle
glUseProgram(shader);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glDeleteProgram(shader);
glfwTerminate();
return 0;
}

Creating a triangle with OpenGL

I am having trouble with my C++ code for an OpenGL program that is supposed to create a 2D triangle and keep receiving this error message:
Error! Fragment shader failed to compile.
ERROR: 0:1: '' : syntax error: #version directive must occur in a shader before anything else.
Error! Shader Program Linker Failure.
I have tried putting the code from lines 13-27 before the const char* APP_TITLE line (line 8) but that doesn't seem to make a difference.
What can I do to generate this 2D triangle?
#include <iostream>
#include <sstream>
#define GLEW_STATIC
#include "GL/glew.h"
#include "GLFW/glfw3.h"
const char* APP_TITLE = "Texturing a Pyramid";
const int gwindowWidth = 800;
const int gwindowHeight = 600;
GLFWwindow* gWindow = NULL;
const GLchar* vertexShaderSrc =
"#version 330 core\n"
"layout (location = 0) in vec3 pos;"
"void main()"
"{"
" gl_Position = vec4(pos.x, pos.y, pos.z, 1.0);"
"}";
const GLchar* fragmentShaderSrc =
"version 330 core\n"
"out vec4 frag_color;"
"void main()"
"{"
" frag_color = vec4(0.35f, 0.96f, 0.3f, 1.0);"
"}";
void glfw_onKey(GLFWwindow* window, int key, int scancode, int action, int mode);
void showFPS(GLFWwindow* window);
bool initOpenGL();
int main()
{
if (!initOpenGL())
{
std::cerr << "GLFW intialization failed." << std::endl;
return false;
}
GLfloat vertices[] = {
0.0f, 0.5f, 0.0f, // Top Vertex
0.5f, -0.5f, 0.0f, // Right Vertex
-0.5f, -0.5f, 0.0f // Left Vertex
};
GLuint vbo, vao;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource (vs, 1, &vertexShaderSrc, NULL);
glCompileShader(vs);
GLint result;
GLchar infoLog[512];
glGetShaderiv(vs, GL_COMPILE_STATUS, &result);
if (!result)
{
glGetShaderInfoLog(vs, sizeof(infoLog), NULL, infoLog);
std::cout << "Error! Vertex shader failed to compile." << infoLog << std::endl;
}
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource (fs, 1, &fragmentShaderSrc, NULL);
glCompileShader(fs);
glGetShaderiv(fs, GL_COMPILE_STATUS, &result);
if (!result)
{
glGetShaderInfoLog(fs, sizeof(infoLog), NULL, infoLog);
std::cout << "Error! Fragment shader failed to compile." << infoLog << std::endl;
}
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vs);
glAttachShader(shaderProgram, fs);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &result);
if (!result)
{
glGetProgramInfoLog(shaderProgram, sizeof(infoLog), NULL, infoLog);
std::cout << "Error! Shader Program Linker Failure" << std::endl;
}
glDeleteShader(vs);
glDeleteShader(fs);
// Main loop
while (!glfwWindowShouldClose(gWindow))
{
showFPS(gWindow);
glfwPollEvents();
glfwSwapBuffers(gWindow);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glfwSetKeyCallback(gWindow, glfw_onKey);
}
glDeleteProgram(shaderProgram);
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glfwTerminate();
return 0;
}
bool initOpenGL()
{
if (!glfwInit())
{
std::cerr << "GLFW initialization failed." << std::endl;
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLFWwindow* gWindow = glfwCreateWindow(gwindowWidth, gwindowHeight, APP_TITLE, NULL, NULL);
if (gWindow == NULL)
{
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(gWindow);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
std::cerr << "GLEW initialization failed." << std::endl;
return false;
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
return true;
}
void glfw_onKey(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
void showFPS(GLFWwindow* window)
{
static double previousSeconds = 0.0;
static int frameCount = 0;
double elapsedSeconds;
double currentSeconds = glfwGetTime(); // returns # of seconds since GLFW started, as a double
elapsedSeconds = currentSeconds - previousSeconds;
// limit text update 4 times per second
if (elapsedSeconds > 0.25)
{
previousSeconds = currentSeconds;
double fps = (double)frameCount / elapsedSeconds;
double msPerFrame = 1000.0 / fps;
std::ostringstream outs;
outs.precision(3);
outs << std::fixed
<< APP_TITLE << " "
<< "FPS: " << fps << " "
<< "FrameTime: " << msPerFrame << " (ms)";
glfwSetWindowTitle(window, outs.str().c_str());
frameCount = 0;
}
frameCount++;
}
fragmentShaderSrc is missing a # (U+0023 NUMBER SIGN) in front of version:
"version 330 core\n"
^ note lack of #
Should be:
"#version 330 core\n"
^ note the #

How to fix black screen output in OpenGL 3.3

I am experiencing a black screen in my project using OpenGL and C++. I am in need of assistance as to where I went wrong rendering a red triangle to the screen.
I have tried checking for errors in the vertex and fragment shader.
#include <GL\glew.h>
#include <GL\GL.h>
#include <GLFW\glfw3.h>
#include <iostream>
#include <string>
using namespace std;
unsigned int CreateShader(int type, const string shaderSource) {
unsigned int shader = glCreateShader(type);
const char *src = shaderSource.c_str();
glShaderSource(shader, 1, &src, NULL);
glCompileShader(shader);
int result;
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
char *message = (char*)alloca(length * sizeof(char));
glGetShaderInfoLog(shader, length, &length, message);
cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "vertex shader " : "fragment shader ") << endl;
cout << message << endl;
}
return shader;
}
unsigned int CreateProgram(const string vertexShader, const string fragmentShader) {
unsigned int program = glCreateProgram();
unsigned int vs = CreateShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = CreateShader(GL_FRAGMENT_SHADER, fragmentShader);
glAttachShader(program, vs);
glAttachShader(program, fs);
glDeleteShader(vs);
glDeleteShader(fs);
glLinkProgram(program);
glValidateProgram(program);
return program;
}
int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow *window = glfwCreateWindow(800, 600, "window", NULL, NULL);
glfwMakeContextCurrent(window);
glewInit();
if (glewInit() != GLEW_OK) {
cout << "Glew initialization Failed! " << endl;
glfwTerminate();
return -1;
}
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
};
cout << "Made By Rial Seebran" << endl;
cout << glfwGetVersionString() << endl;
unsigned int VAO;
unsigned int VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
const string vertexShader =
"#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"void main() {\n"
"gl_Position = vec4(position, 0.0f);\n"
"}\n";
const string fragmentShader =
"#version 330 core\n"
"layout (location = 0) out vec4 color;\n"
"void main() {\n"
"color = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
"}\n";
unsigned int program = CreateProgram(vertexShader, fragmentShader);
while (!glfwWindowShouldClose(window)) {
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glBindVertexArray(VAO);
glDrawArrays(GL_ARRAY_BUFFER, 0, 3);
glBindVertexArray(0);
glfwPollEvents();
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
I'm expecting a red triangle drawn at the coordinates specified with a blueish background.
The first parameter to glDrawArrays has to be the primitive type.
It has to be GL_TRIANGLES rather than GL_ARRAY_BUFFER:
glDrawArrays(GL_ARRAY_BUFFER, 0, 3);
glDrawArrays(GL_TRIANGLES, 0, 3);
The OpenGL enumerator constant GL_ARRAY_BUFFER is not an an accepted value for this parameter and will cause an GL_INVALID_ENUM error (The error can be get by glGetError).
When the clip space coordinate is transformed to normalized device space, then the x, y and z component is divided by the w component.
This means the w component of gl_Position has to be set 1.0 rather the 0.0:
gl_Position = vec4(position, 0.0f);
gl_Position = vec4(position, 1.0);
Glew can enable additional extensions by glewExperimental = GL_TRUE;. See the GLEW documentation which says:
GLEW obtains information on the supported extensions from the graphics driver. Experimental or pre-release drivers, however, might not report every available extension through the standard mechanism, in which case GLEW will report it unsupported. To circumvent this situation, the glewExperimental global switch can be turned on by setting it to GL_TRUE before calling glewInit(), which ensures that all extensions with valid entry points will be exposed.
glewExperimental = GL_TRUE;
if ( glewInit() != GLEW_OK ) {
cout << "Glew initialization Failed! " << endl;
glfwTerminate();
return -1;
}

Display white triangle with SFML and OpenGL?

I should be seeing a white triangle on the output, but I am just seeing a black screen. I think that the issue is with the glsl shaders. What is wrong with my code?
#define GLEW_STATIC
#include <iostream>
#include <GL/glew.h>
#include <SFML/Window.hpp>
#include <SFML/OpenGL.hpp>
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
using namespace std;
// Shader sources
const char* vertexSource = R"glsl(
#version 330 core
in vec2 position;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
}
)glsl";
const char* fragmentSource = R"glsl(
#version 330 core
out vec4 outColor;
void main()
{
outColor = vec4(1.0, 1.0, 1.0, 1.0);
}
)glsl";
int main()
{
sf::ContextSettings settings;
settings.depthBits = 24;
settings.stencilBits = 8;
settings.antialiasingLevel = 2;
settings.majorVersion = 3;
settings.minorVersion = 2;
settings.attributeFlags = sf::ContextSettings::Core;
sf::RenderWindow window(sf::VideoMode(800, 600), "OpenGL", sf::Style::Titlebar | sf::Style::Close, settings);
// Initialize GLEW
glewExperimental = GL_TRUE;
glewInit();
//generate a vao
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//generate 1 buffer
GLuint vbo;
glGenBuffers(1, &vbo);
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)
};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//compiling the vertex shader
GLuint vertexshader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexshader, 1, &vertexSource, NULL);
glCompileShader(vertexshader);
GLint shaderstatus;
glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &shaderstatus);
char buffer[512];
glGetShaderInfoLog(vertexshader, 512, NULL, buffer);
while (shaderstatus = true){
cout << "vertex" << endl;
cout << buffer << endl;
break;
}
//compiling the fragment shader
GLuint fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentshader, 1, &fragmentSource, NULL);
glCompileShader(fragmentshader);
GLint fragmentstatus;
glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &fragmentstatus);
char bufferfrag[512];
glGetShaderInfoLog(fragmentshader, 512, NULL, bufferfrag);
while (fragmentstatus = true){
cout << "fragment" << endl;
cout << bufferfrag << endl;
break;
}
//connecting vertex and fragment shaders
GLuint shaderprogram = glCreateProgram();
glAttachShader(shaderprogram, vertexshader);
glAttachShader(shaderprogram, fragmentshader);
glBindFragDataLocation(shaderprogram, 0, "outColor");
glLinkProgram(shaderprogram);
glUseProgram(shaderprogram);
GLint posAttrib = glGetAttribLocation(shaderprogram, "Position");
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(posAttrib);
while (window.isOpen())
{
// Process events
sf::Event event;
while (window.pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
window.close();
}
// Clear screen
window.clear();
//window.clear();
glDrawArrays(GL_TRIANGLES, 0, 3);
// Update the window
window.display();
}
return 0;
}
At line:
GLint posAttrib = glGetAttribLocation(shaderprogram, "Position");
The p in "Position" should be lowercase, as GLSL is case sensitive.
Also, in:
while (shaderstatus = true){
cout << "vertex" << endl;
cout << buffer << endl;
break;
}
There should be two equal signs, as this is to test equality, not to set shaderstatus to true.

Can't get ids assigned to an attribute in OpenGL

I am trying to have OpenGL automatically assign an ID to a glsl-attribute, but it is failing.
My main program:
#include <iostream>
#include <GL/glew.h>
#include <GL/glfw3.h>
#include "test.h"
#include "shader_utils.h"
static void error_callback(int error, const char* description) {
std::cout << description << std::endl;
}
static void key_callback(GLFWwindow* window, int a, int b) {
if (a == GLFW_KEY_ESCAPE && b == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GL_TRUE);
}
}
void test()
{
std::cout << "Starting up" << std::endl;
init();
run();
}
GLFWwindow *window;
GLuint shaders;
GLuint vertexBuffer;
int init() {
glfwSetErrorCallback(error_callback);
if(!glfwInit()) {
return -1;
}
window = glfwCreateWindow(640, 480, "GLFW test", NULL, NULL);
if (!window) {
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
glewExperimental = true;
glewInit();
shaders = LoadShaders("vertex.glsl", "fragment.glsl");
GLuint vao_id;
glGenVertexArrays(1, &vao_id);
glBindVertexArray(vao_id);
static const GLfloat vertex_data[] = {
// Bottom
-.5f, -.5f, -.5f, 1.f, 0.f, 0.f,
-.5f, -.5f, .5f, 1.f, 0.f, 0.f,
.5f, -.5f, .5f, 1.f, 0.f, 0.f,
};
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
}
void checkE() {
std::cout << "Checking for errors: ";
int err;
int a = 0;
while((err = glGetError()) != GL_NO_ERROR) {
std::cout << "Error: " << err << std::endl;
a = 1;
}
if(a == 0) {
std::cout << "no errors" << std::endl;
}
std::cout.flush();
}
int run() {
GLfloat angle = 0;
while(!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaders);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
GLuint attrLocation = glGetAttribLocation(shaders, "location");
GLuint attrColor = glGetAttribLocation(shaders, "color");
std::cout << "AttribLocation('location'): ";
std::cout << glGetAttribLocation(shaders, "location") << std::endl;
std::cout << "AttribLocation('color'): ";
std::cout << glGetAttribLocation(shaders, "color") << std::endl;
checkE();
std::cout << std::endl;
std::cout << "glEnableVertexAttribArray()" << std::endl;
glEnableVertexAttribArray(attrLocation);
glEnableVertexAttribArray(attrColor);
checkE();
std::cout << std::endl;
std::cout << "glVertexAttribPointer();" << std::endl;
glVertexAttribPointer(
glGetAttribLocation(shaders, "location"), // Attribute
3, // Size
GL_FLOAT, // Size
GL_FALSE, // Normalized
24, // Stride
(GLvoid*) 0 // Offset
);
checkE();
std::cout << std::endl;
std::cout << "glVertexAttribPointer();" << std::endl;
glVertexAttribPointer(
glGetAttribLocation(shaders, "color"),
3,
GL_FLOAT,
GL_FALSE,
24,
(GLvoid*) (3*sizeof(GLfloat))
);
checkE();
std::cout << std::endl;
glDrawArrays(GL_TRIANGLES, 0, 3);
checkE();
std::cout << std::endl;
glDisableVertexAttribArray(attrLocation);
glDisableVertexAttribArray(attrColor);
checkE();
std::cout << std::endl;
glfwSwapBuffers(window);
glfwPollEvents();
glfwSetWindowShouldClose(window, GL_TRUE);
}
glfwDestroyWindow(window);
glfwTerminate();
}
Output from program:
Starting up
Compiling shader : vertex.glsl
Compiling shader : fragment.glsl
Linking program
AttribLocation('location'): -1
AttribLocation('color'): -1
Checking for errors: no errors
glEnableVertexAttribArray()
Checking for errors: Error: 1281
glVertexAttribPointer();
Checking for errors: Error: 1281
glVertexAttribPointer();
Checking for errors: Error: 1281
Checking for errors: no errors
Checking for errors: Error: 1281
Shader loader:
#include "shader_utils.h"
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include "GL/glew.h"
#include "GL/glfw3.h"
GLuint LoadShaders(const char * vertex_file_path, const char * fragment_file_path){
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
// Read the Vertex Shader code from the file
std::string VertexShaderCode;
std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
if(VertexShaderStream.is_open())
{
std::string Line = "";
while(getline(VertexShaderStream, Line))
VertexShaderCode += "\n" + Line;
VertexShaderStream.close();
} else {
std::cout << "could not open\n";
}
// Read the Fragment Shader code from the file
std::string FragmentShaderCode;
std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
if(FragmentShaderStream.is_open()){
std::string Line = "";
while(getline(FragmentShaderStream, Line))
FragmentShaderCode += "\n" + Line;
FragmentShaderStream.close();
}
GLint Result = GL_FALSE;
int InfoLogLength;
// Compile Vertex Shader
printf("Compiling shader : %s\n", vertex_file_path);
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);
// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> VertexShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);
// Compile Fragment Shader
printf("Compiling shader : %s\n", fragment_file_path);
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
glCompileShader(FragmentShaderID);
// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);
// Link the program
fprintf(stdout, "Linking program\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> ProgramErrorMessage( std::max(InfoLogLength, int(1)) );
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
std::cout.flush();
return ProgramID;
}
Vertex shader:
#version 130
in vec4 position;
in vec3 color;
out vec3 f_color;
void main() {
f_color = color;
gl_Position = position * gl_ModelViewProjectionMatrix;
}
Fragment shader:
#version 130
in vec3 color;
void main() {
gl_FragColor = vec4(color, 1);
}
For some reason I get just -1 as the location for both the attributes. Obviously the rest of the errors are caused by invalid location indices?
From OpenGL docs:
If the named attribute variable is not an active attribute in the specified program object or if name starts with the reserved prefix "gl_", a value of -1 is returned.
The names do not begin with gl_ and they are in use in the shaders, so I shouldn't get a value of -1. What am I missing?
You are failing to get an attribute location for color because it is not active. While it is true that color is used to calculate f_color in this example, the fragment shader does not use f_color so the linker determines that the vertex attribute named: color is inactive.
The solution is quite simple, really:
Fragment Shader:
#version 130
in vec3 f_color; // RENAMED from color, so that this matches the output from the VS.
void main() {
gl_FragColor = vec4(f_color, 1);
}
It is not an error to re-use the name color for different purposes in the Vertex Shader (input vertex attribute) and Fragment Shader (input varying) stages so the compiler/linker will not complain. It would be an error if you tried to do something like inout color though, so this is why you have to pass vertex attributes to geometry/tessellation/fragment shaders using a differently named varying. If the input/output names between stages do not match then chances are quite good that the original vertex attribute will be considered inactive.
Also, unless you are transposing your ModelViewProjection matrix, you have the matrix multiplication in your vertex shader backwards. Column-major matrix multiplication, as OpenGL uses, should read right-to-left. That is, you start with an object space position (right-most) and transform to clip space (left-most).
In other words, this is the proper way to transform your vertices...
gl_Position = gl_ModelViewProjectionMatrix * position;
~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~
clip space object space to clip space obj space