55
66#include < iostream>
77
8- namespace {
9- class shader_compilation_error : public std ::runtime_error {
10- public:
11- shader_compilation_error (const std::string& err)
12- : std::runtime_error(err)
13- {
14- }
15- };
16- class shader_linkage_error : public std ::runtime_error {
17- public:
18- shader_linkage_error (const std::string& err)
19- : std::runtime_error(err)
20- {
21- }
22- };
23- GLuint compileShader (const std::string_view source, GLenum shaderType)
8+ namespace
9+ {
10+ enum class IVParameter
2411 {
25- auto shaderID = glCheck (glCreateShader (shaderType));
26-
27- const GLchar* const shaderSourcePtr = source.data ();
28- const GLint shaderSourceLength = source.length ();
29- glCheck (glShaderSource (shaderID, 1 , &shaderSourcePtr, &shaderSourceLength));
30- glCheck (glCompileShader (shaderID));
31-
32- GLint logLength;
12+ CompileStatus = GL_COMPILE_STATUS,
13+ LinkStatus = GL_LINK_STATUS
14+ };
3315
34- glCheck (glGetShaderiv (shaderID, GL_INFO_LOG_LENGTH, &logLength));
35- if (logLength) {
36- std::string infoLog (logLength, 0 );
37- glCheck (glGetShaderInfoLog (shaderID, logLength, nullptr , infoLog.data ()));
16+ [[nodiscard]] constexpr auto to_string (IVParameter param)
17+ {
18+ switch (param)
19+ {
20+ case IVParameter::CompileStatus:
21+ return " compile" ;
3822
39- throw shader_compilation_error (infoLog);
23+ case IVParameter::LinkStatus:
24+ return " link" ;
4025 }
41-
42- return shaderID;
26+ return " ShouldNeverGetHere" ;
4327 }
4428
45- GLuint linkProgram (GLuint vertexShaderID, GLuint fragmentShaderID)
29+ template <IVParameter parameter>
30+ [[nodiscard]] auto verify_shader (GLuint shader)
4631 {
47- auto id = glCheck (glCreateProgram ());
48-
49- glCheck (glAttachShader (id, vertexShaderID));
50- glCheck (glAttachShader (id, fragmentShaderID));
51-
52- glCheck (glLinkProgram (id));
53-
54- glCheck (glDetachShader (id, fragmentShaderID));
55- glCheck (glDetachShader (id, vertexShaderID));
56-
57- GLint logLength;
58-
59- glCheck (glGetProgramiv (id, GL_INFO_LOG_LENGTH, &logLength));
60- if (logLength) {
61- std::string infoLog (logLength, 0 );
62- glCheck (glGetProgramInfoLog (id, logLength, nullptr , infoLog.data ()));
63- throw shader_linkage_error (infoLog);
32+ // Verify
33+ GLint status = 0 ;
34+ if constexpr (parameter == IVParameter::CompileStatus)
35+ {
36+ glGetShaderiv (shader, static_cast <GLenum>(parameter), &status);
37+ }
38+ else if constexpr (parameter == IVParameter::LinkStatus)
39+ {
40+ glGetProgramiv (shader, static_cast <GLenum>(parameter), &status);
41+ }
42+ else
43+ {
44+ std::println (std::cerr, " Unkown verify type for action '{}'." , to_string (parameter));
6445 }
6546
66- return id;
67- }
68-
69- struct ShaderStage {
70- const GLuint shaderID;
71- ShaderStage (const std::string_view shaderPath, const GLenum shaderType)
72- : shaderID(compileShader(loadFileContents(shaderPath), shaderType))
47+ if (status == GL_FALSE)
7348 {
49+ GLsizei length;
50+ glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &length);
51+
52+ if constexpr (parameter == IVParameter::CompileStatus)
53+ {
54+ glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &length);
55+ }
56+ else if constexpr (parameter == IVParameter::LinkStatus)
57+ {
58+ glGetProgramiv (shader, GL_INFO_LOG_LENGTH, &length);
59+ }
60+ std::string buffer (1024 , ' ' );
61+ glGetShaderInfoLog (shader, 1024 , NULL , buffer.data ());
62+ std::println (std::cerr, " Failed to {} shader. Error: {}" , to_string (parameter), buffer);
63+ return false ;
7464 }
75- ~ShaderStage ()
65+ return true ;
66+ }
67+
68+ [[nodiscard]] GLuint compile_shader (const char * source, GLuint shader_type)
69+ {
70+ GLuint shader = glCreateShader (shader_type);
71+ glShaderSource (shader, 1 , (const GLchar* const *)&source, nullptr );
72+ glCompileShader (shader);
73+
74+ if (!verify_shader<IVParameter::CompileStatus>(shader))
7675 {
77- glCheck ( glDeleteShader (shaderID)) ;
76+ return 0 ;
7877 }
79- };
78+ return shader;
79+ }
80+
8081} // namespace
8182
82- namespace gl {
83+ namespace gl
84+ {
8385
8486 Shader::~Shader ()
8587 {
@@ -99,29 +101,72 @@ namespace gl {
99101 return *this ;
100102 }
101103
102- void Shader::create (const std::string_view vertexFile,
103- const std::string_view fragmentFile)
104+ bool Shader::create (const std::string_view vertexFile, const std::string_view fragmentFile)
104105 {
105106 glCheck (glUseProgram (0 ));
106107 const std::string vertFileFull (" assets/shaders/" + std::string (vertexFile) +
107108 " _vertex.glsl" );
108109 const std::string fragFileFull (" assets/shaders/" + std::string (fragmentFile) +
109110 " _fragment.glsl" );
110111
111- try {
112- const ShaderStage vertexShader (vertFileFull, GL_VERTEX_SHADER);
113- const ShaderStage fragmentShader (fragFileFull, GL_FRAGMENT_SHADER);
114- m_handle = linkProgram (vertexShader.shaderID , fragmentShader.shaderID );
112+ return loadStage (vertFileFull, ShaderType::Vertex) &&
113+ loadStage (fragFileFull, ShaderType::Fragment) && linkStages ();
114+ }
115+
116+ bool Shader::loadStage (const std::string_view file_path, ShaderType shader_type)
117+ {
118+ // Load the files into strings and verify
119+ auto source = loadFileContents (file_path);
120+ if (source.length () == 0 )
121+ {
122+ return false ;
123+ }
124+
125+ GLuint shader = compile_shader (source.c_str (), static_cast <GLenum>(shader_type));
126+ if (!shader)
127+ {
128+ return false ;
129+ }
130+ m_stages.push_back (shader);
131+
132+ return true ;
133+ }
134+
135+ bool Shader::linkStages ()
136+ {
137+ // Link the shaders together and verify the link status
138+ m_handle = glCreateProgram ();
139+ for (auto stage : m_stages)
140+ {
141+ glAttachShader (m_handle, stage);
115142 }
116- catch (const shader_compilation_error& e) {
117- throw std::runtime_error (" Shader " + vertFileFull + " failed to compile:\n " +
118- e.what ());
143+ glLinkProgram (m_handle);
144+
145+ if (!verify_shader<IVParameter::LinkStatus>(m_handle))
146+ {
147+ std::println (std::cerr, " Failed to link shader." );
148+
149+ return false ;
119150 }
120- catch (const shader_linkage_error& e) {
121- throw std::runtime_error (" Linking failed for shaders " + vertFileFull +
122- " and " + fragFileFull + " , with reason:\n " +
123- e.what ());
151+ glValidateProgram (m_handle);
152+
153+ int status = 0 ;
154+ glGetProgramiv (m_handle, GL_VALIDATE_STATUS, &status);
155+ if (status == GL_FALSE)
156+ {
157+ std::println (std::cerr, " Failed to validate shader program." );
158+ return false ;
159+ }
160+
161+ // Delete the temporary shaders
162+ for (auto & shader : m_stages)
163+ {
164+ glDeleteShader (shader);
124165 }
166+ m_stages.clear ();
167+ m_stages.shrink_to_fit ();
168+
169+ return true ;
125170 }
126171
127172 void Shader::destroy ()
0 commit comments