Is dynamically load shaders in OpenGL senseless? - c++

I just begin my journey in graphical computing, so I started by understanding this tutorial: https://learnopengl.com/Getting-started/Hello-Triangle.
Before adventuring myself to do some "dynamic" drawing I thought transform
this into a "Renderer" class would be interesting this was the result:
#pragma once
#include <fstream>
#include <vector>
#include "pch.h"
class Renderer {
public:
Renderer(GLFWwindow*);
void initVertexShaders(std::vector<std::string>&);
void initFragmentShaders(std::vector<std::string>&);
void load(float*, size_t);
void draw();
const GLubyte* renderer;
const GLubyte* version;
private:
GLFWwindow* window = nullptr;
GLuint vbo;
GLuint vao;
GLuint shaderProgram = 0; //= glCreateProgram();
GLuint vs[100];
GLuint fs[100];
};
pch.h is a precompiled header in order to not compile glm, glfw and glew everytime y build the project.
The idea was to isolate different utilities, I would use load(float*, size_t) to send information to the gpu, and draw() during the main window loop. The idea is to make a first approximation to a 2d, cameraless render engine.
Anyway, source code is:
#include "Renderer.hpp"
Renderer::Renderer(GLFWwindow* window) {
this->window = window;
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
glewInit();
this->renderer = glGetString(GL_RENDERER);
this->version = glGetString(GL_VERSION);
this->vao = 0;
this->vbo = 0;
}
void Renderer::load(float* points, size_t memory) {
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, memory, points, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
}
void Renderer::draw() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
void Renderer::initVertexShaders(std::vector<std::string>& paths) {
int i = 0;
std::ifstream ifs;
if(this->shaderProgram == 0) shaderProgram = glCreateProgram();
for (const auto& path : paths){
ifs.open(path);
std::string program_str(( std::istreambuf_iterator<char>(ifs)),
( std::istreambuf_iterator<char>() ));
const char* program_src = program_str.c_str();
vs[i] = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs[i], 1, &program_src, NULL);
glCompileShader(vs[i]);
glAttachShader(shaderProgram, vs[i]);
i++;
}
glLinkProgram(shaderProgram);
}
void Renderer::initFragmentShaders(std::vector<std::string>& paths) {
int i = 0;
std::ifstream ifs;
if(this->shaderProgram == 0) shaderProgram = glCreateProgram();
for (const auto& path : paths){
ifs.open();
std::string program_str(( std::istreambuf_iterator<char>(ifs)),
( std::istreambuf_iterator<char>() ));
const char* program_src = program_str.c_str();
fs[i] = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs[i], 1, &program_src, NULL);
glCompileShader(fs[i]);
glAttachShader(shaderProgram, fs[i]);
i++;
}
glLinkProgram(shaderProgram);
}
The problem comes at shader time, I can read the files without problem, but they do nothing.
The questions are: Does store all the shaders in an array make sense?
Can a shader program consist in more than one vertex shader/fragment shader?
Is the error in another spot?
Does the whole class make sense in any way?
Thank you.
edit: Code from main.cpp
#include "Renderer.hpp"
float points[] = {
0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
//
0.5f, 0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f
};
int main() {
std::vector<std::string> vertexShaders;
std::vector<std::string> fragmentShaders;
vertexShaders.push_back("shader/vs.glsl");
fragmentShaders.push_back("shader/fs.glsl");
glfwInit(); //glfwGetPrimaryMonitor()
GLFWwindow *window = glfwCreateWindow(960, 540, "Hello Triangle", NULL, NULL);
Renderer Ren(window);
Ren.load(points, sizeof(points));
Ren.initVertexShaders(vertexShaders);
Ren.initFragmentShaders(fragmentShaders);
while (!glfwWindowShouldClose(window)) {
Ren.draw();
glfwPollEvents();
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}

It is sufficient to link the shader program object once, after all attached shader objects have been compiled.
OpenGL 4.6 API Core Profile Specification; 7.3. PROGRAM OBJECTS; page 94:
Shader objects may be attached to program objects before source code has been loaded into the shader object, or before the shader object has been compiled or specialized.
Note, it is sufficient that the shader object is successfully compiled, before the shader program object, where it is attached to, gets linked.
OpenGL 4.6 API Core Profile Specification; 7.3. PROGRAM OBJECTS; page 94:
Multiple shader objects of the same type may be attached to a single program object, and a single shader object may be attached to more than one program object.
e.g.
One shader object contains a function (FragColor)
#version 460
uniform sampler2D u_texture;
vec4 FragColor(vec2 uv)
{
return texture(u_texture, uv);
}
A second shader object of the same type contains the function signature (but not the implementation) and the usage of the function.
#version 460
in vec2 vUV;
out vec4 fragColor;
vec4 FragColor(vec2 uv);
void main()
{
fragColor = FragColor(vUV);
}
Both of the above code snippets can be placed to 2 separate shader objects of type GL_FRAGMENT_SHADER. Each of the 2 shader objects can be successfully compiled. And if they are attached to the same shader program object, then the shader program object can be successfully liked.
See also Attaching multiple shaders of the same type in a single OpenGL program?
Further, I recommend to check if a shader object was successfully compiled:
GLuint shaderObj = .... ;
glCompileShader( shaderObj );
GLint status = GL_TRUE;
glGetShaderiv( shaderObj, GL_COMPILE_STATUS, &status );
if ( status == GL_FALSE )
{
GLint logLen;
glGetShaderiv( shaderObj, GL_INFO_LOG_LENGTH, &logLen );
std::vector< char >log( logLen );
GLsizei written;
glGetShaderInfoLog( shaderObj, logLen, &written, log.data() );
std::cout << "compile error:" << std::endl << log.data() << std::endl;
}
and a shader program object was successfully linked:
GLuint progObj = ....;
glLinkProgram( progObj );
GLint status = GL_TRUE;
glGetProgramiv( progObj, GL_LINK_STATUS, &status );
if ( status == GL_FALSE )
{
GLint logLen;
glGetProgramiv( progObj, GL_INFO_LOG_LENGTH, &logLen );
std::vector< char >log( logLen );
GLsizei written;
glGetProgramInfoLog( progObj, logLen, &written, log.data() );
std::cout << "link error:" << std::endl << log.data() << std::endl;
}

Related

glAttribLocation returning -1 even though vertex shader is actively using that

Searched Stack Overflow for similar questions in search of my solution , but it doesn't seem to be solved.
main.cpp :
#include"reader.h"
#include"window.h"
#include"shader.h"
int main() {
float vertices[] = {
-0.5f, -0.5f, 0.0f ,
0.5f, -0.5f, 0.0f ,
0.0f, 0.5f, 0.0f
};
Window window;
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
Shader shader;
shader.addShader("./src/shaders/basic.vtx",GL_VERTEX_SHADER);
shader.addShader("./src/shaders/basic.frg", GL_FRAGMENT_SHADER);
shader.compile();
shader.enable();
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices,GL_STATIC_DRAW);
GLint pos_in = glGetAttribLocation(shader.getProgram(), "pos_in");
if (pos_in < 0) {
std::cout << "pos_in not found\n";
}
glVertexAttribPointer(pos_in, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
glEnableVertexAttribArray(pos_in);
while (!window.closed()) {
window.update();
glDrawArrays(GL_TRIANGLES,0,3);
}
return 0;
}
shader.h :
#pragma once
#include<glad/glad.h>
#include<iostream>
#include<vector>
#include"reader.h"
class Shader {
std::vector<GLuint*> shaders;
GLuint program;
public :
GLuint& getProgram() {
return program;
}
Shader() {
program = glCreateProgram();
}
void addShader(const char * path, GLenum type) {
std::string data = ShaderReader(path).read_shader();
const char * chardata = data.c_str();
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &chardata , nullptr);
glCompileShader(shader);
int success;
char buffer[512];
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 512, NULL, buffer);
std::cout << buffer << std::endl;
return;
}
std::cout << "shader inserted into vector\n";
shaders.push_back(&shader);
}
void compile(){
for (int i = 0; i != shaders.size();i++) {
glAttachShader(program, *shaders[i]);
}
glLinkProgram(program);
glValidateProgram(program);
glUseProgram(program);
int status;
glGetProgramiv(program, GL_COMPILE_STATUS, &status);
char buffer[512];
if (!status) {
glGetProgramInfoLog(program,512,NULL,buffer);
std::cout << buffer << std::endl;
return;
}
std::cout << "shader compilation successful\n";
}
void enable() {
glUseProgram(program);
}
void disable() {
glUseProgram(0);
}
~Shader() {
for (int i = 0; i != shaders.size();i++) {
glDeleteShader(*shaders[i]);
}
}
};
vertex shader written in basic.vtx:
#version 400
layout (location = 0 ) in vec3 pos_in ;
void main(){
gl_Position = vec4(pos_in.x , pos_in.y , pos_in.z , 1.0f);
}
fragment shader written in basic.frg :
#version 400
out vec4 color;
void main(){
color = vec4(0.0f, 0.5f , 0.5f , 1.0f);
}
At the time of calling glGetAttribLocation , the vertex shader IS USING pos_in attrib to set gl_Position , yet it returns -1 .
Also the triangle is not rendered when calling glGetAttribLocation() ; or rendered white with direct attrib pointer values like 0 , 1 with an openGL 1281 error.
One thing that is definitely not valid is the shaders.push_back(&shader):
void addShader(const char * path, GLenum type) {
// ....
GLuint shader = glCreateShader(type);
// ....
shaders.push_back(&shader);
}
With the shaders.push_back(&shader) you push back the address of a local variable to the shaders vector. So the glAttachShader(program, *shaders[i]); will result in undefined behavior.
shader holds only an numeric id so there is no need to get a pointer to that, just change the std::vector<GLuint*> shaders to std::vector<GLuint> shaders, use shaders.push_back(shader) and replace all *shaders[i] with shaders[i]
The reason why you don't get an linking error is most likely because the content at the address you get from &shader is not overwritten before you do the glAttachShader(program, *shaders[i]), and that both entries in the shaders vector hold same address of the stack. The result of is that glAttachShader is called each time on the same id, so you bind only the fragement shader to the program.

