Open gl sprite class not working - c++

So first of all, i am a total beginner in open gl, and i am learning opengl from learnopengl.com. So i understood whats going on in the code in the main method.The code works in main method. But when i tried to create a class for it, it doesn't render anything!! I have absolutely no idea whats going wrong!
Sprite.h
#pragma once
#include"Shader.h"
#include<GL\glew.h>
class Sprite {
GLuint vao;
GLuint vbo;
int vertexCount;
Shader shader;
public:
Sprite(const GLfloat vertices[9], int noOfVertices, Shader s = Shader()) : vertexCount(noOfVertices) , shader(s)
{
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, this->vertexCount, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void draw() {
glBindVertexArray(this->vao);
glDrawArrays(GL_TRIANGLES, 0, this->vertexCount);
glBindVertexArray(0);
}
};
Shader.h
#pragma once
#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<vector>
#include<GL\glew.h>
class Shader {
GLuint programID;
GLuint vertID;
GLuint fragID;
public:
Shader(std::string vertex = "Shaders/Dvert.vert", std::string fragment = "Shaders/Dfrag.frag")
{
this->programID = glCreateProgram();
this->vertID = glCreateShader(GL_VERTEX_SHADER);
this->fragID = glCreateShader(GL_FRAGMENT_SHADER);
this->CompileShaders(vertex, fragment);
this->LinkProgram();
}
GLuint getProgramId() {
return this->programID;
}
private:
void CompileShaders(std::string vertexShaderPath, std::string FragShaderPath) {
std::string vCode = GetContentsFrom(vertexShaderPath).c_str();
const char * vertexCode = vCode.c_str();
glShaderSource(this->vertID, 1, &vertexCode, NULL);
glCompileShader(this->vertID);
this->HandleShaderErrors(this->vertID);
std::string fCode = GetContentsFrom(FragShaderPath).c_str();
const char * fragCode = fCode.c_str();
glShaderSource(this->fragID, 1, &fragCode, NULL);
glCompileShader(this->fragID);
std::cout << fragCode << std::endl;
this->HandleShaderErrors(this->fragID);
}
void LinkProgram() {
glAttachShader(this->programID, this->vertID);
glAttachShader(this->programID, this->fragID);
glLinkProgram(this->programID);
this->HandleLinkErrors();
}
std::string GetContentsFrom(std::string path) {
std::ifstream file(path);
std::ostringstream stream;
if (!file) {
std::cout << "Specified file path is invalid" << std::endl;
return "";
}
stream << file.rdbuf();
std::cout << stream.str() << std::endl << std::endl;
return stream.str();
}
void HandleLinkErrors() {
int result;
glGetProgramiv(this->programID, GL_LINK_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetProgramiv(this->programID, GL_INFO_LOG_LENGTH, &length);
std::vector<char> error(length);
glGetProgramInfoLog(this->programID, length , &length, &error[0]);
std::cout << &error[0] << std::endl;
glDetachShader(this->programID, this->vertID);
glDetachShader(this->programID, this->fragID);
}
}
void HandleShaderErrors(GLuint shader) {
int status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
int length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
std::vector<char> error(length);
glGetShaderInfoLog(shader, length, &length, &error[0]);
std::cout << &error[0] << std::endl;
glDeleteShader(shader);
}
}
};
Main.cpp
#include<GL\glew.h>
#include<GLFW\glfw3.h>
#include"Console.h"
#include"Headers\Shader.h"
#include"Headers\Sprite.h"
#include<iostream>
static const GLfloat vertices[] = {
0.5f, -0.5f ,0.0f ,
-0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
int main() {
if (!glfwInit()) {
Console.Log("GLFW could not be initialised!!");
Console.Wait();
}
GLFWwindow *window = glfwCreateWindow(600, 400, "Open GL", nullptr, nullptr);
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) {
Console.Log("GLEW could not be initialised!!");
Console.Wait();
}
Sprite s(vertices, 3);
glClearColor(0, 0, 0, 1);
glfwWindowHint(GLFW_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_VERSION_MINOR, 3);
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwPollEvents();
s.draw();
glfwSwapBuffers(window);
}
}
Please help me out!!
Note:- The code in the main method renders the white triangle without the
shaders,so my graphics card works without shaders.
Also the Console class i have created is just to print to the console and has nothing to do with the opengl stuff. Console.Log isstd::cout<< and Console.Wait is std::cin.get();

