//OpenGL scratch - reference implementation of OpenGL >= 3.3 rendering code //Author: Ugo Varetto //Requires GLFW and GLM, to deal with the missing support for matrix stack //in OpenGL >= 3.3 //g++ ../src/12_scratch.cpp \ // -I/usr/local/glfw/include \ // -DGLM_FORCE_RADIANS // -DGL_GLEXT_PROTOTYPES -L/usr/local/glfw/lib -lglfw \ // -I/usr/local/glm/include \ // -lGL //clang++ -DGL_GLEXT_PROTOTYPES \ //-L /opt/local/lib -lglfw \ //-I /opt/local/include \ //-framework OpenGL //-DGLM_FORCE_RADIANS 12_scratch.cpp #ifdef __APPLE__ #include #endif #include #include // Include GLM #include #include #include #include #include #include #ifdef USE_DOUBLE typedef double real_t; const GLenum GL_REAL_T = GL_DOUBLE; #else typedef float real_t; const GLenum GL_REAL_T = GL_FLOAT; #endif #ifdef LOG_ #define gle std::cout << "[GL] - " \ << __LINE__ << ' ' << glGetError() << std::endl; #else #define gle #endif //------------------------------------------------------------------------------ GLuint create_program(const char* vertexSrc, const char* geometryShaderSrc, const char* fragmentSrc) { // Create the shaders GLuint vs = glCreateShader(GL_VERTEX_SHADER); GLuint gs = glCreateShader(GL_GEOMETRY_SHADER); GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); GLint res = GL_FALSE; int logsize = 0; // Compile Vertex Shader glShaderSource(vs, 1, &vertexSrc, 0); glCompileShader(vs); // Check Vertex Shader glGetShaderiv(vs, GL_COMPILE_STATUS, &res); glGetShaderiv(vs, GL_INFO_LOG_LENGTH, &logsize); if(logsize > 1){ std::vector errmsg(logsize + 1, 0); glGetShaderInfoLog(vs, logsize, 0, &errmsg[0]); std::cout << &errmsg[0] << std::endl; } // Compile Geometry Shader glShaderSource(gs, 1, &geometryShaderSrc, 0); glCompileShader(gs); // Check Geometry Shader glGetShaderiv(gs, GL_COMPILE_STATUS, &res); glGetShaderiv(gs, GL_INFO_LOG_LENGTH, &logsize); if (logsize > 1) { std::vector errmsg(logsize + 1, 0); glGetShaderInfoLog(fs, logsize, 0, &errmsg[0]); std::cout << &errmsg[0] << std::endl; } // Compile Fragment Shader glShaderSource(fs, 1, &fragmentSrc, 0); glCompileShader(fs); // Check Fragment Shader glGetShaderiv(fs, GL_COMPILE_STATUS, &res); glGetShaderiv(fs, GL_INFO_LOG_LENGTH, &logsize); if(logsize > 1){ std::vector errmsg(logsize + 1, 0); glGetShaderInfoLog(fs, logsize, 0, &errmsg[0]); std::cout << &errmsg[0] << std::endl; } // Link the program GLuint program = glCreateProgram(); glAttachShader(program, vs); glAttachShader(program, gs); glAttachShader(program, fs); glLinkProgram(program); // Check the program glGetProgramiv(program, GL_LINK_STATUS, &res); glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logsize); if(logsize > 1) { std::vector errmsg(logsize + 1, 0); glGetShaderInfoLog(program, logsize, 0, &errmsg[0]); std::cout << &errmsg[0] << std::endl; } glDeleteShader(vs); glDeleteShader(gs); glDeleteShader(fs); return program; } //------------------------------------------------------------------------------ void error_callback(int error, const char* description) { std::cerr << description << std::endl; } //------------------------------------------------------------------------------ void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE); } //------------------------------------------------------------------------------ const char fragmentShaderSrc[] = "#version 330 core\n" "in vec4 gsColor;\n" "out vec4 outColor;\n" "void main() {\n" " outColor = gsColor;\n" "}"; const char geometryShaderSrc[] = "#version 330 core\n" "layout(points) in;\n" "layout(triangle_strip, max_vertices = 32) out;\n" "uniform mat4 modelView;\n" "uniform mat4 proj;\n" "uniform float tipDistance = 0.03;\n" "uniform float baseRadius = 0.005;\n" "const float Sqrt2Over2 = 0.70710678118654752440084436210485;\n" "in vec4 vsColor[];\n" "in vec3 vsNormal[];\n" "flat in int vsFlags[];\n" "out vec4 gsColor;\n" "void main()\n" "{\n" "vec3 absNormal = abs(vsNormal[0]);\n" "vec3 localX = vec3(0.0);\n" "vec3 localY = vec3(0.0);\n" "vec3 center = gl_in[0].gl_Position.xyz;\n" "vec3 tip = center + tipDistance * vsNormal[0];\n" "if (absNormal.x > absNormal.y && absNormal.x > absNormal.z)\n" "{\n" " localY = cross(vsNormal[0], vec3(0.0, 1.0, 0.0));\n" "}\n" "else if (absNormal.y > absNormal.x && absNormal.y > absNormal.z)\n" "{\n" " localY = cross(vsNormal[0], vec3(0.0, 0.0, 1.0));\n" "}\n" "else\n" "{\n" " localY = cross(vsNormal[0], vec3(1.0, 0.0, 0.0));\n" "}\n" "\n" "localY = normalize(localY);\n" "localX = cross(localY, vsNormal[0]);\n" "\n" "vec4 centerPos = proj * modelView * vec4(center, 1.0);\n" "vec4 tipPos = proj * modelView * vec4(tip, 1.0);\n" "vec4 positions[8] = vec4[8](\n" " proj * modelView * vec4(center + baseRadius * localX, 1.0),\n" " proj * modelView * vec4(center + baseRadius * Sqrt2Over2 * localX + baseRadius * Sqrt2Over2 * localY, 1.0),\n" " proj * modelView * vec4(center + baseRadius * localY, 1.0),\n" " proj * modelView * vec4(center - baseRadius * Sqrt2Over2 * localX + baseRadius * Sqrt2Over2 * localY, 1.0),\n" " proj * modelView * vec4(center - baseRadius * localX, 1.0),\n" " proj * modelView * vec4(center - baseRadius * Sqrt2Over2 * localX - baseRadius * Sqrt2Over2 * localY, 1.0),\n" " proj * modelView * vec4(center - baseRadius * localY, 1.0),\n" " proj * modelView * vec4(center + baseRadius * Sqrt2Over2 * localX - baseRadius * Sqrt2Over2 * localY, 1.0)\n" " );\n" "\n" "int iPrev = positions.length() - 1;\n" "\n" "for (int i = 0; i < positions.length(); ++i)\n" "{\n" " // triangle in base\n" " gl_Position = centerPos;\n" " gsColor = vsColor[0];\n" " EmitVertex();\n" "\n" " gl_Position = positions[iPrev];\n" " gsColor = vsColor[0];\n" " EmitVertex();\n" "\n" " gl_Position = positions[i];\n" " gsColor = vsColor[0];\n" " EmitVertex();\n" "\n" " // tip of cone\n" " gl_Position = tipPos;\n" " gsColor = vsColor[0];\n" " EmitVertex();\n" "\n" " EndPrimitive();\n" "\n" " iPrev = i;\n" "}\n" "}\n"; const char vertexShaderSrc[] = "#version 330 core\n" "uniform sampler1D gradient;\n" "uniform int valueIndex = 0;\n" "uniform vec4 maxValueColor = vec4(1.0, 0.0, 0.0, 1.0);\n" "\n" "layout(location = 0) in vec4 pos;\n" "layout(location = 1) in vec3 normal;\n" "layout(location = 2) in vec3 value;\n" "layout(location = 3) in int flags;\n" "\n" "out vec4 vsColor;\n" "out vec3 vsNormal;\n" "flat out int vsFlags;\n" "\n" "const float maxValue = 1.5;\n" "\n" "void main()\n" "{\n" " gl_Position = pos;\n" " vsNormal = normal;\n" "\n" " if (value[valueIndex] > maxValue)\n" " {\n" " vsColor = maxValueColor;\n" " }\n" " else\n" " {\n" " vsColor = texture(gradient, value[valueIndex] / maxValue);\n" " }\n" "}\n"; //------------------------------------------------------------------------------ int main(int argc, char** argv) { glfwSetErrorCallback(error_callback); if(!glfwInit()) { std::cerr << "ERROR - glfwInit" << std::endl; exit(EXIT_FAILURE); } //WARNING: THIS DOESN'T WORK glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif GLFWwindow* window = glfwCreateWindow(640, 480, "GL 3.3 core", NULL, NULL); if (!window) { std::cerr << "ERROR - glfwCreateWindow" << std::endl; glfwTerminate(); exit(EXIT_FAILURE); } glfwSetKeyCallback(window, key_callback); glfwMakeContextCurrent(window); glewExperimental = GL_TRUE; glewInit(); std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl; std::cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; std::cout << "Vendor: " << glGetString(GL_VENDOR) << std::endl; std::cout << "Renderer: " << glGetString(GL_RENDERER) << std::endl; //GEOMETRY //geometry const size_t nRows = 64; const size_t nCols = 64; const size_t maxPoints = 3159 < nRows * nCols ? 3159 : nRows * nCols; struct attribute { glm::vec3 pos; glm::vec3 normal; glm::u8vec4 selectionColor; glm::vec3 value; int flags; }; attribute points[nRows][nCols]; for (size_t i = 0; i < nRows; ++i) { for (size_t j = 0; j < nCols; ++j) { points[i][j].pos = glm::vec3(-1.0 + 2.0 * i / (nRows - 1), -1.0 + 2.0 * j / (nCols - 1), 0.0); points[i][j].normal = glm::vec3(1.0, 0.0, 1.0); points[i][j].selectionColor = glm::u8vec4(1.0); points[i][j].value = glm::vec3(static_cast(rand()) / RAND_MAX * 2); points[i][j].flags = 7; } } //OpenGL >= 3.3 core requires a vertex array object containing multiple attribute //buffers GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); //geometry buffer GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, maxPoints * sizeof(attribute), &points[0][0], GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(attribute), reinterpret_cast(offsetof(attribute, pos))); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(attribute), reinterpret_cast(offsetof(attribute, normal))); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(attribute), reinterpret_cast(offsetof(attribute, value))); glVertexAttribIPointer(3, 1, GL_INT, sizeof(attribute), reinterpret_cast(offsetof(attribute, flags))); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); // create texture const size_t gradientSize = 128; glm::vec3 gradient[gradientSize]; for (size_t i = 0; i < gradientSize; ++i) { gradient[i] = glm::vec3(0.0, 0.25 + 0.5 * i / (gradientSize - 1), 0.0); } GLuint tex; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_1D, tex); glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, gradientSize, 0, GL_RGB, GL_FLOAT, &gradient[0]); //optional glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); //required glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_1D, 0); //OPENGL RENDERING SHADERS GLuint glprogram = create_program(vertexShaderSrc, geometryShaderSrc, fragmentShaderSrc); //enable gl program glUseProgram(glprogram); //extract ids of shader variables GLint mvID = glGetUniformLocation(glprogram, "modelView"); assert(mvID>=0); GLint projID = glGetUniformLocation(glprogram, "proj"); assert(projID >= 0); GLint textureID = glGetUniformLocation(glprogram, "gradient"); assert(textureID >= 0); //only need texture unit 0 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, tex); glUniform1i(textureID, 0); //background color glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //RENDER LOOP //rendering & simulation loop while (!glfwWindowShouldClose(window)) { glClear(GL_COLOR_BUFFER_BIT); //setup OpenGL matrices: no more matrix stack in OpenGL >= 3 core //profile, need to co// Clear the screen int width, height; glfwGetFramebufferSize(window, &width, &height); assert(width > 0 && height > 0); const float ratio = width / float(height); const glm::mat4 orthoProj = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 1.0f, -1.0f); const glm::mat4 modelView = glm::mat4(1.0f); //const glm::mat4 MVP = orthoProj * modelView; glViewport(0, 0, width, height); glUniformMatrix4fv(mvID, 1, GL_FALSE, glm::value_ptr(modelView)); glUniformMatrix4fv(projID, 1, GL_FALSE, glm::value_ptr(orthoProj)); //select geometry to render glBindVertexArray(vao); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); //draw glDrawArrays(GL_POINTS, 0, maxPoints); //unbind glBindVertexArray(0); glDisableVertexAttribArray(0); //put pixels on screen glfwSwapBuffers(window); //query events glfwPollEvents(); } //CLEANUP glDeleteBuffers(1, &vbo); glDeleteVertexArrays(1, &vao); glDeleteTextures(1, &tex); glfwDestroyWindow(window); glfwTerminate(); exit(EXIT_SUCCESS); return 0; }