I followed an opengl tutorial and created a more object oriented version. I want to draw a Texture but the only thing which works is the glClearColor command. I have no idea why it doesn't work. I tried everything. Here's the code:
Sprite.cpp
#include "Sprite.h"
#include <SOIL\SOIL.h>
Sprite::Sprite(const char* texturePath, float x, float y, GLuint width, GLuint height)
{
Sprite::init(texturePath, x, y, width, height);
}
Sprite::~Sprite()
{
}
void Sprite::init(const char* texturePath, float x, float y, GLuint width, GLuint height)
{
Logger::info("Initializing Sprite...");
_x = x;
_y = y;
_width = width;
_height = height;
// Build and compile our shader program
// Set up vertex data (and buffer(s)) and attribute pointers
const GLfloat vertices[] = {
// Positions // Colors // Texture Coords
_x, _y, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
_x, _y + _height, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
_x + _width, _y, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
_y + _width, _y + _height, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
};
/*GLfloat vertices[] = {
// Positions // Colors // Texture Coords
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // Top Right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // Bottom Right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // Bottom Left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // Top Left
};
*/
constexpr GLuint indices[] = { // Note that we start from 0!
0, 1, 3, // First Triangle
1, 2, 3 // Second Triangle
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
// TexCoord attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
glBindVertexArray(0); // Unbind VAO
// Load and create a texture
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture); // All upcoming GL_TEXTURE_2D operations now have effect on this texture object
// Set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture wrapping to GL_REPEAT (usually basic wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Load image, create texture and generate mipmaps
int twidth, theight;
unsigned char* image = SOIL_load_image(texturePath, &twidth, &theight, 0, SOIL_LOAD_RGB);
if (image == 0)
{
Logger::fatalError("Image is null!");
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture when done, so we won't accidentily mess up our texture.
//_texture2 = texture2;
Logger::info("Sprite initialization succesful!");
}
void Sprite::draw(Shader *shader)
{
/* glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _texture1);
glUniform1i(glGetUniformLocation(shader->_programID, "ourTexture1"), 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _texture2);
glUniform1i(glGetUniformLocation(shader->_programID, "ourTexture2"), 1);
*/
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Bind Texture
glBindTexture(GL_TEXTURE_2D, texture);
if (texture == 0) {
Logger::fatalError("texture1 is null");
}
if (shader == 0) {
Logger::fatalError("shader is null");
}
if (VAO == 0) {
Logger::fatalError("VAO is null");
}
// Activate shader
// glActiveTexture(GL_TEXTURE0);
// glBindTexture(GL_TEXTURE_2D, texture);
//glUniform1i(glGetUniformLocation(shader->_programID, "ourTexture"), 0);
//shader->Use();
// Draw container
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
Shader.cpp
#include "Shader.h"
Shader::Shader(const GLchar* vertexShaderPath, const GLchar* fragmentShaderPath)
{
std::string vertexCode;
std::string fragmentCode;
std::ifstream vertexShaderFile;
std::ifstream fragmentShaderFile;
// ensures ifstream objects can throw exceptions:
vertexShaderFile.exceptions(std::ifstream::badbit);
fragmentShaderFile.exceptions(std::ifstream::badbit);
try
{
// Open files
vertexShaderFile.open(vertexShaderPath);
fragmentShaderFile.open(fragmentShaderPath);
std::stringstream vShaderStream, fShaderStream;
// Read file's buffer contents into streams
vShaderStream << vertexShaderFile.rdbuf();
fShaderStream << fragmentShaderFile.rdbuf();
// close file handlers
vertexShaderFile.close();
fragmentShaderFile.close();
// Convert stream into GLchar array
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure e)
{
Logger::info("ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ");
}
const GLchar* vertexShaderCode = vertexCode.c_str();
const GLchar* fragmentShaderCode = fragmentCode.c_str();
Shader::compileShaders(vertexShaderCode, fragmentShaderCode);
}
void Shader::compileShaders(const GLchar* vertexShaderCode, const GLchar* fragmentShaderCode) {
Logger::info("Compiling Shaders...");
GLuint vertex, fragment;
GLint success;
GLchar infoLog[512];
// Vertex Shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vertexShaderCode, NULL);
glCompileShader(vertex);
// Print compile errors if any
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
Logger::fatalError("ERROR::SHADER::VERTEX::COMPILATION_FAILED");
};
// Similiar for Fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fragmentShaderCode, NULL);
glCompileShader(fragment);
// Print compile errors if any
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
Logger::fatalError("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED");
};
// Shader Program
this->_programID = glCreateProgram();
glAttachShader(this->_programID, vertex);
glAttachShader(this->_programID, fragment);
glLinkProgram(this->_programID);
// Print linking errors if any
glGetProgramiv(this->_programID, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(this->_programID, 512, NULL, infoLog);
Logger::fatalError("ERROR::SHADER::PROGRAM::LINKING_FAILED");
}
// Delete the shaders as they're linked into our program now and no longer necessery
glDeleteShader(vertex);
glDeleteShader(fragment);
Logger::info("Shader compilation succesful!");
}
void Shader::Use() {
glUseProgram(this->_programID);
}
Shader::~Shader()
{
}
MainGame.cpp
#include "MainGame.h"
MainGame::MainGame()
{
_window = nullptr;
_screenWidth = 1024;
_screenHeight = 768;
_gameState = GameState::PLAY;
}
MainGame::~MainGame()
{
}
void MainGame::run() {
initSystems();
gameLoop();
}
void MainGame::initSystems() {
//Initialize SDL
SDL_Init(SDL_INIT_EVERYTHING);
//Create Window
_window = SDL_CreateWindow("Half Life 3", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _screenWidth, _screenHeight, SDL_WINDOW_OPENGL);
//glViewport(0, 0, _screenWidth, _screenHeight);
if (_window == nullptr) {
Logger::fatalError("SDL Window could not be created!");
}
SDL_GLContext glContext = SDL_GL_CreateContext(_window);
if (glContext == nullptr) {
Logger::fatalError("SDL_GL context could not be created");
}
GLenum error = glewInit();
if (error != GLEW_OK) {
Logger::fatalError("Could not initialize glew!");
}
Logger::info("Initialization succesful");
//Double Buffer: Smooth, no flickering
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
glClearColor(0, 0, 1, 1.0);
Shader shader("Shaders/Shader.vert", "Shaders/Shader.frag");
_shader = &shader;
Sprite sprite("Textures/wall.jpg", 0.5f, 0.5f, 100, 100);
_texture = &sprite;
}
void MainGame::gameLoop() {
while (_gameState != GameState::EXIT) {
processInput();
drawGame();
}
}
void MainGame::processInput() {
SDL_Event evnt;
while (SDL_PollEvent(&evnt) == true) {
switch (evnt.type) {
case SDL_QUIT:
_gameState = GameState::EXIT;
// std::cout << "Quit Event" << std::endl;
break;
case SDL_MOUSEMOTION:
// std::cout << "x: " << evnt.motion.x << " y: " << evnt.motion.y << std::endl;
break;
}
}
}
void MainGame::drawGame() {
// glClearDepth(1.0);
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//_shader->Use();
// Bind Textures using texture units
_texture->draw(_shader);
// Swap the screen buffers
SDL_GL_SwapWindow(_window);
}
Fragment shader:
#version 330 core
in vec3 ourColor;
in vec2 TexCoord;
out vec4 color;
uniform sampler2D ourTexture;
void main()
{
color = texture(ourTexture, TexCoord);
}
Vertex shader:
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec2 texCoord;
out vec3 ourColor;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(position, 1.0f);
ourColor = color;
TexCoord = texCoord;
}
Console log:
Initialization succesful
Compiling Shaders...
Shader compilation succesful!
Initializing Sprite...
Sprite initialization succesful!
You see, everything loads correctly and initializes correctly and there are no errors. It still displays nothing but the glClearColor. What's wrong?
The blank screen effect is very common with Open GL graphics. It means the view, camera, lighting, or something has been set up in such a way that you see nothing.
The cure is to comment out all your code, except the clear which works (that's an important first step, you are at least getting Open GL output). Then add code until you see something, anything, on screen.
You then gradually shift the anything ) to what you want to see by commenting the code back in, and commenting it out again if you go back to the blank screen effect.