Shader* ResourceManager::createShader(const std::string& lexical_name, const std::string& vs, const std::string& fs, ShaderDataType data_type){ if(shader_lexical_names_.find(lexical_name) != shader_lexical_names_.end()){ std::cerr << "Error: Shader lexical names must not be duplicate" << std::endl; return nullptr; } std::uint32_t id = shader_id_counter_++; if(data_type == SHADER_FILE){ std::ifstream vs_file(vs); if(!vs_file.is_open()){ std::cerr << "Error: unable to find vertex shader file" << std::endl; return nullptr; } std::stringstream vs_stream; vs_stream << vs_file.rdbuf(); std::string vs_dat = vs_stream.str(); std::ifstream fs_file(fs); if(!fs_file.is_open()){ std::cerr << "Error: unable to find fragment shader file" << std::endl; return nullptr; } std::stringstream fs_stream; fs_stream << fs_file.rdbuf(); std::string fs_dat = vs_stream.str(); std::unique_ptr<Shader> shader; try{ shader = std::unique_ptr<Shader>(new Shader(lexical_name, id, vs_dat, fs_dat)); } catch(ShaderCompileError e){ std::cerr << "Error: " << e.what() << std::endl; return nullptr; } shaders_[id] = std::move(shader); } else{ std::unique_ptr<Shader> shader; try{ shader = std::unique_ptr<Shader>(new Shader(lexical_name, id, vs, fs)); } catch(ShaderCompileError e){ std::cerr << "Error: " << e.what() << std::endl; return nullptr; } shaders_[id] = std::move(shader); } shader_lexical_names_[lexical_name] = id; }
// Reads, compiles, links and returns a shader from the given paths GLuint loadShader(const std::string &vertexPath, const std::string &fragmentPath) { cout << "Loading shader program with shaders:" << endl; cout << " Vertex: " << std::filesystem::canonical(vertexPath) << endl; cout << " Fragment: " << std::filesystem::canonical(fragmentPath) << endl; // Read our shaders into the appropriate buffers std::ifstream vs_file(vertexPath); std::string vertexSource{ std::istreambuf_iterator<char>(vs_file), std::istreambuf_iterator<char>() }; std::ifstream fs_file(fragmentPath); std::string fragmentSource{ std::istreambuf_iterator<char>(fs_file), std::istreambuf_iterator<char>() }; #if 0 DIR* vertFile = opendir(vertexPath.c_str()); if (vertFile == nullptr) { glutil::fatal_error("Vertex file not found."); } DIR* fragFile = opendir(fragmentPath.c_str()); if (fragFile == nullptr) { glutil::fatal_error("Fragment file not found."); } #endif // 0 #if 1 const char *vs = vertexSource.c_str(); const char *fs = fragmentSource.c_str(); cout << "Vertex shader:" << endl << vs << endl << endl << "Fragment shader:" << endl << fs << endl; #endif // 0 // Create an empty vertex shader handle GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); // Send the vertex shader source code to GL // Note that std::string's .c_str is NULL character terminated. const GLchar *source = (const GLchar *)vertexSource.c_str(); glShaderSource(vertexShader, 1, &source, NULL); // Compile the vertex shader glCompileShader(vertexShader); GLint isCompiled = 0; glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &isCompiled); if (isCompiled == GL_FALSE) { GLint maxLength = 0; glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &maxLength); // The maxLength includes the NULL character std::vector<GLchar> infoLog(maxLength); glGetShaderInfoLog(vertexShader, maxLength, &maxLength, &infoLog[0]); // We don't need the shader anymore. glDeleteShader(vertexShader); // Time to use the infoLog. for (unsigned int i = 0; i < infoLog.size(); i++) { std::cerr << infoLog[i]; } std::cerr << endl; // In this simple program, we'll just leave return -1; } // Create an empty fragment shader handle GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); // Send the fragment shader source code to GL // Note that std::string's .c_str is NULL character terminated. source = (const GLchar *)fragmentSource.c_str(); glShaderSource(fragmentShader, 1, &source, NULL); // Compile the fragment shader glCompileShader(fragmentShader); glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &isCompiled); if (isCompiled == GL_FALSE) { GLint maxLength = 0; glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &maxLength); // The maxLength includes the NULL character std::vector<GLchar> infoLog(maxLength); glGetShaderInfoLog(fragmentShader, maxLength, &maxLength, &infoLog[0]); // We don't need the shader anymore. glDeleteShader(fragmentShader); // Either of them. Don't leak shaders. glDeleteShader(vertexShader); // Time to use the infoLog. for (unsigned int i = 0; i < infoLog.size(); i++) { std::cerr << infoLog[i]; } std::cerr << endl; // In this simple program, we'll just leave return -1; } // Vertex and fragment shaders are successfully compiled. // Now time to link them together into a program. // Get a program object. GLuint program = glCreateProgram(); // Attach our shaders to our program glAttachShader(program, vertexShader); glAttachShader(program, fragmentShader); // Link our program glLinkProgram(program); // Note the different functions here: glGetProgram* instead of glGetShader*. GLint isLinked = 0; glGetProgramiv(program, GL_LINK_STATUS, (int *)&isLinked); if (isLinked == GL_FALSE) { GLint maxLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); // The maxLength includes the NULL character std::vector<GLchar> infoLog(maxLength); glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]); // We don't need the program anymore. glDeleteProgram(program); // Don't leak shaders either. glDeleteShader(vertexShader); glDeleteShader(fragmentShader); // Time to use the infoLog. for (unsigned int i = 0; i < infoLog.size(); i++) { std::cerr << infoLog[i]; } std::cerr << endl; // In this simple program, we'll just leave return -1; } GLint maxLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); if (maxLength > 0) { // The maxLength includes the NULL character std::vector<GLchar> infoLog(maxLength); glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]); for (unsigned int i = 0; i < infoLog.size(); i++) { std::cerr << infoLog[i]; } std::cerr << endl; } // Detach shaders after a successful link. glDetachShader(program, vertexShader); glDetachShader(program, fragmentShader); cout << "Shader loaded." << endl; return program; }