The piece of code you find below draws a cube with a camera inside of it.
I don't understand why when I press escape key or the right, left, up and down arrow keys the program doesn't catch the event.
Inside key_callback I've added std::cout << key << std::endl; expecting to see on the console the identifier of the pressed keys, but everytime I press any keys nothing is printed in the console.
#include <cstdlib>
#include <iostream>
#include <vector>
#include <array>
#include <chrono>
using timer = std::chrono::high_resolution_clock;
#ifdef _WIN32
#include <GL/glew.h>
#else
#define GLFW_INCLUDE_GLCOREARB
#define GL_GLEXT_PROTOTYPES
#endif
#define PI 3.1415926535897932384626433832795f
#include <GLFW/glfw3.h>
#include "lodepng.hpp"
#define GLM_FORCE_RADIANS
#include "glm/glm.hpp"
#include "glm/gtx/norm.hpp"
#include "glm/gtx/rotate_vector.hpp"
#include "glm/gtc/matrix_transform.hpp"
#if defined(_MSC_VER)
#pragma comment(lib,"user32")
#pragma comment(lib,"gdi32")
#pragma comment(lib,"opengl32")
#pragma comment(lib,"glew32")
#pragma comment(lib,"glfw3")
#endif
glm::vec3 camera_position(0.0f, 0.0f, 6.0f);
glm::vec3 camera_direction(0.0f, 0.0f, -1.0f);
glm::vec3 camera_up(0.0f, 1.0f, 0.0f);
using timer = std::chrono::high_resolution_clock;
timer::time_point start_time, last_time;
float t = 0.0;
float dt = 0.0;
bool translate_forward = false;
bool translate_backward = false;
bool translate_right = false;
bool translate_left = false;
bool rotate_up = false;
bool rotate_down = false;
bool rotate_right = false;
bool rotate_left = false;
bool rotate_z_left = false;
bool rotate_z_right = false;
bool sky_on = true;
bool sun_visible = true;
bool earth_visible = true;
bool moon_visible = true;
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
GLuint tex_flag;
static void error_callback(int error, const char* description)
{
std::cerr << description << std::endl;
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
std::cout << key << std::endl;
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
if (key == GLFW_KEY_UP)
{
if (action)
rotate_up = true;
else
rotate_up = false;
}
if (key == GLFW_KEY_DOWN)
{
if (action)
rotate_down = true;
else
rotate_down = false;
}
if (key == GLFW_KEY_RIGHT)
{
if (action)
rotate_right = true;
else
rotate_right = false;
}
if (key == GLFW_KEY_LEFT)
{
if (action)
rotate_left = true;
else
rotate_left = false;
}
}
// Shader sources
const GLchar* vertexSource =
#if defined(__APPLE_CC__)
"#version 150 core\n"
#else
"#version 130\n"
#endif
"in vec3 position;"
"in vec3 color;"
"in vec2 coord;"
"out vec3 Color;"
"out vec2 Coord;"
"uniform mat4 model;"
"uniform mat4 view;"
"uniform mat4 projection;"
"void main() {"
" Color = color;"
" Coord = coord;"
" gl_Position = projection * view * model * vec4(position, 1.0);"
"}";
const GLchar* fragmentSource =
#if defined(__APPLE_CC__)
"#version 150 core\n"
#else
"#version 130\n"
#endif
"in vec3 Color;"
"in vec2 Coord;"
"out vec4 outColor;"
"uniform sampler2D textureSampler;"
"void main() {"
" outColor = vec4(Color, 1.0)*texture(textureSampler, Coord);"
"}";
const GLfloat vertices[] = {
// Position Color Texcoords
-0.5f, 0.5f, -0.5f, 0.15f, 0.33f, 0.55f, .25f, 0.0f, // 0
0.5f, 0.5f, -0.5f, 0.15f, 0.33f, 0.55f, 0.5f, 0.0f, // 1
-0.5f, 0.5f, -0.5f, 0.15f, 0.33f, 0.55f, 0.0f, 1.f / 3.f, // 2
-0.5f, 0.5f, 0.5f, 0.15f, 0.33f, 0.55f, .25f, 1.f / 3.f, // 3
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.5f, 1.f / 3.f, // 4
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, .75f, 1.f / 3.f, // 5
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.f / 3.f, // 6
-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 2.f / 3.f, // 7
-0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, .25f, 2.f / 3.f, // 8
0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.5f, 2.f / 3.f, // 9
0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, .75f, 2.f / 3.f, // 10
-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 2.f / 3.f, // 11
-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, .25f, 1.0f, // 12
0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.5f, 1.0f, // 13
};
const GLuint elements[] = {
0, 3, 4, 0, 4, 1,
2, 7, 8, 2, 8, 3,
3, 8, 9, 3, 9, 4,
4, 9,10, 4,10, 5,
5,10,11, 5,11, 6,
8,12,13, 8,13, 9
};
GLuint vao;
GLuint vbo;
GLuint ibo;
GLuint shaderProgram;
GLuint textures[1];
float t = 0;
void check(int line)
{
GLenum error = glGetError();
while (error != GL_NO_ERROR)
{
switch (error)
{
case GL_INVALID_ENUM: std::cout << "GL_INVALID_ENUM : " << line << std::endl; break;
case GL_INVALID_VALUE: std::cout << "GL_INVALID_VALUE : " << line << std::endl; break;
case GL_INVALID_OPERATION: std::cout << "GL_INVALID_OPERATION : " << line << std::endl; break;
case GL_OUT_OF_MEMORY: std::cout << "GL_OUT_OF_MEMORY : " << line << std::endl; break;
default: std::cout << "Unrecognized error : " << line << std::endl; break;
}
error = glGetError();
}
}
void initialize_shader()
{
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, NULL);
glCompileShader(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glBindFragDataLocation(shaderProgram, 0, "outColor");
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
void destroy_shader()
{
glDeleteProgram(shaderProgram);
}
void initialize_vao()
{
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
// shaderProgram must be already initialized
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0);
GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
GLint cooAttrib = glGetAttribLocation(shaderProgram, "coord");
glEnableVertexAttribArray(cooAttrib);
glVertexAttribPointer(cooAttrib, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));
}
void destroy_vao()
{
glDeleteBuffers(1, &ibo);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
}
void initialize_texture()
{
glGenTextures(1, &textures[0]);
std::vector<unsigned char> image;
unsigned width, height;
unsigned error = lodepng::decode(image, width, height, "cube3.png");
if (error) std::cout << "decode error " << error << ": " << lodepng_error_text(error) << std::endl;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.data());
// shaderProgram must be already initialized
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
void destroy_texture()
{
glDeleteTextures(1, &textures[0]);
}
void update_camera()
{
glm::vec3 right = glm::cross(camera_direction, camera_up);
glm::vec3 left = glm::cross(right, camera_up);
if (translate_forward)
{
camera_position += camera_direction*dt;
}
if (translate_backward)
{
camera_position -= camera_direction*dt;
}
if (translate_right)
{
camera_position += right * dt;
}
if (translate_left)
{
camera_position -= right * dt;
}
if (rotate_up)
{
camera_direction = glm::rotate(camera_direction, dt, right);
camera_up = glm::rotate(camera_up, dt, right);
}
if (rotate_down)
{
camera_direction = glm::rotate(camera_direction, -dt, right);
camera_up = glm::rotate(camera_up, -dt, right);
}
if (rotate_right)
{
camera_direction = glm::rotate(camera_direction, -dt, camera_up);
}
if (rotate_left)
{
camera_direction = glm::rotate(camera_direction, dt, camera_up);
}
if (rotate_z_left)
{
camera_direction = glm::rotate(camera_direction, dt, left);
camera_up = glm::rotate(camera_up, dt, left);
}
if (rotate_z_right)
{
camera_direction = glm::rotate(camera_direction, -dt, left);
camera_up = glm::rotate(camera_up, -dt, left);
}
}
void draw(GLFWwindow* window)
{
t = (timer::now() - start_time).count() * (float(timer::period::num) / float(timer::period::den));
dt = (timer::now() - last_time).count() * (float(timer::period::num) / float(timer::period::den));
update_camera();
last_time = timer::now();
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 projection = glm::perspective(PI / 4, 1.f / 1.f, 1.0f, 10.0f);
glm::mat4 view = glm::lookAt(glm::vec3(0.0f, 0.0f, -1.3f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 model = glm::rotate(glm::mat4(1.f), PI, glm::vec3(0.0f, 1.0f, 0.0f));
glUseProgram(shaderProgram);
glUniform1i(glGetUniformLocation(shaderProgram, "textureSampler"), tex_flag);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, &projection[0][0]);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, &view[0][0]);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, &model[0][0]);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, 6 * 2 * 3, GL_UNSIGNED_INT, 0); // facce * triangoli per faccia * vertici per triangolo
}
int main(int argc, char const *argv[])
{
GLFWwindow *window;
glfwSetErrorCallback(error_callback);
tex_flag = 0;
if (!glfwInit())
return EXIT_FAILURE;
#if defined(__APPLE_CC__)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#else
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
#endif
window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Project", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
#if defined(_MSC_VER)
glewExperimental = true;
if (glewInit() != GL_NO_ERROR)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
#endif
glfwSetKeyCallback(window, key_callback);
initialize_shader(); check(__LINE__);
initialize_vao(); check(__LINE__);
initialize_texture(); check(__LINE__);
//start = timer::now();
glEnable(GL_DEPTH_TEST); check(__LINE__);
while (!glfwWindowShouldClose(window))
{
draw(window); check(__LINE__);
glfwSwapBuffers(window);
glfwPollEvents();
}
destroy_vao(); check(__LINE__);
destroy_shader(); check(__LINE__);
destroy_texture(); check(__LINE__);
glfwDestroyWindow(window);
glfwTerminate();
return EXIT_SUCCESS;
}
First order of business when hunting down problems like yours it to minimize the surface area and reduce the program as far as possible yet retaining the problematic behaviour. Your code snippet does not constitute a Minimal Complete Verifyable Example (MCVE). I stripped it down to a MCVE:
#include <cstdlib>
#include <iostream>
#include <GLFW/glfw3.h>
static void error_callback(int error, const char* description)
{
std::cerr << description << std::endl;
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
std::cout << key << std::endl;
}
int main(int argc, char const *argv[])
{
GLFWwindow *window;
glfwSetErrorCallback( error_callback );
if (!glfwInit())
return EXIT_FAILURE;
window = glfwCreateWindow(100, 100, "Project", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glfwSetKeyCallback(window, key_callback);
while (!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return EXIT_SUCCESS;
}
Given this minimal example I am unable to reproduce your particular problem; i.e. I am getting key events out of this.
That can mean two things: Either the problem resides somewhere else in your code, or it is something about your particular system and development environment. This is why MCVEs are so important (especially the minimal part); it's the only way to pinpoint the actual culprit.
So here's my suggestion: Try the minimal code I put up and see if it still does not report key events. If so, then it's a problem with your system and not with the code. Otherwise you can re-add layers of functionality piece by piece until it breaks.
Related
When running the program, the camera seems to work fine and I can manipulate the clear colour but the cube itself will not render.
Here's my code:
(The camera and renderer objects are both declared in their respective header files along with their methods)
Main.cpp
#include <GL/glew.h>
#include "Shapes.h"
#include "Renderer.h"
#include "Camera.h"
int main()
{
Renderer* renderer = new Renderer(800, 800, (const char*)"OpenGL Sample Test", glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
GLFWwindow* window = renderer->getWindow();
Block* cube = new Block(renderer);
cube->setColourTint(glm::vec4(0.3f, 0.0f, 0.4f, 1.0f));
while (!glfwWindowShouldClose(window))
{
renderer->updateRender();
cube->rotate((float)glfwGetTime() * glm::radians(50.0f), glm::vec3(0.5f, 0.5f, 0.0f));
}
delete renderer;
return 0;
}
Renderer.cpp
#include "Renderer.h"
#include "Shapes.h"
Renderer::Renderer(int Window_X, int Window_Y, const char* Window_Title, glm::vec4 ClearColour)
{
Renderer::renderList = new std::vector<Shape*>;
Renderer::clearColour = ClearColour;
Renderer::WINDOW_X = Window_X;
Renderer::WINDOW_Y = Window_Y;
Renderer::WINDOW_TITLE = Window_Title;
createWindow();
std::cout << "Running OpenGL extension checks... ";
GLenum glewTest = glewInit();
if (GLEW_OK != glewTest)
{
std::cout << "FAILED";
std::cout << (const char*)glewGetErrorString(glewTest) << std::endl;
glfwDestroyWindow(window);
}
else
{
std::cout << "OK" << std::endl;
glfwMakeContextCurrent(window);
}
//OPENGL//
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, Window_X, Window_Y);
Renderer::shader = new Shader("Vertex.glsl", "Fragment.glsl"); //Create the shaders
Renderer::camera = new Camera(Window_X, Window_Y, glm::vec3(0.0f, 0.0f, 2.0f));
Renderer::modelMatrixShaderLocation = glGetUniformLocation(shader->ID, "model"); //Grab the name of the uniform of the model matrix
Renderer::fragmentColourTintLocation = glGetUniformLocation(shader->ID, "colourTint");
glCheckError();
}
void Renderer::createWindow()
{
//Define OpenGL Version | Create Window
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
std::cout << "Creating GLFW Window... ";
Renderer::window = glfwCreateWindow(WINDOW_X, WINDOW_Y, WINDOW_TITLE, NULL, NULL);
if (window == NULL)
{
std::cout << "ERROR: GLFW WINDOW FAILED TO INSTANTIATE" << std::endl;
glfwTerminate();
}
else
{
std::cout << "OK" << std::endl;
glfwMakeContextCurrent(window);
//Key Callbacks
glfwSetKeyCallback(window, key_callback);
glfwSetWindowCloseCallback(window, close_callback);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
}
}
bool Renderer::updateRender()
{
glClearColor(clearColour.r, clearColour.g, clearColour.b, clearColour.a); //Add background color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Clear the color and depth back buffers
shader->use(); //Bind to the shader program
for (int i = 0; i < renderList->size(); i++)
{
Shape* current = renderList->at(i);
current->clearMatrix();
}
//Refresh the projection matrix
//projection = glm::mat4(1.0f);
//projection = glm::perspective(glm::radians(45.0f), (float)WINDOW_X / (float)WINDOW_Y, 0.1f, 100.0f);
//shader->setMat4("projection", projection);
glCheckError();
for (int i = 0; i < renderList->size(); i++) //Update matrix of each renderable object
{
Shape* current = renderList->at(i);
glUniformMatrix4fv(modelMatrixShaderLocation, 1, GL_FALSE, glm::value_ptr(current->getPosition()));
glUniform4f(fragmentColourTintLocation, current->getColourTint().r, current->getColourTint().g, current->getColourTint().b, current->getColourTint().a);
glBindVertexArray(current->getVAO());
std::cout << "Drawing: " << current << " : " << current->getVAO() << std::endl;
glDrawElements(GL_TRIANGLES, current->getIndicesStride(), GL_UNSIGNED_INT, 0);
glCheckError();
}
camera->Inputs(window); //Process camera input
//Camera Matrix updating
camera->Matrix(45.0f, 0.1f, 100.0f, shader, "camMatrix");
glfwSwapBuffers(window);
glfwPollEvents();
if (glCheckError() != NULL)
{
return true;
}
else
{
return false;
}
}
Renderer::~Renderer()
{
for (int i = 0; i < renderList->size(); i++)
{
Shape* current = renderList->at(i);
glDeleteVertexArrays(1, current->getVAOAddress());
glDeleteBuffers(1, current->getVBOAddress());
glDeleteBuffers(1, current->getEBOAddress());
delete current;
}
glfwDestroyWindow(window);
glfwTerminate();
glDeleteProgram(shader->ID);
delete renderList;
delete shader;
delete camera;
}
GLFWwindow* Renderer::getWindow()
{
return window;
}
void Renderer::push_Renderer(Shape* Renderable_Object)
{
renderList->push_back(Renderable_Object);
}
void Renderer::updateClearColour(glm::vec4 ClearColour)
{
clearColour = ClearColour;
}
Camera.cpp
#include "Camera.h"
Camera::Camera(int width, int height, glm::vec3 position)
{
Camera::width = width;
Camera::height = height;
Position = position;
}
void Camera::Matrix(float FOVdeg, float nearPlane, float farPlane, Shader* shader, const char* uniform)
{
//Matrix Magic
glm::mat4 view = glm::mat4(1.0f);
glm::mat4 projection = glm::mat4(1.0f);
view = glm::lookAt(Position, Position + Orientation, Up);
projection = glm::perspective(glm::radians(FOVdeg), (float)(width / height), nearPlane, farPlane);
//std::cout << "XYZ: " << Position.x << " : " << Position.y << " : " << Position.z << std::endl;
glUniformMatrix4fv(glGetUniformLocation(shader->ID, uniform), 1, GL_FALSE, glm::value_ptr(projection * view));
}
void Camera::Inputs(GLFWwindow* window)
{
//Basic Camera Controls
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
{
Position += speed * Orientation;
}
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
{
Position += speed * -glm::normalize(glm::cross(Orientation, Up));
}
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
{
Position += speed * -Orientation;
}
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
{
Position += speed * glm::normalize(glm::cross(Orientation, Up));
}
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
{
Position += speed * Up;
}
if (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS)
{
Position += speed * -Up;
}
if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
{
speed = 0.4f;
}
if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_RELEASE)
{
speed = 0.1f;
}
//Mouse Control
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) //Hide cursor when left mouse button is pressed
{
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
double MouseX;
double MouseY;
glfwGetCursorPos(window, &MouseX, &MouseY);
float rotX = sensitivity * (float)(MouseY - (height / 2)) / height;
float rotY = sensitivity * (float)(MouseX - (height / 2)) / height;
glm::vec3 newOrientation = glm::rotate(Orientation, glm::radians(-rotX), glm::normalize(glm::cross(Orientation, Up)));
if (!((glm::angle(newOrientation, Up) <= glm::radians(5.0f)) or (glm::angle(newOrientation, -Up) <= glm::radians(5.0f))))
{
Orientation = newOrientation;
}
Orientation = glm::rotate(Orientation, glm::radians(-rotY), Up);
glfwSetCursorPos(window, (width / 2), (height / 2));
}
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_RELEASE) //Show cursor when left mouse button is released
{
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
}
Shapes.h
#pragma once
#ifndef SHAPES_H
#define SHAPES_H
#include "Renderer.h"
#include <GL/glew.h>
#include <glm.hpp>
#include <gtc/type_ptr.hpp>
#include <gtx/rotate_vector.hpp>
#include <gtx/vector_angle.hpp>
inline void GeneralVao(GLuint &VAO, GLuint &VBO, GLuint &EBO, GLint* indices, GLfloat* vertices, GLsizeiptr sizeofidef, GLsizeiptr sizeofvdef)
{
//bind the Vertex Array Object first, then bind and set vertex buffer, and then configure vertex attributes(s).
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
//EBO
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeofidef, indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeofvdef, vertices, GL_STATIC_DRAW);
//Position Attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(0);
//Colour Attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
//unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
class Shape
{
protected:
GLfloat* vertices = NULL;
GLint* indices = NULL;
virtual void constructVao() = 0;
GLuint VAO = NULL, VBO = NULL, EBO = NULL;
glm::mat4 ModelMatrix = glm::mat4(1.0f);
glm::vec4 colourTint = glm::vec4(1.0f);
public:
GLuint getVAO()
{
return VAO;
}
glm::vec4 getColourTint()
{
return colourTint;
}
void setColourTint(glm::vec4 Colour)
{
colourTint = Colour;
}
//Addresses
GLuint* getVAOAddress()
{
return &VAO;
}
GLuint* getVBOAddress()
{
return &VBO;
}
GLuint* getEBOAddress()
{
return &EBO;
}
//
void setPosition(glm::mat4 Matrix)
{
ModelMatrix = Matrix;
}
void rotate(glm::f32 angle, glm::vec3 axis) //Rotates by an angle (floating point) and an axis (vector3)
{
ModelMatrix = glm::rotate(ModelMatrix, angle, axis);
}
void scale(glm::vec3 ScaleFactor3)
{
ModelMatrix = glm::scale(ModelMatrix, ScaleFactor3);
}
void move(glm::vec3 Vector)
{
ModelMatrix = glm::translate(ModelMatrix, Vector);
}
void clearMatrix()
{
ModelMatrix = glm::mat4(1.0f);
}
virtual GLsizei getIndicesStride() = 0;
glm::mat4 getPosition()
{
return ModelMatrix;
}
virtual ~Shape()
{
}
};
class Pyramid : public Shape
{
private:
GLfloat vdef[30] = {
//Position Colour
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, //Front Bottom Left | 0
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, //Front Bottom Right | 1
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, //Back Bottom Left | 2
0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, //Back Bottom Right | 3
0.0f, 0.5f, 0.0f, 1.0f, 1.0f, 1.0f //Top | 4
};
GLint idef[18] = {
//Bottom
0, 2, 3,
3, 1, 0,
//Front
1, 4, 0 ,
//Left
0, 4, 2,
//Right
1, 4, 3,
//Back
3, 4, 2
};
public:
Pyramid(Renderer* renderer)
{
indices = idef;
vertices = vdef;
constructVao();
renderer->push_Renderer(this);
}
void constructVao()
{
GeneralVao(VAO, VBO, EBO, idef, vdef, sizeof(idef), sizeof(vdef));
}
GLsizei getIndicesStride()
{
return sizeof(idef) / sizeof(GLint);
}
virtual ~Pyramid()
{
}
};
class Block : public Shape
{
private:
GLfloat vdef[48] = {
//Position Colour
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, //Front Bottom Left | 0
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, //Front Bottom Right | 1
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, //Back Bottom Left | 2
0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, //Back Bottom Right | 3
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, //Front Top Left | 4
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, //Front Top Right | 5
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, //Back Top Left | 6
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, //Back Top Right | 7
};
GLint idef[36] = {
//Bottom
0, 1, 3,
3, 2, 0,
//Front
1, 0, 4,
4, 5, 1,
//Left
0, 2, 6,
6, 4, 0,
//Right
1, 3, 7,
7, 5, 1,
//Top
4, 5, 7,
7, 6, 4,
//Back
2, 3, 5,
5, 5, 2
};
public:
Block(Renderer* renderer)
{
indices = idef;
vertices = vdef;
setColourTint(glm::vec4(0.3, 0.0, 1.0, 1.0));
constructVao();
renderer->push_Renderer(this);
}
void constructVao()
{
GeneralVao(VAO, VBO, EBO, idef, vdef, (GLsizeiptr)sizeof(idef), (GLsizeiptr)sizeof(vdef));
}
GLsizei getIndicesStride()
{
return sizeof(idef) / sizeof(GLint);
}
virtual ~Block()
{
}
};
#endif
Vertex.glsl
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
uniform mat4 model;
uniform mat4 camMatrix;
out vec3 ourColor;
void main()
{
gl_Position = camMatrix * model * vec4(aPos, 1.0);
ourColor = aColor;
}
Fragment.glsl
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
uniform vec4 colourTint;
void main()
{
FragColor.a = colourTint.a;
FragColor.rgb = ((FragColor.rgb - colourTint.rgb) / FragColor.rgb) * 100;
}
I found the issue.
Turns out it worked, just the cube was unexpectedly black along with the clearcolor.
I am having issues rendering textures in OpenGL.
My goal is to render transparent and non transparent textures but the code I am using seems to swap and mix the pixels of my files.
I am mostly taking the code from this tutorial (learnopengl.com) and I only modified a few things.
This is what I get :
and this is what I am supposed to see:
I did not use the same textures as the tutorial but they are the same format (png for the windows and jpg for the floor and the cubes)
I do not get any error message.
Here is my code :
// main.cpp
#define STB_IMAGE_IMPLEMENTATION
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb/stb_image.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <blockpp/Shaders.hpp>
#include <blockpp/Camera.hpp>
#include <iostream>
#include <map>
#include <vector>
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
void mouse_callback(GLFWwindow *window, double xpos, double ypos);
void scroll_callback(GLFWwindow *window, double xoffset, double yoffset);
void processInput(GLFWwindow *window);
unsigned int loadTexture(const char *path);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
// camera
Camera camera(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f), {0.0f, 0.0f});
float lastX = (float)SCR_WIDTH / 2.0;
float lastY = (float)SCR_HEIGHT / 2.0;
bool firstMouse = true;
// timing
float deltaTime = 0.0f;
float lastFrame = 0.0f;
void debug_msg(std::string msg)
{
#ifdef DEBUG
std::cout << "[DEBUG] " << msg << std::endl;
#endif
}
#ifdef DEBUG
void GLAPIENTRY MessageCallback(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar *message,
const void *userParam);
#endif
int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// glfw window creation
// --------------------
GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
// tell GLFW to capture our mouse
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// configure global opengl state
// -----------------------------
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LESS);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#ifdef DEBUG
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(MessageCallback, 0);
#endif
// build and compile shaders
// -------------------------
Shader shader("shaders/default.vs", "shaders/default.fs");
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float cubeVertices[] = {
// positions // texture Coords
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f};
float planeVertices[] = {
// positions // texture Coords
5.0f, -0.5f, 5.0f, 2.0f, 0.0f,
-5.0f, -0.5f, 5.0f, 0.0f, 0.0f,
-5.0f, -0.5f, -5.0f, 0.0f, 2.0f,
5.0f, -0.5f, 5.0f, 2.0f, 0.0f,
-5.0f, -0.5f, -5.0f, 0.0f, 2.0f,
5.0f, -0.5f, -5.0f, 2.0f, 2.0f};
float transparentVertices[] = {
// positions // texture Coords (swapped y coordinates because texture is flipped upside down)
0.0f, 0.5f, 0.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f, 1.0f,
1.0f, -0.5f, 0.0f, 1.0f, 1.0f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f,
1.0f, -0.5f, 0.0f, 1.0f, 1.0f,
1.0f, 0.5f, 0.0f, 1.0f, 0.0f};
// cube VAO
unsigned int cubeVAO, cubeVBO;
glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &cubeVBO);
glBindVertexArray(cubeVAO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(3 * sizeof(float)));
// plane VAO
unsigned int planeVAO, planeVBO;
glGenVertexArrays(1, &planeVAO);
glGenBuffers(1, &planeVBO);
glBindVertexArray(planeVAO);
glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), &planeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(3 * sizeof(float)));
// transparent VAO
unsigned int transparentVAO, transparentVBO;
glGenVertexArrays(1, &transparentVAO);
glGenBuffers(1, &transparentVBO);
glBindVertexArray(transparentVAO);
glBindBuffer(GL_ARRAY_BUFFER, transparentVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(transparentVertices), transparentVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(3 * sizeof(float)));
glBindVertexArray(0);
// load textures
// -------------
unsigned int cubeTexture = loadTexture("assets/brick.jpg");
unsigned int floorTexture = loadTexture("assets/floor.jpg");
unsigned int transparentTexture = loadTexture("assets/window.png");
// transparent window locations
// --------------------------------
std::vector<glm::vec3> windows{
glm::vec3(-1.5f, 0.0f, -0.48f),
glm::vec3(1.5f, 0.0f, 0.51f),
glm::vec3(0.0f, 0.0f, 0.7f),
glm::vec3(-0.3f, 0.0f, -2.3f),
glm::vec3(0.5f, 0.0f, -0.6f)};
// shader configuration
// --------------------
shader.use();
shader.setInt("texture_atlas", 0);
// render loop
// -----------
while (!glfwWindowShouldClose(window))
{
// per-frame time logic
// --------------------
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
// input
// -----
processInput(window);
// sort the transparent windows before rendering
// ---------------------------------------------
std::map<float, glm::vec3> sorted;
for (unsigned int i = 0; i < windows.size(); i++)
{
float distance = glm::length(camera.Position - windows[i]);
sorted[distance] = windows[i];
}
// render
// ------
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw objects
shader.use();
glm::mat4 projection = glm::perspective(glm::radians(camera.Fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glm::mat4 view = camera.GetViewMatrix();
glm::mat4 model = glm::mat4(1.0f);
shader.setMat4("projection", projection);
shader.setMat4("view", view);
// cubes
glBindVertexArray(cubeVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, cubeTexture);
model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);
model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);
// floor
glBindVertexArray(planeVAO);
glBindTexture(GL_TEXTURE_2D, floorTexture);
model = glm::mat4(1.0f);
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 6);
// windows (from furthest to nearest)
glBindVertexArray(transparentVAO);
glBindTexture(GL_TEXTURE_2D, transparentTexture);
for (std::map<float, glm::vec3>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); ++it)
{
model = glm::mat4(1.0f);
model = glm::translate(model, it->second);
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &cubeVAO);
glDeleteVertexArrays(1, &planeVAO);
glDeleteBuffers(1, &cubeVBO);
glDeleteBuffers(1, &planeVBO);
glfwTerminate();
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
camera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime);
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow *window, double xpos, double ypos)
{
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos;
lastY = ypos;
camera.ProcessMouseMovement(xoffset, yoffset);
}
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow *window, double xoffset, double yoffset)
{
camera.ProcessMouseScroll(yoffset);
}
// utility function for loading a 2D texture from file
// ---------------------------------------------------
unsigned int loadTexture(char const *path)
{
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0);
if (data)
{
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, format == GL_RGBA ? GL_CLAMP_TO_EDGE : GL_REPEAT); // for this tutorial: use GL_CLAMP_TO_EDGE to prevent semi-transparent borders. Due to interpolation it takes texels from next repeat
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, format == GL_RGBA ? GL_CLAMP_TO_EDGE : GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
}
else
{
std::cout << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID;
}
#ifdef DEBUG
void GLAPIENTRY MessageCallback(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar *message,
const void *userParam)
{
fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
(type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
type, severity, message);
}
#endif
This is compiled with -DDEBUG
// default.vs
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}
// default.fs
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D texture_atlas;
void main()
{
FragColor = texture(texture_atlas, TexCoords);
}
// Shaders.hpp
#ifndef SHADER_H
#define SHADER_H
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <blockpp/main.hpp>
class Shader
{
public:
unsigned int ID;
// constructor generates the shader on the fly
// ------------------------------------------------------------------------
Shader(const char *vertexPath, const char *fragmentPath, const char *geometryPath = nullptr)
{
// 1. retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::string geometryCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
std::ifstream gShaderFile;
// ensure ifstream objects can throw exceptions:
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
gShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
// open files
debug_msg("Reading shaders ...");
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
// if geometry shader path is present, also load a geometry shader
if (geometryPath != nullptr)
{
debug_msg("Geometry shader provided");
debug_msg("Reading geometry shader ...");
gShaderFile.open(geometryPath);
std::stringstream gShaderStream;
gShaderStream << gShaderFile.rdbuf();
gShaderFile.close();
geometryCode = gShaderStream.str();
}
}
catch (std::ifstream::failure &e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
debug_msg("Compiling shaders ... ");
const char *vShaderCode = vertexCode.c_str();
const char *fShaderCode = fragmentCode.c_str();
// 2. compile shaders
unsigned int vertex, fragment;
// vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// if geometry shader is given, compile geometry shader
unsigned int geometry;
if (geometryPath != nullptr)
{
const char *gShaderCode = geometryCode.c_str();
geometry = glCreateShader(GL_GEOMETRY_SHADER);
glShaderSource(geometry, 1, &gShaderCode, NULL);
glCompileShader(geometry);
checkCompileErrors(geometry, "GEOMETRY");
}
// shader Program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
if (geometryPath != nullptr)
glAttachShader(ID, geometry);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
// delete the shaders as they're linked into our program now and no longer necessery
glDeleteShader(vertex);
glDeleteShader(fragment);
if (geometryPath != nullptr)
glDeleteShader(geometry);
}
// activate the shader
// ------------------------------------------------------------------------
void use()
{
glUseProgram(ID);
}
// utility uniform functions
// ------------------------------------------------------------------------
void setBool(const std::string &name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
// ------------------------------------------------------------------------
void setInt(const std::string &name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
// ------------------------------------------------------------------------
void setFloat(const std::string &name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
// ------------------------------------------------------------------------
void setVec2(const std::string &name, const glm::vec2 &value) const
{
glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec2(const std::string &name, float x, float y) const
{
glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
}
// ------------------------------------------------------------------------
void setVec3(const std::string &name, const glm::vec3 &value) const
{
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec3(const std::string &name, float x, float y, float z) const
{
glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
}
// ------------------------------------------------------------------------
void setVec4(const std::string &name, const glm::vec4 &value) const
{
glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec4(const std::string &name, float x, float y, float z, float w)
{
glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
}
// ------------------------------------------------------------------------
void setMat2(const std::string &name, const glm::mat2 &mat) const
{
glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
// ------------------------------------------------------------------------
void setMat3(const std::string &name, const glm::mat3 &mat) const
{
glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
// ------------------------------------------------------------------------
void setMat4(const std::string &name, const glm::mat4 &mat) const
{
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
private:
// utility function for checking shader compilation/linking errors.
// ------------------------------------------------------------------------
void checkCompileErrors(GLuint shader, std::string type)
{
GLint success;
GLchar infoLog[1024];
if (type != "PROGRAM")
{
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n"
<< infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
else
{
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n"
<< infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
}
};
#endif
The textures I used :
floor.jpg
brick.jpg
window.png
Thank you in advance for your help, tell me if you need more code or details.
Just two typos:
shader.setInt("texture1", 0); has to spell shader.setInt("texture_atlas", 0);
out vec2 TexCoord; in the vertex shader does not match in vec2 TexCoords; in the fragment shader. No matching input makes TexCoords in your fragment shader undefined, giving you more or less "random" values.
I am writing a program in Windows with C++, OpenGL and Freeglut, to learn how to use it..
The code I have written is working as follows:
#define GLEW_STATIC
#include <iostream>
#include <GL/glew.h>;
#include <freeglut.h>
#include <Windows.h>
#include <stdio.h>
#include <string>
#include <vector>
#include "fstream"
#include <algorithm>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>;
#include <chrono>
GLint partColorUniformLocation;
GLint bufferColorUniformLocation;
GLint vpMatrixUniformLocation;
GLint shows;
float radi = 5.0f;
float angx = 0.30;
float angy = 4.60;
float camX = -cos(angx) * sin(angy) * radi;
float camY = -cos(angx) * cos(angy) * radi;
float camZ = sin(angx) * radi;
float zoom = 5.0f;
float ww0;
float ww1;
float wh0;
float wh1;
float menubar;
float menur = 400;
using namespace std;
using glm::vec3;
using glm::vec4;
using glm::mat3;
using glm::mat4;
mat4 PV;
vector <mat3> Model;
mat3 World = mat3(1.0f);
vec3 UP(0.0f, 0.0f, 1.0f);
HWND hWnd;
HINSTANCE hInst;
float ww;
float wh;
int ln0 = 1280;
int shaderProgram;
unsigned int VBO;
GLuint boxID;
unsigned int VCOx;
unsigned int VCOy;
unsigned int VCOz;
GLuint coordxID;
GLuint coordyID;
GLuint coordzID;
unsigned int VTO;
GLuint ptexID;
GLuint texID;
unsigned int VTO2;
GLuint rptexID;
GLuint rtexID;
vector <char> b;
vector <unsigned char> bu;
GLuint texture0;
GLint mW;
void GetDesktopResolution(int& ww, int& wh);
void getDesktop();
void box();
void coord();
void reshape(int ww, int wh);
void display(void);
void texturemenu();
void bmpsread();
void maketexture0(int tw, int th);
void mouseButton(int button, int state, int x, int y);
void mouseMove(int x, int y);
void installShader();
const char* vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"layout (location = 1) in vec3 inNormal;\n"
"layout (location = 2) in vec3 inColor;\n"
"layout (location = 3) in vec2 tex;\n"
"uniform mat4 VP;\n"
"out vec3 outColor;\n"
"out vec3 Normal;\n"
"out vec2 outTex;\n"
"void main()\n"
"{\n"
" vec4 v = vec4(position, 1.0);\n"
" gl_Position = VP * v;\n"
" outColor = inColor;\n"
" Normal = inNormal;\n"
" outTex = tex;\n"
"}\0";
const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 color;\n"
"in vec3 outColor;\n"
"in vec3 Normal;\n"
"in vec2 outTex;\n"
"uniform int shows;\n"
"uniform sampler2D texture0;\n"
"uniform vec3 partColor;"
"uniform vec3 bufferColor;"
"void main()\n"
"{\n"
" if (shows == 0) \n"
" {\n"
" color = vec4(bufferColor/255.0, 1.0);\n"
" }\n"
" else if (shows == 1)\n"
" {\n"
" color = vec4(1.0, 1.0, 1.0, 1.0);\n"
" }\n"
" else if (shows == 2)\n"
" {\n"
" color = vec4(partColor, 1.0);\n"
" }\n"
" else if (shows == 3)\n"
" {\n"
" color = texture(texture0, outTex);\n"
" }\n"
"}\n\0";
void GetDesktopResolution(float& ww, float& wh) {
RECT desktop;
const HWND hDesktop = GetDesktopWindow();
GetWindowRect(hDesktop, &desktop);
ww = desktop.right;
wh = desktop.bottom;
}
void getDesktop() {
wh = glutGet(GLUT_WINDOW_HEIGHT);
ww = glutGet(GLUT_WINDOW_WIDTH);
menubar = 35;
ww0 = -(ww - menur) / 10.0f;
ww1 = (ww - menur) / 10.0f;
wh0 = -(wh - menubar) / 10.0f + 30;
wh1 = (wh - menubar) / 10.0f + 30;
zoom = 0.2f;
}
void box() {
vector <float> box;
box.resize(72);
box = {
-10.0f, -10.0f, 20.0f,
10.0f, -10.0f, 20.0f,
10.0f, -10.0f, 20.0f,
10.0f, 10.0f, 20.0f,
10.0f, 10.0f, 20.0f,
-10.0f, 10.0f, 20.0f,
-10.0f, 10.0f, 20.0f,
-10.0f, -10.0f, 20.0f,
-10.0f, -10.0f, 0.0f,
10.0f, -10.0f, 0.0f,
10.0f, -10.0f, 0.0f,
10.0f, 10.0f, 0.0f,
10.0f, 10.0f, 0.0f,
-10.0f, 10.0f, 0.0f,
-10.0f, 10.0f, 0.0f,
-10.0f, -10.0f, 0.0f,
-10.0f, -10.0f, 20.0f,
-10.0f, -10.0f, 0.0f,
10.0f, -10.0f, 20.0f,
10.0f, -10.0f, 0.0f,
10.0f, 10.0f, 20.0f,
10.0f, 10.0f, 0.0f,
-10.0f, 10.0f, 20.0f,
-10.0f, 10.0f, 0.0f
};
glGenBuffers(1, &boxID);
glBindBuffer(GL_ARRAY_BUFFER, boxID);
glBufferData(GL_ARRAY_BUFFER, box.size() * sizeof(float), box.data(), GL_STATIC_DRAW);
box.clear();
glGenVertexArrays(1, &VBO);
glBindVertexArray(VBO);
glBindBuffer(GL_ARRAY_BUFFER, boxID);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBindVertexArray(0);
}
void coord() {
vector <float> coordx(6);
coordx = {
0.0f, 0.0f, 0.0f,
10.0f, 0.0f, 0.0f
};
vector <float> coordy(6);
coordy = {
0.0f, 0.0f, 0.0f,
0.0f, 10.0f, 0.0f
};
vector <float> coordz(6);
coordz = {
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 10.0f
};
glGenBuffers(1, &coordxID);
glBindBuffer(GL_ARRAY_BUFFER, coordxID);
glBufferData(GL_ARRAY_BUFFER, coordx.size() * sizeof(float), coordx.data(), GL_STATIC_DRAW);
coordx.clear();
glGenBuffers(1, &coordyID);
glBindBuffer(GL_ARRAY_BUFFER, coordyID);
glBufferData(GL_ARRAY_BUFFER, coordy.size() * sizeof(float), coordy.data(), GL_STATIC_DRAW);
coordy.clear();
glGenBuffers(1, &coordzID);
glBindBuffer(GL_ARRAY_BUFFER, coordzID);
glBufferData(GL_ARRAY_BUFFER, coordz.size() * sizeof(float), coordz.data(), GL_STATIC_DRAW);
coordz.clear();
glGenVertexArrays(1, &VCOx);
glBindVertexArray(VCOx);
glBindBuffer(GL_ARRAY_BUFFER, coordxID);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glGenVertexArrays(1, &VCOy);
glBindVertexArray(VCOy);
glBindBuffer(GL_ARRAY_BUFFER, coordyID);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glGenVertexArrays(1, &VCOz);
glBindVertexArray(VCOz);
glBindBuffer(GL_ARRAY_BUFFER, coordzID);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBindVertexArray(0);
}
void reshape(int ww, int wh) {
getDesktop();
glClearColor(0.7f, 0.7f, 0.7f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgram);
partColorUniformLocation = glGetUniformLocation(shaderProgram, "partColor");
bufferColorUniformLocation = glGetUniformLocation(shaderProgram, "bufferColor");
vpMatrixUniformLocation = glGetUniformLocation(shaderProgram, "VP");
shows = glGetUniformLocation(shaderProgram, "shows");
}
void display(void) {
glClearColor(0.7f, 0.7f, 0.7f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, ww - menur, wh - menubar);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glFrontFace(GL_CW);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
mat4 Projection = glm::ortho(ww0, ww1, wh0, wh1, -1000.0f, 1000.0f); //left, right, bottom, top, zNear, zFar
mat4 View = glm::lookAt(glm::vec3(camX, camY, camZ), glm::vec3(0.0f, 0.0f, 0.0f), UP);
mat4 VP = Projection * View;
vec3 partColor;
glUniformMatrix4fv(vpMatrixUniformLocation, 1, GL_FALSE, &VP[0][0]);
glUniform1i(shows, 2);
glLineWidth(2);
glBindVertexArray(VCOx); // Coordx
partColor = vec3(1.0f, 0.0f, 0.0f);
glUniform3fv(partColorUniformLocation, 1, &partColor[0]);
glDrawArrays(GL_LINES, 0, 2);
glBindVertexArray(VCOy); // Coordy
partColor = vec3(0.0f, 1.0f, 0.0f);
glUniform3fv(partColorUniformLocation, 1, &partColor[0]);
glDrawArrays(GL_LINES, 0, 2);
glBindVertexArray(VCOz); // Coordz
partColor = vec3(0.0f, 0.0f, 1.0f);
glUniform3fv(partColorUniformLocation, 1, &partColor[0]);
glDrawArrays(GL_LINES, 0, 2);
glBindVertexArray(VBO); // Box
partColor = vec3(1.0f, 1.0f, 1.0f);
glUniform3fv(partColorUniformLocation, 1, &partColor[0]);
glDrawArrays(GL_LINES, 0, 24);
glUniform1i(shows, 1);
glDisable(GL_DEPTH_TEST);
glViewport(0, wh - 35, ww, wh);
VP = glm::ortho(0.0f, ww, 0.0f, 35.0f) * glm::mat4(1.0f); //left, right, bottom, top
glUniformMatrix4fv(vpMatrixUniformLocation, 1, GL_FALSE, &VP[0][0]);
glBindVertexArray(VTO2);
glDrawArrays(GL_TRIANGLES, 0, 6);
glEnable(GL_TEXTURE0);
glUniform1i(shows, 3);
glViewport(0, wh - menubar, ln0, 35);
VP = glm::ortho(0.0f, float(ln0), 0.0f, 35.0f) * glm::mat4(1.0f); //left, right, bottom, top
glUniformMatrix4fv(vpMatrixUniformLocation, 1, GL_FALSE, &VP[0][0]);
glBindVertexArray(VTO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisable(GL_TEXTURE0);
glutSwapBuffers();
}
void texturemenu() {
vector <float> ptex(18);
float top = 35;
float bottom = 0;
float left = 0;
float right = 1280;
ptex = {
right, top, 0.0f,
left, top, 0.0f,
left, bottom, 0.0f,
left, bottom, 0.0f,
right, bottom, 0.0f,
right, top, 0.0f
};
vector <float> tex(12);
tex = {
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f
};
glGenBuffers(1, &ptexID);
glBindBuffer(GL_ARRAY_BUFFER, ptexID);
glBufferData(GL_ARRAY_BUFFER, ptex.size() * sizeof(float), ptex.data(), GL_STATIC_DRAW);
ptex.clear();
glGenTextures(1, &texID);
glBindBuffer(GL_ARRAY_BUFFER, texID);
glBufferData(GL_ARRAY_BUFFER, tex.size() * sizeof(float), tex.data(), GL_STATIC_DRAW);
tex.clear();
glGenVertexArrays(1, &VTO);
glBindVertexArray(VTO);
glBindBuffer(GL_ARRAY_BUFFER, ptexID);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, texID);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBindVertexArray(0);
}
void bmpsread() {
bu.clear();
bu.resize(3 * 35 * ln0, 255);
int bmpn = 0;
string sbmp;
sbmp = "C:/C++/icons/dll/new.bmp";
if (sbmp.size() > 0) {
ifstream fo;
unsigned int fn = 0;
fo.open(sbmp, std::ios::binary | std::ios::in);
if (fo.is_open()) {
std::ifstream in_file(sbmp, std::ios::binary | std::ios::ate);
fo.seekg(0, std::ios::beg);
int file_size = in_file.tellg();
fn = file_size;
b.resize(fn);
fo.seekg(0, std::ios::beg);
fo.read(b.data(), fn);
}
fo.close();
fo.clear();
int dataPos = *(int*)&(b[0x0A]);
int www = *(int*)&(b[0x12]);
int ka = 0;
int kx = ceil((((float)www * 3) + 1) / 4) * 4 - www * 3;
if (kx == 4) { kx = 0; }
for (int i = 0; i < 35; i++) {
for (int j = 0; j < www; j++) {
bu[i * ln0 * 3 + (bmpn + j) * 3] = (unsigned char)b[i * www * 3 + j * 3 + ka + dataPos];
bu[i * ln0 * 3 + (bmpn + j) * 3 + 1] = (unsigned char)b[i * www * 3 + j * 3 + ka + 1 + dataPos];
bu[i * ln0 * 3 + (bmpn + j) * 3 + 2] = (unsigned char)b[i * www * 3 + j * 3 + ka + 2 + dataPos];
}
ka += kx;
}
b.clear();
}
bmpn += 37;
}
void maketexture0(int tw, int th) {
glGenTextures(1, &texture0);
auto textureUniformLocation = glGetUniformLocation(shaderProgram, "texture0");
glUniform1i(texture0, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture0);
glEnable(GL_TEXTURE0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_BGR, GL_UNSIGNED_BYTE, bu.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
bu.clear();
}
void installShader() {
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDetachShader(shaderProgram, vertexShader);
glDetachShader(shaderProgram, fragmentShader);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitWindowSize(800, 600);
mW = glutCreateWindow(" Texture Test");
glewInit();
HWND win_handle = FindWindow(0, L" Texture Test");
WNDCLASS wc = { 0 };
if (!win_handle) {
return -1;
}
SetWindowLong(win_handle, GWL_STYLE, (GetWindowLong(win_handle, GWL_STYLE) | WS_MAXIMIZE));
ShowWindowAsync(win_handle, SW_SHOWDEFAULT);
ShowWindowAsync(win_handle, SW_SHOWMAXIMIZED);
box();
coord();
installShader();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
Without Texture:
But after I add texture to create a menu bar (in this sample a "new.bmp" picture) with adding following code after "coord();" in "int main(int argc, char** argv)":
bmpsread();
texturemenu();
maketexture0(ln0, 35);
Then my box disappears and my coordinates are wrong.
With Texture:
What am I doing wrong?
I have been using this tutorial to create a skybox but sampling the texture returns black. If I use my texture coordinates as colour then I get sensible looking coloured skybox so I presume the problem is with the texture sampling! Could it be a problem with my graphics card or openGL version?
Here is my code:
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include "utils.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#define CUSTOM_PI 3.1415926535897931
/*
*
* Include files for Windows, Linux and OSX
* __APPLE is defined if OSX, otherwise Windows and Linux.
*
*/
#ifdef __APPLE__
#define GLFW_INCLUDE_GLCOREARB 1
#include <GLFW/glfw3.h>
#else
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#endif
struct Vertex {
GLfloat position[3];
};
float aspectRatio;
// Position of camera in world space
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 200.0f);
// Camera Orientation in view space
glm::vec3 cameraOrientation = glm::vec3(0.0f, 1.0f, 0.0f);
/* yaw is initialized to -90.0 degrees since a yaw of 0.0 results in a direction
* vector pointing to the right so we initially rotate a bit to the left. */
float yaw = -90.0f;
float pitch = 0.0f;
float yawPitchStep = 2.0f;
float cameraSpeed = 0.0f;
float cameraAccelerationStep = 0.025f;
float cameraDecelerationStep = 0.05f;
bool left = false;
bool right = false;
bool page_up = false;
bool page_down = false;
bool up = false;
bool down = false;
GLuint shaderProgram;
unsigned int skyboxVAO, skyboxVBO;
unsigned int cubemapTexture;
/* Whenever the window size changed (by OS or user resize) this callback
* function executes */
void framebuffer_size_callback(GLFWwindow *window, int width, int height) {
/* Make sure the viewport matches the new window dimensions; note that width
* and height will be significantly larger than specified on retina
* displays. */
if (!(width == 0 || height == 0)) {
aspectRatio = (float)width / (float)height;
glViewport(0, 0, width, height);
}
}
static void key_callback(GLFWwindow *window, int key, int scancode, int action,
int mods) {
if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GL_TRUE);
}
if (key == GLFW_KEY_LEFT) {
if (action == GLFW_PRESS)
left = true;
if (action == GLFW_RELEASE)
left = false;
}
if (key == GLFW_KEY_RIGHT) {
if (action == GLFW_PRESS)
right = true;
if (action == GLFW_RELEASE)
right = false;
}
if (key == GLFW_KEY_PAGE_UP) {
if (action == GLFW_PRESS)
page_up = true;
if (action == GLFW_RELEASE)
page_up = false;
}
if (key == GLFW_KEY_PAGE_DOWN) {
if (action == GLFW_PRESS)
page_down = true;
if (action == GLFW_RELEASE)
page_down = false;
}
if (key == GLFW_KEY_UP) {
if (action == GLFW_PRESS)
up = true;
if (action == GLFW_RELEASE)
up = false;
}
if (key == GLFW_KEY_DOWN) {
if (action == GLFW_PRESS)
down = true;
if (action == GLFW_RELEASE)
down = false;
}
}
// loads a cubemap texture from 6 individual texture faces
// order:
// +X (right)
// -X (left)
// +Y (top)
// -Y (bottom)
// +Z (front)
// -Z (back)
// -------------------------------------------------------
unsigned int loadCubemap(std::vector<std::string> faces) {
unsigned int textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
int width, height, nrChannels;
for (unsigned int i = 0; i < faces.size(); i++) {
unsigned char *data =
stbi_load(faces[i].c_str(), &width, &height, &nrChannels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width,
height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
} else {
std::cout << "Cubemap texture failed to load at path: " << faces[i]
<< std::endl;
stbi_image_free(data);
}
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
return textureID;
}
void setup() {
// These pointers will receive the contents of our shader source code files
GLchar *vertexSource, *fragmentSource;
// These are handles used to reference the shaders
GLuint vertexShader, fragmentShader;
/* Read our shaders into the appropriate buffers */
vertexSource = fileToBuf("./skyboxShader.vert");
fragmentSource = fileToBuf("./skyboxShader.frag");
/* Assign our handles a "name" to new shader objects */
vertexShader = glCreateShader(GL_VERTEX_SHADER);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
/* Associate the source code buffers with each handle */
glShaderSource(vertexShader, 1, (const GLchar **)&vertexSource, 0);
glShaderSource(fragmentShader, 1, (const GLchar **)&fragmentSource, 0);
/* Compile our shader objects */
glCompileShader(vertexShader);
glCompileShader(fragmentShader);
/* Assign our program handle a "name" */
shaderProgram = glCreateProgram();
// Attach our shaders to our program
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glBindAttribLocation(shaderProgram, 0, "in_Position");
// Link our program, and set it as being actively used
glLinkProgram(shaderProgram);
checkShader(shaderProgram, "Basic Shader");
glUseProgram(shaderProgram);
GLuint cubemapTexture;
glGenTextures(1, &cubemapTexture);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
float skyboxVertices[] = {
// positions
-1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f};
// skybox VAO
glGenVertexArrays(1, &skyboxVAO);
glGenBuffers(1, &skyboxVBO);
glBindVertexArray(skyboxVAO);
glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices,
GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float),
(void *)0);
// load textures
// -------------
std::vector<std::string> faces{
"./textures/skybox/right.jpg", "./textures/skybox/left.jpg",
"./textures/skybox/top.jpg", "./textures/skybox/bottom.jpg",
"./textures/skybox/front.jpg", "./textures/skybox/back.jpg"};
cubemapTexture = loadCubemap(faces);
// shader configuration
// --------------------
glUniform1i(glGetUniformLocation(shaderProgram, "skybox"), 0);
}
void render(float time, glm::mat4 projection, glm::mat4 view) {
// draw skybox as last
glDepthFunc(GL_LEQUAL); // change depth function so depth test passes when
// values are equal to depth buffer's content
glUseProgram(shaderProgram);
view =
glm::mat4(glm::mat3(view)); // remove translation from the view matrix
glm::mat4 VP = projection * view;
// Bind Model, View, Perspective transformation matrix to be a uniform
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "vpmatrix"), 1,
GL_FALSE, glm::value_ptr(VP));
// skybox cube
glBindVertexArray(skyboxVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glDepthFunc(GL_LESS); // set depth function back to default
}
int main(void) {
int k = 0;
float time = 0;
GLFWwindow *window;
if (!glfwInit()) {
printf("Failed to start GLFW\n");
exit(EXIT_FAILURE);
}
#ifdef __APPLE__
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#endif
window = glfwCreateWindow(800, 800, "Graphics Test", NULL, NULL);
aspectRatio = 1.0f;
if (!window) {
glfwTerminate();
printf("GLFW Failed to start\n");
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
#ifndef __APPLE__
glewExperimental = GL_TRUE;
int err = glewInit();
if (GLEW_OK != err) {
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
}
#endif
glfwSetKeyCallback(window, key_callback);
fprintf(stderr, "GL INFO %s\n", glGetString(GL_VERSION));
glEnable(GL_DEPTH_TEST);
setup();
printf("Ready to render\n");
while (!glfwWindowShouldClose(window)) { // Main loop
time = glfwGetTime();
// Make our blue to ensure skybox is working.
glClearColor(0.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* Defines the projection:
* With 45 degree field of view
* With A given aspect ratio
* Cliping everything closer than 0.1 to the camera
* Cliping everything further than 1000 from the camera */
glm::mat4 Projection =
glm::perspective(45.0f, aspectRatio, 0.1f, 1000.0f);
if (left) {
yaw -= yawPitchStep;
}
if (right) {
yaw += yawPitchStep;
}
if (page_up) {
pitch += yawPitchStep;
}
if (page_down) {
pitch -= yawPitchStep;
}
if (up) {
cameraSpeed += cameraAccelerationStep;
printf("Camera Speed = %f\n", cameraSpeed);
}
if (down) {
cameraSpeed -= cameraDecelerationStep;
if (cameraSpeed < 0) {
cameraSpeed = 0;
}
printf("Camera Speed = %f\n", cameraSpeed);
}
glm::vec3 front;
front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
front.y = sin(glm::radians(pitch));
front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
glm::vec3 cameraDirection = glm::normalize(front);
cameraPos += cameraSpeed * cameraDirection;
glm::mat4 View = glm::lookAt(cameraPos, cameraPos + cameraDirection,
cameraOrientation);
render(time, Projection, View);
k++;
glfwSwapBuffers(window); // Swap front and back rendering buffers
glfwPollEvents(); // Poll for events.
}
glfwTerminate(); // Close window and terminate GLFW
exit(EXIT_SUCCESS); // Exit program
}
And my vertex shader:
#version 400
precision highp float;
// Position of vertex
in vec3 in_Position;
// The model, view, and projection matrices which needs to be applied to every vertex
uniform mat4 vpmatrix;
// Texture coordinates passed on to fragment shader
out vec3 TexCoords;
void main(void) {
TexCoords = in_Position;
vec4 pos = vpmatrix * vec4(in_Position, 1.0);
gl_Position = pos.xyww;
}
And my fragment shader:
#version 400
precision highp float;
in vec3 TexCoords;
out vec4 FragColor;
uniform samplerCube skybox;
void main()
{
FragColor = texture(skybox, TexCoords);
// FragColor = vec4(TexCoords, 1.0f);
}
The global variable unsigned int cubemapTexture;, which is used in the function render is never set, because there is a 2nd (local) variable named cubemapTexture in the function setup.
Remove the local variable cubemapTexture from the function setup to solve the issue:
unsigned int cubemapTexture;
void setup() {
.....
GLuint cubemapTexture; // delete this part of the
glGenTextures(1, &cubemapTexture); //
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture); //
.....
cubemapTexture = loadCubemap(faces);
.....
}
void render(float time, glm::mat4 projection, glm::mat4 view) {
.....
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
.....
}
I am trying to draw a simple cube for a homework assignment for a class but for some reason it isn't showing up.
I am using uniform blocks and modern OpenGL. I am sure I am not doing something correctly.
My complete code is below. The below example depends on GLEW + GLFW + GLM.
What I found interesting is that for my light and material uniform blocks I get the index but the uniform block for my MVP matrix I don't get the index.
Any ideas?
Here is the C++ code:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
#ifndef OPENGL_INCLUDES_
#define OPENGL_INCLUDES_
#include "GL\glew.h"
#ifndef GLFW_INCLUDES_
#define GLFW_INCLUDES_
#if defined(_WIN32)
#include <Windows.h>
#define GLFW_EXPOSE_NATIVE_WIN32
#define GLFW_EXPOSE_NATIVE_WGL
#elif defined(__linux__)
#include <X11/X.h>
#include <X11/extensions/Xrandr.h>
#define GLFW_EXPOSE_NATIVE_X11
#define GLFW_EXPOSE_NATIVE_GLX
#endif
#include "GLFW\glfw3.h"
#include "GLFW\glfw3native.h"
#endif
#endif
#ifndef GLM_INCLUDES_
#define GLM_INCLUDES_
#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
#endif
GLFWwindow* MainWindow;
#ifdef _WIN32
HWND MainWindowWin32Handle;
#endif
GLint WindowWidth = 1024;
GLint WindowHeight = 768;
GLulong SizeDivizor = 1;
GLboolean RiftAvailable = false;
GLboolean UseApplicationWindowFrame = false;
GLuint MainOpenGLShaderProgramID;
GLuint MatricesUniformBlockID;
GLuint MatricesUniformBufferID;
GLuint LightsUniformBlockID;
GLuint LightsUniformBufferID;
GLuint MaterialsUniformBlockID;
GLuint MaterialsUniformBufferID;
glm::mat4 ViewMatrix;
glm::mat4 ViewModelMatrix;
glm::mat4 ProjectionMatrix;
glm::mat4 MVPMatrix;
glm::mat3 NormalMatrix;
class StandardCube;
std::vector<StandardCube> Cubes;
class StandardCube {
private:
GLfloat* Vertices;
GLfloat* Normals;
GLuint* Indices;
GLuint VAO;
glm::mat4 ModelMatrix;
public:
void LoadIntoOpenGL() {
Vertices = new GLfloat[72]
{
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f
};
Normals = new GLfloat[72] {
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f
};
Indices = new GLuint[36] {0, 1, 2, 2, 3, 0,
4, 5, 6, 6, 7, 4,
8, 9, 10, 10, 11, 8,
12, 13, 14, 14, 15, 12,
16, 17, 18, 18, 19, 16,
20, 21, 22, 22, 23, 20
};
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
GLuint MeshBufferID;
glGenBuffers(1, &MeshBufferID);
glBindBuffer(GL_ARRAY_BUFFER, MeshBufferID);
GLuint TotalBufferData = (sizeof(GLfloat) * 72) + (sizeof(GLfloat) * 72);
glBufferData(GL_ARRAY_BUFFER, TotalBufferData, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, NULL, sizeof(GLfloat) * 72, Vertices);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 72, sizeof(GLfloat) * 72, Normals);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(sizeof(GLfloat) * 72));
glEnableVertexAttribArray(1);
GLuint IndexBufferID;
glGenBuffers(1, &IndexBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * 36, Indices, GL_STATIC_DRAW);
glBindVertexArray(NULL);
ModelMatrix = glm::mat4(1.0f);
}
void DrawMe() {
MVPMatrix = ProjectionMatrix * ViewMatrix * ModelMatrix;
ViewModelMatrix = ViewMatrix * ModelMatrix;
NormalMatrix = glm::transpose(glm::inverse(glm::mat3(MVPMatrix)));
glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);
glBufferSubData(GL_UNIFORM_BUFFER, NULL, sizeof(glm::mat4), glm::value_ptr(MVPMatrix));
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(ViewModelMatrix));
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4) + sizeof(glm::mat4), sizeof(glm::mat3), glm::value_ptr(NormalMatrix));
glBindBuffer(GL_UNIFORM_BUFFER, NULL);
glBindVertexArray(VAO);
glDrawElementsInstanced(GL_TRIANGLES, 36, GL_UNSIGNED_INT, NULL, 1);
glBindVertexArray(NULL);
}
};
static void GLFWKeyCallback(GLFWwindow* p_Window, GLint p_Key, GLint p_Scancode, GLint p_Action, GLint p_Mods) {
if (p_Key == GLFW_KEY_ESCAPE && p_Action == GLFW_PRESS) {
glfwSetWindowShouldClose(p_Window, GL_TRUE);
}
if (p_Key == GLFW_KEY_O && p_Action == GLFW_PRESS) {
glClearColor(0.2f, 0.1f, 0.3f, 1.0f);
}
if (p_Key == GLFW_KEY_I && p_Action == GLFW_PRESS) {
glClearColor(1.0f, 0.5f, 0.5f, 1.0f);
}
}
static void GLFWWindowResizeCallBack(GLFWwindow* p_Window, GLint width, GLint height) {
//CurrentGLFWApplication->WindowResizeCallBack(p_Window, width, height);
}
static void GLFWMouseMovementCallBack(GLFWwindow* p_Window, GLdouble MouseX, GLdouble MouseY) {
//CurrentGLFWApplication->MouseMovementCallBack(p_Window, MouseX, MouseY);
}
static void GLFWFramebufferSizeCallback(GLFWwindow* window, GLint width, GLint height)
{
glViewport(0, 0, width, height);
}
int initializeGLFWGLEW() {
MainWindow = NULL;
if (!glfwInit())
{
fprintf(stderr, "GLFW failed to initialize.");
glfwTerminate();
return EXIT_FAILURE;
}
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE);
if (UseApplicationWindowFrame) {
MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Basic Oculus Rift Example", NULL, NULL);
}
else {
if (!RiftAvailable) {
MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Basic Oculus Rift Example", NULL, NULL);
}
else {
GLint MonitorCount;
GLFWmonitor** GLFW_Monitors = glfwGetMonitors(&MonitorCount);
GLFWmonitor* MonitorToUse;
switch (MonitorCount)
{
case 0:
printf("No monitors found, exiting.\n");
return EXIT_FAILURE;
break;
case 1:
printf("Two monitors expected, found only one, using primary...\n");
MonitorToUse = glfwGetPrimaryMonitor();
break;
case 2:
printf("Two monitors found, using second monitor\n");
MonitorToUse = GLFW_Monitors[1];
break;
default:
printf("More than two monitors found, using second monitor\n");
MonitorToUse = GLFW_Monitors[1];
}
MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Basic Oculus Rift Example", MonitorToUse, NULL);
}
}
if (!MainWindow)
{
fprintf(stderr, "Could not determine OpenGL version; exiting.");
glfwTerminate();
return EXIT_FAILURE;
}
glfwMakeContextCurrent(MainWindow);
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return EXIT_FAILURE;
}
glfwSetInputMode(MainWindow, GLFW_STICKY_KEYS, GL_TRUE);
glfwSetKeyCallback(MainWindow, GLFWKeyCallback);
glfwSetWindowSizeCallback(MainWindow, GLFWWindowResizeCallBack);
glfwSetCursorPosCallback(MainWindow, GLFWMouseMovementCallBack);
glfwSetFramebufferSizeCallback(MainWindow, GLFWFramebufferSizeCallback);
glfwSwapBuffers(MainWindow);
glfwPollEvents();
return EXIT_SUCCESS;
}
int prepareOpenGL() {
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glEnable(GL_CULL_FACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_MULTISAMPLE);
return EXIT_SUCCESS;
}
int loadShaders() {
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
// Compile Vertex Shader
printf("Compiling Vertext Shader.\n\n");
char const * VertexSource = "#version 330 \n\n\
layout(std140) uniform MatrixInformation {\n\
mat4 m_pvm;\n\
mat4 m_viewModel;\n\
mat3 m_normal;\n\
};\n\
layout(std140) uniform Lights {\n\
vec3 l_dir; \n\
};\n\
in vec4 position;\n\
in vec3 normal;\n\
\n\
\n\
out Data{\n\
vec3 normal;\n\
vec4 eye;\n\
} DataOut;\n\
\n\
void main() {\n\
\n\
DataOut.normal = normalize(m_normal * normal);\n\
DataOut.eye = -(m_viewModel * position);\n\
\n\
gl_Position = m_pvm * position;\n\
}\n\
\n";
glShaderSource(VertexShaderID, 1, &VertexSource, NULL);
glCompileShader(VertexShaderID);
// Check Vertex Shader
GLint Result = GL_FALSE;
int InfoLogLength;
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0){
std::vector<char> VertexShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
std::string ErrorMessage = std::string(&VertexShaderErrorMessage[0]);
printf("%s\n", &VertexShaderErrorMessage[0]);
}
printf("Compiling Fragment Shader.\n\n");
char const * FragmentSource = "#version 330\n\
layout(std140) uniform Materials {\n\
vec4 diffuse;\n\
vec4 ambient;\n\
vec4 specular;\n\
vec4 emissive;\n\
float shininess;\n\
int texCount;\n\
};\
\n\
layout(std140) uniform Lights {\n\
vec3 l_dir; \n\
};\
\n\
in Data{\n\
vec3 normal;\n\
vec4 eye;\n\
} DataIn;\n\
\n\
out vec4 colorOut;\
\n\
void main() {\n\
\n\
vec4 spec = vec4(0.0);\n\
\n\
vec3 n = normalize(DataIn.normal);\n\
vec3 e = normalize(vec3(DataIn.eye));\n\
\n\
float intensity = max(dot(n, l_dir), 0.0);\n\
\n\
if (intensity > 0.0) {\n\
vec3 h = normalize(l_dir + e);\n\
\n\
float intSpec = max(dot(h, n), 0.0);\n\
spec = specular * pow(intSpec, shininess);\n\
}\n\
\n\
colorOut = max(intensity * diffuse + spec, ambient);\n\
}";
glShaderSource(FragmentShaderID, 1, &FragmentSource, NULL);
glCompileShader(FragmentShaderID);
// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0){
std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
std::string ErrorMessage = std::string(&FragmentShaderErrorMessage[0]);
printf("%s\n", &FragmentShaderErrorMessage[0]);
}
// Link the program
printf("Linking shader program.\n\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0){
std::vector<char> ProgramErrorMessage(InfoLogLength + 1);
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
std::string ErrorMessage = std::string(&ProgramErrorMessage[0]);
printf("%s\n", &ProgramErrorMessage[0]);
}
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
MainOpenGLShaderProgramID = ProgramID;
return EXIT_SUCCESS;
}
int prepareShaderUniforms() {
glUseProgram(MainOpenGLShaderProgramID);
LightsUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "Lights");
glUniformBlockBinding(MainOpenGLShaderProgramID, LightsUniformBlockID, 2);
glGenBuffers(1, &LightsUniformBufferID);
glBindBuffer(GL_UNIFORM_BUFFER, LightsUniformBufferID);
glBindBufferBase(GL_UNIFORM_BUFFER, 2, LightsUniformBufferID);
GLfloat LightDirection[3] = { 1.0f, 1.0f, 0.0f };
glBufferData(GL_UNIFORM_BUFFER, sizeof(LightDirection), &LightDirection, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, NULL);
MatricesUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "MatrixInformation");
glUniformBlockBinding(MainOpenGLShaderProgramID, MatricesUniformBlockID, 1);
glGenBuffers(1, &MatricesUniformBufferID);
glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);
glBindBufferBase(GL_UNIFORM_BUFFER, 1, MatricesUniformBufferID);
GLsizeiptr TotalBufferSize = sizeof(glm::mat4) + sizeof(glm::mat4);
TotalBufferSize += sizeof(glm::mat3);
glBufferData(GL_ARRAY_BUFFER, TotalBufferSize, NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, NULL);
MaterialsUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "Materials");
glUniformBlockBinding(MainOpenGLShaderProgramID, MaterialsUniformBlockID, 3);
glGenBuffers(1, &MaterialsUniformBufferID);
glBindBuffer(GL_UNIFORM_BUFFER, MaterialsUniformBufferID);
glBindBufferBase(GL_UNIFORM_BUFFER, 3, MaterialsUniformBufferID);
GLfloat Material[18];
//Diffuse
Material[0] = 0.5f;
Material[1] = 0.0f;
Material[2] = 0.0f;
Material[3] = 1.0f;
//Ambient
Material[4] = 0.2f;
Material[5] = 0.2f;
Material[6] = 0.2f;
Material[7] = 1.0f;
//Specular
Material[8] = 0.0f;
Material[9] = 0.0f;
Material[10] = 0.0f;
Material[11] = 1.0f;
//Emissive
Material[12] = 0.0f;
Material[13] = 0.0f;
Material[14] = 0.0f;
Material[15] = 1.0f;
//Shininess
Material[16] = 2.0f;
//Texture Count
Material[17] = 0.0f;
glBufferData(GL_UNIFORM_BUFFER, sizeof(Material), &Material, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, NULL);
return EXIT_SUCCESS;
}
int loadCubes() {
StandardCube NewCube;
NewCube.LoadIntoOpenGL();
Cubes.push_back(NewCube);
return EXIT_SUCCESS;
}
int prepareMatricies() {
GLfloat AspectRatio = (GLfloat)(WindowWidth) / (GLfloat)(WindowHeight);
ProjectionMatrix = glm::perspective(45.0f, AspectRatio, 1.0f, 1000.0f);
ViewMatrix = glm::lookAt(
glm::vec3(4.0f, 3.0f, 3.0f), // camera is at (4,3,3), in world space - Where the camera is inside world.
glm::vec3(0.0f, 0.0f, 0.0f), // and looks at the origin - What point the camera is looking at inside world.
glm::vec3(0.0f, 1.0f, 0.0f)// head is up(set to 0,1,0) - the direction of up for camera.
);
glViewport(0, 0, WindowWidth, WindowHeight);
return EXIT_SUCCESS;
}
int main(int argc, char** argv) {
if (initializeGLFWGLEW() == EXIT_FAILURE) {
exit(EXIT_FAILURE);
}
if (prepareOpenGL() == EXIT_FAILURE) {
exit(EXIT_FAILURE);
}
if (loadShaders() == EXIT_FAILURE) {
exit(EXIT_FAILURE);
}
if (prepareShaderUniforms() == EXIT_FAILURE) {
exit(EXIT_FAILURE);
}
if (loadCubes() == EXIT_FAILURE) {
exit(EXIT_FAILURE);
}
if (prepareMatricies() == EXIT_FAILURE) {
exit(EXIT_FAILURE);
}
while (!glfwWindowShouldClose(MainWindow))
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (auto & C : Cubes) {
C.DrawMe();
}
glfwSwapBuffers(MainWindow);
glfwPollEvents();
}
exit(EXIT_SUCCESS);
}
Here is my vertex shader:
#version 330
layout(std140) uniform MatrixInformation {
mat4 m_pvm;
mat4 m_viewModel;
mat3 m_normal;
};
layout(std140) uniform Lights {
vec3 l_dir;
};
in vec4 position;
in vec3 normal;
out Data{
vec3 normal;
vec4 eye;
} DataOut;
void main() {
DataOut.normal = normalize(m_normal * normal);
DataOut.eye = -(m_viewModel * position);
gl_Position = m_pvm * position;
}
And here is my fragment shader:
#version 330
layout(std140) uniform Materials {
vec4 diffuse;
vec4 ambient;
vec4 specular;
vec4 emissive;
float shininess;
int texCount;
};
layout(std140) uniform Lights {
vec3 l_dir;
};
in Data{
vec3 normal;
vec4 eye;
} DataIn;
out vec4 colorOut;
void main() {
vec4 spec = vec4(0.0);
vec3 n = normalize(DataIn.normal);
vec3 e = normalize(vec3(DataIn.eye));
float intensity = max(dot(n, l_dir), 0.0);
if (intensity > 0.0) {
vec3 h = normalize(l_dir + e);
float intSpec = max(dot(h, n), 0.0);
spec = specular * pow(intSpec, shininess);
}
colorOut = max(intensity * diffuse + spec, ambient);
}
So the issue is this part:
//Binding uniform buffer
glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);
glBindBufferBase(GL_UNIFORM_BUFFER, 1, MatricesUniformBufferID);
GLsizeiptr TotalBufferSize = sizeof(glm::mat4) + sizeof(glm::mat4);
TotalBufferSize += sizeof(glm::mat3);
//uploading to the unbound array buffer
glBufferData(GL_ARRAY_BUFFER, TotalBufferSize, NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, NULL);
So you need to change
glBufferData(GL_ARRAY_BUFFER, TotalBufferSize, NULL, GL_DYNAMIC_DRAW);
to
glBufferData(GL_UNIFORM_BUFFER, TotalBufferSize, NULL, GL_DYNAMIC_DRAW);
Additionally uploading NULL doesn't work on my OpenGL driver (although it should), so I had to
std::array<unsigned char,sizeof(glm::mat4)*2+sizeof(glm::mat3)> buff;
glBufferData(GL_UNIFORM_BUFFER, TotalBufferSize, buff.data(), GL_DYNAMIC_DRAW);
As for how you would find that out: the old-school method is to litter your code with glGetError calls that only go off in debug mode. The more modern method is to create a debug context and print break on the callback to find out whereabouts the error is (then you can make glGetError calls in that area to get the exact function call if you don't know it by then, since modern OpenGL drivers are threaded and the callback may be triggered one or two function calls later).