/
Shader.cpp
131 lines (103 loc) · 4.34 KB
/
Shader.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Shader.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sejpark <sejpark@student.42seoul.kr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/08/31 17:16:40 by sejpark #+# #+# */
/* Updated: 2022/09/06 15:07:55 by sejpark ### ########.fr */
/* */
/* ************************************************************************** */
#include "Base/Shader.h"
Shader::Shader(const std::array<std::filesystem::path, 2> &paths)
: programId_(createGraphicsPipeline(paths)) {}
Shader::~Shader() {}
GLuint Shader::getProgramId() const {
return programId_;
}
GLenum Shader::shaderType(const std::filesystem::path &path) {
if (path.extension() == ".vert" || path.extension() == ".vs")
return GL_VERTEX_SHADER;
if (path.extension() == ".frag" || path.extension() == ".fs")
return GL_FRAGMENT_SHADER;
spdlog::error("Use of unknown extension '{}'.", path.extension().string());
throw std::runtime_error("Fail to cast the shader type.");
}
std::string Shader::readFile(const std::filesystem::path &path) {
std::ifstream fin;
fin.open(path, std::ios::binary | std::ios::ate);
if (!fin.is_open()) {
spdlog::error("Fail to open {}.", path.string());
throw std::runtime_error("Fail to read file.");
}
const std::streamsize size = fin.tellg();
if (!size) {
spdlog::error("{} is empty.", path.string());
throw std::runtime_error("Fail to read file.");
}
std::string contents(size, '\0');
fin.seekg(std::ios::beg);
if (!fin.read(contents.data(), size)) {
spdlog::error("Fail to read {}.", path.string());
throw std::runtime_error("Fail to read file.");
}
return contents;
}
GLuint Shader::createShader(GLenum shaderType, const std::string &source) {
GLuint shader = glCreateShader(shaderType);
if (!shader) {
spdlog::error("Fail to create a shader.");
throw std::runtime_error("Fail to create a shader.");
}
const char *data = source.data();
GL_TEST(glShaderSource(shader, 1, &data, nullptr));
GL_TEST(glCompileShader(shader));
GLint status;
GL_TEST(glGetShaderiv(shader, GL_COMPILE_STATUS, &status));
if (!status) {
GLint length;
GL_TEST(glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length));
if (length) {
std::string log(length, '\n');
GL_TEST(glGetShaderInfoLog(shader, length, nullptr, log.data()));
spdlog::error("{}.", log);
}
GL_TEST(glDeleteShader(shader));
throw std::runtime_error("Fail to create a shader.");
}
return shader;
}
GLuint Shader::createShader(const std::filesystem::path &path) {
return createShader(shaderType(path), readFile(path));
}
GLuint Shader::createGraphicsPipeline(const std::array<std::filesystem::path, 2> &paths) {
GLuint program = glCreateProgram();
if (!program) {
spdlog::error("Fail to create a program.");
throw std::runtime_error("Fail to create a program.");
}
const GLuint shaders[] = {
createShader(paths[0]),
createShader(paths[1])
};
GL_TEST(glAttachShader(program, shaders[0]));
GL_TEST(glAttachShader(program, shaders[1]));
GL_TEST(glLinkProgram(program));
GLint status;
GL_TEST(glGetProgramiv(program, GL_LINK_STATUS, &status));
if (!status) {
GLint length;
GL_TEST(glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length));
if (length) {
std::string log(length, '\n');
GL_TEST(glGetProgramInfoLog(program, length, nullptr, log.data()));
spdlog::error("Err to link a program.\n{}.", log);
}
GL_TEST(glDeleteProgram(program));
throw std::runtime_error("Fail to create a program.");
}
GL_TEST(glDeleteShader(shaders[0]));
GL_TEST(glDeleteShader(shaders[1]));
return program;
}