Here is my main.cpp
#define STB_IMAGE_IMPLEMENTATION
#include"stb_image.h"
#include<GL/glew.h> // It links from the driver to the opengl function pointers
#include<GLFW/glfw3.h>
#include<iostream>
#include<glm/glm.hpp>
#include<glm/vec2.hpp>
#include<glm/vec3.hpp>
#include<glm/vec4.hpp>
#include<glm/mat4x4.hpp>
#include<glm/gtc/matrix_transform.hpp>
#include<glm/gtc/type_ptr.hpp>
#include<SOIL2/SOIL2.h>
#include<string>
#include<vector>
#include<fstream>
#define GLEW_STATIC
struct Vertex{
glm::vec3 position;
glm::vec3 color;
glm::vec2 texcoord;
};
void framebuffer_size_callback(GLFWwindow* window, int width, int height){ // For the resizeability
glViewport(0, 0, width, height);
}
float 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
};
unsigned int indices[] = {
0, 1, 2,
0, 2, 3 // second triangle
};
unsigned nofVertices = sizeof(vertices)/sizeof(Vertex); // WIll work here, but if I am sending it to a function and then recienving a pointer then sizeof() will take the size of the pointer and will give errors.
unsigned nofIndices = sizeof(indices)/sizeof(GLuint);
/// Handling Input. This one is currently just closes the window at esc.
void updateInput(GLFWwindow* window){
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS){
glfwSetWindowShouldClose(window, true);
}
}
// Loading shaders:
bool loadshaders(GLuint &program){
bool flag = true;
char infoLog[512];
GLint success;
// glsl ig compiles ie links in runtime.
std::string temp="";
std::string src="";
std::ifstream in_file;
in_file.open("vertex_core.glsl");
if(in_file.is_open()){
while(std::getline(in_file, temp)){
src+=temp+'\n';
}
}
else{
flag=false;
std::cout<<"ERROR::LOADSHADERS::COULDNOT_OPEN_THE_FILE\n";
}
in_file.close();
// createing a vertex shader.
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); // id of vertex shader beign created in the background, of gl memory.
// setting a source to the shader;
const GLchar* vertexSRC = src.c_str();
glShaderSource(vertexShader, 1, &vertexSRC, NULL);
glCompileShader(vertexShader); // compiles the shader from source.
// checking any compile error:
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if(!success){
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout<<"ERROR: "<<infoLog<<"\n";
}
temp="";
src="";
// Making a fragment:
in_file.open("fragment_core.glsl");
if(in_file.is_open()){
while(std::getline(in_file, temp)){
src+=temp+'\n';
}
}
else{
std::cout<<"ERROR::LOADSHADERS::COULDNOT_OPEN_THE_FILE\n";
}
in_file.close();
// createing a vertex shader.
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER ); // id of vertex shader beign created in the background, of gl memory.
// setting a source to the shader;
const GLchar* fragSRC = src.c_str();
glShaderSource(fragmentShader, 1, &fragSRC, NULL);
glCompileShader(fragmentShader); // compiles the shader from source.
// checking any compile error:
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if(!success){
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout<<"ERROR: "<<infoLog<<"\n";
}
// Program
// attaching shaders to a program:
program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
glGetProgramiv(program,GL_LINK_STATUS, &success);
// error handling:
if(!success){
glGetProgramInfoLog(program, 512, NULL, infoLog);
std::cout<<infoLog<<std::endl;
}
// End: resets everything
glUseProgram(0);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return flag;
}
GLuint Texture; // Make this global or return it from function
void setTexture() {
glGenTextures(1, &Texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
// Settings
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Load image
stbi_set_flip_vertically_on_load(true); // Add this
int width, height, nrChannels;
unsigned char *data = stbi_load("sumner-mahaffey-7Y0NshQLohk-unsplash.jpg", &width, &height, &nrChannels, 0);
if (!data) {
std::cout << "Failed to load texture" << std::endl;
}
if (data) {
std::cout << "Channels: " << nrChannels << std::endl;
GLenum format = (nrChannels == 4) ? GL_RGBA : GL_RGB;
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
stbi_image_free(data);
}
int main(){
// GLFWwindow* window = glfwCreateWindow();
glfwInit(); // initializing the glfw
// ! Consts
const int WINDOW_WIDTH = 640;
const int WINDOW_HEIGHT = 800;
// framebuff can be diff that window
int frame_buff_width = 0; // Its the canvas that been strecthed to fit the frame.
int frame_buff_height = 0;
// To set some options to OPENGL.
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); // this one sets the version of opengl to use.
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // To use the modern version of the core functions.
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
// glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); for Mac
// Create Window
GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "My window", NULL, NULL);
glfwGetFramebufferSize(window, &frame_buff_width, &frame_buff_height); // To set the Frame buffer size
// set Viewport: how much window we are drawing on
glViewport(0,0,frame_buff_width,frame_buff_height); // Canvas size
// Set Context to the window for glew and all libs.
glfwMakeContextCurrent(window); // ! Very Important.
// Init GLEW (It needs a window and openGL context to properly run)
glewExperimental = GL_TRUE; // to use modern opengl functionalities.
// Check glew Init
if(glewInit() != GLEW_OK){
std::cout<<"ERROR::openGL_init.cpp::GLEW_INIT_FAILED\n";
glfwTerminate();
}
// Some OpenGL options:
// As openGL is a state machine. we can enable some setting that are always running in the background
glEnable(GL_DEPTH_TEST); // This lets us draw depth
glEnable(GL_CULL_FACE); // This helps us in such a way that if something is blocked some some other obj it dont get rendered at all.
glCullFace(GL_BACK); // Telling what not to render. ie the backside.
glFrontFace(GL_CCW); // counter clock wise
glEnable(GL_BLEND); // enable the blending of colors etc.
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); // doing setting of the blend.
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // LINE for jus lines. fill for filling
// Shader Initialization
GLuint core_program;
loadshaders(core_program);
// MODEL
// sending vertices/data to the shaders
// VAO, VBO. EBO
// vertex Aarray object. Id for the whole model
// Vertex buffer object. sends vertex info to GC.
// Vertex element object. sends indices data to the GC.
// Generating VAO and Binding
GLuint VAO;
glCreateVertexArrays(1, &VAO); // We kind of created a shell to use.
glBindVertexArray(VAO); // binding it to the variable
// Generating VBO and sending Data
GLuint VBO;
glGenBuffers(1, &VBO); // genertating the buffer
glBindBuffer(GL_ARRAY_BUFFER, VBO); // 1st: array buffer tells the type of buffer kind of
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // static draw cause we don't want to change the drawing often. use other enums for dynamic usage
// Generating VEO and sending Data
GLuint EBO;
glGenBuffers(1, &EBO); // genertating the buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // static draw cause we don't want to change the drawing often. use other enums for dynamic usage
// We don't wnat to send data again. as sending mem from cpu to gpu is expensive.
// seting VertexAttribute pointer and enable some options (input assembly)
// GLuint attribLoc = glGetAttribLocation(core_program, "vertex_position"); /// Can give the index like this way also
// Position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// Color
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// TextureCoord
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
// Bind VAO 0
glBindVertexArray(0);
setTexture();
glUseProgram(core_program);
GLint texLoc = glGetUniformLocation(core_program, "OurTexture");
if (texLoc == -1) {
std::cout << "Failed to find uniform location for 'OurTexture'" << std::endl;
} else {
glUniform1i(texLoc, 0); // Ensure this is done after glUseProgram
}
// glUniform1i(glGetUniformLocation(shader.ID, "texture1"), 0);
// Main loop
while(!glfwWindowShouldClose(window)){
GLenum err;
while ((err = glGetError()) != GL_NO_ERROR) {
std::cerr << "OpenGL error: " << err << std::endl;
}
/// setting resizing of window. (Currently not working)
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// Log runtime information
// std::cout << "Frame buffer size: " << frame_buff_width << "x" << frame_buff_height << std::endl;
// std::cout << "Window size: " << WINDOW_WIDTH << "x" << WINDOW_HEIGHT << std::endl;
// std::cout << "Number of vertices: " << nofVertices << std::endl;
// std::cout << "Number of indices: " << nofIndices << std::endl;
// update Input --
glfwPollEvents();
// update
updateInput(window);
// draw
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
// clear
glClearColor(0.f,0.f,0.f,1.f); // R,G,B,alpha
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // uses to clear buffers. Here we are clearing color buff.
// use a program
glUseProgram(core_program);
// Bind Vertex array object. know where our data is
glBindVertexArray(VAO);
// draw
// glDrawArrays(GL_TRIANGLES, 0, nofIndices );
glDrawElements(GL_TRIANGLES, nofIndices, GL_UNSIGNED_INT, 0);
// Change the fragment shader for the final texture of the drawing. eg I can change the color of triangle by just changining it to not get the index data but hardcoded values.
// Vertex shader runs for no. verteces and fragment runs vertex shader. Total here they both run 3,3 times.
// end draw
glfwSwapBuffers(window); // swap and
glFlush(); // flush
}
// End
glfwTerminate(); // to free up the memory etc.
// delet program
glDeleteProgram(core_program);
}
here is my fragment_core.glsl
:
#version 440 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
uniform sampler2D OurTexture;
void main()
{
FragColor = texture(OurTexture, TexCoord) * vec4(ourColor, 1.0);
}
here is my vertex_core.glsl
:
#version 440 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}
Here is the Picture of what issue I am facing:
Both of the triangles in your vertex geometry:
float 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
};
unsigned int indices[] = {
0, 1, 2,
0, 2, 3, // second triangle
};
...are wound clockwise.
And since you asked OpenGL to cull those:
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
...neither triangle will be drawn.
You have multiple options:
glDisable(GL_CULL_FACE)
glCullFace(GL_FRONT)
glFrontFace(GL_CW)