2

I have been working to create a circle based on a shader that changes color periodically. My code prints out a blank window. I decided to set-up some methods to check for errors using GL_LINK_STATUS and it seems that my code is encountering an issue linking the program and the shader. I did some research into similar issues that people have had but they don't seem to have similar causes. I have posted my shader code, the driver program(named Priomary) and the Shader Program below.

Vertex Shader

 #version 330 core

layout (location = 0) in vec3 pos;

uniform vec2 posOffset;

void main()
{
    gl_Position = vec4(pos.x + posOffset.x, pos.y + posOffset.y, pos.z, 1.0);
}

Fragment Shader

    #version 330 core

uniform vec4 vertColor;
out vec4 frag_color;

void main()
{
    frag_color = vertColor;
}

Shader Program

    #include "ShaderProgram.h"
#include <fstream>
#include <iostream>
#include <sstream>


ShaderProgram::ShaderProgram()
    : mProgram(0){
}


ShaderProgram::~ShaderProgram()
{
    glDeleteProgram(mProgram);
}

bool ShaderProgram::assignShaders(const char* vertFileName, const char* fragFileName)
{
    //Shaders output objects called programs that define their relationship and lead to .exe functionality

    //assigning pointer to the shader

        string vsString = readFile(vertFileName);
        string fsString = readFile(fragFileName);

        // c_str returns a const char* that points to a null-terminated string (i.e. a C-style string). It is useful when you want to pass the "contents"¹ of an std::string to a function that expects to work with a C-style string.
        const GLchar* vsSourcePtr = vsString.c_str();
        const GLchar* fsSourcePtr = fsString.c_str();

    //creating vertex shader(vs) shader object
    GLuint vs = glCreateShader(GL_VERTEX_SHADER);
    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);

    //assigning shader source using address. Replaces the source code in a shader object //@arg (shader, count Strings, pointer to const File ,size)
    glShaderSource(vs, 1, &vsSourcePtr, NULL);
    glShaderSource(fs, 1, &fsSourcePtr, NULL);

    glCompileShader(vs);
    testShaderCompile(vs);

    glCompileShader(fs);
    testShaderCompile(fs);

    //createProgram returns GLUint which is basically an unsigned int... we will use This Handler to create a program object
    mProgram = glCreateProgram();
    if (mProgram == 0)
    {
        std::cerr << "Shader cannot be created" << std::endl;
        return false;
    }
    //assign the program object(mProgram) to the Shader
    glAttachShader(mProgram, vs);
    glAttachShader(mProgram, fs);

    //this method accepts a GLuint "program" . If its an object of type GL_VERTEX_SHADER,
    //itll create a .exe that runs on the programmable vertex processor. same goes for geometric and fragment shaders if they were included
    //it will also bind all user defined uniform variables and attributes to the program 
    //The program can then be made part of a defined state by calling useProgram
    glLinkProgram(mProgram);
    testProgramCompile();

    //cleaning up the elements we already used
    glDeleteShader(vs);
    glDeleteShader(fs);

        //clear the identifier lookup map(in this case, there's only one)
    mUniformIdentifiers.clear();

    return true;
}//end main

    //Read the shaderFile. strngstream for reading multiple lines
string ShaderProgram:: readFile(const string& filename) {

    std::stringstream strgstream;
    std::ifstream file;

    try
    {
        file.open(filename, std::ios::in);

        if (!file.fail())
        {
            strgstream << file.rdbuf();
        }

        file.close();
    }
    catch (std::exception ex)
    {
        std::cerr << "Error: File or File Name Issues" << std::endl;
    }

    return strgstream.str();
}
    //use the Program Object we created in this current state(color)
void ShaderProgram::use()
{
        //check if it is not null
    if (mProgram > 0)
        glUseProgram(mProgram);
}

