I was following an OpenGL tutorial when I ran into an issue where I wasn't getting the expected outcome. I was expecting to see a triangle in a window, but instead, I got an empty window. I have made many changes to the code to help it run on my machine, but none fixed the issue. Some of these changes include adding:
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
to request the core profile context, adding a VAO with the VBO, I even downloaded the code from the tutorial, but to no avail. Does anyone know a way to fix my issue?
Code:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
static unsigned int CompileShader(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);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if(result == GL_FALSE){
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));
glGetShaderInfoLog(id, length, &length, message);
std::cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader!" << std::endl;
std::cout << message << std::endl;
glDeleteShader(id);
return 0;
}
return id;
}
static unsigned int CreateShader(const std::string& vertexshader, const std::string& fragmentshader){
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexshader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentshader);
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;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if(glewInit() != GLEW_OK){
std::cout << "REEEEEEEEEEE" << std::endl;
}
float vertices[6] = {
-0.5f, -0.5f,
0.0f, 0.5f,
-0.5f, -0.5f
};
unsigned int buf;
glGenBuffers(1, &buf);
glBindBuffer(GL_ARRAY_BUFFER, buf);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
std::string vertexshader =
"#version 330 core\n"
"\n"
"in vec4 position;\n"
"out vec4 color;\n"
"\n"
"void main(){\n"
" gl_Position = position;\n"
" color = position;\n"
"}\n";
std::string fragmentshader =
"#version 330 core\n"
"\n"
"in vec4 in_color;\n"
"out vec4 color;\n"
"\n"
"void main(){\n"
" color = in_color;\n"
"}\n";
unsigned int shader = CreateShader(vertexshader, fragmentshader);
glUseProgram(shader);
glClearColor(0.33f, 0.33f, 0.33f, 1.0f);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
CMakeLists:
cmake_minimum_required (VERSION 3.5)
if(POLICY CMP0072)
cmake_policy(SET CMP0072 NEW)
else(NOT POLICY CMP0072)
message(STATUS "Error")
endif(POLICY CMP0072)
project (opengl-learning)
find_package(PkgConfig REQUIRED)
pkg_search_module(GLFW REQUIRED glfw3)
include_directories(${GLFW_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIR})
set (GCC_COVERAGE_LINK_FLAGS "-lglfw3 -pthread -ldl -lGLU -lGL -lrt -lXrandr -lXxf86vm -lXi -lXinerama -lX11 -lGLEW -lGLU -lGL")
add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -std=c++14")
set (source_dir "${PROJECT_SOURCE_DIR}/src/")
file (GLOB source_files "${source_dir}/*.cpp")
add_executable (opengl-learning ${source_files})
find_package(OpenGL REQUIRED)
find_package(GLEW REQUIRED)
target_link_libraries(opengl-learning ${GLFW_LIBRARIES} ${GLEW_LIBRARIES} ${OPENGL_LIBRARIES})
Versions (requesting core profile)
glGetString(GL_VERSION) >> 3.3 (Core Profile) Mesa 18.3.6
glGetString(GL_SHADING_LANGUAGE_VERSION) >> 3.30
OS: Linux Debian 10
If any extra information is required, feel free to ask.
When you use a core profile OpenGL Context you must create a Vertex Array Object:
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, buf);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
The default Vertex Array Object (0) is only valid using a compatibility profile OpenGL context:
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
I recommend reading Vertex Specification.
Related
I am working on compiling a simple openGL program in Xcode on my M1 Mac. When I build, It succeeds, but I get a nasty
2022-04-05 09:54:18.959203-0500 opengl[24908:835152] [default] error finding potential wrapper bundle for node <FSNode 0x100a09910> { isDir = ?, path = '/Users/liamwhite/Library/Developer/Xcode/DerivedData/opengl-awawpgevgzpjofbrfmzvucbfrzpp/Build/Products/Debug' }: Error Domain=NSOSStatusErrorDomain Code=-10811 "kLSNotAnApplicationErr: Item needs to be an application, but is not" UserInfo={_LSLine=1579, _LSFunction=wrapperBundleNodeForWrappedNode}
2022-04-05 09:54:18.959276-0500 opengl[24908:835152] [default] error finding potential wrapper bundle for node <FSNode 0x100a09910> { isDir = ?, path = '/Users/liamwhite/Library/Developer/Xcode/DerivedData/opengl-awawpgevgzpjofbrfmzvucbfrzpp/Build/Products/Debug' }: Error Domain=NSOSStatusErrorDomain Code=-10811 "kLSNotAnApplicationErr: Item needs to be an application, but is not" UserInfo={_LSLine=1579, _LSFunction=wrapperBundleNodeForWrappedNode}
2022-04-05 09:54:18.959308-0500 opengl[24908:835152] [default] error finding potential wrapper bundle for node <FSNode 0x100a09910> { isDir = ?, path = '/Users/liamwhite/Library/Developer/Xcode/DerivedData/opengl-awawpgevgzpjofbrfmzvucbfrzpp/Build/Products/Debug' }: Error Domain=NSOSStatusErrorDomain Code=-10811 "kLSNotAnApplicationErr: Item needs to be an application, but is not" UserInfo={_LSLine=1579, _LSFunction=wrapperBundleNodeForWrappedNode}
2022-04-05 09:54:19.019242-0500 opengl[24908:835152] [default] error finding potential wrapper bundle for node <FSNode 0x100a09910> { isDir = ?, path = '/Users/liamwhite/Library/Developer/Xcode/DerivedData/opengl-awawpgevgzpjofbrfmzvucbfrzpp/Build/Products/Debug' }: Error Domain=NSOSStatusErrorDomain Code=-10811 "kLSNotAnApplicationErr: Item needs to be an application, but is not" UserInfo={_LSLine=1579, _LSFunction=wrapperBundleNodeForWrappedNode}
2022-04-05 09:54:19.054172-0500 opengl[24908:835152] Metal API Validation Enabled
Program ended with exit code: 0
A potential fix is proposed in a similar SO post, but I am new to Xcode and the answer is too vague for me.
Below is my code, if it is of any consequence:
#include <iostream>
#include <string>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
static unsigned int CompileShader(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);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if(!result)
{
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = static_cast<char*>(alloca(length * sizeof(char))); // alloca is from C. it allows dynamic stack allocation!
glGetShaderInfoLog(id, length, &length, message);
std::cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader" << std::endl;
std::cout << message << std::endl;
return 0;
}
return id;
}
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
int main()
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if(!glewInit())
return 0;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
float positions[6] = {
-0.5f, -0.5f,
0.0f, 0.5f,
0.5f, -0.5f
};
unsigned int vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
unsigned int buffer;
glGenBuffers(1, &buffer);
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, 0);
std::string vertexShader =
"#version 330 core\n"
"layout(location = 0) in vec4 position;\n"
"void main()\n"
"{\n"
"gl_Position = position;\n"
"}\n";
std::string fragmentShader =
"#version 330 core\n"
"layout(location = 0) out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(1.0, 0.0, 0.0, 0.0, 1.0);\n"
"}\n";
unsigned int shader = CreateShader(vertexShader, fragmentShader);
glUseProgram(shader);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
I'm using Xcode (Version 12.0.1) on macOS 10.15.7.
I brew installed the latest versions of glew, glfw, glm with Homebrew, and tried running this simple code snippet, my OpenGL version seems to be incompatible with the shaders used.
I do not want to change the code, any way to downgrade the shaders? (Could it be done with Homebrew as well?)
Here's the code:
#include <iostream>
//#define GLEW_STATIC 1 // This allows linking with Static Library on Windows, without DLL
#include <GL/glew.h> // Include GLEW - OpenGL Extension Wrangler
#include <GLFW/glfw3.h> // GLFW provides a cross-platform interface for creating a graphical context,
// initializing OpenGL and binding inputs
#include <glm/glm.hpp> // GLM is an optimized math library with syntax to similar to OpenGL Shading Language
const char* getVertexShaderSource()
{
// Insert Shaders here ...
// For now, you use a string for your shader code, in the assignment, shaders will be stored in .glsl files
return
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;"
"layout (location = 1) in vec3 aColor;"
"out vec3 vertexColor;"
"void main()"
"{"
" vertexColor = aColor;"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);"
"}";
}
const char* getFragmentShaderSource()
{
return
"#version 330 core\n"
"in vec3 vertexColor;"
"out vec4 FragColor;"
"void main()"
"{"
" FragColor = vec4(vertexColor.r, vertexColor.g, vertexColor.b, 1.0f);"
"}";
}
int compileAndLinkShaders()
{
// compile and link shader program
// return shader program id
// ------------------------------------
// vertex shader
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
const char* vertexShaderSource = getVertexShaderSource();
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// check for shader compile errors
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// fragment shader
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
const char* fragmentShaderSource = getFragmentShaderSource();
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// check for shader compile errors
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// link shaders
int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// check for linking errors
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return shaderProgram;
//return -1;
}
int createVertexArrayObject()
{
// A vertex is a point on a polygon, it contains positions and other data (eg: colors)
glm::vec3 vertexArray[] = {
glm::vec3( 0.0f, 0.5f, 0.0f), // top center position
glm::vec3( 1.0f, 0.0f, 0.0f), // top center color (red)
glm::vec3( 0.5f, -0.5f, 0.0f), // bottom right
glm::vec3( 0.0f, 1.0f, 0.0f), // bottom right color (green)
glm::vec3(-0.5f, -0.5f, 0.0f), // bottom left
glm::vec3( 0.0f, 0.0f, 1.0f), // bottom left color (blue)
};
// Create a vertex array
GLuint vertexArrayObject;
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
// Upload Vertex Buffer to the GPU, keep a reference to it (vertexBufferObject)
GLuint vertexBufferObject;
glGenBuffers(1, &vertexBufferObject);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexArray), vertexArray, GL_STATIC_DRAW);
glVertexAttribPointer(0, // attribute 0 matches aPos in Vertex Shader
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
2*sizeof(glm::vec3), // stride - each vertex contain 2 vec3 (position, color)
(void*)0 // array buffer offset
);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, // attribute 1 matches aColor in Vertex Shader
3,
GL_FLOAT,
GL_FALSE,
2*sizeof(glm::vec3),
(void*)sizeof(glm::vec3) // color is offseted a vec3 (comes after position)
);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0); // VAO already stored the state we just defined, safe to unbind buffer
glBindVertexArray(0); // Unbind to not modify the VAO
return vertexArrayObject;
}
int main(int argc, char*argv[])
{
// Initialize GLFW and OpenGL version
glfwInit();
#if defined(PLATFORM_OSX)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#else
// On windows, we set OpenGL version to 2.1, to support more hardware
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
#endif
// Create Window and rendering context using GLFW, resolution is 800x600
GLFWwindow* window = glfwCreateWindow(800, 600, "Comp371 - Lab 01", NULL, NULL);
if (window == NULL)
{
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// Initialize GLEW
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
std::cerr << "Failed to create GLEW" << std::endl;
glfwTerminate();
return -1;
}
// Black background
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Compile and link shaders here ...
int shaderProgram = compileAndLinkShaders();
// Define and upload geometry to the GPU here ...
int vao = createVertexArrayObject();
// Entering Main Loop
while(!glfwWindowShouldClose(window))
{
// Each frame, reset color of each pixel to glClearColor
glClear(GL_COLOR_BUFFER_BIT);
// TODO - draw rainbow triangle
glUseProgram(shaderProgram);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3); // 3 vertices, starting at index 0
glBindVertexArray(0);
// End frame
glfwSwapBuffers(window);
// Detect inputs
glfwPollEvents();
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
// Shutdown GLFW
glfwTerminate();
return 0;
}
And here's the error i'm getting
2021-01-22 21:23:23.336552-0500 OpenGLtest [27358:306573] Metal API Validation Enabled
2021-01-22 21:23:23.361027-0500 OpenGLtest [27358:306750] flock failed to lock maps file: errno = 35
2021-01-22 21:23:23.361368-0500 OpenGLtest [27358:306750] flock failed to lock maps file: errno = 35
ERROR::SHADER::VERTEX::COMPILATION_FAILED
ERROR: 0:1: '' : version '330' is not supported
ERROR: 0:1: '' : syntax error: #version
ERROR: 0:2: 'layout' : syntax error: syntax error
ERROR::SHADER::FRAGMENT::COMPILATION_FAILED
ERROR: 0:1: '' : version '330' is not supported
ERROR: 0:1: '' : syntax error: #version
ERROR: 0:2: 'f' : syntax error: syntax error
ERROR::SHADER::PROGRAM::LINKING_FAILED
ERROR: One or more attached shaders not successfully compiled
Program ended with exit code: 9
How can this be fixed?
You're trying to compile #version 330 GLSL code on a GL 3.2 context. Since GL 3.2 only supports #versions up to 150 that won't work.
Either re-write your GLSL to target #version 150 or request a GL 3.3 context.
Okay so for some reason there's no way to install an older version of glew using homebrew commands, and after wasting an entire day on this, the error was solved by the following:
Xcode wasn't going into the #if, and was therefore executing the #else:
#if defined(PLATFORM_OSX)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#else
// On windows, we set OpenGL version to 2.1, to support more hardware
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
#endif
So I solved this by keeping this code only
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
I couldn't recreate this issue on VS code... Xcode was just being dumb?
You're restricted to OpenGL 2.1 Context when calling OpenGL from a Unix System perspective on MacOSX. In order to get OpenGL3.2 in XCode use GLKit (GLK) Library functions to automatically retrieve a GL 3.2 context. These libraries are all now deprecated past OSX 10.14.
I am trying to simplify my example to show exact abnormal case. I am running this example on MacOS 10.14.6, compiling clang LLVM compiler, using GLFW3. Also I am trying to run same example on Windows 10/64 using SFML and got same error, therefore the problem is not in the environment
OpenGL version 4.1 ATI-2.11.20
Shading language version 4.10
Exact code where problem is
glUseProgram(id_shader);
glEnableVertexAttribArray(param_Position);
//HERE IS ERROR "OpenGL ERROR: 0x00000502 GL_INVALID_OPERATION" RAISED
glVertexAttribPointer(param_Position, 3, GL_FLOAT, (GLboolean) false, 0, vertices);
Here is source full code
#include <stdlib.h>
#include <OpenGL/gl3.h>
#include <GLFW/glfw3.h>
#include "engine/Camera.h"
static const char *get_error_string_by_enum(GLenum err)
{
switch (err) {
case GL_INVALID_ENUM :
return "GL_INVALID_ENUM";
case GL_INVALID_VALUE :
return "GL_INVALID_VALUE";
case GL_INVALID_OPERATION :
return "GL_INVALID_OPERATION";
case GL_STACK_OVERFLOW :
return "GL_STACK_OVERFLOW";
case GL_STACK_UNDERFLOW :
return "GL_STACK_UNDERFLOW";
case GL_OUT_OF_MEMORY :
return "GL_OUT_OF_MEMORY";
#ifdef GL_INVALID_FRAMEBUFFER_OPERATION
case GL_INVALID_FRAMEBUFFER_OPERATION :
return "GL_INVALID_FRAMEBUFFER_OPERATION";
#endif
default: {
return "UNKNOWN";
}
}
}
static void check_gl()
{
char line[300];
GLenum err;
err = glGetError();
if (err != GL_NO_ERROR) {
sprintf(line, "OpenGL ERROR: 0x%.8X %s", err, get_error_string_by_enum(err));
printf("%s\n", line);
exit(-1);
}
}
int main()
{
char line[2000];
unsigned int windowWidth = 1024;
unsigned int windowHeight = 1024;
GLFWwindow* window;
//SETUP WINDOW AND CONTEXT
if (!glfwInit()){
fprintf(stdout, "ERROR on glfwInit");
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(windowWidth, windowHeight, "OpenGL", NULL, NULL);
if (!window)
{
fprintf(stderr, "Unable to create window.");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
sprintf(line, "OpenGL version %s\n", (const char *) glGetString(GL_VERSION));
fprintf(stdout, line);
sprintf(line, "Shading language version %s\n", (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION));
fprintf(stdout, line);
//SETUP OPENGL
glViewport(0, 0, windowWidth, windowHeight);
glEnable(GL_BLEND);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDepthMask(true);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//SETUP SHADER PROGRAM
GLint success;
GLuint id_v = glCreateShader(GL_VERTEX_SHADER);
GLuint id_f = glCreateShader(GL_FRAGMENT_SHADER);
const char *vertex_shader_source = "#version 330\n"
"precision mediump float;\n"
"\n"
"in vec4 Position;\n"
"uniform mat4 MVPMatrix;\n"
"\n"
"void main()\n"
"{\n"
"\tgl_Position = MVPMatrix * Position;\n"
"\tgl_PointSize = 10.0;\n"
"}";
const char *fragment_shader_source = "#version 330\n"
"precision mediump float;\n"
"\n"
"uniform vec4 Color;\n"
"out vec4 FragCoord;\n"
"\n"
"void main()\n"
"{\n"
" FragCoord = Color;\n"
"}";
glShaderSource(id_v, 1, &vertex_shader_source, NULL);
glCompileShader(id_v);
glGetShaderiv(id_v, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(id_v, 2000, NULL, line);
fprintf(stderr, line);
exit(-1);
}
glShaderSource(id_f, 1, &fragment_shader_source, NULL);
glCompileShader(id_f);
glGetShaderiv(id_f, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(id_f, 2000, NULL, line);
fprintf(stderr, line);
exit(-1);
}
GLuint id_shader = glCreateProgram();
glAttachShader(id_shader, id_v);
glAttachShader(id_shader, id_f);
glLinkProgram(id_shader);
glGetProgramiv(id_shader, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(id_shader, 2000, NULL, line);
fprintf(stderr, "program link error");
fprintf(stderr, line);
exit(-1);
}
GLuint param_Position = glGetAttribLocation(id_shader, "Position");
GLuint param_MVPMatrix = glGetUniformLocation(id_shader, "MVPMatrix");
GLuint param_Color = glGetUniformLocation(id_shader, "Color");
sprintf(line, "Params: param_Position=%d param_MVPMatrix=%d param_Color=%d\n", param_Position, param_MVPMatrix, param_Color);
fprintf(stdout, line);
//SETUP MATRIX
Camera *c = new Camera();
c->setCameraType(CameraType::PERSPECTIVE);
c->setWorldSize(100, 100);
c->lookFrom(5, 5, 5);
c->lookAt(0, 0, 0);
c->setFOV(100);
c->setUp(0, 0, 1);
c->calc();
c->getResultMatrix().dump();
//SETUP TRIANGLE
float vertices[] = {
0, 0, 0,
1, 0, 0,
1, 1, 0
};
while (!glfwWindowShouldClose(window))
{
//CLEAR FRAME
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
//RENDER TRIANGLE
glUseProgram(id_shader);
glUniformMatrix4fv(param_MVPMatrix, 1, (GLboolean) false, c->getResultMatrix().data);
glUniform4f(param_Color, 1.0f, 0.5f, 0.0f, 1.0f);
glEnableVertexAttribArray(param_Position);
check_gl();
//HERE IS ERROR "OpenGL ERROR: 0x00000502 GL_INVALID_OPERATION" RAISED
glVertexAttribPointer(param_Position, 3, GL_FLOAT, (GLboolean) false, 0, vertices);
check_gl();
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
Before line
glVertexAttribPointer(param_Position, 3, GL_FLOAT, (GLboolean) false, 0, vertices);
No errors detected before and just after this line GL_INVALID_OPERATION raised.
Program output is:
Environment versions:
OpenGL version 4.1 ATI-2.11.20
Shading language version 4.10
Shader param names:
Params: param_Position=0 param_MVPMatrix=1 param_Color=0
Matrix
-0.593333 -0.342561 -0.577350 -0.577350
0.593333 -0.342561 -0.577350 -0.577350
0.000000 0.685122 -0.577350 -0.577350
0.000000 0.000000 8.640252 8.660253
Error
OpenGL ERROR: 0x00000502 GL_INVALID_OPERATION
I already spent few days on that problem and have no more idea to put it on. I would be grateful for any advice and clarifications.
P.S. Here is glfwinfo output for my system
/glfwinfo -m3 -n2 --profile=compat
GLFW header version: 3.4.0
GLFW library version: 3.4.0
GLFW library version string: "3.4.0 Cocoa NSGL EGL OSMesa"
OpenGL context version string: "4.1 ATI-2.11.20"
OpenGL context version parsed by GLFW: 4.1.0
OpenGL context flags (0x00000001): forward-compatible
OpenGL context flags parsed by GLFW: forward-compatible
OpenGL profile mask (0x00000001): core
OpenGL profile mask parsed by GLFW: core
OpenGL context renderer string: "AMD Radeon R9 M370X OpenGL Engine"
OpenGL context vendor string: "ATI Technologies Inc."
OpenGL context shading language version: "4.10"
OpenGL framebuffer:
red: 8 green: 8 blue: 8 alpha: 8 depth: 24 stencil: 8
samples: 0 sample buffers: 0
Vulkan loader: missing
Since you use a core profile context (GLFW_OPENGL_CORE_PROFILE), the default Vertex Array Object 0 is not valid further you've to use Vertex Buffer Object.
When glVertexAttribPointer is called, then the vertex array specification is stored in the state vector of the currently bound vertex array object. The buffer which is currently bound to the target ARRAY_BUFFER is associated to the attribute and the name (value) of the object is stored in the state vector of the VAO.
In compatibility profile there exists the default vertex array object 0, which can be used at any time but this is not valid in a core profile context. Further it is not necessary in a compatibility profile to use a VBO, the last parameter of glVertexAttribPointer can be a pointer to the vertex data.
The easiest solution is to switch to a compatibility profile GLFW_OPENGL_COMPAT_PROFILE:
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
If you don't want to do that or your system doesn't provide that, then you've to read about Vertex Specification. Create a vertex buffer object a vertex array object before the program loop:
// vertex buffer object
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// vertex array object
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo); // this is not necessary, because "vbo" is still bound
glVertexAttribPointer(param_Position, 3, GL_FLOAT, (GLboolean) false, 0, nullptr);
// the following is not necessary, you can let them bound
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
And use it in the loop to draw the mesh:
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
Using GLFW, the C++ OpenGL ES code below calculates the square roots of five numbers and outputs them on the command line. The code makes use of Transform Feedback. When I compile on Ubuntu 17.10, using the following command, I get the result I expect:
$ g++ tf.cpp -lGL -lglfw
If I use Emscripten, however, an exception is thrown, which indicates that
glMapBufferRange is only supported when access is MAP_WRITE|INVALIDATE_BUFFER. I do want to read rather than write, so perhaps I shouldn't use glMapBufferRange, but what can I use instead? I have tried on both Firefox and Chromium. The command I use to compile with Emscripten is:
$ em++ -std=c++11 tf.cpp -s USE_GLFW=3 -s USE_WEBGL2=1 -s FULL_ES3=1 -o a.out.html
The code follows:
#include <iostream>
#define GLFW_INCLUDE_ES3
#include <GLFW/glfw3.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
static const GLuint WIDTH = 800;
static const GLuint HEIGHT = 600;
static const GLchar *vertex_shader_src =
"#version 300 es\n"
"precision mediump float;\n"
"in float inValue;\n"
"out float outValue;\n"
"void main() {\n"
" outValue = sqrt(inValue);\n"
"}\n";
// Emscripten complains if there's no fragment shader
static const GLchar *fragment_shader_src =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 colour;\n"
"void main() {\n"
" colour = vec4(1.0, 1.0, 0.0, 1.0);\n"
"}\n";
static const GLfloat vertices[] = {
0.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
};
GLint get_shader_prog(const char *vert_src, const char *frag_src = "")
{
enum Consts { INFOLOG_LEN = 512 };
GLchar infoLog[INFOLOG_LEN];
GLint fragment_shader, vertex_shader, shader_program, success;
shader_program = glCreateProgram();
auto mk_shader = [&](GLint &shader, const GLchar **str, GLenum shader_type) {
shader = glCreateShader(shader_type);
glShaderSource(shader, 1, str, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, INFOLOG_LEN, NULL, infoLog);
std::cout << "ERROR::SHADER::COMPILATION_FAILED\n" << infoLog << '\n';
}
glAttachShader(shader_program, shader);
};
mk_shader(vertex_shader, &vert_src, GL_VERTEX_SHADER);
mk_shader(fragment_shader, &frag_src, GL_FRAGMENT_SHADER);
const GLchar* feedbackVaryings[] = { "outValue" };
glTransformFeedbackVaryings(shader_program, 1, feedbackVaryings,
GL_INTERLEAVED_ATTRIBS);
glLinkProgram(shader_program);
glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader_program, INFOLOG_LEN, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << '\n';
}
glUseProgram(shader_program);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return shader_program;
}
int main(int argc, char *argv[])
{
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
GLFWwindow *window = glfwCreateWindow(WIDTH, HEIGHT, __FILE__, NULL, NULL);
glfwMakeContextCurrent(window);
GLuint shader_prog = get_shader_prog(vertex_shader_src, fragment_shader_src);
GLint inputAttrib = glGetAttribLocation(shader_prog, "inValue");
glViewport(0, 0, WIDTH, HEIGHT);
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLfloat data[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glVertexAttribPointer(inputAttrib, 1, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(inputAttrib);
GLuint tbo;
glGenBuffers(1, &tbo);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(data),
nullptr, GL_STATIC_READ);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
glEnable(GL_RASTERIZER_DISCARD);
glBeginTransformFeedback(GL_POINTS);
glDrawArrays(GL_POINTS, 0, 5);
glEndTransformFeedback();
glDisable(GL_RASTERIZER_DISCARD);
glFlush();
GLfloat feedback[5]{1,2,3,4,5};
void *void_buf = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER,0,
sizeof(feedback), GL_MAP_READ_BIT);
GLfloat *buf = static_cast<GLfloat *>(void_buf);
for (int i = 0; i < 5; i++)
feedback[i] = buf[i];
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
for (int i = 0; i < 5; i++)
std::cout << feedback[i] << ' ';
std::cout << std::endl;
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &tbo);
glDeleteVertexArrays(1, &vao);
glfwTerminate();
return 0;
}
As has been mentioned by another answer, WebGL 2.0 is close to OpenGL ES 3.0, but confusingly does not define glMapBufferRange() function, so that Emscripten tries emulating only part of functionality of this function.
Real WebGL 2.0, however, exposes glGetBufferSubData() analog, which does not exist in OpenGL ES, but exist in desktop OpenGL. The method can be wrapped in code via EM_ASM_:
void myGetBufferSubData (GLenum theTarget, GLintptr theOffset, GLsizeiptr theSize, void* theData)
{
#ifdef __EMSCRIPTEN__
EM_ASM_(
{
Module.ctx.getBufferSubData($0, $1, HEAPU8.subarray($2, $2 + $3));
}, theTarget, theOffset, theData, theSize);
#else
glGetBufferSubData (theTarget, theOffset, theSize, theData);
#endif
}
Fetching VBO data back is troublesome in multi-platform code:
OpenGL 1.5+
glGetBufferSubData(): YES
glMapBufferRange(): YES
OpenGL ES 2.0
glGetBufferSubData(): NO
glMapBufferRange(): NO
OpenGL ES 3.0+
glGetBufferSubData(): NO
glMapBufferRange(): YES
WebGL 1.0
glGetBufferSubData(): NO
glMapBufferRange(): NO
WebGL 2.0
glGetBufferSubData(): YES
glMapBufferRange(): NO
So that:
Desktop OpenGL gives maximum flexibility.
OpenGL ES 2.0 and WebGL 1.0 give no chance to retrieve data back.
OpenGL ES 3.0+ gives only mapping buffer.
WebGL 2.0 gives only getBufferSubData().
WebGL2 does not support MapBufferRange because it would be a security nightmare. Instead it supports getBufferSubData. I have no idea if that is exposed to WebAssembly in emscripten. Emscripten is emulating MapBufferRange for the cases you mentioned by using bufferData. See here and here
If getBufferSubData is not supported you can add it. See the code in library_gl.js for how readPixels is implemented and use that as inspiration for how to expose getBufferSubData to WebAssembly. Either that or add some inline JavaScript with the _EM_ASM. I haven't done it but googling for "getBufferSubData emscripten" bought up this gist
My computer runs Ubuntu 16.04 and is equipped with a Nvidia GeForce GT 630M graphics card with a proprietary driver installed. The glGetString(GL_VERSION) function shows that, by default, my graphics card supports OpenGL 4.5.
I have been following the Learn OpenGL tutorial series and I have the following difficulty: I can only get the tutorial's "Hello Triangle" program to run properly if I comment out the lines
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
Leaving those lines as-is will prevent the triangle from appearing.
I am having trouble understanding why setting a required OpenGL version lower than the OpenGL version my card can support would make the program fail.
EDIT: the commands
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;
output
Renderer: GeForce GT 630M/PCIe/SSE2
Version: 4.5.0 NVIDIA 361.42
Shading Language: 4.50 NVIDIA
if those lines are commented out, and
Renderer: GeForce GT 630M/PCIe/SSE2
Version: 3.3.0 NVIDIA 361.42
Shading Language: 3.30 NVIDIA via Cg compiler
if those lines are left in place.
EDIT2: Here's the actual source code:
#include <array>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
constexpr char FRAGMENT_SHADER_SOURCE_FILE[] = "simple_fragment.shader";
constexpr char VERTEX_SHADER_SOURCE_FILE[] = "simple_vertex.shader";
constexpr int WINDOW_WIDTH = 800;
constexpr int WINDOW_HEIGHT = 800;
constexpr char WINDOW_TITLE[] = "Triangle";
constexpr std::array<GLfloat, 4> bgColour { 0.3f, 0.1f, 0.3f, 1.0f };
/*
* Instructs GLFW to close window if escape key is pressed.
*/
void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mode);
int main() {
// Start GLFW.
if (not glfwInit()) {
std::cerr << "ERROR: Failed to start GLFW.\n";
return 1;
}
// Set OpenGL version.
//glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
//glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Create window and bind to current contex.
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 keyboard callback functions.
glfwSetKeyCallback(window, keyCallback);
// Initialize GLEW with experimental features turned on.
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
std::cerr << "ERROR: Failed to start GLEW.\n";
glfwTerminate();
return 1;
}
// Create viewport coordinate system.
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;
}
// Create a shader program by linking the vertex and fragment shaders.
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 triangle vertices in Normalized Device Coordinates (NDC).
std::array<GLfloat, 9> vertices {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
// Create a vertex array object.
GLuint vao;
glGenBuffers(1, &vao);
glBindVertexArray(vao);
// Create a vertex buffer object.
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Pass vertex data into currently bound vertex buffer object.
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(), GL_STATIC_DRAW);
// Create vertex attribute.
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), static_cast<GLvoid*>(0));
glEnableVertexAttribArray(0);
// Unbind the vertex array object and vertex buffer object.
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glClearColor(bgColour[0], bgColour[1], bgColour[2], bgColour[3]);
while (not glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT);
glfwPollEvents();
// Inform OpenGL to use the shader program created above.
glUseProgram(shaderProgram);
// Bind the vertex array object.
glBindVertexArray(vao);
// Draw the triangle.
glDrawArrays(GL_TRIANGLES, 0, 3);
// Unbind the vertex array object.
glBindVertexArray(0);
glfwSwapBuffers(window);
}
// Delete vertex array object.
glDeleteVertexArrays(1, &vao);
// Delete vertex buffer object.
glDeleteBuffers(1, &vbo);
// Delete shader program.
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);
}
}
Here are the contents of simple_vertex.shader and simple_fragment.shader:
#version 330 core
layout (location = 0) in vec3 position;
void main() {
gl_Position = vec4(position.x, position.y, position.z, 1.0);
}
and
#version 330 core
out vec4 color;
void main() {
color = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
I made a typo in my code.
I used the function glGenBuffers instead of glGenVertexArrays to create my vertex array object. Apparently Nvidia accepts this, unless I specify an OpenGL version. I still find it puzzling but at least the problem is fixed.