|
| 1 | +/******************************************************************************\ |
| 2 | +| OpenGL 4 Example Code. | |
| 3 | +| Accompanies written series "Anton's OpenGL 4 Tutorials" | |
| 4 | +| Email: anton at antongerdelan dot net | |
| 5 | +| First version 27 Jan 2014 | |
| 6 | +| Copyright Dr Anton Gerdelan, Trinity College Dublin, Ireland. | |
| 7 | +| See individual libraries for separate legal notices | |
| 8 | +|******************************************************************************| |
| 9 | +| "Hello Triangle". Just the basics. | |
| 10 | +| If you're on Mac un-comment the version number code at the beginning. It | |
| 11 | +| will give you the latest, even if you say 3.2! | |
| 12 | +| This uses the libraries GLEW and GLFW3 to start GL. Download and compile | |
| 13 | +| these first. Linking them might be a pain, but you'll need to master this. | |
| 14 | +| | |
| 15 | +| I wrote this so that it compiles in pedantic ISO C90, to show that it's | |
| 16 | +| easily done. I usually use minimalist C++ though, for tidier-looking maths | |
| 17 | +| functions. | |
| 18 | +\******************************************************************************/ |
| 19 | +#include <GL/glew.h> /* include GLEW and new version of GL on Windows */ |
| 20 | +#include <GLFW/glfw3.h> /* GLFW helper library */ |
| 21 | +#include <stdio.h> |
| 22 | + |
| 23 | +int main () { |
| 24 | + GLFWwindow* window = NULL; |
| 25 | + const GLubyte* renderer; |
| 26 | + const GLubyte* version; |
| 27 | + GLuint vao; |
| 28 | + GLuint vbo; |
| 29 | + /* geometry to use. these are 3 xyz points (9 floats total) to make a triangle |
| 30 | + */ |
| 31 | + GLfloat points[] = { |
| 32 | + 0.0f, 0.5f, 0.0f, |
| 33 | + 0.5f, -0.5f, 0.0f, |
| 34 | + -0.5f, -0.5f, 0.0f |
| 35 | + }; |
| 36 | + /* these are the strings of code for the shaders |
| 37 | + the vertex shader positions each vertex point */ |
| 38 | + const char* vertex_shader = |
| 39 | + "#version 400\n" |
| 40 | + "in vec3 vp;" |
| 41 | + "void main () {" |
| 42 | + " gl_Position = vec4 (vp, 1.0);" |
| 43 | + "}"; |
| 44 | + /* the fragment shader colours each fragment (pixel-sized area of the |
| 45 | + triangle) */ |
| 46 | + const char* fragment_shader = |
| 47 | + "#version 400\n" |
| 48 | + "out vec4 frag_colour;" |
| 49 | + "void main () {" |
| 50 | + " frag_colour = vec4 (0.5, 0.0, 0.5, 1.0);" |
| 51 | + "}"; |
| 52 | + /* GL shader objects for vertex and fragment shader [components] */ |
| 53 | + GLuint vs, fs; |
| 54 | + /* GL shader programme object [combined, to link] */ |
| 55 | + GLuint shader_programme; |
| 56 | + |
| 57 | + /* start GL context and O/S window using the GLFW helper library */ |
| 58 | + if (!glfwInit ()) { |
| 59 | + fprintf (stderr, "ERROR: could not start GLFW3\n"); |
| 60 | + return 1; |
| 61 | + } |
| 62 | + |
| 63 | + /* change to 3.2 if on Apple OS X */ |
| 64 | + glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 4); |
| 65 | + glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 0); |
| 66 | + glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); |
| 67 | + glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); |
| 68 | + |
| 69 | + window = glfwCreateWindow ( |
| 70 | + 640, 480, "Hello Triangle", NULL, NULL |
| 71 | + ); |
| 72 | + if (!window) { |
| 73 | + fprintf (stderr, "ERROR: could not open window with GLFW3\n"); |
| 74 | + glfwTerminate(); |
| 75 | + return 1; |
| 76 | + } |
| 77 | + glfwMakeContextCurrent (window); |
| 78 | + /* start GLEW extension handler */ |
| 79 | + glewExperimental = GL_TRUE; |
| 80 | + glewInit (); |
| 81 | + |
| 82 | + /* get version info */ |
| 83 | + renderer = glGetString (GL_RENDERER); /* get renderer string */ |
| 84 | + version = glGetString (GL_VERSION); /* version as a string */ |
| 85 | + printf ("Renderer: %s\n", renderer); |
| 86 | + printf ("OpenGL version supported %s\n", version); |
| 87 | + |
| 88 | + /* tell GL to only draw onto a pixel if the shape is closer to the viewer */ |
| 89 | + glEnable (GL_DEPTH_TEST); /* enable depth-testing */ |
| 90 | + glDepthFunc (GL_LESS);/*depth-testing interprets a smaller value as "closer"*/ |
| 91 | + |
| 92 | + /* a vertex buffer object (VBO) is created here. this stores an array of data |
| 93 | + on the graphics adapter's memory. in our case - the vertex points */ |
| 94 | + glGenBuffers (1, &vbo); |
| 95 | + glBindBuffer (GL_ARRAY_BUFFER, vbo); |
| 96 | + glBufferData (GL_ARRAY_BUFFER, 9 * sizeof (GLfloat), points, GL_STATIC_DRAW); |
| 97 | + |
| 98 | + /* the vertex array object (VAO) is a little descriptor that defines which |
| 99 | + data from vertex buffer objects should be used as input variables to vertex |
| 100 | + shaders. in our case - use our only VBO, and say 'every three floats is a |
| 101 | + variable' */ |
| 102 | + glGenVertexArrays (1, &vao); |
| 103 | + glBindVertexArray (vao); |
| 104 | + glEnableVertexAttribArray (0); |
| 105 | + glBindBuffer (GL_ARRAY_BUFFER, vbo); |
| 106 | + glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL); |
| 107 | + |
| 108 | + /* here we copy the shader strings into GL shaders, and compile them. we then |
| 109 | + create an executable shader 'program' and attach both of the compiled shaders. |
| 110 | + we link this, which matches the outputs of the vertex shader to the inputs of |
| 111 | + the fragment shader, etc. and it is then ready to use */ |
| 112 | + vs = glCreateShader (GL_VERTEX_SHADER); |
| 113 | + glShaderSource (vs, 1, &vertex_shader, NULL); |
| 114 | + glCompileShader (vs); |
| 115 | + fs = glCreateShader (GL_FRAGMENT_SHADER); |
| 116 | + glShaderSource (fs, 1, &fragment_shader, NULL); |
| 117 | + glCompileShader (fs); |
| 118 | + shader_programme = glCreateProgram (); |
| 119 | + glAttachShader (shader_programme, fs); |
| 120 | + glAttachShader (shader_programme, vs); |
| 121 | + glLinkProgram (shader_programme); |
| 122 | + |
| 123 | + /* this loop clears the drawing surface, then draws the geometry described by |
| 124 | + the VAO onto the drawing surface. we 'poll events' to see if the window was |
| 125 | + closed, etc. finally, we 'swap the buffers' which displays our drawing surface |
| 126 | + onto the view area. we use a double-buffering system which means that we have |
| 127 | + a 'currently displayed' surface, and 'currently being drawn' surface. hence |
| 128 | + the 'swap' idea. in a single-buffering system we would see stuff being drawn |
| 129 | + one-after-the-other */ |
| 130 | + while (!glfwWindowShouldClose (window)) { |
| 131 | + /* wipe the drawing surface clear */ |
| 132 | + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| 133 | + glUseProgram (shader_programme); |
| 134 | + glBindVertexArray (vao); |
| 135 | + /* draw points 0-3 from the currently bound VAO with current in-use shader*/ |
| 136 | + glDrawArrays (GL_TRIANGLES, 0, 3); |
| 137 | + /* update other events like input handling */ |
| 138 | + glfwPollEvents (); |
| 139 | + /* put the stuff we've been drawing onto the display */ |
| 140 | + glfwSwapBuffers (window); |
| 141 | + } |
| 142 | + |
| 143 | + /* close GL context and any other GLFW resources */ |
| 144 | + glfwTerminate(); |
| 145 | + return 0; |
| 146 | +} |
0 commit comments