Browse Source

Rename shader class to shader_object, as well as extend its functionality and improve error handling

master
C. J. Howard 2 years ago
parent
commit
49431013b9
13 changed files with 289 additions and 170 deletions
  1. +1
    -0
      CMakeLists.txt
  2. +1
    -1
      src/application.cpp
  3. +2
    -2
      src/gl/gl.hpp
  4. +123
    -0
      src/gl/shader-object.cpp
  5. +116
    -0
      src/gl/shader-object.hpp
  6. +4
    -4
      src/gl/shader-program.cpp
  7. +2
    -2
      src/gl/shader-program.hpp
  8. +12
    -4
      src/gl/shader-stage.hpp
  9. +0
    -72
      src/gl/shader.cpp
  10. +0
    -59
      src/gl/shader.hpp
  11. +0
    -2
      src/renderer/passes/material-pass.cpp
  12. +0
    -2
      src/renderer/passes/ui-pass.cpp
  13. +28
    -22
      src/resources/shader-program-loader.cpp

+ 1
- 0
CMakeLists.txt View File

@ -14,6 +14,7 @@ find_package(SDL2 REQUIRED COMPONENTS SDL2::SDL2-static SDL2::SDL2main CONFIG)
find_package(OpenAL REQUIRED CONFIG)
find_library(physfs REQUIRED NAMES physfs-static PATHS "${CMAKE_PREFIX_PATH}/lib")
# Determine dependencies
set(STATIC_LIBS
dr_wav

+ 1
- 1
src/application.cpp View File

@ -49,7 +49,7 @@ application::application():
window_dimensions({0, 0}),
viewport_dimensions({0, 0}),
mouse_position({0, 0}),
update_rate(5.0),
update_rate(60.0),
logger(nullptr),
sdl_window(nullptr),
sdl_gl_context(nullptr)

+ 2
- 2
src/gl/gl.hpp View File

@ -31,10 +31,10 @@ namespace gl {}
#include "pixel-format.hpp"
#include "pixel-type.hpp"
#include "rasterizer.hpp"
#include "shader.hpp"
#include "shader-input.hpp"
#include "shader-object.hpp"
#include "shader-program.hpp"
#include "shader-type.hpp"
#include "shader-stage.hpp"
#include "shader-variable-type.hpp"
#include "texture-2d.hpp"
#include "texture-cube.hpp"

+ 123
- 0
src/gl/shader-object.cpp View File

@ -0,0 +1,123 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gl/shader-object.hpp"
#include <glad/glad.h>
#include <stdexcept>
namespace gl {
static constexpr GLenum gl_shader_type_lut[] =
{
GL_VERTEX_SHADER,
GL_FRAGMENT_SHADER,
GL_GEOMETRY_SHADER
};
shader_object::shader_object(shader_stage stage):
gl_shader_id(0),
stage(stage),
compiled(false)
{
// Look up OpenGL shader type enumeration that corresponds to the given stage
GLenum gl_shader_type = gl_shader_type_lut[static_cast<std::size_t>(stage)];
// Create an OpenGL shader object
gl_shader_id = glCreateShader(gl_shader_type);
// Handle OpenGL errors
if (!gl_shader_id)
{
throw std::runtime_error("An error occurred while creating an OpenGL shader object.");
}
}
shader_object::~shader_object()
{
// Flags the OpenGL shader object for deletion
glDeleteShader(gl_shader_id);
}
void shader_object::source(const char* buffer, std::size_t size)
{
// Replace OpenGL shader object source code
GLint gl_length = size;
glShaderSource(gl_shader_id, 1, &buffer, &gl_length);
// Handle OpenGL errors
switch (glGetError())
{
case GL_INVALID_VALUE:
throw std::runtime_error("Shader object handle is not a value generated by OpenGL.");
break;
case GL_INVALID_OPERATION:
throw std::runtime_error("Shader object handle is not a shader object.");
break;
}
}
bool shader_object::compile()
{
// Compile OpenGL shader object
glCompileShader(gl_shader_id);
// Handle OpenGL errors
switch (glGetError())
{
case GL_INVALID_VALUE:
throw std::runtime_error("Shader object handle is not a value generated by OpenGL.");
break;
case GL_INVALID_OPERATION:
throw std::runtime_error("Shader object handle is not a shader object.");
break;
}
// Get OpenGL shader object compilation status
GLint gl_compile_status;
glGetShaderiv(gl_shader_id, GL_COMPILE_STATUS, &gl_compile_status);
compiled = (gl_compile_status == GL_TRUE);
// Get OpenGL shader object info log length
GLint gl_info_log_length;
glGetShaderiv(gl_shader_id, GL_INFO_LOG_LENGTH, &gl_info_log_length);
if (gl_info_log_length > 0)
{
// Resize string to accommodate OpenGL shader object info log
info_log.resize(gl_info_log_length);
// Read OpenGL shader object info log into string
glGetShaderInfoLog(gl_shader_id, gl_info_log_length, &gl_info_log_length, info_log.data());
// Remove redundant null terminator from string
info_log.pop_back();
}
else
{
// Empty info log
info_log.clear();
}
// Return compilation status
return compiled;
}
} // namespace gl

+ 116
- 0
src/gl/shader-object.hpp View File

@ -0,0 +1,116 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GL_SHADER_OBJECT_HPP
#define ANTKEEPER_GL_SHADER_OBJECT_HPP
#include "gl/shader-stage.hpp"
#include <cstdlib>
#include <string>
namespace gl {
class shader_program;
/**
* Shader object which can be compiled and linked to a shader program.
*
* @see gl::shader_program
* @see gl::shader_stage
*/
class shader_object
{
public:
/**
* Creates an empty shader object for the specified shader stage.
*
* @param stage Shader stage in which this shader object will be used.
*
* @exception std::runtime_error An error occurred while creating an OpenGL shader object.
*/
shader_object(shader_stage stage);
/**
* Destroys a shader object.
*/
~shader_object();
/**
* Replaces the source code of the shader object.
*
* @param buffer Buffer containing shader object source code.
* @param size Size of the source code, in bytes.
*
* @exception std::runtime_error Shader object handle is not a value generated by OpenGL.
* @exception std::runtime_error Shader object handle is not a shader object.
*/
void source(const char* buffer, std::size_t size);
/**
* Compiles the shader object.
*
* @return `true` if the shader object was compiled successfully, `false` otherwise. If compilation fails, check the info log via shader_object::get_info_log() for more information.
*
* @exception std::runtime_error Shader object handle is not a value generated by OpenGL.
* @exception std::runtime_error Shader object handle is not a shader object.
*
* @see shader_object::get_info_log()
*/
bool compile();
/// Returns the shader stage of this shader object.
shader_stage get_stage() const;
/// Returns the shader object info log, which is updated when the shader is compiled.
const std::string& get_info_log() const;
/// Returns `true` if the shader object has been successfully compiled, `false` otherwise.
bool was_compiled() const;
shader_object(const shader_object&) = delete;
shader_object& operator=(const shader_object&) = delete;
private:
friend class shader_program;
unsigned int gl_shader_id;
shader_stage stage;
bool compiled;
std::string info_log;
};
inline shader_stage shader_object::get_stage() const
{
return stage;
}
inline const std::string& shader_object::get_info_log() const
{
return info_log;
}
inline bool shader_object::was_compiled() const
{
return compiled;
}
} // namespace gl
#endif // ANTKEEPER_GL_SHADER_OBJECT_HPP

+ 4
- 4
src/gl/shader-program.cpp View File

@ -18,7 +18,7 @@
*/
#include "gl/shader-program.hpp"
#include "gl/shader.hpp"
#include "gl/shader-object.hpp"
#include "gl/shader-variable-type.hpp"
#include "gl/shader-input.hpp"
#include <glad/glad.h>
@ -26,12 +26,12 @@
namespace gl {
shader_program::shader_program(const std::list<shader*>& shaders):
shader_program::shader_program(const std::list<shader_object*>& shaders):
gl_program_id(0)
{
gl_program_id = glCreateProgram();
for (shader* shader: shaders)
for (shader_object* shader: shaders)
{
glAttachShader(gl_program_id, shader->gl_shader_id);
}
@ -45,7 +45,7 @@ shader_program::shader_program(const std::list& shaders):
throw std::runtime_error(get_info_log().c_str());
}
for (shader* shader: shaders)
for (shader_object* shader: shaders)
{
glDetachShader(gl_program_id, shader->gl_shader_id);
}

+ 2
- 2
src/gl/shader-program.hpp View File

@ -27,7 +27,7 @@
namespace gl {
class shader;
class shader_object;
class rasterizer;
class shader_input;
@ -39,7 +39,7 @@ public:
*
* @param shaders List of shaders to be linked to the program. Note that after the shader program has been created, these shaders can be deleted if desired with no effect on the shader program.
*/
explicit shader_program(const std::list<shader*>& shaders);
explicit shader_program(const std::list<shader_object*>& shaders);
~shader_program();
shader_program(const shader_program&) = delete;

src/gl/shader-type.hpp → src/gl/shader-stage.hpp View File

@ -17,19 +17,27 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GL_SHADER_TYPE_HPP
#define ANTKEEPER_GL_SHADER_TYPE_HPP
#ifndef ANTKEEPER_GL_SHADER_STAGE_HPP
#define ANTKEEPER_GL_SHADER_STAGE_HPP
namespace gl {
enum class shader_type
/**
* Enumerates all supported shader stages.
*/
enum class shader_stage
{
/// Indicates a vertex shader stage.
vertex,
/// Indicates a fragment shader stage.
fragment,
/// Indicates a geometry shader stage.
geometry
};
} // namespace gl
#endif // ANTKEEPER_GL_SHADER_TYPE_HPP
#endif // ANTKEEPER_GL_SHADER_STAGE_HPP

+ 0
- 72
src/gl/shader.cpp View File

@ -1,72 +0,0 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gl/shader.hpp"
#include <glad/glad.h>
#include <stdexcept>
namespace gl {
static constexpr GLenum shader_type_lut[] =
{
GL_VERTEX_SHADER,
GL_FRAGMENT_SHADER,
GL_GEOMETRY_SHADER
};
shader::shader(shader_type type, const std::string& source):
gl_shader_id(0),
type(type)
{
GLenum gl_shader_type = shader_type_lut[static_cast<std::size_t>(type)];
const char* source_c_str = source.c_str();
gl_shader_id = glCreateShader(gl_shader_type);
glShaderSource(gl_shader_id, 1, &source_c_str, nullptr);
glCompileShader(gl_shader_id);
GLint status;
glGetShaderiv(gl_shader_id, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
throw std::runtime_error(get_info_log().c_str());
}
}
shader::~shader()
{
glDeleteShader(gl_shader_id);
}
std::string shader::get_info_log() const
{
GLint length;
glGetShaderiv(gl_shader_id, GL_INFO_LOG_LENGTH, &length);
if (length > 0)
{
std::string log(length, '\0');
glGetShaderInfoLog(gl_shader_id, length, &length, &log[0]);
return log;
}
return std::string();
}
} // namespace gl

+ 0
- 59
src/gl/shader.hpp View File

@ -1,59 +0,0 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GL_SHADER_HPP
#define ANTKEEPER_GL_SHADER_HPP
#include <cstdlib>
#include <string>
namespace gl {
enum class shader_type;
class shader_program;
class shader
{
public:
shader(shader_type type, const std::string& source);
~shader();
shader(const shader&) = delete;
shader& operator=(const shader&) = delete;
shader_type get_type() const;
private:
friend class shader_program;
std::string get_info_log() const;
unsigned int gl_shader_id;
shader_type type;
};
inline shader_type shader::get_type() const
{
return type;
}
} // namespace gl
#endif // ANTKEEPER_GL_SHADER_HPP

+ 0
- 2
src/renderer/passes/material-pass.cpp View File

@ -22,8 +22,6 @@
#include "resources/resource-manager.hpp"
#include "gl/rasterizer.hpp"
#include "gl/framebuffer.hpp"
#include "gl/shader.hpp"
#include "gl/shader-type.hpp"
#include "gl/shader-program.hpp"
#include "gl/shader-input.hpp"
#include "gl/vertex-buffer.hpp"

+ 0
- 2
src/renderer/passes/ui-pass.cpp View File

@ -21,8 +21,6 @@
#include "resources/resource-manager.hpp"
#include "gl/rasterizer.hpp"
#include "gl/framebuffer.hpp"
#include "gl/shader.hpp"
#include "gl/shader-type.hpp"
#include "gl/shader-program.hpp"
#include "gl/shader-input.hpp"
#include "gl/vertex-buffer.hpp"

+ 28
- 22
src/resources/shader-program-loader.cpp View File

@ -20,10 +20,11 @@
#include "resources/resource-loader.hpp"
#include "resources/resource-manager.hpp"
#include "resources/text-file.hpp"
#include "gl/shader-type.hpp"
#include "gl/shader.hpp"
#include "gl/shader-stage.hpp"
#include "gl/shader-object.hpp"
#include "gl/shader-program.hpp"
#include <sstream>
#include <unordered_set>
#include <iterator>
/**
@ -104,18 +105,18 @@ static void inject_debug_macro(text_file* source)
/**
* Injects a shader type macro definition after the `#version` directive.
*/
static void inject_shader_type_macro(text_file* source, gl::shader_type type)
static void inject_shader_stage_macro(text_file* source, gl::shader_stage stage)
{
const char* vertex_macro = "#define _VERTEX";
const char* fragment_macro = "#define _FRAGMENT";
const char* geometry_macro = "#define _GEOMETRY";
const char* macro = nullptr;
if (type == gl::shader_type::vertex)
if (stage == gl::shader_stage::vertex)
macro = vertex_macro;
else if (type == gl::shader_type::fragment)
else if (stage == gl::shader_stage::fragment)
macro = fragment_macro;
else if (type == gl::shader_type::geometry)
else if (stage == gl::shader_stage::geometry)
macro = geometry_macro;
// For each line in the source
@ -124,7 +125,7 @@ static void inject_shader_type_macro(text_file* source, gl::shader_type type)
// Tokenize line
std::vector<std::string> tokens = tokenize((*source)[i]);
// Inject shader type macro
// Inject shader stage macro
if (!tokens.empty() && tokens[0] == "#version")
{
source->insert(source->begin() + i + 1, macro);
@ -133,9 +134,9 @@ static void inject_shader_type_macro(text_file* source, gl::shader_type type)
}
}
static std::list<gl::shader_type> detect_shader_types(text_file* source)
static std::unordered_set<gl::shader_stage> detect_shader_stages(text_file* source)
{
std::list<gl::shader_type> types;
std::unordered_set<gl::shader_stage> types;
// For each line in the source
for (std::size_t i = 0; i < source->size(); ++i)
@ -148,15 +149,15 @@ static std::list detect_shader_types(text_file* source)
{
if (tokens[1] == "vertex")
{
types.push_back(gl::shader_type::vertex);
types.insert(gl::shader_stage::vertex);
}
else if (tokens[1] == "fragment")
{
types.push_back(gl::shader_type::fragment);
types.insert(gl::shader_stage::fragment);
}
else if (tokens[1] == "geometry")
{
types.push_back(gl::shader_type::geometry);
types.insert(gl::shader_stage::geometry);
}
}
}
@ -184,23 +185,28 @@ gl::shader_program* resource_loader::load(resource_manager*
inject_debug_macro(source);
// Detect declared shader types via the `#pragma vertex`, `#pragma fragment` and `#pragma geometry` directives
std::list<gl::shader_type> shader_types = detect_shader_types(source);
std::unordered_set<gl::shader_stage> shade_stages = detect_shader_stages(source);
// Load detected shaders
std::list<gl::shader*> shaders;
for (gl::shader_type type: shader_types)
std::list<gl::shader_object*> shaders;
for (gl::shader_stage stage: shade_stages)
{
text_file type_source = *source;
inject_shader_type_macro(&type_source, type);
std::string source_buffer = generate_source_buffer(type_source);
shaders.push_back(new gl::shader(type, source_buffer));
text_file stage_source = *source;
inject_shader_stage_macro(&stage_source, stage);
std::string source_buffer = generate_source_buffer(stage_source);
gl::shader_object* object = new gl::shader_object(stage);
object->source(source_buffer.c_str(), source_buffer.length());
object->compile();
shaders.push_back(object);
}
// Create shader program
gl::shader_program* program = new gl::shader_program(shaders);
// Delete shaders
for (gl::shader* shader: shaders)
// Delete shaders objects
for (gl::shader_object* shader: shaders)
{
delete shader;
}

Loading…
Cancel
Save