void ShaderProgram::dumpShaderLog(bool is_shader, GLuint obj)
{
    int maxlen = 0;
    if (is_shader) glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &maxlen);
    else             glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &maxlen);

    if (maxlen > 0)
    {
        char *log = new char[maxlen];
        int   len;

        if (is_shader)  glGetShaderInfoLog(obj, maxlen, &len, log);
        else              glGetProgramInfoLog(obj, maxlen, &len, log);

        if (len > 0 && log[0] != '\0')
            fprintf(stderr, "%s\n", log);

        delete[] log;
    }
}

void ShaderProgram::testProgramCompile() {
    int status = 0;

    GLuint program = mProgram;

        // ///CHECKING GL_LINK_STATUS to see if Program Link was successul. Link Status will return GL_TRUE if it was
        glGetProgramiv( mProgram, GL_LINK_STATUS, &status); //requesting the status
        if (status == GL_FALSE)
        {
            GLint length = 0;
        glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &length);

    string errorLog(length, ' ');   // Resize and fill with space character
    glGetProgramInfoLog(mProgram, length, &length, &errorLog[0]);


dumpShaderLog(false, mProgram);
        std::cerr << "Linking Error with Program and Shader" << std::endl;
        }

}
void ShaderProgram :: testShaderCompile(GLuint shader) {
    int status = 0;


    // ///CHECKING GL_LINK_STATUS to see if Program Link was successul. Link Status will return GL_TRUE if it was
glGetShaderiv (shader, GL_COMPILE_STATUS, &status);//requesting the status
    if (status == GL_FALSE)
    {
        GLint length = 0;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);

        string errorLog(length, ' ');  // Resize and fill with space character
        glGetShaderInfoLog(shader, length, &length, &errorLog[0]);
        std::cerr << "SHADER COMPILE TEST ERROR " << std::endl;
    }

}
////GETTERS AND SETTERS

GLuint ShaderProgram::getProgram() const
{
    return mProgram;
}



void ShaderProgram::setUniform(const GLchar* name, const glm::vec2& v)
{
    GLint address = getUniformIdentifier(name);
    glUniform2f(address, v.x, v.y);
}

void ShaderProgram::setUniform(const GLchar* name, const glm::vec3& v)
{
    GLint address = getUniformIdentifier(name);
    glUniform3f(address, v.x, v.y, v.z);
}

void ShaderProgram:: setUniform(const GLchar* name, const glm::vec4& v) {
    GLint address = getUniformIdentifier(name);
    glUniform4f(address, v.x, v.y, v.z, v.w);
}

//Maybe need to switch places with setUniform
GLint ShaderProgram :: getUniformIdentifier(const GLchar* name) {

    std::map<std::string, GLint>::iterator it;
    it = mUniformIdentifiers.find(name);
    //std::map<std::string, GLint>


        // Only need to query the shader program IF it doesn't already exist.
        if (it == mUniformIdentifiers.end())
        {
            // Find it and add it to the map
            mUniformIdentifiers[name] = glGetUniformLocation(mProgram, name);
        }

        // Return it
        return mUniformIdentifiers[name];
    }

Primary Program

#include <iostream>
#include <vector>

#include <sstream>
#define GLEW_STATIC
    //always GLEW before GLFW
#include "GL/glew.h"    
#include "GLFW/glfw3.h"
#include "glm/glm.hpp"

#include "ShaderProgram.h"

#ifndef M_PI
# define M_PI 3.141592653
#endif


/////gLOBAL
GLFWwindow* w = NULL;
const int wWidth = 800;
const int wHeight = 600;
 std::vector<glm::vec3> vertices;
std::vector<unsigned int> indices;
GLfloat Radius = 6;
GLfloat Stacks = 5;
GLfloat Slices = 5;



void key_callback(GLFWwindow *w, int key, int scancode, int action, int mode);
//update colors based on average framerate
void averageFPS(GLFWwindow* window);
//screen resizing
void glfw_onFramebufferSize(GLFWwindow* window, int width, int height);
bool initOpenGL();


static void error(int error, const char *desc)
{
    fputs(desc, stderr);
}
//setting up values for keys