Getting OpenGL ES Transform Feedback data back to the host using Emscripten

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

SFML - Opengl VAO issue giving me an (1282) error

I am getting an error when trying to use VAO's inside of SFML and not sure if it is SFML or it is my own opengl code
GLenum err = glewInit();
if (err != GLEW_OK)
{
std::cout << "NOT WORKING" << std::endl;
}
std::vector<sf::Vector3f> g_vertext_buffer_data;
g_vertex_buffer_data.push_back({ -1.0f, -1.0f, 0.0f });
g_vertex_buffer_data.push_back({1.0f, -1.0f, 0.0f});
g_vertex_buffer_data.push_back({ 0.0f, 1.0f, 0.0f });
const char* vertexShaderSource =
"#version 330\n\
in vec4 position;\
void main(void){\ gl_Position = position;\
}";
// compile fragment shader source
const GLchar* fragmentShaderSource =
"#version 330\n\
void main(void) {\
out vec4 fragcolor; fragcolor= vec4(1.0,1.0,1.0,1.0);\
}";
/* Creating Shader */
this->programId = glCreateProgram();
this->vId = glCreateShader(GL_VERTEX_SHADER);
this->fId = glCreateShader(GL_FRAGMENT_SHADER);
/* Get Shader Size */
int vertexShaderLength = strlen(vertexShaderSource);
int fragmentShaderLength = strlen(fragmentShaderSource);
/* Loading and binding shader */
glShaderSource(this->vId, 1, &vertexShaderSource, NULL);
glShaderSource(this->fId, 1, &fragmentShaderSource, NULL);
/* Compile Shaders */
glCompileShader(vId);
glCompileShader(fId);
/* Attach Shaders */
glAttachShader(this->programId, this->vId);
glAttachShader(this->programId, this->fId);
/* Linkg program */
glLinkProgram(this->programId);
/* Use and bind attribute */
glUseProgram(this->programId);
this->positionId = glGetAttribLocation(this->programId, "position");
glUseProgram(0);
/* VAO Time */
glGenVertexArrays(1, &this->vaoId);
glBindVertexArray(this->vaoId);
/* VBO Time assigning to VAO */
glGenBuffers(1, &this->vboId);
glBindBuffer(GL_ARRAY_BUFFER, this->vboId);
glBufferData(GL_ARRAY_BUFFER, g_vertex_buffer_data.size() * sizeof(sf::Vector3f), &g_vertex_buffer_data[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(this->positionId);
glVertexAttribPointer(this->positionId, 2, GL_FLOAT, GL_FALSE, sizeof(sf::Vector3f), 0);
/* Close out bindings */
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
while(1)
{
glUseProgram(this->programId);
glBindVertexArray(this->vaoId);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glUseProgram(0);
gameWindow.glPushStates();
}
The error code I get is: opengl error in user code (1282)​
I have changed the size() issue that was brought up in the blBufferData() but still am getting the issue.
There is at least a problem with the size that is passed to glBufferData:
glBufferData(GL_ARRAY_BUFFER,
sizeof(g_vertex_buffer_data) * sizeof(sf::Vector3f),
g_vertex_buffer_data[0], GL_STATIC_DRAW);
sizeof(g_vertex_buffer_data) is equal to sizeof(std::vector<?>) which is the size of the vector object and not the size of the data contained. Try using
glBufferData(GL_ARRAY_BUFFER,
g_vertex_buffer_data.size() * sizeof(sf::Vector3f),
g_vertex_buffer_data[0], GL_STATIC_DRAW);
Another thing: In OpenGL 3.3 Core Profile there is no gl_FragColor variable. You will have to define an out variable.
Next: Your vertex shader seems to be empty. You have to write to gl_Position otherwise nothing will be shown.
Possible error codes for glGetAttribLocation are:
GL_INVALID_OPERATION
Which don't have a fixed value. Try to get the error string with gluErrorString() or take a look in the header to which of those 1282 maps.
• check your shader got compiled without error?
• check your shader got linked without error?
What type have positionId? All object id's must be GLuint type.
And btw allways enable shader compilation-linking error check, and debug will be more informative.
I do that in this way (OpenGL-ES 2.0):
m_nVertexShader = glCreateShader(GL_VERTEX_SHADER);
m_nPixelShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(m_nVertexShader, 1, &lpszVertexBuffer, NULL);
glShaderSource(m_nPixelShader, 1, &lpszFragmentBuffer, NULL);
glCompileShader(m_nVertexShader);
int iIsOk = 0;
glGetShaderiv(m_nVertexShader, GL_COMPILE_STATUS, &iIsOk);
if(!iIsOk)
{
GLint infoLen = 0;
glGetShaderiv(m_nVertexShader, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen > 1)
{
char* infoLog = (char*)malloc(sizeof(char) * infoLen);
glGetShaderInfoLog(m_nVertexShader, infoLen, NULL, infoLog);
QMessageBox::warning(this, QString("Error"),
QString(infoLog), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes);
free(infoLog);
}
glDeleteShader(m_nVertexShader);
return;
}
glCompileShader(m_nPixelShader);
glGetShaderiv(m_nPixelShader, GL_COMPILE_STATUS, &iIsOk);
if(!iIsOk)
{
GLint infoLen = 0;
glGetShaderiv(m_nPixelShader, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen > 1)
{
char* infoLog = (char*)malloc(sizeof(char) * infoLen);
glGetShaderInfoLog(m_nPixelShader, infoLen, NULL, infoLog);
QMessageBox::warning(this, QString("Error"),
QString(infoLog), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes);
free(infoLog);
}
glDeleteShader(m_nPixelShader);
return;
}
m_nProgram = glCreateProgram();
glAttachShader(m_nProgram, m_nVertexShader);
glAttachShader(m_nProgram, m_nPixelShader);
glBindAttribLocation(m_nProgram, 0, "rm_Vertex");
glLinkProgram(m_nProgram);
glGetProgramiv(m_nProgram, GL_LINK_STATUS, &iIsOk);
// Fail to pass status validation
if(!iIsOk)
{
GLint infoLen = 0;
glGetProgramiv(m_nProgram, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen > 1)
{
char* infoLog = (char*)malloc(sizeof(char) * infoLen);
glGetProgramInfoLog(m_nProgram, infoLen, NULL, infoLog);
QMessageBox::warning(this, QString("Error"),
QString(infoLog), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes);
free(infoLog);
}
glDeleteProgram(m_nProgram);
return;
}
glUseProgram(m_nProgram);
As you use GLSL 3.3, fist you must specify fragment rendertarget output by calling
glBindFragDataLocation(this->programId, 0, "fragcolor");
Secondly your fragment shader must be like
"#version 330
out vec4 fragcolor;
void main(void) {
fragcolor= vec4(1.0,1.0,1.0,1.0);
}
The example of using this kind of shaders is on OpenGL 3.3 + GLSL 1.5 Sample.

Opengl 3.3 doesn't draw anything. Using GLSL 330 Core

I am following the guides from this site and have stopped on the lesson 2. At first I have tried wiriting my own code but after it didn't work I have simply taken the code from the site. And it still doesn't draw anything besides the glClearColor.
What I have done:
Checked compiling and linking. Works fine
Checked errors. Not sure if I have done it right but seems like everything's allright (I get a 1280 error but I have read that GLEW can cause it and it can be ignored).
Moved the glUseProgram through the main loop but didn't get any results.
Changed colors and tried modifying shaders. Still nothing
I will post the code I have at the moment (the original code from the site):
main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <glew.h>
#include <glfw3.h>
#include <glm/glm.hpp>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
int max(int i, int j)
{
if (i > j) return i;
return j;
}
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();
}
// 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\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(max(InfoLogLength, int(1)));
std::cout << "Checking program\n";
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
std::cout << "END";
return ProgramID;
}
int main(void)
{
if (!glfwInit())
{
std::cout << "Cannot init glfw";
return -1;
}
//glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want OpenGL 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //We don't want the old OpenGL
// Open a window and create its OpenGL context
GLFWwindow* window; // (In the accompanying source code, this variable is global)
window = glfwCreateWindow(1024, 768, "Tutorial 01", NULL, NULL);
if (window == NULL){
fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window); // Initialize GLEW
glewExperimental = GL_TRUE; // Needed in core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
return -1;
}
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
// This will identify our vertex buffer
GLuint vertexbuffer;
// Generate 1 buffer, put the resulting identifier in vertexbuffer
glGenBuffers(1, &vertexbuffer);
// The following commands will talk about our 'vertexbuffer' buffer
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
// Give our vertices to OpenGL.
static const GLfloat g_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f
};
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
GLuint programID = LoadShaders("res\\vertex.glsl", "res\\fragment.glsl");
do{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(programID);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangle !
glDrawArrays(GL_TRIANGLES, 0, 3); // Starting from vertex 0; 3 vertices total -> 1 triangle
glDisableVertexAttribArray(0);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
} // Check if the ESC key was pressed or the window was closed
while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0);
return 0;
}
fragment.glsl
#version 330 core
out vec3 color;
void main(){
color = vec3(1,1,0);
}
vertex.glsl
#version 330 core
layout(location = 0) in vec3 vertexPosition_modelspace;
void main(){
gl_Position.xyz = vertexPosition_modelspace;
gl_Position.w = 1.0;
}
The OpenGL Core Profile requires the use of Vertex Array Objects (VAOs). This is in the "Deprecated and Removed Features" of the spec:
Client vertex and index arrays - all vertex array attribute and element array index pointers must refer to buffer objects. The default vertex array object (the name zero) is also deprecated. Calling VertexAttribPointer when no buffer object or no vertex array object is bound will generate an INVALID_OPERATION error, as will calling any array drawing command when no vertex array object is bound.
The tutorial you are using suggests to use this code as part of your initialization:
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
This will be enough to get the tutorial code working. To make productive use of VAOs in more complex applications, you will probably want to create a VAO for each object. This will then track the full vertex setup state for the object, and allow you to set the state with a single glBindVertexArray() call before drawing.