There are at least two problems. The first is that your sizeof(vertices) in Sprite produces wrong result, because it gives the size of a pointer, not the size of the array. To fix it, replace it with sizeof(GLfloat) * 9.
The second problem is that you are specifying the OpenGL context version too late, after creating the window and context. To fix it, call these methods before glfwCreateWindow, not after:
glfwWindowHint(GLFW_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_VERSION_MINOR, 3);

Related

VAO isn't rendering my simple triangle, what could be causing this?

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);

Rendering a single triangle using TriangleStrip renders a rectangle

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.

I am having trouble understanding the correlation between buffers in this program [duplicate]

This question already has answers here:
How do OpenGL's buffers work?
(2 answers)
OpenGL Vertex Array/Buffer Objects
(2 answers)
Drawing multiple triangles in OpenGL
(1 answer)
glVertexAttribPointer and glVertexAttribFormat: What's the difference?
(1 answer)
Closed 2 years ago.
I am fairly new to opengl and don't see how element buffer vbo and array buffer buffer1 work together in creating this square. I don't understand buffer objects in general and a brief explanation of how they work would be appreciated. Once again there are no errors in this code i just don't understand the how the vertex data and indices data are being carried throughout the program and how the buffers work together. This is source code. Also the fragment shader and vertex shader I am not including.
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
struct Shaderprogramsource
{
std::string VertexSouce;
std::string FragmentSource;
};
static Shaderprogramsource Parseshader(const std::string& filepath)
{
std::ifstream stream(filepath);
enum class Shadertype
{
VERTEX = 0,
FRAGMENT = 1,
NONE = 5
};
std::string line;
std::stringstream ss[3];
Shadertype type = Shadertype::NONE;
while (getline(stream, line))
{
if (line.find("#shader") != std::string::npos)
{
if (line.find("vertex") != std::string::npos)
type = Shadertype::VERTEX;
else if (line.find("fragment") != std::string::npos)
type = Shadertype::FRAGMENT;
}
else
{
ss[(int)type] << line << "\n";
}
}
return Shaderprogramsource{ ss[0].str(), ss[1].str() };
}
static int CompileShader(unsigned int type, const std::string& Source)
{
unsigned int id = glCreateShader(type);
const char* src = Source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));
glGetShaderInfoLog(id, length, &length, message);
std::cout << message;
return 0;
}
return id;
}
static unsigned int CreateShader(
const std::string& Vertexshader,
const std::string& Fragmentshader)
{
unsigned int program = glCreateProgram();
unsigned int vertex = CompileShader(GL_VERTEX_SHADER, Vertexshader);
unsigned int fragment = CompileShader(GL_FRAGMENT_SHADER, Fragmentshader);
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
glValidateProgram(program);
return program;
}
int main(void)
{
GLFWwindow* window;
/* 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);
if (GLEW_OK == glewInit())
{
}
float vertices[] = { -0.5, -0.5,
0.5, -0.5,
0.5, 0.5,
-0.5, 0.5 };
unsigned int indices[] = {
0, 1, 2,
2, 3, 0
};
unsigned int buffer1;
unsigned int vbo;
glGenBuffers(1, &buffer1);
glBindBuffer(GL_ARRAY_BUFFER, buffer1);
glBufferData(GL_ARRAY_BUFFER, 6 * 2 * sizeof(float), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
glEnableVertexAttribArray(0);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned int), indices, GL_STATIC_DRAW);
Shaderprogramsource source = Parseshader("res/shaders/Basic.Shader");
unsigned int shader =
CreateShader(source.VertexSouce, source.FragmentSource);
glUseProgram(shader);
int location = glGetUniformLocation(shader, "Color_u");
if (location > -1) {
glUniform4f(location, 0.8f, 0.0f, 0.0f, 1.0f);
}
std::cout << source.VertexSouce;
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shader);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glDeleteProgram(shader);
glfwTerminate();
return 0;
}

Badly contained in a string except when I store it in C++ class

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.

SDL2 with OpenGL 4.4: Triangle Not Rendering Properly

I'm using OpenGL 4.4 with SDL2. I am trying to render a simple triangle with the vertices (-1, -1, 0), (1, -1, 0), (0, 1, 0). However, when I think I'm doing everything correctly, nothing is drawn.
I extracted and reorganized the relevant code from my project:
#include <cerrno>
#include <cstring>
#include <exception>
#include <fstream>
#include <iostream>
#include <string>
#include <GL/glew.h>
#include <GL/glu.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
void init();
void cleanUp();
std::string loadShader(std::string filepath);
void checkShaderSuccess(GLuint shader);
SDL_Window* win;
SDL_GLContext glContext;
GLuint program, vertShader, fragShader, vao, vbo;
class GenError: public std::exception {
public:
GenError():
exception(), msg("") {}
GenError(const std::string& m):
exception(), msg(m) {}
virtual ~GenError() throw() {}
virtual const char* what() const throw() {
return msg.c_str();
}
private:
std::string msg;
};
int main() {
init();
program = glCreateProgram();
if (program == 0) {
throw GenError("Shader creation failed: "
"Could not find valid memory location in "
"constructor");
}
vertShader = glCreateShader(GL_VERTEX_SHADER);
fragShader = glCreateShader(GL_FRAGMENT_SHADER);
if (vertShader == 0 || fragShader == 0) {
std::string m;
m += "Shader creation failed: "
"Could not find valid memory location when "
"adding shader: ";
m += (char *)gluErrorString(glGetError());
throw GenError(m);
}
std::cout << "Creating vertex shader..." << std::endl;
std::string data = loadShader("./shaders/basicVertex.vs");
const GLchar* data_c = data.c_str();
glShaderSource(vertShader, 1, &data_c, NULL);
glCompileShader(vertShader);
checkShaderSuccess(vertShader);
glAttachShader(program, vertShader);
std::cout << "Vertex shader created" << std::endl;
std::cout << "Creating fragment shader..." << std::endl;
data = loadShader("./shaders/basicFragment.fs");
data_c = data.c_str();
glShaderSource(fragShader, 1, &data_c, NULL);
glCompileShader(fragShader);
checkShaderSuccess(fragShader);
glAttachShader(program, fragShader);
std::cout << "Fragment shader created" << std::endl;
glLinkProgram(program);
GLint success;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (success == GL_FALSE) {
GLint logLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLen);
GLchar programLog[logLen];
glGetProgramInfoLog(program, logLen, &logLen, programLog);
std::string m;
m += "Failed to link program: ";
m += (char *)gluErrorString(glGetError());
m += ": ";
m += (char *)programLog;
throw GenError(m);
}
glValidateProgram(program);
glGetProgramiv(program, GL_VALIDATE_STATUS, &success);
if (success == GL_FALSE) {
GLint logLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLen);
GLchar programLog[logLen];
glGetProgramInfoLog(program, logLen, &logLen, programLog);
std::string m;
m += "Failed to validate program: ";
m += (char *)gluErrorString(glGetError());
m += ": ";
m += (char *)programLog;
throw GenError(m);
}
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
const GLfloat verts[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f
};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER,
sizeof(verts),
verts,
GL_STATIC_DRAW );
SDL_Event ev;
bool running = true;
while (true) {
while (SDL_PollEvent(&ev)) {
if (ev.type == SDL_WINDOWEVENT &&
ev.window.event == SDL_WINDOWEVENT_CLOSE) {
std::cout << "Closing window..." << std::endl;
running = false;
break;
}
}
if (!running) break;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0,
3,
GL_FLOAT,
GL_FALSE,
3*sizeof(GLfloat),
(GLvoid*)0 );
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
SDL_GL_SwapWindow(win);
}
std::cout << "Window closed" << std::endl;
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
glDeleteProgram(program);
glDeleteShader(vertShader);
glDeleteShader(fragShader);
cleanUp();
return 0;
}
void init() {
std::cout << "Initializing..." << std::endl;
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::string m;
m.append("Error initializing SDL2: ");
m.append(SDL_GetError());
throw GenError(m);
}
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 4);
win = SDL_CreateWindow("Triangle Test",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
800, 600,
SDL_WINDOW_OPENGL );
if (win == NULL) {
throw GenError(SDL_GetError());
}
glContext = SDL_GL_CreateContext(win);
if (glContext == NULL) {
std::string m;
m.append("Error associating window with OpenGL: SDL Error: ");
m.append(SDL_GetError());
throw GenError(m);
}
glewExperimental = GL_TRUE;
GLenum glewErr = glewInit();
if (glewErr != GLEW_OK) {
std::string m;
m.append("Error initializing OpenGL GLEW extension: ");
m.append((const char*)glewGetErrorString(glewErr));
throw GenError(m);
} else {
/* GLEW does not play nice with OpenGL 4.4.
* GLEW thinks OpenGL 4.4 is "pretentious" and
* "entitled". GLEW likes to throw an invalid
* enumerant error the next time glGetError is
* called after GLEW's initialization.
* glGetError must be envoked to discard this
* faulty error. GLEW makes my code look sloppy.
* We do not like GLEW. We tolerate GLEW.
*/
GLenum junk = glGetError();
}
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glFrontFace(GL_CW);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_FRAMEBUFFER_SRGB);
if(SDL_GL_SetSwapInterval(1) < 0) {
std::cerr << "Warning: Unable to set VSync! "
<< "SDL Error: "
<< SDL_GetError() << std::endl;
}
GLenum error = glGetError();
if (error != GL_NO_ERROR) {
std::string m;
m.append("Error initializing OpenGL: OpenGL Error: ");
m.append(reinterpret_cast<const char*>(gluErrorString(error)));
throw GenError(m);
}
std::cout << "Initialized" << std::endl;
}
void cleanUp() {
std::cout << "Cleaning up..." << std::endl;
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(win);
SDL_Quit();
std::cout << "Cleaned" << std::endl;
}
std::string loadShader(std::string filepath) {
std::ifstream shaderFile(filepath.c_str());
if (!shaderFile.is_open()) {
std::cerr << "Could not load shader: "
<< "Error opening "
<< filepath
<< ": " << std::strerror(errno)
<< std::endl;
return std::string("");
}
std::string content, line;
while (std::getline(shaderFile, line)) {
content += line + '\n';
}
shaderFile.close();
return content;
}
void checkShaderSuccess(GLuint shader) {
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (success == GL_FALSE) {
GLint logLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLen);
GLchar shaderLog[logLen];
glGetShaderInfoLog(shader, logLen, &logLen, shaderLog);
std::string m;
m += "Shader compilation failed: ";
m += (char *)gluErrorString(glGetError());
m += ": ";
m += (char *)shaderLog;
glDeleteShader(shader);
throw GenError(m);
}
}
...without error catching (for faster skimming):
#include <cerrno>
#include <cstring>
#include <exception>
#include <fstream>
#include <iostream>
#include <string>
#include <GL/glew.h>
#include <GL/glu.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
void init();
void cleanUp();
std::string loadShader(std::string filepath);
SDL_Window* win;
SDL_GLContext glContext;
GLuint program, vertShader, fragShader, vao, vbo;
int main() {
init();
program = glCreateProgram();
vertShader = glCreateShader(GL_VERTEX_SHADER);
fragShader = glCreateShader(GL_FRAGMENT_SHADER);
std::cout << "Creating vertex shader..." << std::endl;
std::string data = loadShader("./shaders/basicVertex.vs");
const GLchar* data_c = data.c_str();
glShaderSource(vertShader, 1, &data_c, NULL);
glCompileShader(vertShader);
glAttachShader(program, vertShader);
std::cout << "Vertex shader created" << std::endl;
std::cout << "Creating fragment shader..." << std::endl;
data = loadShader("./shaders/basicFragment.fs");
data_c = data.c_str();
glShaderSource(fragShader, 1, &data_c, NULL);
glCompileShader(fragShader);
glAttachShader(program, fragShader);
std::cout << "Fragment shader created" << std::endl;
glLinkProgram(program);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
const GLfloat verts[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f
};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER,
sizeof(verts),
verts,
GL_STATIC_DRAW );
SDL_Event ev;
bool running = true;
while (true) {
while (SDL_PollEvent(&ev)) {
if (ev.type == SDL_WINDOWEVENT &&
ev.window.event == SDL_WINDOWEVENT_CLOSE) {
std::cout << "Closing window..." << std::endl;
running = false;
break;
}
}
if (!running) break;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0,
3,
GL_FLOAT,
GL_FALSE,
3*sizeof(GLfloat),
(GLvoid*)0 );
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
SDL_GL_SwapWindow(win);
}
std::cout << "Window closed" << std::endl;
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
glDeleteProgram(program);
glDeleteShader(vertShader);
glDeleteShader(fragShader);
cleanUp();
return 0;
}
void init() {
std::cout << "Initializing..." << std::endl;
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 4);
win = SDL_CreateWindow("Triangle Test",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
800, 600,
SDL_WINDOW_OPENGL );
glContext = SDL_GL_CreateContext(win);
glewExperimental = GL_TRUE;
GLenum glewErr = glewInit();
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glFrontFace(GL_CW);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_FRAMEBUFFER_SRGB);
std::cout << "Initialized" << std::endl;
}
void cleanUp() {
std::cout << "Cleaning up..." << std::endl;
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(win);
SDL_Quit();
std::cout << "Cleaned" << std::endl;
}
std::string loadShader(std::string filepath) {
std::ifstream shaderFile(filepath.c_str());
std::string content, line;
while (std::getline(shaderFile, line)) {
content += line + '\n';
}
shaderFile.close();
return content;
}
...my vertex shader (GLSL):
#version 440
layout (location = 0) in vec3 position;
void main() {
gl_Position = vec4(0.5 * position, 1.0);
}
...and my fragment shader:
#version 440
out vec4 fragColor;
void main() {
fragColor = vec4(0.0, 1.0, 1.0, 1.0);
}
Now oddly enough, when I change line 148 in my C++ code (with error catching) from this...
3*sizeof(GLfloat),
...to this (in other words, changing the stride)...
3*sizeof(GLdouble),
...compiling and running produces a triangle with the vertices (-1, -1, 0), (0, 0, 0), (0, 1, 0). The second vertex is apparently getting obscured. Instead of an isosceles triangle, I get a scalene triangle.
I would like to 1) figure out how to fix my program so that it displays a triangle with the specified vertices, and 2) understand what I did wrong initially that caused my such an odd result when modifying the aforementioned line of code.
I have been tinkering with this for almost a week. Any insight is appreciated. Thanks!
Your code has a problem with the winding order of the polygons. You specify clockwise winding for the front faces, and enable culling of the back faces:
glFrontFace(GL_CW);
glCullFace(GL_BACK);
But the triangle has counter-clockwise winding order:
const GLfloat verts[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f
};
This means that the triangle will be eliminated by culling.
Using counter-clockwise winding is mostly standard in OpenGL, and is also the default. So the best option is that you simply remove this line of code:
glFrontFace(GL_CW);
This will leave the value at GL_CCW, which matches your geometry.
Disabling backface culling is always one of the first things you should do when polygons don't show up. Having the wrong winding order is one of the most common causes of things not rendering, and it's very easy to triage by simply disabling culling, and checking if that makes the geometry show up.