int main() {
    //pointing to GLFW window
    //GLFWwindow *w; //may want to initialize as null outside before main
    if (!initOpenGL())  ///5IMPR
    {
        // An error occured
        std::cerr << "GLFW not initialized" << std::endl;
        return -1;
    }

    glfwSetErrorCallback(error);

    ///TEMP CIRCLE VERTICES

    // Calc The Vertices

    for (int i = 0; i <= Stacks; ++i) {

        float V = i / (float)Stacks;
        float phi = V * M_PI; //change to glm:: pi

        // Loop Through Slices
        for (int j = 0; j <= Slices; ++j) {

            float U = j / (float)Slices;
            float theta = U * (M_PI * 2);

            // Calc The Vertex Positions
            float x = cosf(theta) * sinf(phi);
            float y = cosf(phi);
            float z = sinf(theta) * sinf(phi);

            // Push Back Vertex Data //push_back is a standard vector function which adds a parameter to the end of the vector

            //std::vector<glm::vec3> vertices; //moved to global variables at top

            vertices.push_back(glm::vec3(x, y, z) * Radius);

        }

    }

    // Calc The Index Positions
    for (int i = 0; i < Slices * Stacks + Slices; ++i) {




        indices.push_back(i);
        indices.push_back(i + Slices + 1);
        indices.push_back(i + Slices);

        indices.push_back(i + Slices + 1);
        indices.push_back(i);
        indices.push_back(i + 1);
    }

    ////TEMP CIRCLE VERTICES END

    // 2. Set up buffers on the GPU
    GLuint vbo, ibo, vao;                       ///5IMPROVEdown

    glGenBuffers(1, &vbo);                  // Generate an empty vertex buffer on the GPU
    glBindBuffer(GL_ARRAY_BUFFER, vbo);     // "bind" or set as the current buffer we are working with
        //3rd argument of glBufferData needs a pointer to the std:vector data...A pointer to the data can be obtained by vertices.data() accrding to std: ector docs...
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);// copy the data from CPU to GPU


    glGenVertexArrays(1, &vao);             // Tell OpenGL to create new Vertex Array Object
    glBindVertexArray(vao);                 // Make it the current one
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);   // Define a layout for the first vertex buffer "0"
    glEnableVertexAttribArray(0);           // Enable the first attribute or attribute "0"

                                            // Set up index buffer
    glGenBuffers(1, &ibo);  // Create buffer space on the GPU for the index buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
        // glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); - REPLACED

    glBindVertexArray(0);                   // unbind to make sure other code doesn't change it

    ShaderProgram shaderProgram;        ///5ADD
    shaderProgram.assignShaders("shaders\\ColorShader.vert", "shaders\\ColorShader.frag"); ///5ADD

            ////////SETUP RENDERING
    while (!glfwWindowShouldClose(w))
    {
        averageFPS(w);

            //process events
        glfwPollEvents();           

            // Clear the screen
        glClear(GL_COLOR_BUFFER_BIT);   

        shaderProgram.use();    ///5ADD

        GLfloat time = (GLfloat)glfwGetTime();          ///5ADD
        GLfloat blueSetting = (sin(time) / 2) + 0.5f;       ///5ADD
        glm::vec2 pos;
        pos.x = sin(time) / 2;
        pos.y = cos(time) / 2;
        shaderProgram.setUniform("vertColor", glm::vec4(0.0f, 0.0f, blueSetting, 1.0f));    ///5ADD
        shaderProgram.setUniform("posOffset", pos);


        glBindVertexArray(vao);

            //og for quad
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
            //glDrawElements(GL_LINE_LOOP, 6, GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);
        // Swap buffers and look for events

        glfwSwapBuffers(w);


    }
        //clean up
    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(1, &vbo);
    glDeleteBuffers(1, &ibo);

    //glfwDestroyWindow(w);
    glfwTerminate();

    return 0;
    }


            ///////START Initializing glfw glew etc
