#include #include #include #include #include // glad must be loaded before GLFW #include "graphics.hpp" #include "main.hpp" #include using namespace std; ShaderProgram::Base ShaderProgram::baseFromName(string name) { string lname = name; boost::algorithm::to_lower(lname); // yes, cpp needs a library to do this. // luckily I'm already using boost so I // don't need to worry too much about it. // can't do a switch over strings in cpp. if (lname == "empty") { return Empty; } if (lname == "triangle") { return Triangle; } else { BOOST_LOG_TRIVIAL(fatal) << "unknown base program \"" << name << "\""; exit(EXIT_USAGE); } } /* class ShaderProgram Implementations */ string ShaderProgram::baseName() { /* BOOST_LOG_TRIVIAL(debug) << "this->base: " << this->base << " Base::Empty: " << Base::Empty << " Base::Triangle: " << Base::Triangle; */ switch (this->base) { case ShaderProgram::Base::Empty: return "Empty"; case ShaderProgram::Base::Triangle: return "Triangle"; default: // this should never occur, as the switch case should cover all variants. throw std::runtime_error("Undefined base Program"); } } /** * @param vertexSource C style string with NULL termination * @param fragSource C style string with NULL termination */ ShaderProgram::ShaderProgram(Base base, string vertexSource, string fragSource) { int success; char infoLog[512]; const char *vertexSource_c = vertexSource.c_str(); const char *fragSource_c = fragSource.c_str(); this->base = base; BOOST_LOG_TRIVIAL(info) << "With base program \"" << this->baseName() << "\""; // NOTE: char arrays and char pointers are not actually the same. // glShaderSource requires a char[] as it appears. We pass the // variable by reference to avoid duplication in memory. BOOST_LOG_TRIVIAL(trace) << "creating empty shaders"; this->vertex = glCreateShader(GL_VERTEX_SHADER); this->frag = glCreateShader(GL_FRAGMENT_SHADER); BOOST_LOG_TRIVIAL(trace) << "loading vertex shader"; glShaderSource(this->vertex, 1, &vertexSource_c, NULL); BOOST_LOG_TRIVIAL(trace) << "compiling vertex shader"; glCompileShader(this->vertex); // check if it worked glGetShaderiv(this->vertex, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(this->vertex, 512, NULL, infoLog); BOOST_LOG_TRIVIAL(fatal) << "could not compile vertex shader:\n\n" << infoLog << std::endl; exit(EXIT_SHADER); } BOOST_LOG_TRIVIAL(trace) << "loading fragments shader"; glShaderSource(this->frag, 1, &fragSource_c, NULL); BOOST_LOG_TRIVIAL(trace) << "compiling fragments shader"; glCompileShader(this->frag); // check if it worked glGetShaderiv(this->frag, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(this->frag, 512, NULL, infoLog); BOOST_LOG_TRIVIAL(fatal) << "could not compile fragments shader:\n\n" << infoLog << std::endl; exit(EXIT_SHADER); } // combine it all in a actual program this->program = glCreateProgram(); glAttachShader(this->program, this->vertex); glAttachShader(this->program, this->frag); glLinkProgram(this->program); glGetProgramiv(this->program, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(this->program, 512, NULL, infoLog); BOOST_LOG_TRIVIAL(fatal) << "could not link shader program:\n\n" << infoLog << std::endl; exit(EXIT_SHADER); } // finalizing our setup glUseProgram(this->program); glDeleteShader(this->vertex); glDeleteShader(this->frag); } /** defines the base program behavior. * * will be called in `mainWindow`. */ int ShaderProgram::run(GLFWwindow *window) { if (this->base == Triangle) { float vTriangle[] = { -0.5f, -0.5f, 0.0f, // opengl 0.5f, -0.5f, 0.0f, // treats 3d arrays 0.0f, 0.5f, 0.0f // as large 1d arrays }; unsigned int oTriangle; glGenBuffers(1, &oTriangle); glBindBuffer(GL_ARRAY_BUFFER, oTriangle); glBufferData(GL_ARRAY_BUFFER, sizeof(vTriangle), vTriangle, GL_STATIC_DRAW); while (!glfwWindowShouldClose(window)) { processInput(window); glClearColor(0.9f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glfwSwapBuffers(window); glfwPollEvents(); } return 0; } else // Empty { return 0; while (!glfwWindowShouldClose(window)) { processInput(window); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glfwSwapBuffers(window); glfwPollEvents(); } return 0; } } /* functions that run out graphics stuff */ void framebuffer_size_callback(GLFWwindow *window, int width, int height) { glViewport(0, 0, width, height); } GLFWwindow *initGl() { /* graphics stuff */ glfwInit(); 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); GLFWwindow *window = glfwCreateWindow(800, 600, "Shader Loader", NULL, NULL); if (window == NULL) { printf("Failed to create GLFW window\n"); glfwTerminate(); exit(EXIT_GL); } glfwMakeContextCurrent(window); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { printf("Failed to initialize GLAD\n"); exit(EXIT_GL); } glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); return window; } int mainWindow(ShaderProgram *shaderProgram, GLFWwindow *window) { int result = 0; BOOST_LOG_TRIVIAL(trace) << "Base program"; result = shaderProgram->run(window); BOOST_LOG_TRIVIAL(trace) << "Left base program"; glfwTerminate(); return result; } void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); }