I am trying to experiment using basic shaders in my program, I came across a nice tutorial that talks you through writing a basic shader "util class" i guess you would call it? Which should allow me to apply a vertex and fragment shader...So I linked glew to my project (i have also glu, glut and glaux included) and inserted the following into a header file
#include "include\gl\glew.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
static struct {
/* ... fields for buffer and texture objects */
GLuint vertex_shader, fragment_shader, program;
struct {
GLint fade_factor;
GLint textures[2];
} uniforms;
struct {
GLint position;
} attributes;
GLfloat fade_factor;
} g_resources;
static GLuint make_shader(GLenum type, const char *filename)
{
GLint length;
char *source = file_content(filename, &length);
GLuint shader;
GLint shader_ok;
if (!source)
return 0;
shader = glCreateShader(type);
glShaderSource(shader, 1, (const GLchar**)&source, &length);
free(source);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok);
if (!shader_ok) {
fprintf(stderr, "Failed to compile %s:\n", filename);
show_info_log(shader, glGetShaderiv, glGetShaderInfoLog);
glDeleteShader(shader);
return 0;
}
return shader;
}
static void show_info_log(
GLuint object,
PFNGLGETSHADERIVPROC glGet__iv,
PFNGLGETSHADERINFOLOGPROC glGet__InfoLog)
{
GLint log_length;
char *log;
glGet__iv(object, GL_INFO_LOG_LENGTH, &log_length);
log = malloc(log_length);
glGet__InfoLog(object, log_length, NULL, log);
fprintf(stderr, "%s", log);
free(log);
}
static GLuint make_program(GLuint vertex_shader, GLuint fragment_shader)
{
GLint program_ok;
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &program_ok);
if (!program_ok) {
fprintf(stderr, "Failed to link shader program:\n");
show_info_log(program, glGetProgramiv, glGetProgramInfoLog);
glDeleteProgram(program);
return 0;
}
return program;
}
static int make_resources(void)
{
/* make buffers and textures ... */
g_resources.vertex_shader = make_shader(
GL_VERTEX_SHADER,
"hello-gl.v.glsl"
);
if (g_resources.vertex_shader == 0)
return 0;
g_resources.fragment_shader = make_shader(
GL_FRAGMENT_SHADER,
"hello-gl.f.glsl"
);
if (g_resources.fragment_shader == 0)
return 0;
g_resources.program = make_program(
g_resources.vertex_shader,
g_resources.fragment_shader
);
if (g_resources.program == 0)
return 0;
g_resources.uniforms.fade_factor
= glGetUniformLocation(g_resources.program, "fade_factor");
g_resources.uniforms.textures[0]
= glGetUniformLocation(g_resources.program, "textures[0]");
g_resources.uniforms.textures[1]
= glGetUniformLocation(g_resources.program, "textures[1]");
g_resources.attributes.position
= glGetAttribLocation(g_resources.program, "position");
return 1;
}
But my compiler complains about the following:
9 IntelliSense: "GLchar" is not a type name
11 IntelliSense: a value of type "void *" cannot be assigned to an entity of type "char *"
7 IntelliSense: identifier "file_contents" is undefined
5 IntelliSense: identifier "GLchar" is undefined
Am I missing something? I searched the internet and it seems like GLchar and the file_contents function do exist?
The error line you gave is the compiler telling you, that it doesn't know about the type GLchar, which is defined in GL/gl.h – or GL/glew.h in your case, which also defines it. But it seems to be not properly included.
Your first line should be
#include <GL/glew.h>
i.e. uppercae GL, a forward slash (backslashes are a Microsoaft addition, but forwards are accepted just fine), and the whole thing in angle brackets, as you want to include from the standard includes.
Next you should not link against glaux. That one is so outdated that it's become toxic.
If you want a working OpenGL shader example program, I prepared one at https://github.com/datenwolf/codesamples/tree/master/samples/OpenGL/minimal_glsl
Related
I am currently working on a OpenGL Shader class, that uses SPIR-V to compile the shaders. Getting the compiled binaries from SPIR-V works fine, the problem is, that my program crashes with the OpenGL exception GL_INVALID_OPERATION error generated. <program> has not been linked, or is not a program object. when trying to bind the Shader with glUseProgram(m_RendererID).
This is my shader creation function:
void OpenGLShader::LoadAndCreateShaders(const std::unordered_map<GLenum, std::vector<uint32>> &shaderData)
{
if (m_RendererID)
glDeleteProgram(m_RendererID);
GLuint program = glCreateProgram();
m_RendererID = program;
std::vector<GLuint> shaderRendererIds;
shaderRendererIds.reserve(shaderData.size());
for (auto &[stage, data] : shaderData)
{
GLuint shaderId = glCreateShader(stage);
glShaderBinary(1, &shaderId, GL_SHADER_BINARY_FORMAT_SPIR_V, data.data(), (uint32)data.size());
glSpecializeShader(shaderId, "main", 0, nullptr, nullptr);
glAttachShader(program, shaderId);
GLint status;
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
std::cout << "Shader compilation failed" << std::endl;
}
shaderRendererIds.emplace_back(shaderId);
}
// Link shader program
glLinkProgram(program);
int32 isLinked = 0;
glGetProgramiv(program, GL_LINK_STATUS, (int32*)&isLinked);
if (isLinked == GL_FALSE)
{
int32 maxLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
if (maxLength > 0)
{
std::vector<GLchar> infoLog(maxLength);
glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
std::cout << "Shader linking failed: " << &infoLog[0] << std::endl;
glDeleteProgram(program);
for (auto id : shaderRendererIds)
glDeleteShader(id);
}
}
for (auto id : shaderRendererIds)
glDetachShader(program, id);
}
This function basically takes in the compiled sources from SPIR-V and tries to create the OpenGL shader. When I debugged the program, I found out that after glLinkProgram() isLinked stays 0, but the maxLength variable stays also 0. So the linking process failed, but didn't give an error. Did anyone have the same issue before?
I'm working off a code base that I know compiles correctly. Currently, I've introduced a purposeful spelling mistake into my shader to simulate an error. At this point, the code refuses to compile. I can then call
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, ¶ms);
to find that params is now 108 where is was previously 0, so I know that there is a log associated with this shader (which I have tried to compile). However, when I call
glGetProgramInfoLog(shader, 512, &size, ErrorLog);
size returns 0, and ErrorLog is still empty.
Here's the important code in this situation:
void Shader::AddShader(GLuint ShaderProgram, const char* pShaderText, GLenum ShaderType)
{
GLuint ShaderObj = glCreateShader(ShaderType);
if (ShaderObj == 0) {
fprintf(stderr, "Error creating shader type %d\n", ShaderType);
exit(1);
}
const char* pShaderSource = readShaderSource(pShaderText);
glShaderSource(ShaderObj, 1, (const GLchar**)&pShaderSource, NULL);
glCompileShader(ShaderObj);
checkCompileError(ShaderObj, ShaderType);
glAttachShader(ShaderProgram, ShaderObj);
}
bool Shader::checkCompileError(GLuint shader, GLenum ShaderType)
{
GLint params = -1;
GLchar ErrorLog[512] = { 0 };
GLint size = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, ¶ms);
if (GL_TRUE != params) {
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, ¶ms);
glGetProgramInfoLog(shader, 512, &size, ErrorLog);
fprintf(stderr, "Error compiling shader type %d: '%s'\n", ShaderType, ErrorLog);
exit(1);
}
return true;
}
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, ¶ms);
glGetProgramInfoLog(shader, 512, &size, ErrorLog);
^^^^^^^ should be Shader
You're compiling & checking a shader so you should use glGetShaderInfoLog().
glGetProgramInfoLog() is for grabbing the link log of the complete shader program object you get from glCreateProgram()
I am currently attempting to write a basic graphics engine with OpenGl and C++. In doing so, OpenGl is behaving in a very strange way with no apparent explanation. It claims that a shader failed to compile, but then refuses to give any sort of error explaining why. Specifically, when I call glGetProgramiv the returned value is 0, but glGetProgramInfoLog gives an empty string¹.
Here is a minimum complete verifiable example:
#include <SDL2/SDL.h>
#include <GL/glew.h>
#include <sstream>
#include <stdexcept>
#include <fstream>
GLuint loadShader(const std::string &path, GLenum type);
int main(int argc, char *argv[]){
//show window & other housekeeping
SDL_Init(SDL_INIT_EVERYTHING);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_Window *window = SDL_CreateWindow("test window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
SDL_GLContext glContext = SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, glContext);
GLenum c = glewInit();
if(c != GLEW_OK){
std::ostringstream sout;
sout << "Failed to initialize OpenGl: " << glewGetErrorString(c);
throw std::runtime_error(sout.str());
}
//**** -- BEGIN IMPORTANT BIT -- ****//
//This is where the shaders are loaded
//load shaders
GLuint vertexShader = loadShader("shader.vert", GL_VERTEX_SHADER);
GLuint fragmentShader = loadShader("shader.frag", GL_FRAGMENT_SHADER);
//create & link program
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
//check for errors
GLint success;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if(!success){
GLchar infoLog[512];
GLint size; //gives 0 when checked in debugger
glGetProgramInfoLog(program, 512, &size, infoLog);
throw std::runtime_error(std::string("Failed to link shader program: ") + infoLog);
}
//cleanup
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
//**** -- END IMPORTANT BIT -- ****//
//update loop
bool isClosed = false;
while(!isClosed){
SDL_GL_SwapWindow(window);
SDL_Event e;
while(SDL_PollEvent(&e)){
switch(e.type){
case SDL_QUIT:
isClosed = true;
break;
}
}
}
}
GLuint loadShader(const std::string &path, GLenum type){
//load file
std::ifstream fin(path);
std::string line, total = "";
while(std::getline(fin, line)){
total += (line + "\n");
}
//reformat source into OpenGl's ridiculous format
const char *cArray = total.c_str();
const char **pointerToCArray = &cArray;
//create shader
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, pointerToCArray, nullptr);
glCompileShader(shader);
//check for erros
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if(!success){
GLchar infoLog[512];
glGetShaderInfoLog(shader, 512, nullptr, infoLog);
throw std::runtime_error(std::string("Failed to compile shader: ") + infoLog);
}
}
MCVE testshader.vert:
#version 330 core
layout (location = 0) in vec3 position;
void main()
{
gl_Position = vec4(position.x, position.y, position.z, 1.0);
}
MCVE testshader.frag:
#version 330 core
out vec4 color;
void main()
{
color = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
When I run this I get the following output in addition to a brief flash of a window:
terminate called after throwing an instance of 'std::runtime_error'
what(): Failed to link shader program:
Aborted (core dumped)
Extra Notes:
I am using Ubuntu 16.10 x64
I am using a Nvidia GTX 1070 with driver version 375.39
The SDL and glew versions are those installed from the libsdl2-dev and libglew-dev packages respectively. I am using pkg-config to link.
During my research to solve this error I mostly found various forum and StackOverflow posts that found specific errors in other people's code. None of these apply to my code, and after finding this error I compared my code to this supposedly working example. This example also compiles and runs correctly on my computer, which rules out any sort of configuration error.
¹: It is not possible that glGetProgramInfoLog is doing nothing with external consequences and that the infoLog array happened to be allocated with a null-terminator character at its first address because the size return of glGetProgramInfoLog returns 0 even if set to a different value before glGetProgramInfoLog is called.
I have found the issue: a missing return statement in the loadShader() method. This, however, as I experienced when attempting to solve this was not helpful. As such, I recommend to any future person reading this that you find a working example (ie. this one) that does something similar as what you are trying to do and copy/paste progressively smaller parts of its code into yours (or visa-versa) to do a kind of binary search to find your error.
when I call glCompileShader() for the vertex shader, and use glGetShaderiv to get the status, it returns a false. However when I look at the log, it is empty. I'm new to shaders so I'm sure i've done something wrong. Here is my code:
void GLSLProgram::compileShader(const std::string& filePath, GLuint id)
{
/*Shader Program Reading*/
//don't worry about this \/, it just loads my shader program from the file.
std::string shader = gdcUtil::implode(gdcFile::readBlock(filePath, 0, 0, '\n', 0, true), true);
const char* shaderPtr = shader.c_str();
/*Shader Source Refering*/
glShaderSource(id, 1, &shaderPtr, nullptr);
/*Shader Compiling*/
glCompileShader(id);
GLint success = 0;
glGetShaderiv(id, GL_COMPILE_STATUS, &success);
if (success == GL_FALSE) {
//Setup Error Log
GLint maxLength = 0;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<char> errorLog(maxLength);
glGetShaderInfoLog(id, maxLength, &maxLength, &errorLog[0]);
std::string log;
for (int i = 0; i < errorLog.size(); i++) {
log += errorLog[i];
}
gdcUtil::error(log, "GD_GLSL");
glDeleteShader(id);
gdcUtil::quit();
}
}
Vertex Shader Program:
#version 130
in vec2 vertexPosition;
void main() {
gl_Position.xy = vertexPosition;
gl_Position.z = 0.0;
gl_Position.w = 1.0;
}
I know for a fact that it loads the shader program correctly, just fails upon compilation.
EDIT: Here is the code that calls compileShader
//Create Shaders
_vertID = glCreateShader(GL_VERTEX_SHADER);
bool shaderValid = glIsShader(_vertID);
if (_vertID = 0) {
gdcUtil::error("Could not create Vertex Shader", "GD_GLSL");
gdcUtil::quit();
}
_fragID = glCreateShader(GL_FRAGMENT_SHADER);
if (_fragID = 0) {
gdcUtil::error("Could not create Fragment Shader", "GD_GLSL");
gdcUtil::quit();
}
//Compile Shaders
compileShader(vertFilePath, _vertID);
compileShader(fragFilePath, _fragID);
I am following the 8Th edition and below is the code I modified from book. it does not give me what I want, but a blank window instead. I wonder what mistake(s) did I make during modifications?
below is the code I modified, hope anyone can point out the mistake.
#include <iostream>
#include <OpenGL/glu.h>
#include <OpenGL/gl3.h>
#include <GLUT/GLUT.h>
GLuint vaoNames[1];
GLuint bufferNames[1];
int vPosition = 0;
GLuint createProgram();
GLuint createShader(GLenum type, const char* src);
GLuint program;
void init()
{
glGenVertexArrays(1, vaoNames);
glBindVertexArray(vaoNames[0]);
GLfloat vertices[6][2] = {
{ -0.90, -0.90 }, // Triangle 1
{ 0.85, -0.90 },
{ -0.90, 0.85 },
{ 0.90, -0.85 }, // Triangle 2
{ 0.90, 0.90 },
{ -0.85, 0.90 }
};
glGenBuffers(1, bufferNames);
glBindBuffer(GL_ARRAY_BUFFER, bufferNames[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glUseProgram(createProgram());
glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(vPosition);
}
void render()
{
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vaoNames[0]);
glDrawArrays(GL_TRIANGLES, 0, 6);
glFlush();
}
GLuint createProgram()
{
GLuint program = glCreateProgram();
const char* vertexShaderSrc =
"#version 400 core \n"
"layout( location = 0 ) in vec4 vPosition; \n"
"void main() \n"
"{ \n"
"gl_Position = vPosition; \n"
"}";
GLuint vertexShader = createShader(GL_VERTEX_SHADER, vertexShaderSrc);
const char* fragmentShaderSrc =
"#version 400 core \n"
"out vec4 fColor; \n"
"void main() \n"
"{ \n"
"fColor = vec4( 0.0, 0.0, 1.0, 1.0 ); \n"
"}";
GLuint fragmentShader = createShader(GL_FRAGMENT_SHADER, fragmentShaderSrc);
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
return program;
}
GLuint createShader(GLenum type, const char* src){
GLuint shaderID = glCreateShader(type);
glShaderSource(shaderID, 1, &src, 0);
glCompileShader(shaderID);
return shaderID;
}
int main(int argc, char ** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA);
glutInitWindowSize(512, 512);
glutCreateWindow("8877");
init();
glutDisplayFunc(render);
glutMainLoop();
}
When you say 'there is no error during shader compilation and program linking', do you mean that the the program doesn't stop, or do you mean that you actually ran a different program and checked the results of glGetError() at various points, or fetched the compilation or linking log? Your program as is does no actual error checking, and OpenGL doesn't throw exceptions or produce error output as a matter of course. You have to actually request these things.
Simply because glCompileShader() doesn't generate an error doesn't mean your shader actually compiled. You need to be checking the compilation status of shaders and the link status of programs with code similar to this:
GLint compiled;
glGetShaderiv(newShader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
std::string log = getLog(newShader);
SAY(log.c_str());
throw std::runtime_error("Failed to compile shader " + log);
}
where getLog is
static std::string getLog(GLuint shader) {
std::string log;
GLint infoLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char* infoLog = new char[infoLen];
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
log = std::string(infoLog);
delete[] infoLog;
}
return log;
}
This is for checking shaders, and there are equivalent functions for checking the results and getting the logs for program linking. Unless you're calling them you have no guarantee that the shaders are compiling. Assuming you haven't made some simple mistake in the shader syntax, the most likely problem you're facing is a lack of support for OpenGL 4.x, which would cause the shaders to fail right off.