Opengl Sierpinski Shader based C code in Visual Studio2012 & 2010

I'm doing my first steps in OpenGl Shader base programming and computer graphics. I'm trying the following example, but when I try to compile the project I got the following error:
fragment shader failed to link. vertex shader failed to link.
ERROR: Not all shaders has valid object code
i tried running the program in Visual Studio 2012 and 2010. glut library version is 3.7 and glew library version is 1.10.0. what is the problem?
.cpp Program
#include <stdio.h>
#include <stdlib.h>
#include <glew.h>
#include <glut.h>
#include <gl.h>
#pragma comment(lib,"glew32.lib")
#define NoP 50000
GLuint InitShader(char *, char *);
void mydisplay();
struct points
{ GLfloat x,y,z;
};
void init();
void Sierpinski(points Num[]);
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE|GLUT_DEPTH);
glutInitWindowSize(600, 600);
glutInitWindowPosition(0,0);
glutCreateWindow("Sierpinski 3D");
glewInit();
init();
glEnable(GL_DEPTH_TEST);
glutDisplayFunc(mydisplay);
glutMainLoop();
}
void init()
{
points Num[NoP];
Sierpinski(Num);
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);//set the color for clearing the display
glPointSize(2); // set the point size
// Creating a program object containing shader files
GLuint program;
program = InitShader("vshader.glsl","fshader.glsl");
glUseProgram(program);
//Creating a buffer object containing Sirepinski verteces data
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Num), Num, GL_STATIC_DRAW);
//Make a conncetion between data in object buffer and "vPosition in vertex shader
GLuint location = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray ( location );
glVertexAttribPointer( location, 3, GL_FLOAT, GL_FALSE,0, 0);//BUFFER_OFFSET(0));
}
void mydisplay()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //the clear call will affect the color buffer
glDrawArrays(GL_POINTS,0,NoP);//Rendering verteces data
glFlush(); //Empty all commands buffer, causing all issued commands to be executed as quickly as they are accepted by the actual rendering engine
}
static char * ReadShaderSource(char * ShaderFile)
{
FILE *fp;
fp = fopen(ShaderFile,"rt");
if (!fp) return NULL;
long size=0;
while (!feof(fp))
{
fgetc (fp);
size++;
}
size--;//EOF should not be counted
fseek(fp, 0, SEEK_SET);
char * buf= new char[size + 1];
fread(buf, 1, size,fp);
buf[size]=0;// string is NULL terminated
fclose(fp);
return buf;
}
GLuint InitShader(char * vShaderFile, char * fShaderFile)
{
char * svs, * sfs;
GLuint program, VertexShader, FragmentShader;
program = glCreateProgram();
VertexShader = glCreateShader(GL_VERTEX_SHADER);
svs=ReadShaderSource(vShaderFile);
glShaderSource(VertexShader,1,(const GLchar **)&svs,NULL);
glCompileShader(VertexShader);
// reading GLSL compiler error messages for vertex shader
GLint compiled;
glGetShaderiv(VertexShader, GL_COMPILE_STATUS, &compiled);
if(!compiled)
{ printf("/n failed to compile");
GLint logSize;
glGetShaderiv(VertexShader, GL_INFO_LOG_LENGTH,&logSize);
char * logMsg = new char[logSize];
glGetShaderInfoLog(VertexShader, logSize, NULL, logMsg);
printf("\n %s",logMsg);
delete [] logMsg;
getchar();
exit(EXIT_FAILURE);
}
FragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
sfs = ReadShaderSource(fShaderFile);
glShaderSource(FragmentShader, 1, (const GLchar **)&sfs, NULL);
glCompileShader(FragmentShader);
// reading GLSL compiler error messages for fragment shader
glGetShaderiv(FragmentShader, GL_COMPILE_STATUS, &compiled);
if(!compiled)
{ printf("\n failed to compile");
GLint logSize2;
glGetShaderiv(FragmentShader, GL_INFO_LOG_LENGTH,&logSize2);
char * logMsg2 = new char[logSize2];
glGetShaderInfoLog(FragmentShader, logSize2, NULL, logMsg2);
printf("\n %s",logMsg2);
delete [] logMsg2;
getchar();
exit(EXIT_FAILURE);
}
glAttachShader(program,VertexShader);
glAttachShader(program, FragmentShader);
glLinkProgram(program);
// reading GLSL linker error messages for program object
GLint linked;
glGetProgramiv(program, GL_LINK_STATUS, &linked);
if(!linked)
{ printf("/n failed to link");
GLint logSize;
glGetProgramiv(program, GL_INFO_LOG_LENGTH,&logSize);
char * logMsg = new char[logSize];
glGetProgramInfoLog(program, logSize, NULL, logMsg);
printf("\n %s",logMsg);
delete [] logMsg;
getchar();
exit(EXIT_FAILURE);
}
glUseProgram(program);
return program;
}
void Sierpinski(points Num[])
{
int j;
points Vertices[4]={{-1.0,-1.0, -1.0},{1.0,-1.0,-1.0},{0.0,1.0,-1.0},{0.0,0.0,1.0}};
Num[0].x = 0;
Num[0].y = 0;
Num[0].z = 0;
for(int i=1;i<NoP;i++)
{
j = rand() % 4;
Num[i].x = (Vertices[j].x + Num[i - 1].x)/2;
Num[i].y = (Vertices[j].y + Num[i - 1].y)/2;
Num[i].z = (Vertices[j].z + Num[i - 1].z)/2;
}
}
vshader.glsl
#version 130
in vec4 vPosition;
out vec4 color;
void main()
{
gl_Position = vPosition;
color = vPosition;
}
fshader.glsl
#version 130
in vec4 color;
void main()
{
gl_FragColor = vec4((1.0 + color.xyz)/2.0,1.0);
}
Seems to work fine:
#include <GL/glew.h>
#include <GL/glut.h>
#include <iostream>
void CheckStatus( GLuint obj )
{
GLint status = GL_FALSE;
if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
if( status == GL_TRUE ) return;
GLchar log[ 1 << 17 ] = { 0 };
if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
std::cerr << log << std::endl;
exit( -1 );
}
void AttachShader( GLuint program, GLenum type, const char* src )
{
GLuint shader = glCreateShader( type );
glShaderSource( shader, 1, &src, NULL );
glCompileShader( shader );
CheckStatus( shader );
glAttachShader( program, shader );
glDeleteShader( shader );
}
GLuint LoadProgram( const char* vert, const char* geom, const char* frag )
{
GLuint prog = glCreateProgram();
if( vert ) AttachShader( prog, GL_VERTEX_SHADER, vert );
if( geom ) AttachShader( prog, GL_GEOMETRY_SHADER, geom );
if( frag ) AttachShader( prog, GL_FRAGMENT_SHADER, frag );
glLinkProgram( prog );
CheckStatus( prog );
return prog;
}
#define GLSL(version, shader) "#version " #version "\n" #shader
const char* vert = GLSL
(
130,
in vec4 vPosition;
out vec4 color;
void main()
{
gl_Position = vPosition;
color = vPosition;
}
);
const char* frag = GLSL
(
130,
precision mediump float;
in vec4 color;
void main()
{
gl_FragColor = vec4((1.0 + color.xyz)/2.0,1.0);
}
);
#define NoP 50000
struct points
{
GLfloat x,y,z;
};
void Sierpinski(points Num[])
{
int j;
points Vertices[4]={{-1.0,-1.0, -1.0},{1.0,-1.0,-1.0},{0.0,1.0,-1.0},{0.0,0.0,1.0}};
Num[0].x = 0;
Num[0].y = 0;
Num[0].z = 0;
for(int i=1;i<NoP;i++)
{
j = rand() % 4;
Num[i].x = (Vertices[j].x + Num[i - 1].x)/2;
Num[i].y = (Vertices[j].y + Num[i - 1].y)/2;
Num[i].z = (Vertices[j].z + Num[i - 1].z)/2;
}
}
void init()
{
points Num[NoP];
Sierpinski(Num);
GLuint program = LoadProgram( vert, NULL, frag );
glUseProgram(program);
//Creating a buffer object containing Sirepinski verteces data
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Num), Num, GL_STATIC_DRAW);
//Make a conncetion between data in object buffer and "vPosition in vertex shader
GLuint location = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray ( location );
glVertexAttribPointer( location, 3, GL_FLOAT, GL_FALSE,0, 0);//BUFFER_OFFSET(0));
}
void mydisplay()
{
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);//set the color for clearing the display
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //the clear call will affect the color buffer
glPointSize(2); // set the point size
glDrawArrays(GL_POINTS,0,NoP);//Rendering verteces data
glutSwapBuffers();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE|GLUT_DEPTH);
glutInitWindowSize(600, 600);
glutInitWindowPosition(0,0);
glutCreateWindow("Sierpinski 3D");
glewInit();
init();
glEnable(GL_DEPTH_TEST);
glutDisplayFunc(mydisplay);
glutMainLoop();
}
Make sure you use FreeGLUT, Nate's GLUT is way, way old.