#include "compile.hpp" #include #include #include #include #include #include #include #include #include #include static constexpr std::string KEYWORD = "#include"; enum include_mode_t { WHITESPACE, READING, ENDING, }; static bool parse(std::vector& source, const std::filesystem::path& path) { std::ifstream file(path); std::vector line; int n_line = 1; int n_col = 0; int keyword_at = 0; include_mode_t mode = include_mode_t::WHITESPACE; if(!file.is_open()) { return false; } for(auto it = std::istreambuf_iterator(file); it != std::istreambuf_iterator(); it++) { char c = *it; if(c == '\0') { break; } if(c == '\n') { n_line++; n_col = 0; } else { n_col++; } if(keyword_at < KEYWORD.size()) { if(keyword_at == n_col - 1 && KEYWORD[keyword_at] == c) { keyword_at++; continue; } else if(keyword_at > 0) { source.insert(source.end(), &KEYWORD[0], &KEYWORD[keyword_at]); keyword_at = 0; } source.push_back(c); continue; } switch(mode) { case include_mode_t::WHITESPACE: { if(c != ' ' && c != '\t' && c != '\r' && c != '"') { throw std::runtime_error(std::format("At {}:{}: Syntax error", n_line, n_col)); } if(c == '"') { mode = include_mode_t::READING; } break; } case include_mode_t::READING: { if(c != '"') { line.push_back(c); break; } mode = include_mode_t::ENDING; std::filesystem::path path_next = path.parent_path().append(line.begin(), line.end()); std::string comment = std::format("//'{}' {}\n", path_next.string(), '{'); source.insert(source.end(), comment.begin(), comment.end()); if(!parse(source, path_next)) { throw std::runtime_error(std::format("At {}:{} in '{}': File '{}' not found", n_line, n_col, path.string(), path_next.string())); } comment = "//}\n"; source.insert(source.end(), comment.begin(), comment.end()); line.clear(); break; } case include_mode_t::ENDING: { if(c == '\r') { break; } if(c != '\n') { throw std::runtime_error(std::format("At {}:{} in '{}': Syntax error", n_line, n_col, path.string())); } mode = include_mode_t::WHITESPACE; keyword_at = 0; break; }} } if(keyword_at > 0) { source.insert(source.end(), &KEYWORD[0], &KEYWORD[keyword_at]); } return true; } void Graphics::Shader::compile(unsigned int shader, const std::filesystem::path& path) { std::vector source; if(!parse(source, path)) { throw std::runtime_error(std::format("File '{}' not found", path.string())); } const char* data = source.data(); int data_len = source.size(); glShaderSource(shader, 1, &data, &data_len); glCompileShader(shader); int success; glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if(!success) { char info_log[1024]; glGetShaderInfoLog(shader, sizeof(info_log), nullptr, info_log); std::ostringstream source_processed; int n_line = 1; source_processed << n_line << '\t'; for(char c : source) { if(c == '\n') { source_processed << '\n' << ++n_line << '\t'; } else { source_processed << c; } } throw std::runtime_error(std::format("OpenGL shader compilation error\n{}\nIn expanded source file '{}'\n{}", source_processed.str(), path.string(), info_log)); } }