/// Includes #include #include #include #include #include #include #include /// Constants constexpr auto width = 640; constexpr auto height = 480; constexpr auto title = ""; /// Helpers //// Debug void GLAPIENTRY debug_message_callback( GLenum /* source */, GLenum /* type */, GLuint /* id */, GLenum /* severity */, GLsizei /* length */, GLchar const * message, void const * /* param */ ) { std::cerr << message << std::endl; }; //// Uniform void uniform(GLint location, int value ) { glUniform1i (location, value); } void uniform(GLint location, bool value ) { glUniform1i (location, value); } void uniform(GLint location, float value ) { glUniform1f (location, value); } void uniform(GLint location, float const (& value)[1]) { glUniform1fv(location, 1, value); } void uniform(GLint location, float const (& value)[2]) { glUniform2fv(location, 1, value); } void uniform(GLint location, float const (& value)[3]) { glUniform3fv(location, 1, value); } void uniform(GLint location, float const (& value)[4]) { glUniform4fv(location, 1, value); } template void uniform(char const * name, T const & value) { GLuint program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *)&program); GLint location = glGetUniformLocation(program, name); uniform(location, value); } //// Write void write_tga(char const * base) { char header[] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, (char)(width >> 0U), (char)(width >> 8U), (char)(height >> 0U), (char)(height >> 8U), 4*8, 0, }; char data[4*width*height]; glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, data); auto t = std::time(nullptr); auto pt = std::put_time(std::localtime(&t), "%Y-%m-%d_%H-%M-%S"); std::ofstream((std::ostringstream{} << base << "_" << pt << ".tga").str()) .write(header, sizeof(header)) .write(data, sizeof(data)); } /// Main int main(int /*argc*/, char * argv[]) { //// Window/context glfwInit(); auto window = glfwCreateWindow(width, height, title, nullptr, nullptr); glfwMakeContextCurrent(window); glewInit(); //// Callbacks glfwSetWindowUserPointer(window, argv[0]); glfwSetKeyCallback(window, [](GLFWwindow* w, int key, int /*scancode*/, int action, int /*mods*/) { auto ptr = glfwGetWindowUserPointer(w); if (action != GLFW_RELEASE) return; if (key == GLFW_KEY_Q) glfwSetWindowShouldClose(w, GLFW_TRUE); if (key == GLFW_KEY_W) write_tga((char *)ptr); } ); //// Debug glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallback(debug_message_callback, nullptr); //// Shader auto make_program = [](char const * vert_source, char const * frag_source) { auto program = glCreateProgram(); auto vert = glCreateShader(GL_VERTEX_SHADER); auto frag = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(vert, 1, &vert_source, nullptr); glShaderSource(frag, 1, &frag_source, nullptr); glCompileShader(vert); glCompileShader(frag); glAttachShader(program, vert); glAttachShader(program, frag); glLinkProgram(program); return program; }; auto vert_source = R"( #version 140 out vec2 tex_coord; void main() { tex_coord = vec2[]( vec2(0, 0), vec2(2, 0), vec2(0, 2) )[gl_VertexID]; gl_Position = vec4(tex_coord*2-1, 0, 1); } )"; auto tex_coord_program = make_program(vert_source, R"( #version 140 uniform int view; uniform bool debug; uniform float time; in vec2 tex_coord; void main() { gl_FragColor = vec4(fract(tex_coord - float(!debug)*time), 0, 1); // Exercise the debugging colors. // if (view >= 2) { float x = tex_coord.x; x -= 0.5; x *= 10; x = clamp(x, -3, +3); x /= (3 + x) * (3 - x); x *= (3 + 1) * (3 - 1); x *= 0.5; x += 0.5; gl_FragColor = vec4(x / (1 / float(tex_coord.y > 0.5))); } bvec3 debug_color = bvec3( any(lessThan (gl_FragColor, vec4(0))), any(greaterThan(gl_FragColor, vec4(1))), any(isinf (gl_FragColor)) || any(isnan (gl_FragColor)) ); if (debug && any(debug_color)) gl_FragColor = vec4(debug_color, 1); } )"); //// Main loop int view = 1; bool debug = true; float time = (float)glfwGetTime(); while (glfwPollEvents(), !glfwWindowShouldClose(window)) { ///// Time float pt = time; float dt = (time = (float)glfwGetTime()) - pt; ///// Input for (int num = 0; num <= 9; ++num) if (glfwGetKey(window, GLFW_KEY_0 + num)) view = num; if (glfwGetKey(window, GLFW_KEY_R)) debug = false; if (glfwGetKey(window, GLFW_KEY_E)) debug = true; ///// Draw glClear(GL_COLOR_BUFFER_BIT); glUseProgram(tex_coord_program); uniform("view", view); uniform("debug", debug); uniform("time", time); uniform("dt", dt); glDrawArrays(GL_TRIANGLES, 0, 3); ///// Swap glfwSwapBuffers(window); } //// Cleanup glfwDestroyWindow(window); glfwTerminate(); }