bool initOpenGL(){

    //this method will exit on these conditions
    GLuint error = glfwInit();
    if (!error)
        return false;

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);


    w = glfwCreateWindow(wWidth, wHeight, "Exercise", NULL, NULL);


    if (w== NULL)
    {
        std::cerr << "glfw window not created" << std::endl;
        glfwTerminate();
        return false;
    }

        //update context
    glfwMakeContextCurrent(w);

    // Initialize GLEWunifor
    glewExperimental = GL_TRUE;
    GLuint err = glewInit();
    if (err != GLEW_OK)
    {
        std::cerr << "initialize GLEW Failed" << std::endl;
        return false;
    }

        //setup key callbacks
    glfwSetKeyCallback(w, key_callback);
    glfwSetFramebufferSizeCallback(w, glfw_onFramebufferSize);

    glClearColor(0.23f, 0.38f, 0.47f, 1.0f);    ///5ADD

                                                // Define the viewport dimensions
    glViewport(0, 0, wWidth, wHeight);  //necessary?

    return true;

}

void key_callback(GLFWwindow *w, int key, int scancode, int action, int mode)
{
    // See http://www.glfw.org/docs/latest/group__keys.html
    if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_PRESS)
        glfwSetWindowShouldClose(w, GL_TRUE);

    if (key == GLFW_KEY_W && action == GLFW_PRESS)
    {
        bool showWires = false;
        if (showWires)
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        else
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    }

}

    //whever window resizes, do this
void glfw_onFramebufferSize(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

void averageFPS(GLFWwindow* window) ///5ADDdown
{
    static double previousSeconds = 0.0;
    static int frameCount = 0;
    double passedSeconds;
    double currentSeconds = glfwGetTime(); //seconds since GLFW started

    passedSeconds = currentSeconds - previousSeconds;

// Limit time updates to 4 times per second
if (passedSeconds > 0.25)
{
    previousSeconds = currentSeconds;
    double fps = (double)frameCount / passedSeconds;
//  double frameInMilSecs = 1000.0 / fps;
     frameCount = 0;} 
frameCount++;

}

5
  • 3
    "encountering an issue" is a bit imprecise for an error description. You might want to tell us exactly what the linker says. Commented Apr 16, 2018 at 15:24
  • Sorry what is exactly the error returned by the shader compiler? Commented Apr 16, 2018 at 15:26
  • Sorry about thar. My console prints SHADER COMPILE TEST ERROR SHADER COMPILE TEST ERROR Linking Error with Program and Shader. So the shaders are not compiling and naturally, nothing is being linked. Commented Apr 16, 2018 at 15:42
  • Why don't you actually print the info log which you queried? Commented Apr 17, 2018 at 19:57
  • I updated the code above to show more of the error. When I dump the Log, it tells me that "void main() cannot be found. It seems that there is trouble with reading the string stream of the shader files? Commented Apr 18, 2018 at 16:15

1 Answer 1

1

While glGetShaderiv returns a parameter from a shader object, glGetProgramiv returns a parameter from a program object.

This means you have to change your code like this:

// glGetProgramiv(shader, GL_COMPILE_STATUS, &status); <--- delete
glGetShaderiv (shader, GL_COMPILE_STATUS, &status);

Ensure that the shader files are correctly loaded and trace them for debug reasons:

glShaderSource(vs, 1, &vsSourcePtr, NULL);
glShaderSource(fs, 1, &fsSourcePtr, NULL);

std::cout << "VERTEX SHADER:" << std::endl << vsSourcePtr << std::endl << std::endl;
glCompileShader(vs);
testShaderCompile(vs);

std::cout << "FRAGMENT SHADER:" << std::endl << fsSourcePtr << std::endl << std::endl;
glCompileShader(fs);
testShaderCompile(fs);

Since you don't set any matrices, you have to set up all the vertex coordinates in normalized device space, which is in [-1.0, 1.0].

To make the mesh proper "visible" on the viewport set the radius of the sphere to 0.5:

GLfloat Radius = 0.5f;

and draw all the primitives:

glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
Sign up to request clarification or add additional context in comments.

2 Comments

I see. That was a small oversight. I'm afraid I still receive the same overall issue with the blank screen. The shader compilation issue is fine now, but the Program still has issues. "Linking Error with Program and Shader"
@FolaranmiOgunfemi I tested you code, and it works fine for me. Make sure that the shader programs are proper loaded.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.