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++;
}
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);
Related
I've already looked all over the internet for the past couple days and I cannot find a fix to this problem. I believe I've got the basic debugging stuff setup yet I get no errors telling me what I've done wrong. This is my first attempt at a renderer, and I'm also trying to use a OOP/DOD (Data oriented design) structure. I think the error is just something small that I am blind to, or I'm completely doing this wrong... please help if you can.
Also I'm using shaders, EBOs, VBOs, linking to a VAO (I think)
Additional information: I'm using SDL + GLAD(opengl 4.6, core)
If you need me to reply with anything else that could help you help me, let me know.
Here is my console output:
screenshot
All I see on the window: screenshot
Here are my files (that might have the error):
vertex shader
#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
out vec3 ourColor;
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
}
fragment shader
#version 460 core
out vec4 FragColor;
in vec3 ourColor;
void main()
{
FragColor = vec4(ourColor, 1.0f);
}
main.cpp (the window)
#include <loader.h>
using namespace testProgram;
int close(SDL_Window* window, SDL_GLContext glContext) {
IMG_Quit();
SDL_DestroyWindow(window);
SDL_GL_DeleteContext(glContext);
SDL_Quit();
return 0;
}
// Simple debugger callback, will most likely modify in the future.
static void APIENTRY openglCallbackFunction(
GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam
){
(void)source; (void)type; (void)id;
(void)severity; (void)length; (void)userParam;
fprintf(stderr, "%s\n", message);
if (severity==GL_DEBUG_SEVERITY_HIGH) {
fprintf(stderr, "Aborting...\n");
abort();
}
}
std::vector<GLfloat> vertices {
// positions // colors
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom left
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top
};
std::vector<GLuint> indices {
0, 1, 2
};
std::vector<int> vertexAttribSizes {
3
};
int main(int argc, char* argv[]) {
// Variables
bool quit = false;
// Initializations
SDL_Init(SDL_INIT_EVERYTHING);
IMG_Init(IMG_INIT_PNG);
setGLAttributes();
// Creating the window
SDL_Window* window = SDL_CreateWindow("test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, winW, winH, flags);
SDL_GLContext glContext = SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, glContext);
SDL_Surface* icon = IMG_Load("images/icon.png");
setIcon(window, icon);
// Setting up OpenGL
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
printf("Failed to initialize GLAD\n");
return -1;
}
glViewport(0, 0, winW, winH);
// Enable the debug callback
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(openglCallbackFunction, nullptr);
glDebugMessageControl
(
GL_DONT_CARE,
GL_DONT_CARE,
GL_DONT_CARE,
0, NULL, true
);
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
Renderer::Queue queue;
Renderer::Shader shader;
Renderer::Object object;
shader.Update("CUT OUT THE DIRECTORY FOR THIS POST (because it doesn't matter)", "CUT OUT THE DIRECTORY FOR THIS POST (because it doesn't matter)");
object.Update(vertices, indices, shader.id, "triangle", vertexAttribSizes);
object.Attach(queue);
while(!quit) {
SDL_Event event;
mouseX = event.motion.x;
mouseY = event.motion.y;
while (SDL_PollEvent(&event) != 0) {
inputCollection(event, quit);
}
SDL_SetWindowHitTest(window, hitCallback, 0);
glClearColor(0.085f, 0.085f, 0.085f, 0.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
queue.Render();
SDL_GL_SwapWindow(window);
}
// Closes all processes
object.Detach(queue);
close(window, glContext);
return 0;
}
renderer.h (it is included in loader.h, which is included in main.cpp. loader.h I believe doesn't contain the issue, so I dont want to pollute this post with even more code haha)
// Includes
#include <glad/glad.h>
#include <stdio.h>
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <ctype.h>
#include <fstream>
#include <cstring>
#include <sstream>
// Renderer
namespace Renderer {
class Shader {
private:
// Read the shader's source code.
std::string readFile(const char* _path);
// Check the shader.
bool checkShader(GLuint &_shader);
// Check the program.
bool checkProgram(GLuint &_program);
public:
const char* vertexPath;
const char* fragmentPath;
GLuint id;
void Update(const char* _vertexPath, const char* _fragmentPath); // Update the shader's parameters.
void Use() { glUseProgram(id); } // Use the shader.
};
class Queue {
public:
GLuint VAO;
void listObjects(); // List all objects in the queue (BY NAME, INDEX IS THE ID FOR ALL VALUES/PARAMETERS)
GLuint getObject(std::string objName); // Grab an object from the queue (BY NAME, INDEX IS THE ID FOR ALL VALUES/PARAMETERS) [Returns the id of the object]
bool findObject(std::string objName); // Returns true or false if the object is found.
void Render(); // Render all objects in the queue. (Sets VAOs)
std::vector<std::vector<GLfloat>> vertices;
std::vector<std::vector<int>> indices;
std::vector<std::vector<int>> vertexAttribs;
std::vector<int> shaderProgramIDs;
std::vector<std::string> names;
};
class Object {
public:
GLuint VBO, EBO;
std::vector<GLfloat> vertices;
std::vector<int> indices;
std::vector<int> vertexAttribSizes; // This is the sizes of the vertex attributes, not the values.
GLuint shaderProgramID;
std::string name;
// Set the object's parameters.
void Update(
std::vector<GLfloat> _vertices,
std::vector<GLuint> _indices,
int _shaderProgramID,
std::string _name,
std::vector<int> _vertexAttribSizes
);
void Attach(Queue &queue);
void Detach(Queue &queue);
};
};
renderer.cpp
#include <renderer.h>
using namespace Renderer;
// List all objects in the queue.
void Queue::listObjects() {
for (auto name : names) {
std::cout << name << std::endl;
}
}
// Returns true or false if the object is found.
bool Queue::findObject(std::string objName) {
auto index = std::find(names.begin(), names.end(), objName);
if (index != names.end()) {
return true;
} else {
return false;
}
}
// Returns the object id.
GLuint Queue::getObject(std::string objName) {
auto index = std::find(names.begin(), names.end(), objName);
if (findObject(objName)) {
return index - names.begin();
} else {
return -1;
}
}
// Renders all objects linked to the current queue.
void Queue::Render() {
for (int i = 0; i < names.size(); i++) {
glUseProgram(shaderProgramIDs[i]);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, indices[i].size(), GL_UNSIGNED_INT, 0);
}
}
std::string Shader::readFile(const char* _path) {
std::string content;
std::ifstream fileStream(_path, std::ios::in);
if (!fileStream.is_open()) {
std::cerr << "Could not read file " << _path << ". File does not exist." << std::endl;
return "";
}
std::string line = "";
while (!fileStream.eof()) {
std::getline(fileStream, line);
content.append(line + "\n");
}
fileStream.close();
return content;
}
bool Shader::checkShader(GLuint &_shader) {
GLint success;
glGetShaderiv(_shader, GL_COMPILE_STATUS, &success);
if(!success) {
GLint maxLength = 0;
glGetShaderiv(_shader, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<GLchar> errorLog(maxLength);
glGetShaderInfoLog(_shader, maxLength, &maxLength, &errorLog[0]);
std::cout << "Shader compilation failed: " << std::endl;
std::cout << &errorLog[0] << std::endl;
return false;
}
return true;
}
bool Shader::checkProgram(GLuint &_program) {
GLint success;
glGetProgramiv(_program, GL_LINK_STATUS, &success);
if(!success) {
GLint maxLength = 0;
glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<GLchar> errorLog(maxLength);
glGetProgramInfoLog(_program, maxLength, &maxLength, &errorLog[0]);
std::cout << "Program linking failed: " << std::endl;
std::cout << &errorLog[0] << std::endl;
return false;
}
return true;
}
void Shader::Update(
const char* _vertexPath,
const char* _fragmentPath
){
GLuint vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
vertexPath = _vertexPath;
fragmentPath = _fragmentPath;
std::string vertexString = readFile(_vertexPath);
std::string fragmentString = readFile(_fragmentPath);
const char *vertexSource = vertexString.c_str();
const char *fragmentSource = fragmentString.c_str();
glShaderSource(vertex, 1, &vertexSource, NULL);
glCompileShader(vertex);
checkShader(vertex);
glShaderSource(fragment, 1, &fragmentSource, NULL);
glCompileShader(fragment);
checkShader(fragment);
this->id = glCreateProgram();
glAttachShader(this->id, vertex);
glAttachShader(this->id, fragment);
glLinkProgram(this->id);
checkProgram(this->id);
glDeleteShader(vertex);
glDeleteShader(fragment);
}
void Object::Attach(Queue &queue) {
queue.names.push_back(this->name);
GLuint id = queue.getObject(this->name);
queue.shaderProgramIDs.insert(queue.shaderProgramIDs.begin()+id, this->shaderProgramID);
queue.vertices.insert(queue.vertices.begin()+id, this->vertices);
queue.indices.insert(queue.indices.begin()+id, this->indices);
queue.vertexAttribs.insert(queue.vertexAttribs.begin()+id, this->vertexAttribSizes);
glGenBuffers(1, &this->VBO);
glGenBuffers(1, &this->EBO);
glGenVertexArrays(1, &queue.VAO);
glBindVertexArray(queue.VAO);
glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(this->vertices), &this->vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(this->indices), &this->indices, GL_STATIC_DRAW);
int stride = 3;
for (int i = 0; i < this->vertexAttribSizes.size(); i++) {
stride+=this->vertexAttribSizes[i];
}
// Positions
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// Other attributes
int totalSize = 3;
for (int i = 0; i < this->vertexAttribSizes.size(); i++) {
glVertexAttribPointer(i+1, this->vertexAttribSizes[i], GL_FLOAT, GL_FALSE, stride * sizeof(float), (void*)(totalSize * sizeof(float)));
glEnableVertexAttribArray(i+1);
totalSize+=this->vertexAttribSizes[i];
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void Object::Detach(Queue &queue) {
GLuint id = queue.getObject(this->name);
queue.names.erase(std::remove(queue.names.begin(), queue.names.end(), this->name), queue.names.end());
queue.vertices.erase(queue.vertices.begin()+id, queue.vertices.begin()+id+this->vertices.size());
queue.indices.erase(queue.indices.begin()+id, queue.indices.begin()+id+this->indices.size());
queue.vertexAttribs.erase(queue.vertexAttribs.begin()+id, queue.vertexAttribs.begin()+id+this->vertexAttribSizes.size());
glDeleteBuffers(1, &this->VBO);
glDeleteBuffers(1, &this->EBO);
}
void Object::Update(
std::vector<GLfloat> _vertices,
std::vector<GLuint> _indices,
int _shaderProgramID,
std::string _name,
std::vector<int> _vertexAttribSizes
){
// TODO: Clear all vectors, also detach and reattach automatically.
for (int i = 0; i < _vertices.size(); i++) {
vertices.push_back(_vertices[i]);
}
for (int i = 0; i < _indices.size(); i++) {
indices.push_back(_indices[i]);
}
for (int i = 0; i < _vertexAttribSizes.size(); i++) {
vertexAttribSizes.push_back(_vertexAttribSizes[i]);
}
shaderProgramID = _shaderProgramID;
name = _name;
}
glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(this->vertices), &this->vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(this->indices), &this->indices, GL_STATIC_DRAW);
this->vertices is a std::vector. You are uploading raw pointer values where there should be actual data in the buffer.
glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * this->vertices.size(), this->vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * this->indices.size(), this->indices.data(), GL_STATIC_DRAW);
I am trying to render a triangle with a triangle strip, but the word thing is that I am getting a rectangle.
Here is my client application code. I hardcoded points and the indices, create a VBO and an index buffer, and just call glDrawElements.
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
using namespace std;
#define PI 3.14159265359
static string ParseShader(string filepath) {
ifstream stream(filepath);
string line;
stringstream stringStream;
while (getline(stream, line))
{
stringStream << line << '\n';
}
return stringStream.str();
}
static unsigned int CompileShader(unsigned int type, const string& source) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str(); // this returns a pointer to data inside the string, the first character
glShaderSource(id, 1, &src, nullptr); // shader id, count of source codes, a pointer to the array that holds the strings
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);
cout << type << endl;
cout << message << endl;
glDeleteShader(id);
return 0;
}
return id;
}
// takes the shader codes as a string parameters
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader)
{
GLuint 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); // validate if the program is valid and can be run in the current state of opengl
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
int main(void)
{
GLFWwindow* window;
float Angle = 40;
/* Initialize the library */
if (!glfwInit())
return -1;
/* 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);
// call glewInit after creating the context...
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
}
const int vertexCoordinateCount = 2;
const int coordinateCount = 6;
const int indexCount = 3;
GLfloat coordinates[coordinateCount] = {
500.0f, 0.0f,
-250.0f, 250.f,
-250.f, -250.f,
};
GLuint indices[indexCount] = { 0, 1, 2 };
GLuint position_buffer;
glGenBuffers(1, &position_buffer);
glBindBuffer(GL_ARRAY_BUFFER, position_buffer);
glBufferData(GL_ARRAY_BUFFER, coordinateCount * sizeof(float), coordinates, GL_STATIC_DRAW);
glVertexAttribPointer(0, vertexCoordinateCount, GL_FLOAT, GL_FALSE, sizeof(float) * vertexCoordinateCount, 0);
glEnableVertexAttribArray(0);
GLuint index_buffer;
glGenBuffers(1, &index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(GLuint), indices, GL_STATIC_DRAW);
string vertexSource = ParseShader("vertex.shader");
string fragmentSource = ParseShader("fragment.shader");
unsigned int program = CreateShader(vertexSource, fragmentSource);
glUseProgram(program);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
// Render here
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_INT, nullptr);
//Swap front and back buffers
glfwSwapBuffers(window);
// Poll for and process events
glfwPollEvents();
}
glDeleteProgram(program);
glfwTerminate();
return 0;
}
My vertex shader :
#version 330 core
layout(location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos, 1.0);
}
And my fragment shader:
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
Edit: Adding a screenshot of the render result.
You do not transform the vertex coordinates. Therefore the vertices must be spepcified in Normalized Device Space, in range [-1.0, 1.0]. e.g.:
GLfloat coordinates[coordinateCount] = {
1.0f, 1.0f,
-1.0f, 1.0f,
1.0f, -1.0f,
};
You're actually drawing a triangle, but you only see an inner part of it. The rest is clipped.
This is a question following OpenGL and loading/reading data in AoSoA (hybrid SoA) format.
I am trying to use a shader storage buffer object (SSBO) to store vertex data which is represented in AoSoA format. I am having trouble drawing the vertices, which obviously means that I am doing something wrong somewhere. The problem is that I can't seem to figure out what or where. The answer to the initial question above seems to indicate that I should not be using vertex attribute arrays, so the question then becomes, how do I render this SSBO, given the code I am about to present?
VertexData structure
constexpr auto VECTOR_WIDTH = 4;
constexpr auto VERTEX_COUNT = 16;
struct VertexData
{
std::array<float, VECTOR_WIDTH> px;
std::array<float, VECTOR_WIDTH> py;
};
// Later stored in a std::vector
std::vector<VertexData> vertices(VERTEX_COUNT / VECTOR_WIDTH);
Vertex shader (should this really be a compute shader?)
struct Vertex4
{
float px[4]; // position x
float py[4]; // position y
};
layout(std430, binding=0) buffer VertexData
{
Vertex4 vertices[];
};
void main()
{
int dataIx = gl_VertexID / 4;
int vertexIx = gl_VertexID % 4;
vec2 vertexPosition = vec2(vertices[dataIx].px[vertexIx], vertices[dataIx].py[vertexIx]);
}
Assign vertexPosition index
// Do I need this? Where do I use it? glEnableVertexAttribArray(position_attrib_index)?
const GLuint position_attrib_index = 0;
glBindAttribLocation(program, position_attrib_index, "vertexPosition");
SSBO setup
const GLuint ssbo_binding_point = 0;
GLuint ssbo{};
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
//glBufferStorage(GL_SHADER_STORAGE_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_MAP_WRITE_BIT);
glBufferData(GL_SHADER_STORAGE_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_STATIC_DRAW);
const auto block_index = glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, "VertexData");
glShaderStorageBlockBinding(program, block_index, ssbo_binding_point);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, ssbo_binding_point, ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
Render loop
while (!glfwWindowShouldClose(window)) {
process_input(window);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
// ???
glfwSwapBuffers(window);
glfwPollEvents();
}
I just can't seem to figure out how this is supposed to work. Grabbing at straws, I also tried creating a VAO with a later call to glDrawArrays(GL_POINTS, 0, VERTEX_COUNT), but it didn't work either:
GLuint vao{};
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(position_attrib_index);
glVertexAttribPointer(position_attrib_index, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
It seems to me that I should be using position_attrib_index (which should point to vertexPosition) for something, the question is for what?
Complete example code
requires OpenGL 4.3, GLEW and GLFW
build command example: g++ -std=c++17 main.cpp -lGLEW -lglfw -lGL -o ssbo
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <array>
#include <iostream>
#include <vector>
void process_input(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
}
void glfw_error_callback(int error_code, const char *description)
{
std::cerr << "GLFW Error: [" << error_code << "] " << description << '\n';
}
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
glViewport(0, 0, width, height);
}
auto create_glfw_window()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
return glfwCreateWindow(800, 600, "OpenGL and AoSoA layout", nullptr, nullptr);
}
void set_callbacks(GLFWwindow *window)
{
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetErrorCallback(glfw_error_callback);
}
void print_versions()
{
std::cout << "Using GLFW " << glfwGetVersionString() << '\n';
std::cout << "Using GLEW " << glewGetString(GLEW_VERSION) << '\n';
}
bool init_loader()
{
GLenum err = glewInit();
if (GLEW_OK != err) {
std::cerr << "GLEW error: " << glewGetErrorString(err);
}
return err == GLEW_OK;
}
void GLAPIENTRY MessageCallback(
GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam = nullptr)
{
std::cerr << "[GL DEBUG] " << (type == GL_DEBUG_TYPE_ERROR ? "Error: " : "") << message << '\n';
}
constexpr auto VECTOR_WIDTH = 4;
constexpr auto VERTEX_COUNT = 16;
struct VertexData
{
std::array<float, VECTOR_WIDTH> px;
std::array<float, VECTOR_WIDTH> py;
};
static const char* vertex_shader_source =
"#version 430\n"
"struct Vertex4\n"
"{\n"
" float px[4]; // position x\n"
" float py[4]; // position y\n"
"};\n"
"layout(std430, binding=0) buffer VertexData\n"
"{\n"
" Vertex4 vertices[];\n"
"};\n"
"void main()\n"
"{\n"
" int dataIx = gl_VertexID / 4;\n"
" int vertexIx = gl_VertexID % 4;\n"
" vec2 vertexPosition = vec2(vertices[dataIx].px[vertexIx], vertices[dataIx].py[vertexIx]);\n"
"}\n";
static const char* fragment_shader_source =
"#version 430\n"
"out vec4 out_color;\n"
"void main()\n"
"{\n"
" out_color = vec4(1.0, 0.5, 0.5, 0.25);\n"
"}\n";
int main(int argc, char *argv[])
{
glewExperimental = GL_TRUE;
auto window = create_glfw_window();
if (window == nullptr) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
set_callbacks(window);
init_loader();
print_versions();
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(MessageCallback, nullptr);
std::vector<VertexData> vertices(VERTEX_COUNT / VECTOR_WIDTH);
vertices[0] = {
{-0.75f, 0.75f, 0.75f, -0.75f},
{-0.75f, -0.75f, 0.75f, 0.75f}
};
vertices[1] = {
{-0.50f, 0.50f, 0.50f, -0.50f},
{-0.50f, -0.50f, 0.50f, 0.50f},
};
vertices[2] = {
{-0.25f, 0.25f, 0.25f, -0.25f},
{-0.25f, -0.25f, 0.25f, 0.25f},
};
vertices[3] = {
{-0.05f, 0.05f, 0.05f, -0.05f},
{-0.05f, -0.05f, 0.05f, 0.05f},
};
auto vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_source, nullptr);
glCompileShader(vertex_shader);
auto fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_source, nullptr);
glCompileShader(fragment_shader);
auto program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
const GLuint position_attrib_index = 0;
glBindAttribLocation(program, position_attrib_index, "vertexPosition");
glLinkProgram(program);
//glUseProgram(program);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
//
// SSBO
//
const GLuint ssbo_binding_point = 0;
GLuint ssbo{};
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
//glBufferStorage(GL_SHADER_STORAGE_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_MAP_WRITE_BIT);
glBufferData(GL_SHADER_STORAGE_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_STATIC_DRAW);
const auto block_index = glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, "VertexData");
glShaderStorageBlockBinding(program, block_index, ssbo_binding_point);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, ssbo_binding_point, ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
//
// VAO
//
//GLuint vao{};
//glGenVertexArrays(1, &vao);
//glBindVertexArray(vao);
//glEnableVertexAttribArray(position_attrib_index);
//glVertexAttribPointer(position_attrib_index, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glClearColor(0.15f, 0.15f, 0.2f, 1.0f);
glPointSize(10.0f);
while (!glfwWindowShouldClose(window)) {
process_input(window);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
//glDrawArrays(GL_POINTS, 0, VERTEX_COUNT);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
This is the correct way to issue a draw with the data you have:
glBindVertexArray(vao);
glDrawArrays(GL_POINTS, 0, VERTEX_COUNT);
However, your issue is that your vertex shader does not write to gl_Position, therefore nothing gets rasterized (whatever undefined behavior happens). You should set the position of the vertices in the shader as follows:
//...
out gl_PerVertex {
vec4 gl_Position;
};
void main()
{
int dataIx = gl_VertexID / 4;
int vertexIx = gl_VertexID % 4;
vec2 vertexPosition = vec2(vertices[dataIx].px[vertexIx], vertices[dataIx].py[vertexIx]);
gl_Position = vec4(vertexPosition, 0, 1);
}
You can get rid of "Assign vertexPosition index", and your VAO doesn't need to have any attributes.
I'm training in openGL programmation and I want to create my own classes to make me life easier. However, I'm faced to a problem in my Shader class.
My Shader class is composed of one C++ string (the name of the shader) and two others C strings (which contain the code of the fragment and vertex shaders).
Then, during initialization, I read my files to stock every character into my both C string. At this moment, these two variable are correctly filled, but if I try to read them by my getVertex() method, it does not show me at all what must be in it.
Fragment and Vertex shaders code must be stock in a const GLchar * because of glShaderSource() which is used to load shaders. Here is the prototype of this function: void glShaderSource(GLuint shader, GLsizei count, const GLchar **string, const GLint *length);.
I have already tried to use basic const char * as const GLchar *, but it is even.
I also tried to stock shaders code into C++ strings and convert them into C string in the main but it it does not change anything.
Here is my code with the debug print:
-main.cpp
#include "head.h"
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
int main(){
glfwInit();
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); //For MacOS
/*Window initialization*/
GLFWwindow* window = glfwCreateWindow(800, 600, "Hello Window!", NULL, NULL);
if (window == NULL){
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
/*GLAD initialization*/
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
/*Initialize shaders*/
Shader myShaders("Hello");
std::cout << "Main Print\n" << myShaders.getVertex() << std::endl;
/*Triangle Vertices*/
/*float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};*/
/*Rectangle Vertices*/
float vertices[] = {
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
unsigned int VBO;
glGenBuffers(1, &VBO);
/*Define the type of the VBO*/
glBindBuffer(GL_ARRAY_BUFFER, VBO);
/*Copy vertices into the GL_ARRAY_BUFFER object (VBO)*/
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
/*Creating a VS object*/
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
/*Link the VS code to the VS object*/
glShaderSource(vertexShader, 1, &myShaders.getVertex(), NULL);
glCompileShader(vertexShader);
/*Testing the VS compilation*/
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success){
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
/*As the VS, same for FS*/
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &myShaders.getFragment(), NULL);
glCompileShader(fragmentShader);
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
/*Creating the program Shader*/
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
/*Testing PS compilation*/
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::COMPILATION_FAILED\n" << infoLog << std::endl;
}
/*Deleting shaders already used*/
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
/*Activating our shader*/
glUseProgram(shaderProgram);
/*How to interprets data*/
/*(layout (location = 0),vec3,type of the vec,for [-1.0;1.0],stride worked with 0 too, offset to begin*/
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
/*Creating Vertex Array Object*/
unsigned int VAO;
glGenVertexArrays(1, &VAO);
// 1. Lier le Vertex Array Object (VAO)
glBindVertexArray(VAO);
// 2. Copier les sommets dans un tampon pour qu’OpenGL les utilise
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 3. Initialiser les pointeurs d’attributs de sommets
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
/*Creating an EBO for tell the order of vertices to being draw*/
unsigned int EBO;
glGenBuffers(1, &EBO);
/*GL_ELEMENT_ARRAY_BUFFER for EBO*/
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
/*Setting the view*/
glViewport(0, 0, 800, 600);
/*To get a thread style*/
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
/*Render Loop*/
while (!glfwWindowShouldClose(window)){
glClearColor(0.5f, 0.3f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
processInput(window);
glUseProgram(shaderProgram);
//glBindVertexArray(VAO);
/*(Kind of primitive to use, begin of vertices tab, end of vertices tab)*/
//glDrawArrays(GL_TRIANGLES, 0, 3);
/*6 for length of EBO*/
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwPollEvents();
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
/*Resize*/
void framebuffer_size_callback(GLFWwindow* window, int width, int height){
glViewport(0, 0, width, height);
}
/*Handle inputs*/
void processInput(GLFWwindow* window){
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
-shader.hpp:
#pragma once
class Shader {
public:
Shader(std::string const& name) : name_(name){
std::string tmp;
std::ifstream stream("./shaders/" + name_ + ".fs");
if(stream) {
while (stream.good()) {
tmp += stream.get();
}
}
fragment_ = tmp.c_str();
stream.close();
tmp = "";
stream.open("./shaders/" + name_ + ".vs");
if(stream) {
while (stream.good()) {
tmp += stream.get();
}
}
vertex_ = tmp.c_str();
stream.close();
std::cout << "Shader Initialization Print\n" << vertex_ << "\n\n";
}
void initialize(){
if (name_.size() > 0) {
std::string tmp;
std::ifstream stream("./shaders/" + name_ + ".fs");
if (stream) {
while (stream.good()) {
tmp += stream.get();
}
}
fragment_ = tmp.c_str();
stream.close();
tmp = "";
stream.open("./shaders/" + name_ + ".vs");
if (stream) {
while (stream.good()) {
tmp += stream.get();
}
}
vertex_ = tmp.c_str();
stream.close();
}
}
void setName(std::string const& name) {
name_ = name;
}
std::string getName() {
return name_;
}
void setFragment(std::string const& fragment) {
fragment_ = fragment.c_str();
}
const GLchar* & getFragment() {
return fragment_;
}
void setVertex(std::string const& vertex) {
vertex_ = vertex.c_str();
}
const GLchar* & getVertex() {
std::cout << "getVertex() Print\n" << vertex_ << "\n\n";
return vertex_;
}
private:
std::string name_;
const GLchar * vertex_;
const GLchar * fragment_;
};
-head.h:
#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "shader.hpp"
-Trace of execution
Shader Initialization Print
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
getVertex() Print
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
Main Print
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
getVertex() Print
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
ERROR::SHADER::VERTEX::COMPILATION_FAILED
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
ERROR::SHADER::FRAGMENT::COMPILATION_FAILED
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
ERROR::SHADER::PROGRAM::COMPILATION_FAILED
Vertex info
-----------
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
(0) : error C2003: incompatible options for link
Fragment info
-------------
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
(0) : error C2003: incompatible options for link
Actually, I expect to get what shader initialization print everywhere I call my getVertex()/getFragment() methods.
First of all there is an issue when you read the file you've to evaluate stream.good() after the character is read but befor the cahrater is add to the string. Note, .get sets the eofbit when it fails to read a character, but not when th kast charater was read:
std::string tmp;
std::ifstream stream("./shaders/" + name_ + ".fs");
while (true) {
char c = stream.get();
if (!stream)
break;
tmp += c;
}
Anyway i recmmend to use std::istreambuf_iterator:
std::ifstream stream("./shaders/" + name_ + ".fs");
std::string tmp = std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
getVertex and getFragment. Should return a reference to a pointer to the shader code characters (const GLchar*&). So you've to store the shader code in an attribute. I recommend to stroe the code in a std::string. Further you need an attribute of type const GLchar*, which holds a pointer to the code and can be returned by reference:
class Shader {
public:
// ...
void setVertex(std::string const& vertex) {
vertex_ = vertex;
vs_ptr_ = vertex_.c_str();
}
const GLchar*& getVertex() {
return vs_ptr_;
}
private:
// ...
std::string vertex_;
const GLchar *vs_ptr_;
};
The entire class my look as follows:
class Shader {
public:
Shader(std::string const& name)
: name_(name){
initialize();
}
void initialize(){
if (name_.empty())
return;
std::ifstream stream("./shaders/" + name_ + ".fs");
std::string tmp = std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
stream.close();
setFragment(tmp);
stream.open("./shaders/" + name_ + ".vs");
tmp = std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
stream.close();
setVertex(tmp);
}
void setName(std::string const& name) {
name_ = name;
}
std::string getName() {
return name_;
}
void setFragment(std::string const& fragment) {
fragment_ = fragment;
fs_ptr_ = fragment_.c_str();
}
const GLchar*& getFragment() {
return fs_ptr_;
}
void setVertex(std::string const& vertex) {
vertex_ = vertex;
vs_ptr_ = vertex_.c_str();
}
const GLchar*& getVertex() {
return vs_ptr_;
}
private:
std::string name_;
std::string vertex_;
std::string fragment_;
const GLchar *vs_ptr_;
const GLchar *fs_ptr_;
};
Here's one way to handle this. It uses a string and also stores the result of c_str() on that string. The point is that by storing the pointer as well as the string it is based on you make sure that the pointer remains valid for as long as the string is valid.
class Shader
{
public:
void setVertex(std::string const& vertex) {
vertex_ = vertex;
vertexPtr_ = vertex_.c_str(); // this must be vertex_ not vertex, otherwise we have exactly the same problem as before
}
const GLchar* & getVertex() {
std::cout << "getVertex() Print\n" << vertex_ << "\n\n";
return vertexPtr_;
}
private:
string vertex_;
const GLchar* vertexPtr_;
};
This is untested code.
C++ is not a language where data remains valid as long as it is accessible (unlike Java for instance). You cannot program C++ without understanding the lifetime of the objects you create. Your program got the types correct but failed to understand that the pointer was invalid by the time you used it. This version keeps the string and the pointer to it together so that both have the same lifetime.
Well, as in the title the Shaders aren't doing a thing they should draw a point but it isn't appearing in the screen :/. I have being checking for solutions but it appears that they don't work. Also glfw and glew are initialising okay and the red color is appearing.
#include <GL/glew.h>
#define GLFW_DLL
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <iostream>
#include "jelly/lua_manager.h"
#include "jelly/keysManager.h"
jelly::keys_buttons::KeysManager km;
GLuint vertex_array_obj;
GLuint program;
GLuint startRender(GLFWwindow* window)
{
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
std::cout << "ASD" << std::endl;
static const GLchar * vertexShader_src[] =
{
"#version 430 core \n"
" \n"
"void main(void) \n"
"{ \n"
" gl_Position = vec4(0, 0.5, 0.0, 1); \n"
"} \n"
};
static const GLchar * fragmentShader_src[] =
{
"#version 430 core \n"
" \n"
"out vec4 color; \n"
" \n"
"void main(void) \n"
"{ \n"
" color = vec4(0.0, 0.8, 1.0, 1.0); \n"
"} \n"
};
glShaderSource(vertexShader, 1, vertexShader_src, NULL);
glCompileShader(vertexShader);
glShaderSource(fragmentShader, 1, fragmentShader_src, NULL);
glCompileShader(fragmentShader);
GLuint tprogram = glCreateProgram();
glAttachShader(tprogram, vertexShader);
glAttachShader(tprogram, fragmentShader);
glLinkProgram(tprogram);
glValidateProgram(tprogram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glGenVertexArrays(1, &vertex_array_obj);
glBindVertexArray(vertex_array_obj);
return tprogram;
}
void render(GLFWwindow* window)
{
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_POINTS, 0, 1);
}
void mouseCallback(GLFWwindow* window, int button, int action, int mods)
{
km.mouseClick(button, action, mods);
}
void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
km.keyPressed(key, action, mods);
}
int main()
{
jelly::lua::LuaManager lm;
// 0 = Build | 1 = Release | 2 = Alpha | 3 = Beta
int buildType = 0;
std::string title = "Relieved";
if (buildType != 1)
{
switch (buildType) {
case 0 :
title += " | Build Version";
break;
case 2 :
title += " | Alpha Version";
break;
case 3 :
title += " | Beta Version";
break;
default :
break;
}
}
GLFWwindow* window;
if (!glfwInit()) {
glfwTerminate();
return -1;
}
window = glfwCreateWindow(640, 400, title.c_str(), NULL, NULL);
if (!window) {
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err)
{
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
}
glLoadIdentity();
program = startRender(window);
glUseProgram(program);
glfwSetKeyCallback(window, keyCallback);
glfwSetMouseButtonCallback(window, mouseCallback);
while(!glfwWindowShouldClose(window))
{
render(window);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &vertex_array_obj);
glDeleteProgram(program);
glDeleteVertexArrays(1, &vertex_array_obj);
glfwTerminate();
return 0;
}
You are creating your vertexarray
glGenVertexArrays(1, &vertex_array_obj);
glBindVertexArray(vertex_array_obj);
but there is not data in it. You need to add some data so that the shaders are fired (even if the value is hardcoded in the vertex shader, as it is your case)
So, add some vertices to your vertex array like this:
std::vector<float> v({0.0f,0.0f,0.0f});
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, v.size() *sizeof(float), &v[0], GL_STATIC_DRAW); //v is a std::vector<float>, it size is the size of the data (buffer), and &v[0] gives the pointer of the data
glEnableVertexAttribArray(0); //layout 0. In this example, position
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glVertexAttribPointer(
0, // layout in shader
3, // number of elements
GL_FLOAT, // type
GL_FALSE, // normalized?
0,
reinterpret_cast<void*>(0)
);
A good way to send data is to pack everything in a std::vector and just arrange the layouts
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, v.size() *sizeof(float), &v[0], GL_STATIC_DRAW); //v is a std::vector<float>, it size is the size of the data (buffer), and &v[0] gives the pointer of the data
const int s[] = { 3, 3, 2 }; //size of data, in my case 3 floats for position, 3 for normals and 2 for texture coordinates
size_t accum = 0;
for (int z = 0; z < 3; ++z){
glEnableVertexAttribArray(z);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glVertexAttribPointer(
z, // layout in shader
s[z], // number of elements
GL_FLOAT, // type
GL_FALSE, // normalized?
8 * sizeof(float), // stride (3+3+2)
reinterpret_cast<void*>(accum*sizeof(float)) //shift from the previous data [3,3,2]
);
accum += s[z];
}
Read about vertex arrays here:
https://stackoverflow.com/a/17517103/5729376