Advertisement

My first experience in starting OpenGL

Started by November 13, 2017 10:59 AM
4 comments, last by penguinbyebye 7 years, 2 months ago

Hi,

I'm trying to learn OpenGL through a website and have proceeded until this page of it. The output is a simple triangle. The problem is the complexity.

I have read that page several times and tried to analyse the code but I haven't understood the code properly and completely yet. This is the code:

 


#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <C:\Users\Abbasi\Desktop\std_lib_facilities_4.h>
using namespace std;

//******************************************************************************

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";

const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";

//*******************************

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

	  // glfw window creation
	GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "My First Triangle", nullptr, nullptr);
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

	  // glad: load all OpenGL function pointers
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		cout << "Failed to initialize GLAD" << endl;
		return -1;
	}

	  // build and compile our shader program
	   // vertex shader
	int vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
	glCompileShader(vertexShader);

	  // check for shader compile errors
	int success;
	char infoLog[512];
	glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
		cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << endl;
	}

	   // fragment shader
	int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
	glCompileShader(fragmentShader);

	  // check for shader compile errors
	glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
		cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << endl;
	}

	   // link shaders
	int shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);
	   
	   // check for linking errors
	glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
	if (!success) {
		glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
		cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << endl;
	}
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);

	   // set up vertex data (and buffer(s)) and configure vertex attributes
	float vertices[] = {
	   -0.5f, -0.5f, 0.0f, // left  
		0.5f, -0.5f, 0.0f, // right 
		0.0f,  0.5f, 0.0f  // top   
	};

	unsigned int VBO, VAO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);

	    // bind the Vertex Array Object first, then bind and set vertex buffer(s), 
	     //and then configure vertex attributes(s).
	glBindVertexArray(VAO);

	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);

	    // note that this is allowed, the call to glVertexAttribPointer registered VBO 
	    // as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	   // You can unbind the VAO afterwards so other VAO calls won't accidentally 
	   // modify this VAO, but this rarely happens. Modifying other
	   // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind
	   // VAOs (nor VBOs) when it's not directly necessary.
	glBindVertexArray(0);

	   // uncomment this call to draw in wireframe polygons.
	   //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	   // render loop
	while (!glfwWindowShouldClose(window))
	{
		// input
		// -----
		processInput(window);

		// render
		// ------
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		   // draw our first triangle
		glUseProgram(shaderProgram);
		glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to 
		  // bind it every time, but we'll do so to keep things a bit more organized
		glDrawArrays(GL_TRIANGLES, 0, 3);
		   // glBindVertexArray(0); // no need to unbind it every time 

		   // 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, &VAO);
	glDeleteBuffers(1, &VBO);

	   // glfw: terminate, clearing all previously allocated GLFW resources.
	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);
}

//********************************************************************

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

As you see, about 200 lines of complicated code only for a simple triangle. 

I don't know what parts are necessary for that output. And also, what the correct order of instructions for such an output or programs is, generally. That start point is too complex for a beginner of OpenGL like me and I don't know how to make the issue solved. What are your ideas please? What is the way to figure both the code and the whole program out correctly please?

I wish I'd read a reference that would teach me OpenGL through a step-by-step method. 

Well, I can't see how the OpenGL stuff could be made any more simpler in that code:  you need to set up and link the shader pipeline (ie. program the GPU), you have to set up what you're going to draw in the memory accessibly by the GPU, and you need to tell the CPU to tell the GPU to draw stuff.  It's as simle as necessary, but no simpler.

You could simplify your program by getting rid of the GLFW code, but I think you may find it more instructive in the long run to leave it in.

The above code is not a lot of code.  In fact, it's going to disappear into the background noise of a useful application.  Learning to program means learning to read and understand stuff like that, but in larger quantities.  Give it time, it will come with hard work and practice just like any else that's difficult but worthwhile.

Stephen M. Webb
Professional Free Software Developer

Advertisement

Thanks for the reply.

Yeah, it seems that way but honestly complicated for a starter. :(

I guess this part (that is, most of my code), is just like framework for the rest of the programs. That is, we supply that code as a base and after that our hands are free to by code to tell the compiler what we want, in programs.

5 hours ago, Bregma said:

You could simplify your program by getting rid of the GLFW code

What lines did you exactly mean please?

 

5 hours ago, Bregma said:

Learning to program means learning to read and understand stuff like that, but in larger quantities.  Give it time, it will come with hard work and practice just like any else that's difficult but worthwhile.

 

Yes, I accept. What at this point I need is that, what stages do we need to code for making such a triangle in OpenGL? For example, how many steps/stages are needed to create such a triangle specifically or other OpenGL programs generally? (If we can divide the code into stages) and what lines in that code do belong to each stage please? 

Did you read all the text in the tutorial and previous ones?  It's pretty self explanatory about what each step is.  He also, at the bottom of the article you linked to gives you other sites to read like this one: http://antongerdelan.net/opengl/hellotriangle.html  It goes into even more detail covering GLEW setup.  I'm sure the previous tutorials in the learnopengl site covered this too.  Both tutorials are pretty simple in terms of minimizing excess code.  Maybe learning C# and unity instead of C++ and OpenGL at this point?
 

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

You don't have an excess of code, the issue is that your your code isn't fragmented in systems (yet). As a learner, what you are doing (writing everything in a single function) is OK, that way you learn what does what in OpenGL. When you want to use what you learned to build a framework/engine, then you need to separate things into systems/modules. Then you won't have to repeat that kind of code everywhere.

This topic is closed to new replies.

Advertisement