From 97e1ce44cd98feb809fce58415e6e299ecc127fa Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Sat, 27 Nov 2021 13:52:48 -0500 Subject: [PATCH] Implement textures and add more stuff to Shader --- .../resources/shaders/fragment_core.glsl | 9 +- .../resources/shaders/vertex_core.glsl | 2 +- examples/dev_testing/src/main.cpp | 31 +- include/simpleengine/gfx/shader.h | 202 ++ include/simpleengine/gfx/texture.h | 139 ++ include/simpleengine/gfx/vao.h | 17 +- include/simpleengine/gfx/vbo.h | 2 +- include/simpleengine/optional.h | 1807 +++++++++++++++++ include/simpleengine/shader.h | 166 -- include/simpleengine/shader_program.h | 20 +- include/simpleengine/shapes/2d/square.h | 9 +- include/simpleengine/shapes/2d/triangle.h | 63 +- src/gfx/shader.cpp | 343 ++++ 13 files changed, 2565 insertions(+), 245 deletions(-) create mode 100644 include/simpleengine/gfx/shader.h create mode 100644 include/simpleengine/gfx/texture.h create mode 100644 include/simpleengine/optional.h delete mode 100644 include/simpleengine/shader.h create mode 100644 src/gfx/shader.cpp diff --git a/examples/dev_testing/resources/shaders/fragment_core.glsl b/examples/dev_testing/resources/shaders/fragment_core.glsl index 166b593..5880045 100644 --- a/examples/dev_testing/resources/shaders/fragment_core.glsl +++ b/examples/dev_testing/resources/shaders/fragment_core.glsl @@ -4,8 +4,15 @@ in vec3 vs_position; in vec3 vs_color; in vec2 vs_texcoord; +uniform bool texture_is_set; +uniform sampler2D vs_texture; + out vec4 fs_color; void main() { - fs_color = vec4(vs_color, 1.f); + if (texture_is_set) { + fs_color = texture(vs_texture, vs_texcoord) * vec4(vs_color, 1.0); + } else { + fs_color = vec4(vs_color, 1.0); + } } \ No newline at end of file diff --git a/examples/dev_testing/resources/shaders/vertex_core.glsl b/examples/dev_testing/resources/shaders/vertex_core.glsl index 0ef4feb..485cfda 100644 --- a/examples/dev_testing/resources/shaders/vertex_core.glsl +++ b/examples/dev_testing/resources/shaders/vertex_core.glsl @@ -11,7 +11,7 @@ out vec2 vs_texcoord; void main() { vs_position = vertex_position; vs_color = vertex_color; - vs_texcoord = vec2(vertex_texcoord.x, vertex_texcoord.y); + vs_texcoord = vertex_texcoord; gl_Position = vec4(vertex_position, 1.f); } \ No newline at end of file diff --git a/examples/dev_testing/src/main.cpp b/examples/dev_testing/src/main.cpp index 6a41d0c..c09386a 100644 --- a/examples/dev_testing/src/main.cpp +++ b/examples/dev_testing/src/main.cpp @@ -3,8 +3,9 @@ // Github: https://github.com/SeanOMik // +#include "simpleengine/gfx/texture.h" #include "simpleengine/shapes/2d/square.h" -#include +#include #include #include #include @@ -20,6 +21,8 @@ #include CMRC_DECLARE(resource_shaders); +#include + std::string read_resource_shader(const std::string& path) { auto fs = cmrc::resource_shaders::get_filesystem(); cmrc::file vertex_file = fs.open(path); @@ -36,25 +39,29 @@ int main(int argc, char *argv[]) { // Create shader program simpleengine::ShaderProgram shader_prog; - shader_prog.add_shader_from_source(simpleengine::ShaderType::ST_Vertex, vertex_core); - shader_prog.add_shader_from_source(simpleengine::ShaderType::ST_Fragment, fragment_core); + shader_prog.add_shader_from_source(simpleengine::gfx::ShaderType::ST_Vertex, vertex_core); + shader_prog.add_shader_from_source(simpleengine::gfx::ShaderType::ST_Fragment, fragment_core); shader_prog.link(); std::shared_ptr base_shader_program = shader_prog.program; + simpleengine::Texture wall_texture("resources/wall.jpg"); + simpleengine::Texture crate_texture("resources/container.jpg", true, true); + std::vector vertices = { - {glm::vec3(-0.5f, -0.5f, 0.f), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 1.f)}, - {glm::vec3(0.5f, -0.5f, 0.f), glm::vec3(0.f, 1.f, 0.f), glm::vec2(0.f, 0.f)}, - {glm::vec3(0.f, 0.5f, 0.f), glm::vec3(0.f, 0.f, 1.f), glm::vec2(1.f, 0.f)}, + {glm::vec3(-0.5f, -0.5f, 0.f), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 0.f)}, // bottom left + {glm::vec3(0.5f, -0.5f, 0.f), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, 0.f)}, // bottom right + {glm::vec3(0.f, 0.5f, 0.f), glm::vec3(0.f, 0.f, 1.f), glm::vec2(0.5f, 1.0f)}, // top }; - std::shared_ptr tri(new simpleengine::shapes_2d::Triangle(base_shader_program, vertices)); + std::shared_ptr tri(new simpleengine::shapes_2d::Triangle(base_shader_program, vertices)); + //tri->set_texture(wall_texture); game.add_event(tri); /* std::vector vertices = { - { glm::vec3(0.5f, 0.5f, 0.f), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 1.f) }, - { glm::vec3(0.5f, -0.5f, 0.f), glm::vec3(0.f, 1.f, 0.f), glm::vec2(0.f, 0.f) }, - { glm::vec3(-0.5f, -0.5f, 0.f), glm::vec3(0.f, 0.f, 1.f), glm::vec2(1.f, 0.f) }, - { glm::vec3(-0.5f, 0.5f, 0.f), glm::vec3(0.75f, 0.75f, 0.75f), glm::vec2(1.f, 1.f) }, + { glm::vec3(0.5f, 0.5f, 0.f), glm::vec3(1.f, 0.f, 0.f), glm::vec2(1.f, 1.f) }, + { glm::vec3(0.5f, -0.5f, 0.f), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, 0.f) }, + { glm::vec3(-0.5f, -0.5f, 0.f), glm::vec3(0.f, 0.f, 1.f), glm::vec2(0.f, 0.f) }, + { glm::vec3(-0.5f, 0.5f, 0.f), glm::vec3(1.f, 1.f, 0.f), glm::vec2(0.f, 1.f) }, }; std::vector indicies = { @@ -62,7 +69,7 @@ int main(int argc, char *argv[]) { 1, 2, 3 }; - std::shared_ptr square(new simpleengine::shapes_2d::Square(base_shader_program, vertices, indicies)); + std::shared_ptr square(new simpleengine::shapes_2d::Square(base_shader_program, crate_texture, vertices, indicies)); game.add_event(square); */ return game.run(); diff --git a/include/simpleengine/gfx/shader.h b/include/simpleengine/gfx/shader.h new file mode 100644 index 0000000..aa5d501 --- /dev/null +++ b/include/simpleengine/gfx/shader.h @@ -0,0 +1,202 @@ +// +// Created by SeanOMik on 7/2/2020. +// Github: https://github.com/SeanOMik +// + +#ifndef SIMPLEENGINE_SHADER_H +#define SIMPLEENGINE_SHADER_H + +#include +#include +#include + +#include + +#include + +#include "../event/event.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace simpleengine::gfx { + class ShaderException : public std::runtime_error { + public: + explicit ShaderException(char const* const msg) : std::runtime_error(msg) { + + } + }; + + enum ShaderType { + ST_Vertex = GL_VERTEX_SHADER, + ST_Fragment = GL_FRAGMENT_SHADER, + }; + + class Shader { + protected: + Shader() { + + } + public: + std::shared_ptr program; + GLuint shader; + + Shader(std::shared_ptr program); + + Shader(std::shared_ptr program, GLuint shader); + + static Shader from_source(const ShaderType& type, std::string& shader_source); + + static Shader from_source(std::shared_ptr program, const ShaderType& type, std::string& shader_source); + + /** + * @brief Load a shader from a filepath. + * + * @param type The type of the shader. + * @param shader_path The path of the shader source. + */ + static Shader from_filepath(const ShaderType& type, const std::string& shader_path); + + /** + * @brief Load a shader from a filepath. + * + * @param program The shader program that this shader will be attached to. + * @param type The type of the shader. + * @param shader_path The path of shader source. + */ + static Shader from_filepath(std::shared_ptr program, const ShaderType& type, const std::string& shader_path); + + virtual ~Shader(); + + /** + * @brief Link the shader program and checks for errors. + * + */ + void link(); + + /** + * @brief Delete the shader with glDeleteShader. Only do this after we've linked. + * + */ + void delete_shader(); + + /** + * @brief Use the shader program. + * + */ + void use() const; + + /** + * @brief Un-use the shader program by using the id of "0". + * + */ + static void unuse(); + + /** + * @brief Get a Uniform Float from the shader using a `location`. + * + * @param location The location of the uniform float. + * @return GLfloat The value of the uniform float from the shader. + */ + GLfloat getUniformFloat(GLint location) const; + + /** + * @brief Get a Uniform Float from the shader finding the location of the uniform using `uniform_name`. + * + * @param uniform_name The name of the uniform inside of the shader. + * @return GLfloat The value of the uniform float from the shader. + */ + GLfloat getUniformFloat(const char* uniform_name) const; + + /** + * @brief Get a Uniform integer from the shader using a `location`. + * + * @param location The location of the uniform integer. + * @return GLint The value of the uniform integer from the shader. + */ + GLint getUniformInt(GLint location) const; + + /** + * @brief Get a Uniform integer from the shader finding the location of the uniform using `uniform_name`. + * + * @param uniform_name The name of the uniform inside of the shader. + * @return GLint The value of the uniform integer from the shader. + */ + GLint getUniformInt(const char* uniform_name) const; + + /** + * @brief Get a Uniform unsigned integer from the shader using a `location`. + * + * @param location The location of the uniform unsigned integer. + * @return GLuint The value of the uniform unsigned integer from the shader. + */ + GLuint getUniformUInt(GLint location) const; + + /** + * @brief Get a Uniform unsigned integer from the shader finding the location of the uniform using `uniform_name`. + * + * @param uniform_name The name of the uniform inside of the shader. + * @return GLuint The value of the uniform unsigned integer from the shader. + */ + GLuint getUniformUInt(const char* uniform_name) const; + + /** + * @brief Get a Uniform double from the shader using a `location`. + * + * @param location The location of the uniform double. + * @return GLdouble The value of the uniform double from the shader. + */ + GLdouble getUniformDouble(GLint location) const; + + /** + * @brief Get a Uniform double from the shader finding the location of the uniform using `uniform_name`. + * + * @param uniform_name The name of the uniform inside of the shader. + * @return GLdouble The value of the uniform double from the shader. + */ + GLdouble getUniformDouble(const char* uniform_name) const; + + void setUniformFloat(GLint location, GLfloat fl, bool bind_shader = true); + void setUniformFloat(const char* uniform_name, GLfloat fl, bool bind_shader = true); + + void setUniformFloatVec2(GLint location, glm::vec2 vec, bool bind_shader = true); + void setUniformFloatVec2(const char* uniform_name, glm::vec2 vec, bool bind_shader = true); + + void setUniformFloatVec3(GLint location, glm::vec3 vec, bool bind_shader = true); + void setUniformFloatVec3(const char* uniform_name, glm::vec3 vec, bool bind_shader = true); + + void setUniformFloatVec4(GLint location, glm::vec4 vec, bool bind_shader = true); + void setUniformFloatVec4(const char* uniform_name, glm::vec4 vec, bool bind_shader = true); + + void setUniformInt(GLint location, GLint i, bool bind_shader = true); + void setUniformInt(const char* uniform_name, GLint i, bool bind_shader = true); + + void setUniformIntVec2(GLint location, glm::ivec2 vec, bool bind_shader = true); + void setUniformIntVec2(const char* uniform_name, glm::ivec2 vec, bool bind_shader = true); + + void setUniformIntVec3(GLint location, glm::ivec3 vec, bool bind_shader = true); + void setUniformIntVec3(const char* uniform_name, glm::ivec3 vec, bool bind_shader = true); + + void setUniformIntVec4(GLint location, glm::ivec4 vec, bool bind_shader = true); + void setUniformIntVec4(const char* uniform_name, glm::ivec4 vec, bool bind_shader = true); + + void setUniformUInt(GLint location, GLuint ui, bool bind_shader = true); + void setUniformUInt(const char* uniform_name, GLuint ui, bool bind_shader = true); + + void setUniformUIntVec2(GLint location, glm::uvec2 vec, bool bind_shader = true); + void setUniformUIntVec2(const char* uniform_name, glm::uvec2 vec, bool bind_shader = true); + + void setUniformUIntVec3(GLint location, glm::uvec3 vec, bool bind_shader = true); + void setUniformUIntVec3(const char* uniform_name, glm::uvec3 vec, bool bind_shader = true); + + void setUniformUIntVec4(GLint location, glm::uvec4 vec, bool bind_shader = true); + void setUniformUIntVec4(const char* uniform_name, glm::uvec4 vec, bool bind_shader = true); + }; +} + +#endif //SIMPLEENGINE_SHADER_H \ No newline at end of file diff --git a/include/simpleengine/gfx/texture.h b/include/simpleengine/gfx/texture.h new file mode 100644 index 0000000..8fa1746 --- /dev/null +++ b/include/simpleengine/gfx/texture.h @@ -0,0 +1,139 @@ +// +// Created by SeanOMik on 7/2/2020. +// Github: https://github.com/SeanOMik +// + +#ifndef SIMPLEENGINE_TEXTURE_H +#define SIMPLEENGINE_TEXTURE_H + +#include +#include + +#include + +#include + +#include + +#include +#include +#include + +namespace simpleengine { + class Texture { + private: + unsigned char* img_data; + unsigned int texture_id; + + unsigned int image_type; + public: + int height; + int width; + int channels; + + /** + * @brief Construct a new Texture object from a path. + * + * @param path The path of the image for the Texture. + * @param img_2d Whether or not the texture is 2D. + * @param mipmap Whether or not to generate mipmaps for this texture. + */ + Texture(const char* path, bool img_2d = true, bool mipmap = true) { + image_type = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D; + + glGenTextures(1, &texture_id); + bind(); + + glTexParameteri(image_type, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(image_type, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(image_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(image_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + img_data = SOIL_load_image + ( + path, + &width, &height, &channels, + SOIL_LOAD_RGBA + ); + + if (!img_data) { + std::cerr << "Failed to load texture from memory! (" << SOIL_last_result() << ")" << std::endl; + throw std::runtime_error("Failed to load texture from memory!"); + } + + glTexImage2D(image_type, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data); + + if (mipmap) { + glGenerateMipmap(image_type); + } + + SOIL_free_image_data(img_data); + glBindTexture(image_type, 0); + } + + /** + * @brief Construct a new Texture object from the loaded file buffer. + * + * @param buffer The bytes of the loaded file. + * @param buffer_length The length of the buffer. + * @param img_2d Whether or not the texture is 2D. + * @param mipmap Whether or not to generate mipmaps for this texture. + */ + Texture(const unsigned char *const buffer, int buffer_length, bool img_2d = true, bool mipmap = true) { + image_type = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D; + + glGenTextures(1, &texture_id); + bind(); + + glTexParameteri(image_type, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(image_type, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(image_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(image_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + img_data = SOIL_load_image_from_memory + ( + buffer, buffer_length, + &width, &height, &channels, + SOIL_LOAD_RGBA + ); + + if (!img_data) { + std::cerr << "Failed to load texture from memory! (" << SOIL_last_result() << ")" << std::endl; + throw std::runtime_error("Failed to load texture from memory!"); + } + + glTexImage2D(image_type, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data); + + if (mipmap) { + glGenerateMipmap(image_type); + } + + SOIL_free_image_data(img_data); + glBindTexture(image_type, 0); + } + + /** + * @brief Construct a new Texture object from the loaded file buffer. + * + * @param buffer The bytes of the loaded file. + * @param img_2d Whether or not the texture is 2D. + * @param mipmap Whether or not to generate mipmaps for this texture. + */ + Texture(std::vector buffer, bool img_2d = true, bool mipmap = true) : + Texture(buffer.data(), buffer.size(), img_2d, mipmap) { + + } + + /* ~Texture() { + if (img_data != nullptr) { + SOIL_free_image_data(img_data); + } + } */ + + void bind() const { + glBindTexture(image_type, texture_id); + } + }; +} + +#endif \ No newline at end of file diff --git a/include/simpleengine/gfx/vao.h b/include/simpleengine/gfx/vao.h index 787e578..a796385 100644 --- a/include/simpleengine/gfx/vao.h +++ b/include/simpleengine/gfx/vao.h @@ -28,23 +28,12 @@ namespace simpleengine::gfx { glDeleteVertexArrays(1, &handle); } - void bind() { + void bind() const { glBindVertexArray(handle); } - void attr(VBO vbo) { - bind(); - vbo.bind(); - - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); - glEnableVertexAttribArray(0); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - } - // TODO: Fix this. - void enable_attrib(VBO vbo, GLuint index, GLint size, GLenum type, GLsizei stride, size_t offset) { + void enable_attrib(const VBO& vbo, GLuint index, GLint size, GLenum type, GLsizei stride, size_t offset) const { bind(); vbo.bind(); @@ -63,7 +52,7 @@ namespace simpleengine::gfx { glVertexAttribIPointer(index, size, type, stride, (void *) offset); break; default: - glVertexAttribPointer(index, size, type, GL_FALSE, stride, (void *) 0); + glVertexAttribPointer(index, size, type, GL_FALSE, stride, (void *) offset); break; } glEnableVertexAttribArray(index); diff --git a/include/simpleengine/gfx/vbo.h b/include/simpleengine/gfx/vbo.h index 9596752..1b61f67 100644 --- a/include/simpleengine/gfx/vbo.h +++ b/include/simpleengine/gfx/vbo.h @@ -28,7 +28,7 @@ namespace simpleengine::gfx { glDeleteBuffers(1, &handle); } - void bind() { + void bind() const { glBindBuffer(type, handle); } diff --git a/include/simpleengine/optional.h b/include/simpleengine/optional.h new file mode 100644 index 0000000..2c9f122 --- /dev/null +++ b/include/simpleengine/optional.h @@ -0,0 +1,1807 @@ +// +// Copyright (c) 2014-2021 Martin Moene +// +// https://github.com/martinmoene/optional-lite +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma once + +#ifndef NONSTD_OPTIONAL_LITE_HPP +#define NONSTD_OPTIONAL_LITE_HPP + +#define optional_lite_MAJOR 3 +#define optional_lite_MINOR 5 +#define optional_lite_PATCH 0 + +#define optional_lite_VERSION optional_STRINGIFY(optional_lite_MAJOR) "." optional_STRINGIFY(optional_lite_MINOR) "." optional_STRINGIFY(optional_lite_PATCH) + +#define optional_STRINGIFY( x ) optional_STRINGIFY_( x ) +#define optional_STRINGIFY_( x ) #x + +// optional-lite configuration: + +#define optional_OPTIONAL_DEFAULT 0 +#define optional_OPTIONAL_NONSTD 1 +#define optional_OPTIONAL_STD 2 + +// tweak header support: + +#ifdef __has_include +# if __has_include() +# include +# endif +#define optional_HAVE_TWEAK_HEADER 1 +#else +#define optional_HAVE_TWEAK_HEADER 0 +//# pragma message("optional.hpp: Note: Tweak header not supported.") +#endif + +// optional selection and configuration: + +#if !defined( optional_CONFIG_SELECT_OPTIONAL ) +# define optional_CONFIG_SELECT_OPTIONAL ( optional_HAVE_STD_OPTIONAL ? optional_OPTIONAL_STD : optional_OPTIONAL_NONSTD ) +#endif + +// Control presence of exception handling (try and auto discover): + +#ifndef optional_CONFIG_NO_EXCEPTIONS +# if defined(_MSC_VER) +# include // for _HAS_EXCEPTIONS +# endif +# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS) +# define optional_CONFIG_NO_EXCEPTIONS 0 +# else +# define optional_CONFIG_NO_EXCEPTIONS 1 +# endif +#endif + +// C++ language version detection (C++20 is speculative): +// Note: VC14.0/1900 (VS2015) lacks too much from C++14. + +#ifndef optional_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define optional_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define optional_CPLUSPLUS __cplusplus +# endif +#endif + +#define optional_CPP98_OR_GREATER ( optional_CPLUSPLUS >= 199711L ) +#define optional_CPP11_OR_GREATER ( optional_CPLUSPLUS >= 201103L ) +#define optional_CPP11_OR_GREATER_ ( optional_CPLUSPLUS >= 201103L ) +#define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L ) +#define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L ) +#define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202000L ) + +// C++ language version (represent 98 as 3): + +#define optional_CPLUSPLUS_V ( optional_CPLUSPLUS / 100 - (optional_CPLUSPLUS > 200000 ? 2000 : 1994) ) + +// Use C++17 std::optional if available and requested: + +#if optional_CPP17_OR_GREATER && defined(__has_include ) +# if __has_include( ) +# define optional_HAVE_STD_OPTIONAL 1 +# else +# define optional_HAVE_STD_OPTIONAL 0 +# endif +#else +# define optional_HAVE_STD_OPTIONAL 0 +#endif + +#define optional_USES_STD_OPTIONAL ( (optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_STD) || ((optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_DEFAULT) && optional_HAVE_STD_OPTIONAL) ) + +// +// in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite: +// + +#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES +#define nonstd_lite_HAVE_IN_PLACE_TYPES 1 + +// C++17 std::in_place in : + +#if optional_CPP17_OR_GREATER + +#include + +namespace nonstd { + +using std::in_place; +using std::in_place_type; +using std::in_place_index; +using std::in_place_t; +using std::in_place_type_t; +using std::in_place_index_t; + +#define nonstd_lite_in_place_t( T) std::in_place_t +#define nonstd_lite_in_place_type_t( T) std::in_place_type_t +#define nonstd_lite_in_place_index_t(K) std::in_place_index_t + +#define nonstd_lite_in_place( T) std::in_place_t{} +#define nonstd_lite_in_place_type( T) std::in_place_type_t{} +#define nonstd_lite_in_place_index(K) std::in_place_index_t{} + +} // namespace nonstd + +#else // optional_CPP17_OR_GREATER + +#include + +namespace nonstd { +namespace detail { + +template< class T > +struct in_place_type_tag {}; + +template< std::size_t K > +struct in_place_index_tag {}; + +} // namespace detail + +struct in_place_t {}; + +template< class T > +inline in_place_t in_place( detail::in_place_type_tag /*unused*/ = detail::in_place_type_tag() ) +{ + return in_place_t(); +} + +template< std::size_t K > +inline in_place_t in_place( detail::in_place_index_tag /*unused*/ = detail::in_place_index_tag() ) +{ + return in_place_t(); +} + +template< class T > +inline in_place_t in_place_type( detail::in_place_type_tag /*unused*/ = detail::in_place_type_tag() ) +{ + return in_place_t(); +} + +template< std::size_t K > +inline in_place_t in_place_index( detail::in_place_index_tag /*unused*/ = detail::in_place_index_tag() ) +{ + return in_place_t(); +} + +// mimic templated typedef: + +#define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) +#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) +#define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag ) + +#define nonstd_lite_in_place( T) nonstd::in_place_type +#define nonstd_lite_in_place_type( T) nonstd::in_place_type +#define nonstd_lite_in_place_index(K) nonstd::in_place_index + +} // namespace nonstd + +#endif // optional_CPP17_OR_GREATER +#endif // nonstd_lite_HAVE_IN_PLACE_TYPES + +// +// Using std::optional: +// + +#if optional_USES_STD_OPTIONAL + +#include + +namespace nonstd { + + using std::optional; + using std::bad_optional_access; + using std::hash; + + using std::nullopt; + using std::nullopt_t; + + using std::operator==; + using std::operator!=; + using std::operator<; + using std::operator<=; + using std::operator>; + using std::operator>=; + using std::make_optional; + using std::swap; +} + +#else // optional_USES_STD_OPTIONAL + +#include +#include + +// optional-lite alignment configuration: + +#ifndef optional_CONFIG_MAX_ALIGN_HACK +# define optional_CONFIG_MAX_ALIGN_HACK 0 +#endif + +#ifndef optional_CONFIG_ALIGN_AS +// no default, used in #if defined() +#endif + +#ifndef optional_CONFIG_ALIGN_AS_FALLBACK +# define optional_CONFIG_ALIGN_AS_FALLBACK double +#endif + +// Compiler warning suppression: + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wundef" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wundef" +#elif defined(_MSC_VER ) +# pragma warning( push ) +#endif + +// half-open range [lo..hi): +#define optional_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) + +// Compiler versions: +// +// MSVC++ 6.0 _MSC_VER == 1200 optional_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) +// MSVC++ 7.0 _MSC_VER == 1300 optional_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) +// MSVC++ 7.1 _MSC_VER == 1310 optional_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) +// MSVC++ 8.0 _MSC_VER == 1400 optional_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) +// MSVC++ 9.0 _MSC_VER == 1500 optional_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) +// MSVC++ 10.0 _MSC_VER == 1600 optional_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) +// MSVC++ 11.0 _MSC_VER == 1700 optional_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) +// MSVC++ 12.0 _MSC_VER == 1800 optional_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) +// MSVC++ 14.0 _MSC_VER == 1900 optional_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) +// MSVC++ 14.1 _MSC_VER >= 1910 optional_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) +// MSVC++ 14.2 _MSC_VER >= 1920 optional_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) + +#if defined(_MSC_VER ) && !defined(__clang__) +# define optional_COMPILER_MSVC_VER (_MSC_VER ) +# define optional_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) +#else +# define optional_COMPILER_MSVC_VER 0 +# define optional_COMPILER_MSVC_VERSION 0 +#endif + +#define optional_COMPILER_VERSION( major, minor, patch ) ( 10 * (10 * (major) + (minor) ) + (patch) ) + +#if defined(__GNUC__) && !defined(__clang__) +# define optional_COMPILER_GNUC_VERSION optional_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#else +# define optional_COMPILER_GNUC_VERSION 0 +#endif + +#if defined(__clang__) +# define optional_COMPILER_CLANG_VERSION optional_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +#else +# define optional_COMPILER_CLANG_VERSION 0 +#endif + +#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 140 ) +# pragma warning( disable: 4345 ) // initialization behavior changed +#endif + +#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 150 ) +# pragma warning( disable: 4814 ) // in C++14 'constexpr' will not imply 'const' +#endif + +// Presence of language and library features: + +#define optional_HAVE(FEATURE) ( optional_HAVE_##FEATURE ) + +#ifdef _HAS_CPP0X +# define optional_HAS_CPP0X _HAS_CPP0X +#else +# define optional_HAS_CPP0X 0 +#endif + +// Unless defined otherwise below, consider VC14 as C++11 for optional-lite: + +#if optional_COMPILER_MSVC_VER >= 1900 +# undef optional_CPP11_OR_GREATER +# define optional_CPP11_OR_GREATER 1 +#endif + +#define optional_CPP11_90 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1500) +#define optional_CPP11_100 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1600) +#define optional_CPP11_110 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1700) +#define optional_CPP11_120 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1800) +#define optional_CPP11_140 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1900) +#define optional_CPP11_141 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1910) + +#define optional_CPP14_000 (optional_CPP14_OR_GREATER) +#define optional_CPP17_000 (optional_CPP17_OR_GREATER) + +// clang >= 2.9, gcc >= 4.9, msvc >= vc14.0/1900 (vs15): +#define optional_CPP11_140_C290_G490 ((optional_CPP11_OR_GREATER_ && (optional_COMPILER_CLANG_VERSION >= 290 || optional_COMPILER_GNUC_VERSION >= 490)) || (optional_COMPILER_MSVC_VER >= 1900)) + +// clang >= 3.5, msvc >= vc11 (vs12): +#define optional_CPP11_110_C350 ( optional_CPP11_110 && !optional_BETWEEN( optional_COMPILER_CLANG_VERSION, 1, 350 ) ) + +// clang >= 3.5, gcc >= 5.0, msvc >= vc11 (vs12): +#define optional_CPP11_110_C350_G500 \ + ( optional_CPP11_110 && \ + !( optional_BETWEEN( optional_COMPILER_CLANG_VERSION, 1, 350 ) \ + || optional_BETWEEN( optional_COMPILER_GNUC_VERSION , 1, 500 ) ) ) + +// Presence of C++11 language features: + +#define optional_HAVE_CONSTEXPR_11 optional_CPP11_140 +#define optional_HAVE_IS_DEFAULT optional_CPP11_140 +#define optional_HAVE_NOEXCEPT optional_CPP11_140 +#define optional_HAVE_NULLPTR optional_CPP11_100 +#define optional_HAVE_REF_QUALIFIER optional_CPP11_140_C290_G490 +#define optional_HAVE_STATIC_ASSERT optional_CPP11_110 +#define optional_HAVE_INITIALIZER_LIST optional_CPP11_140 + +// Presence of C++14 language features: + +#define optional_HAVE_CONSTEXPR_14 optional_CPP14_000 + +// Presence of C++17 language features: + +#define optional_HAVE_NODISCARD optional_CPP17_000 + +// Presence of C++ library features: + +#define optional_HAVE_CONDITIONAL optional_CPP11_120 +#define optional_HAVE_REMOVE_CV optional_CPP11_120 +#define optional_HAVE_TYPE_TRAITS optional_CPP11_90 + +#define optional_HAVE_TR1_TYPE_TRAITS (!! optional_COMPILER_GNUC_VERSION ) +#define optional_HAVE_TR1_ADD_POINTER (!! optional_COMPILER_GNUC_VERSION ) + +#define optional_HAVE_IS_ASSIGNABLE optional_CPP11_110_C350 +#define optional_HAVE_IS_MOVE_CONSTRUCTIBLE optional_CPP11_110_C350 +#define optional_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE optional_CPP11_110_C350 +#define optional_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE optional_CPP11_110_C350 +#define optional_HAVE_IS_TRIVIALLY_COPY_CONSTRUCTIBLE optional_CPP11_110_C350_G500 +#define optional_HAVE_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE optional_CPP11_110_C350_G500 + +// C++ feature usage: + +#if optional_HAVE( CONSTEXPR_11 ) +# define optional_constexpr constexpr +#else +# define optional_constexpr /*constexpr*/ +#endif + +#if optional_HAVE( IS_DEFAULT ) +# define optional_is_default = default; +#else +# define optional_is_default {} +#endif + +#if optional_HAVE( CONSTEXPR_14 ) +# define optional_constexpr14 constexpr +#else +# define optional_constexpr14 /*constexpr*/ +#endif + +#if optional_HAVE( NODISCARD ) +# define optional_nodiscard [[nodiscard]] +#else +# define optional_nodiscard /*[[nodiscard]]*/ +#endif + +#if optional_HAVE( NOEXCEPT ) +# define optional_noexcept noexcept +#else +# define optional_noexcept /*noexcept*/ +#endif + +#if optional_HAVE( NULLPTR ) +# define optional_nullptr nullptr +#else +# define optional_nullptr NULL +#endif + +#if optional_HAVE( REF_QUALIFIER ) +// NOLINTNEXTLINE( bugprone-macro-parentheses ) +# define optional_ref_qual & +# define optional_refref_qual && +#else +# define optional_ref_qual /*&*/ +# define optional_refref_qual /*&&*/ +#endif + +#if optional_HAVE( STATIC_ASSERT ) +# define optional_static_assert(expr, text) static_assert(expr, text); +#else +# define optional_static_assert(expr, text) /*static_assert(expr, text);*/ +#endif + +// additional includes: + +#if optional_CONFIG_NO_EXCEPTIONS +// already included: +#else +# include +#endif + +#if optional_CPP11_OR_GREATER +# include +#endif + +#if optional_HAVE( INITIALIZER_LIST ) +# include +#endif + +#if optional_HAVE( TYPE_TRAITS ) +# include +#elif optional_HAVE( TR1_TYPE_TRAITS ) +# include +#endif + +// Method enabling + +#if optional_CPP11_OR_GREATER + +#define optional_REQUIRES_0(...) \ + template< bool B = (__VA_ARGS__), typename std::enable_if::type = 0 > + +#define optional_REQUIRES_T(...) \ + , typename std::enable_if< (__VA_ARGS__), int >::type = 0 + +#define optional_REQUIRES_R(R, ...) \ + typename std::enable_if< (__VA_ARGS__), R>::type + +#define optional_REQUIRES_A(...) \ + , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr + +#endif + +// +// optional: +// + +namespace nonstd { namespace optional_lite { + +namespace std11 { + +template< class T, T v > struct integral_constant { enum { value = v }; }; +template< bool B > struct bool_constant : integral_constant{}; + +typedef bool_constant< true > true_type; +typedef bool_constant< false > false_type; + +#if optional_CPP11_OR_GREATER + using std::move; +#else + template< typename T > T & move( T & t ) { return t; } +#endif + +#if optional_HAVE( CONDITIONAL ) + using std::conditional; +#else + template< bool B, typename T, typename F > struct conditional { typedef T type; }; + template< typename T, typename F > struct conditional { typedef F type; }; +#endif // optional_HAVE_CONDITIONAL + +#if optional_HAVE( IS_ASSIGNABLE ) + using std::is_assignable; +#else + template< class T, class U > struct is_assignable : std11::true_type{}; +#endif + +#if optional_HAVE( IS_MOVE_CONSTRUCTIBLE ) + using std::is_move_constructible; +#else + template< class T > struct is_move_constructible : std11::true_type{}; +#endif + +#if optional_HAVE( IS_NOTHROW_MOVE_ASSIGNABLE ) + using std::is_nothrow_move_assignable; +#else + template< class T > struct is_nothrow_move_assignable : std11::true_type{}; +#endif + +#if optional_HAVE( IS_NOTHROW_MOVE_CONSTRUCTIBLE ) + using std::is_nothrow_move_constructible; +#else + template< class T > struct is_nothrow_move_constructible : std11::true_type{}; +#endif + +#if optional_HAVE( IS_TRIVIALLY_COPY_CONSTRUCTIBLE ) + using std::is_trivially_copy_constructible; +#else + template< class T > struct is_trivially_copy_constructible : std11::true_type{}; +#endif + +#if optional_HAVE( IS_TRIVIALLY_MOVE_CONSTRUCTIBLE ) + using std::is_trivially_move_constructible; +#else + template< class T > struct is_trivially_move_constructible : std11::true_type{}; +#endif + +} // namespace std11 + +#if optional_CPP11_OR_GREATER + +/// type traits C++17: + +namespace std17 { + +#if optional_CPP17_OR_GREATER + +using std::is_swappable; +using std::is_nothrow_swappable; + +#elif optional_CPP11_OR_GREATER + +namespace detail { + +using std::swap; + +struct is_swappable +{ + template< typename T, typename = decltype( swap( std::declval(), std::declval() ) ) > + static std11::true_type test( int /*unused*/ ); + + template< typename > + static std11::false_type test(...); +}; + +struct is_nothrow_swappable +{ + // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015): + + template< typename T > + static constexpr bool satisfies() + { + return noexcept( swap( std::declval(), std::declval() ) ); + } + + template< typename T > + static auto test( int /*unused*/ ) -> std11::integral_constant()>{} + + template< typename > + static auto test(...) -> std11::false_type; +}; + +} // namespace detail + +// is [nothow] swappable: + +template< typename T > +struct is_swappable : decltype( detail::is_swappable::test(0) ){}; + +template< typename T > +struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test(0) ){}; + +#endif // optional_CPP17_OR_GREATER + +} // namespace std17 + +/// type traits C++20: + +namespace std20 { + +template< typename T > +struct remove_cvref +{ + typedef typename std::remove_cv< typename std::remove_reference::type >::type type; +}; + +} // namespace std20 + +#endif // optional_CPP11_OR_GREATER + +/// class optional + +template< typename T > +class optional; + +namespace detail { + +// C++11 emulation: + +struct nulltype{}; + +template< typename Head, typename Tail > +struct typelist +{ + typedef Head head; + typedef Tail tail; +}; + +#if optional_CONFIG_MAX_ALIGN_HACK + +// Max align, use most restricted type for alignment: + +#define optional_UNIQUE( name ) optional_UNIQUE2( name, __LINE__ ) +#define optional_UNIQUE2( name, line ) optional_UNIQUE3( name, line ) +#define optional_UNIQUE3( name, line ) name ## line + +#define optional_ALIGN_TYPE( type ) \ + type optional_UNIQUE( _t ); struct_t< type > optional_UNIQUE( _st ) + +template< typename T > +struct struct_t { T _; }; + +union max_align_t +{ + optional_ALIGN_TYPE( char ); + optional_ALIGN_TYPE( short int ); + optional_ALIGN_TYPE( int ); + optional_ALIGN_TYPE( long int ); + optional_ALIGN_TYPE( float ); + optional_ALIGN_TYPE( double ); + optional_ALIGN_TYPE( long double ); + optional_ALIGN_TYPE( char * ); + optional_ALIGN_TYPE( short int * ); + optional_ALIGN_TYPE( int * ); + optional_ALIGN_TYPE( long int * ); + optional_ALIGN_TYPE( float * ); + optional_ALIGN_TYPE( double * ); + optional_ALIGN_TYPE( long double * ); + optional_ALIGN_TYPE( void * ); + +#ifdef HAVE_LONG_LONG + optional_ALIGN_TYPE( long long ); +#endif + + struct Unknown; + + Unknown ( * optional_UNIQUE(_) )( Unknown ); + Unknown * Unknown::* optional_UNIQUE(_); + Unknown ( Unknown::* optional_UNIQUE(_) )( Unknown ); + + struct_t< Unknown ( * )( Unknown) > optional_UNIQUE(_); + struct_t< Unknown * Unknown::* > optional_UNIQUE(_); + struct_t< Unknown ( Unknown::* )(Unknown) > optional_UNIQUE(_); +}; + +#undef optional_UNIQUE +#undef optional_UNIQUE2 +#undef optional_UNIQUE3 + +#undef optional_ALIGN_TYPE + +#elif defined( optional_CONFIG_ALIGN_AS ) // optional_CONFIG_MAX_ALIGN_HACK + +// Use user-specified type for alignment: + +#define optional_ALIGN_AS( unused ) \ + optional_CONFIG_ALIGN_AS + +#else // optional_CONFIG_MAX_ALIGN_HACK + +// Determine POD type to use for alignment: + +#define optional_ALIGN_AS( to_align ) \ + typename type_of_size< alignment_types, alignment_of< to_align >::value >::type + +template< typename T > +struct alignment_of; + +template< typename T > +struct alignment_of_hack +{ + char c; + T t; + alignment_of_hack(); +}; + +template< size_t A, size_t S > +struct alignment_logic +{ + enum { value = A < S ? A : S }; +}; + +template< typename T > +struct alignment_of +{ + enum { value = alignment_logic< + sizeof( alignment_of_hack ) - sizeof(T), sizeof(T) >::value }; +}; + +template< typename List, size_t N > +struct type_of_size +{ + typedef typename std11::conditional< + N == sizeof( typename List::head ), + typename List::head, + typename type_of_size::type >::type type; +}; + +template< size_t N > +struct type_of_size< nulltype, N > +{ + typedef optional_CONFIG_ALIGN_AS_FALLBACK type; +}; + +template< typename T> +struct struct_t { T _; }; + +#define optional_ALIGN_TYPE( type ) \ + typelist< type , typelist< struct_t< type > + +struct Unknown; + +typedef + optional_ALIGN_TYPE( char ), + optional_ALIGN_TYPE( short ), + optional_ALIGN_TYPE( int ), + optional_ALIGN_TYPE( long ), + optional_ALIGN_TYPE( float ), + optional_ALIGN_TYPE( double ), + optional_ALIGN_TYPE( long double ), + + optional_ALIGN_TYPE( char *), + optional_ALIGN_TYPE( short * ), + optional_ALIGN_TYPE( int * ), + optional_ALIGN_TYPE( long * ), + optional_ALIGN_TYPE( float * ), + optional_ALIGN_TYPE( double * ), + optional_ALIGN_TYPE( long double * ), + + optional_ALIGN_TYPE( Unknown ( * )( Unknown ) ), + optional_ALIGN_TYPE( Unknown * Unknown::* ), + optional_ALIGN_TYPE( Unknown ( Unknown::* )( Unknown ) ), + + nulltype + > > > > > > > > > > > > > > + > > > > > > > > > > > > > > + > > > > > > + alignment_types; + +#undef optional_ALIGN_TYPE + +#endif // optional_CONFIG_MAX_ALIGN_HACK + +/// C++03 constructed union to hold value. + +template< typename T > +union storage_t +{ +//private: +// template< typename > friend class optional; + + typedef T value_type; + + storage_t() optional_is_default + + explicit storage_t( value_type const & v ) + { + construct_value( v ); + } + + void construct_value( value_type const & v ) + { + ::new( value_ptr() ) value_type( v ); + } + +#if optional_CPP11_OR_GREATER + + explicit storage_t( value_type && v ) + { + construct_value( std::move( v ) ); + } + + void construct_value( value_type && v ) + { + ::new( value_ptr() ) value_type( std::move( v ) ); + } + + template< class... Args > + storage_t( nonstd_lite_in_place_t(T), Args&&... args ) + { + emplace( std::forward(args)... ); + } + + template< class... Args > + void emplace( Args&&... args ) + { + ::new( value_ptr() ) value_type( std::forward(args)... ); + } + + template< class U, class... Args > + void emplace( std::initializer_list il, Args&&... args ) + { + ::new( value_ptr() ) value_type( il, std::forward(args)... ); + } + +#endif + + void destruct_value() + { + value_ptr()->~T(); + } + + optional_nodiscard value_type const * value_ptr() const + { + return as(); + } + + value_type * value_ptr() + { + return as(); + } + + optional_nodiscard value_type const & value() const optional_ref_qual + { + return * value_ptr(); + } + + value_type & value() optional_ref_qual + { + return * value_ptr(); + } + +#if optional_HAVE( REF_QUALIFIER ) + + optional_nodiscard value_type const && value() const optional_refref_qual + { + return std::move( value() ); + } + + value_type && value() optional_refref_qual + { + return std::move( value() ); + } + +#endif + +#if optional_CPP11_OR_GREATER + + using aligned_storage_t = typename std::aligned_storage< sizeof(value_type), alignof(value_type) >::type; + aligned_storage_t data; + +#elif optional_CONFIG_MAX_ALIGN_HACK + + typedef struct { unsigned char data[ sizeof(value_type) ]; } aligned_storage_t; + + max_align_t hack; + aligned_storage_t data; + +#else + typedef optional_ALIGN_AS(value_type) align_as_type; + + typedef struct { align_as_type data[ 1 + ( sizeof(value_type) - 1 ) / sizeof(align_as_type) ]; } aligned_storage_t; + aligned_storage_t data; + +# undef optional_ALIGN_AS + +#endif // optional_CONFIG_MAX_ALIGN_HACK + + optional_nodiscard void * ptr() optional_noexcept + { + return &data; + } + + optional_nodiscard void const * ptr() const optional_noexcept + { + return &data; + } + + template + optional_nodiscard U * as() + { + return reinterpret_cast( ptr() ); + } + + template + optional_nodiscard U const * as() const + { + return reinterpret_cast( ptr() ); + } +}; + +} // namespace detail + +/// disengaged state tag + +struct nullopt_t +{ + struct init{}; + explicit optional_constexpr nullopt_t( init /*unused*/ ) optional_noexcept {} +}; + +#if optional_HAVE( CONSTEXPR_11 ) +constexpr nullopt_t nullopt{ nullopt_t::init{} }; +#else +// extra parenthesis to prevent the most vexing parse: +const nullopt_t nullopt(( nullopt_t::init() )); +#endif + +/// optional access error + +#if ! optional_CONFIG_NO_EXCEPTIONS + +class bad_optional_access : public std::logic_error +{ +public: + explicit bad_optional_access() + : logic_error( "bad optional access" ) {} +}; + +#endif //optional_CONFIG_NO_EXCEPTIONS + +/// optional + +template< typename T> +class optional +{ + optional_static_assert(( !std::is_same::type, nullopt_t>::value ), + "T in optional must not be of type 'nullopt_t'.") + + optional_static_assert(( !std::is_same::type, in_place_t>::value ), + "T in optional must not be of type 'in_place_t'.") + + optional_static_assert(( std::is_object::value && std::is_destructible::value && !std::is_array::value ), + "T in optional must meet the Cpp17Destructible requirements.") + +private: + template< typename > friend class optional; + + typedef void (optional::*safe_bool)() const; + +public: + typedef T value_type; + + // x.x.3.1, constructors + + // 1a - default construct + optional_constexpr optional() optional_noexcept + : has_value_( false ) + , contained() + {} + + // 1b - construct explicitly empty + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + optional_constexpr optional( nullopt_t /*unused*/ ) optional_noexcept + : has_value_( false ) + , contained() + {} + + // 2 - copy-construct +#if optional_CPP11_OR_GREATER + // template< typename U = T + // optional_REQUIRES_T( + // std::is_copy_constructible::value + // || std11::is_trivially_copy_constructible::value + // ) + // > +#endif + optional_constexpr14 optional( optional const & other ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( other.contained.value() ); + } + } + +#if optional_CPP11_OR_GREATER + + // 3 (C++11) - move-construct from optional + template< typename U = T + optional_REQUIRES_T( + std11::is_move_constructible::value + || std11::is_trivially_move_constructible::value + ) + > + optional_constexpr14 optional( optional && other ) + // NOLINTNEXTLINE( performance-noexcept-move-constructor ) + noexcept( std11::is_nothrow_move_constructible::value ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( std::move( other.contained.value() ) ); + } + } + + // 4a (C++11) - explicit converting copy-construct from optional + template< typename U + optional_REQUIRES_T( + std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && !std::is_convertible< U const & , T>::value /*=> explicit */ + ) + > + explicit optional( optional const & other ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( T{ other.contained.value() } ); + } + } +#endif // optional_CPP11_OR_GREATER + + // 4b (C++98 and later) - non-explicit converting copy-construct from optional + template< typename U +#if optional_CPP11_OR_GREATER + optional_REQUIRES_T( + std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && std::is_convertible< U const & , T>::value /*=> non-explicit */ + ) +#endif // optional_CPP11_OR_GREATER + > + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + /*non-explicit*/ optional( optional const & other ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( other.contained.value() ); + } + } + +#if optional_CPP11_OR_GREATER + + // 5a (C++11) - explicit converting move-construct from optional + template< typename U + optional_REQUIRES_T( + std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && !std::is_convertible< U &&, T>::value /*=> explicit */ + ) + > + explicit optional( optional && other + ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( T{ std::move( other.contained.value() ) } ); + } + } + + // 5a (C++11) - non-explicit converting move-construct from optional + template< typename U + optional_REQUIRES_T( + std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && std::is_convertible< U &&, T>::value /*=> non-explicit */ + ) + > + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + /*non-explicit*/ optional( optional && other ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( std::move( other.contained.value() ) ); + } + } + + // 6 (C++11) - in-place construct + template< typename... Args + optional_REQUIRES_T( + std::is_constructible::value + ) + > + optional_constexpr explicit optional( nonstd_lite_in_place_t(T), Args&&... args ) + : has_value_( true ) + , contained( in_place, std::forward(args)... ) + {} + + // 7 (C++11) - in-place construct, initializer-list + template< typename U, typename... Args + optional_REQUIRES_T( + std::is_constructible&, Args&&...>::value + ) + > + optional_constexpr explicit optional( nonstd_lite_in_place_t(T), std::initializer_list il, Args&&... args ) + : has_value_( true ) + , contained( T( il, std::forward(args)...) ) + {} + + // 8a (C++11) - explicit move construct from value + template< typename U = T + optional_REQUIRES_T( + std::is_constructible::value + && !std::is_same::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same::type, optional>::value + && !std::is_convertible::value /*=> explicit */ + ) + > + optional_constexpr explicit optional( U && value ) + : has_value_( true ) + , contained( nonstd_lite_in_place(T), std::forward( value ) ) + {} + + // 8b (C++11) - non-explicit move construct from value + template< typename U = T + optional_REQUIRES_T( + std::is_constructible::value + && !std::is_same::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same::type, optional>::value + && std::is_convertible::value /*=> non-explicit */ + ) + > + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + optional_constexpr /*non-explicit*/ optional( U && value ) + : has_value_( true ) + , contained( nonstd_lite_in_place(T), std::forward( value ) ) + {} + +#else // optional_CPP11_OR_GREATER + + // 8 (C++98) + optional( value_type const & value ) + : has_value_( true ) + , contained( value ) + {} + +#endif // optional_CPP11_OR_GREATER + + // x.x.3.2, destructor + + ~optional() + { + if ( has_value() ) + { + contained.destruct_value(); + } + } + + // x.x.3.3, assignment + + // 1 (C++98and later) - assign explicitly empty + optional & operator=( nullopt_t /*unused*/) optional_noexcept + { + reset(); + return *this; + } + + // 2 (C++98and later) - copy-assign from optional +#if optional_CPP11_OR_GREATER + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional &, + true +// std::is_copy_constructible::value +// && std::is_copy_assignable::value + ) + operator=( optional const & other ) + noexcept( + std11::is_nothrow_move_assignable::value + && std11::is_nothrow_move_constructible::value + ) +#else + optional & operator=( optional const & other ) +#endif + { + if ( (has_value() == true ) && (other.has_value() == false) ) { reset(); } + else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( *other ); } + else if ( (has_value() == true ) && (other.has_value() == true ) ) { contained.value() = *other; } + return *this; + } + +#if optional_CPP11_OR_GREATER + + // 3 (C++11) - move-assign from optional + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional &, + true +// std11::is_move_constructible::value +// && std::is_move_assignable::value + ) + operator=( optional && other ) noexcept + { + if ( (has_value() == true ) && (other.has_value() == false) ) { reset(); } + else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( std::move( *other ) ); } + else if ( (has_value() == true ) && (other.has_value() == true ) ) { contained.value() = std::move( *other ); } + return *this; + } + + // 4 (C++11) - move-assign from value + template< typename U = T > + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional &, + std::is_constructible::value + && std11::is_assignable::value + && !std::is_same::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same::type, optional>::value + && !(std::is_scalar::value && std::is_same::type>::value) + ) + operator=( U && value ) + { + if ( has_value() ) + { + contained.value() = std::forward( value ); + } + else + { + initialize( T( std::forward( value ) ) ); + } + return *this; + } + +#else // optional_CPP11_OR_GREATER + + // 4 (C++98) - copy-assign from value + template< typename U /*= T*/ > + optional & operator=( U const & value ) + { + if ( has_value() ) contained.value() = value; + else initialize( T( value ) ); + return *this; + } + +#endif // optional_CPP11_OR_GREATER + + // 5 (C++98 and later) - converting copy-assign from optional + template< typename U > +#if optional_CPP11_OR_GREATER + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional&, + std::is_constructible< T , U const &>::value + && std11::is_assignable< T&, U const &>::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && !std11::is_assignable< T&, optional & >::value + && !std11::is_assignable< T&, optional && >::value + && !std11::is_assignable< T&, optional const & >::value + && !std11::is_assignable< T&, optional const && >::value + ) +#else + optional& +#endif // optional_CPP11_OR_GREATER + operator=( optional const & other ) + { + return *this = optional( other ); + } + +#if optional_CPP11_OR_GREATER + + // 6 (C++11) - converting move-assign from optional + template< typename U > + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional&, + std::is_constructible< T , U>::value + && std11::is_assignable< T&, U>::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && !std11::is_assignable< T&, optional & >::value + && !std11::is_assignable< T&, optional && >::value + && !std11::is_assignable< T&, optional const & >::value + && !std11::is_assignable< T&, optional const && >::value + ) + operator=( optional && other ) + { + return *this = optional( std::move( other ) ); + } + + // 7 (C++11) - emplace + template< typename... Args + optional_REQUIRES_T( + std::is_constructible::value + ) + > + T& emplace( Args&&... args ) + { + *this = nullopt; + contained.emplace( std::forward(args)... ); + has_value_ = true; + return contained.value(); + } + + // 8 (C++11) - emplace, initializer-list + template< typename U, typename... Args + optional_REQUIRES_T( + std::is_constructible&, Args&&...>::value + ) + > + T& emplace( std::initializer_list il, Args&&... args ) + { + *this = nullopt; + contained.emplace( il, std::forward(args)... ); + has_value_ = true; + return contained.value(); + } + +#endif // optional_CPP11_OR_GREATER + + // x.x.3.4, swap + + void swap( optional & other ) +#if optional_CPP11_OR_GREATER + noexcept( + std11::is_nothrow_move_constructible::value + && std17::is_nothrow_swappable::value + ) +#endif + { + using std::swap; + if ( (has_value() == true ) && (other.has_value() == true ) ) { swap( **this, *other ); } + else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( std11::move(*other) ); other.reset(); } + else if ( (has_value() == true ) && (other.has_value() == false) ) { other.initialize( std11::move(**this) ); reset(); } + } + + // x.x.3.5, observers + + optional_constexpr value_type const * operator ->() const + { + return assert( has_value() ), + contained.value_ptr(); + } + + optional_constexpr14 value_type * operator ->() + { + return assert( has_value() ), + contained.value_ptr(); + } + + optional_constexpr value_type const & operator *() const optional_ref_qual + { + return assert( has_value() ), + contained.value(); + } + + optional_constexpr14 value_type & operator *() optional_ref_qual + { + return assert( has_value() ), + contained.value(); + } + +#if optional_HAVE( REF_QUALIFIER ) + + optional_constexpr value_type const && operator *() const optional_refref_qual + { + return std::move( **this ); + } + + optional_constexpr14 value_type && operator *() optional_refref_qual + { + return std::move( **this ); + } + +#endif + +#if optional_CPP11_OR_GREATER + optional_constexpr explicit operator bool() const optional_noexcept + { + return has_value(); + } +#else + optional_constexpr operator safe_bool() const optional_noexcept + { + return has_value() ? &optional::this_type_does_not_support_comparisons : 0; + } +#endif + + // NOLINTNEXTLINE( modernize-use-nodiscard ) + /*optional_nodiscard*/ optional_constexpr bool has_value() const optional_noexcept + { + return has_value_; + } + + // NOLINTNEXTLINE( modernize-use-nodiscard ) + /*optional_nodiscard*/ optional_constexpr14 value_type const & value() const optional_ref_qual + { +#if optional_CONFIG_NO_EXCEPTIONS + assert( has_value() ); +#else + if ( ! has_value() ) + { + throw bad_optional_access(); + } +#endif + return contained.value(); + } + + optional_constexpr14 value_type & value() optional_ref_qual + { +#if optional_CONFIG_NO_EXCEPTIONS + assert( has_value() ); +#else + if ( ! has_value() ) + { + throw bad_optional_access(); + } +#endif + return contained.value(); + } + +#if optional_HAVE( REF_QUALIFIER ) && ( !optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490 ) + + // NOLINTNEXTLINE( modernize-use-nodiscard ) + /*optional_nodiscard*/ optional_constexpr value_type const && value() const optional_refref_qual + { + return std::move( value() ); + } + + optional_constexpr14 value_type && value() optional_refref_qual + { + return std::move( value() ); + } + +#endif + +#if optional_HAVE( REF_QUALIFIER ) + + template< typename U > + optional_constexpr value_type value_or( U && v ) const optional_ref_qual + { + return has_value() ? contained.value() : static_cast(std::forward( v ) ); + } + + template< typename U > + optional_constexpr14 value_type value_or( U && v ) optional_refref_qual + { +#if optional_COMPILER_CLANG_VERSION + return has_value() ? /*std::move*/( contained.value() ) : static_cast(std::forward( v ) ); +#else + return has_value() ? std::move( contained.value() ) : static_cast(std::forward( v ) ); +#endif + } + +#else + + template< typename U > + optional_constexpr value_type value_or( U const & v ) const + { + return has_value() ? contained.value() : static_cast( v ); + } + +#endif // optional_CPP11_OR_GREATER + + // x.x.3.6, modifiers + + void reset() optional_noexcept + { + if ( has_value() ) + { + contained.destruct_value(); + } + + has_value_ = false; + } + +private: + void this_type_does_not_support_comparisons() const {} + + template< typename V > + void initialize( V const & value ) + { + assert( ! has_value() ); + contained.construct_value( value ); + has_value_ = true; + } + +#if optional_CPP11_OR_GREATER + template< typename V > + void initialize( V && value ) + { + assert( ! has_value() ); + contained.construct_value( std::move( value ) ); + has_value_ = true; + } + +#endif + +private: + bool has_value_; + detail::storage_t< value_type > contained; + +}; + +// Relational operators + +template< typename T, typename U > +inline optional_constexpr bool operator==( optional const & x, optional const & y ) +{ + return bool(x) != bool(y) ? false : !bool( x ) ? true : *x == *y; +} + +template< typename T, typename U > +inline optional_constexpr bool operator!=( optional const & x, optional const & y ) +{ + return !(x == y); +} + +template< typename T, typename U > +inline optional_constexpr bool operator<( optional const & x, optional const & y ) +{ + return (!y) ? false : (!x) ? true : *x < *y; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>( optional const & x, optional const & y ) +{ + return (y < x); +} + +template< typename T, typename U > +inline optional_constexpr bool operator<=( optional const & x, optional const & y ) +{ + return !(y < x); +} + +template< typename T, typename U > +inline optional_constexpr bool operator>=( optional const & x, optional const & y ) +{ + return !(x < y); +} + +// Comparison with nullopt + +template< typename T > +inline optional_constexpr bool operator==( optional const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return (!x); +} + +template< typename T > +inline optional_constexpr bool operator==( nullopt_t /*unused*/, optional const & x ) optional_noexcept +{ + return (!x); +} + +template< typename T > +inline optional_constexpr bool operator!=( optional const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +inline optional_constexpr bool operator!=( nullopt_t /*unused*/, optional const & x ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +inline optional_constexpr bool operator<( optional const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept +{ + return false; +} + +template< typename T > +inline optional_constexpr bool operator<( nullopt_t /*unused*/, optional const & x ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +inline optional_constexpr bool operator<=( optional const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return (!x); +} + +template< typename T > +inline optional_constexpr bool operator<=( nullopt_t /*unused*/, optional const & /*unused*/ ) optional_noexcept +{ + return true; +} + +template< typename T > +inline optional_constexpr bool operator>( optional const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +inline optional_constexpr bool operator>( nullopt_t /*unused*/, optional const & /*unused*/ ) optional_noexcept +{ + return false; +} + +template< typename T > +inline optional_constexpr bool operator>=( optional const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept +{ + return true; +} + +template< typename T > +inline optional_constexpr bool operator>=( nullopt_t /*unused*/, optional const & x ) optional_noexcept +{ + return (!x); +} + +// Comparison with T + +template< typename T, typename U > +inline optional_constexpr bool operator==( optional const & x, U const & v ) +{ + return bool(x) ? *x == v : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator==( U const & v, optional const & x ) +{ + return bool(x) ? v == *x : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator!=( optional const & x, U const & v ) +{ + return bool(x) ? *x != v : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator!=( U const & v, optional const & x ) +{ + return bool(x) ? v != *x : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator<( optional const & x, U const & v ) +{ + return bool(x) ? *x < v : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator<( U const & v, optional const & x ) +{ + return bool(x) ? v < *x : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator<=( optional const & x, U const & v ) +{ + return bool(x) ? *x <= v : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator<=( U const & v, optional const & x ) +{ + return bool(x) ? v <= *x : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>( optional const & x, U const & v ) +{ + return bool(x) ? *x > v : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>( U const & v, optional const & x ) +{ + return bool(x) ? v > *x : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>=( optional const & x, U const & v ) +{ + return bool(x) ? *x >= v : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>=( U const & v, optional const & x ) +{ + return bool(x) ? v >= *x : true; +} + +// Specialized algorithms + +template< typename T +#if optional_CPP11_OR_GREATER + optional_REQUIRES_T( + std11::is_move_constructible::value + && std17::is_swappable::value ) +#endif +> +void swap( optional & x, optional & y ) +#if optional_CPP11_OR_GREATER + noexcept( noexcept( x.swap(y) ) ) +#endif +{ + x.swap( y ); +} + +#if optional_CPP11_OR_GREATER + +template< typename T > +optional_constexpr optional< typename std::decay::type > make_optional( T && value ) +{ + return optional< typename std::decay::type >( std::forward( value ) ); +} + +template< typename T, typename...Args > +optional_constexpr optional make_optional( Args&&... args ) +{ + return optional( nonstd_lite_in_place(T), std::forward(args)...); +} + +template< typename T, typename U, typename... Args > +optional_constexpr optional make_optional( std::initializer_list il, Args&&... args ) +{ + return optional( nonstd_lite_in_place(T), il, std::forward(args)...); +} + +#else + +template< typename T > +optional make_optional( T const & value ) +{ + return optional( value ); +} + +#endif // optional_CPP11_OR_GREATER + +} // namespace optional_lite + +using optional_lite::optional; +using optional_lite::nullopt_t; +using optional_lite::nullopt; + +#if ! optional_CONFIG_NO_EXCEPTIONS +using optional_lite::bad_optional_access; +#endif + +using optional_lite::make_optional; + +} // namespace nonstd + +#if optional_CPP11_OR_GREATER + +// specialize the std::hash algorithm: + +namespace std { + +template< class T > +struct hash< nonstd::optional > +{ +public: + std::size_t operator()( nonstd::optional const & v ) const optional_noexcept + { + return bool( v ) ? std::hash{}( *v ) : 0; + } +}; + +} //namespace std + +#endif // optional_CPP11_OR_GREATER + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER ) +# pragma warning( pop ) +#endif + +#endif // optional_USES_STD_OPTIONAL + +#endif // NONSTD_OPTIONAL_LITE_HPP diff --git a/include/simpleengine/shader.h b/include/simpleengine/shader.h deleted file mode 100644 index 8c26f66..0000000 --- a/include/simpleengine/shader.h +++ /dev/null @@ -1,166 +0,0 @@ -// -// Created by SeanOMik on 7/2/2020. -// Github: https://github.com/SeanOMik -// - -#ifndef SIMPLEENGINE_SHADER_H -#define SIMPLEENGINE_SHADER_H - -#include -#include - -#include - -#include "event/event.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace simpleengine { - class ShaderException : public std::runtime_error { - public: - explicit ShaderException(char const* const msg) : std::runtime_error(msg) { - - } - }; - - enum ShaderType { - ST_Vertex = GL_VERTEX_SHADER, - ST_Fragment = GL_FRAGMENT_SHADER, - }; - - class Shader : public simpleengine::Event { - private: - using super = simpleengine::Event; - protected: - Shader() { - - } - public: - static Shader from_source(const ShaderType& type, std::string& shader_source) { - Shader shd = Shader::from_source(std::make_shared(glCreateProgram()), type, shader_source); - - shd.link(); - shd.delete_shader(); - - return shd; - } - - static Shader from_source(std::shared_ptr program, const ShaderType& type, std::string& shader_source) { - Shader shd; - shd.program = program; - shd.shader = glCreateShader(type); - - const GLchar* vert_src = shader_source.c_str(); - glShaderSource(shd.shader, 1, &vert_src, NULL); - glCompileShader(shd.shader); - - GLint success = false; - glGetShaderiv(shd.shader, GL_COMPILE_STATUS, &success); - - if (!success) { - char log[512]; - glGetShaderInfoLog(shd.shader, 512, NULL, log); - - std::cerr << "Failed to load shader from source:" << std::endl << log << std::endl; - throw ShaderException("Failed to compile shader!"); - } - - glAttachShader(*shd.program, shd.shader); - - return shd; - } - - /** - * @brief Load a shader from a filepath. - * - * @param type The type of the shader. - * @param shader_path The path of the shader source. - */ - static Shader from_filepath(const ShaderType& type, const std::string& shader_path) { - Shader shd = Shader::from_filepath(std::make_shared(glCreateProgram()), type, shader_path); - - shd.link(); - shd.delete_shader(); - - return shd; - } - - /** - * @brief Load a shader from a filepath. - * - * @param program The shader program that this shader will be attached to. - * @param type The type of the shader. - * @param shader_path The path of shader source. - */ - static Shader from_filepath(std::shared_ptr program, const ShaderType& type, - const std::string& shader_path) { - std::ifstream fstream(shader_path, std::ios::in); - - if (!fstream.is_open()) { - std::cerr << "Failed to open shader file: " << shader_path << std::endl; - throw ShaderException("Failed to open shader file!"); - } - - std::stringstream ss; - { - std::string str; - while (std::getline(fstream, str)) - { - ss << str << std::endl; - } - } - std::string ss_str = ss.str(); - - return Shader::from_source(type, ss_str); - } - - virtual ~Shader() { - delete_shader(); - } - - /** - * @brief Link the shader program and checks for errors. - * - */ - void link() { - glLinkProgram(*program); - - GLint success = false; - glGetProgramiv(*program, GL_LINK_STATUS, &success); - - if (!success) { - std::cerr << "Failed to link shader program!" << std::endl; - throw ShaderException("Failed to link shader program!"); - } - } - - /** - * @brief Delete the shader with glDeleteShader. Only do this after we've linked. - * - */ - void delete_shader() { - glDeleteShader(shader); - } - - virtual void update(const float& delta_time) override { - //super::update(delta_time); - } - - virtual void render(std::shared_ptr target) override { - //super::render(target); - } - - std::shared_ptr program; - private: - GLuint shader; - }; -} - -#endif //SIMPLEENGINE_SHADER_H \ No newline at end of file diff --git a/include/simpleengine/shader_program.h b/include/simpleengine/shader_program.h index 032f316..5d29b79 100644 --- a/include/simpleengine/shader_program.h +++ b/include/simpleengine/shader_program.h @@ -12,7 +12,7 @@ #include #include "event/event.h" -#include "shader.h" +#include "gfx/shader.h" #include #include @@ -38,11 +38,11 @@ namespace simpleengine { /** * @brief Add a shader to this shader program. Also checks that its using the same `program` as this. * - * @see ShaderProgram::add_shader(const ShaderType& type, const std::string& shader_path) + * @see ShaderProgram::add_shader(const gfx::ShaderType& type, const std::string& shader_path) * @param shader The shader to add. * @return ShaderProgram& self */ - ShaderProgram& add_shader(Shader& shader) { + ShaderProgram& add_shader(gfx::Shader& shader) { if (shader.program != this->program) { throw std::runtime_error("The added shader does not have the same program as this shade program!"); } @@ -59,8 +59,8 @@ namespace simpleengine { * @param shader_path The path of the shader. * @return ShaderProgram& self */ - ShaderProgram& add_shader_from_source(const ShaderType& type, std::string& shader_source) { - Shader shd = Shader::from_source(program, type, shader_source); + ShaderProgram& add_shader_from_source(const gfx::ShaderType& type, std::string& shader_source) { + gfx::Shader shd = gfx::Shader::from_source(program, type, shader_source); shaders.emplace_back(shd); @@ -74,8 +74,8 @@ namespace simpleengine { * @param shader_path The path of the shader. * @return ShaderProgram& self */ - ShaderProgram& add_shader_from_path(const ShaderType& type, const std::string& shader_path) { - Shader shd = Shader::from_filepath(program, type, shader_path); + ShaderProgram& add_shader_from_path(const gfx::ShaderType& type, const std::string& shader_path) { + gfx::Shader shd = gfx::Shader::from_filepath(program, type, shader_path); shaders.emplace_back(shd); @@ -98,10 +98,10 @@ namespace simpleengine { if (!success) { std::cerr << "Failed to link shader program!" << std::endl; - throw ShaderException("Failed to link shader program!"); + throw gfx::ShaderException("Failed to link shader program!"); } - for (Shader& shader : shaders) { + for (gfx::Shader& shader : shaders) { shader.delete_shader(); } } @@ -115,7 +115,7 @@ namespace simpleengine { } std::shared_ptr program; - std::vector shaders; + std::vector shaders; }; } diff --git a/include/simpleengine/shapes/2d/square.h b/include/simpleengine/shapes/2d/square.h index 0322201..eabab85 100644 --- a/include/simpleengine/shapes/2d/square.h +++ b/include/simpleengine/shapes/2d/square.h @@ -18,7 +18,7 @@ #include "../../gfx/vbo.h" #include "../../gfx/vao.h" -#include "simpleengine/gfx/vao.h" +#include "../../gfx/texture.h" #include #include @@ -29,6 +29,7 @@ namespace simpleengine::shapes_2d { using super = simpleengine::Renderable; private: std::shared_ptr shader_program; + Texture& texture; public: std::vector vertices; std::vector indicies; @@ -36,10 +37,10 @@ namespace simpleengine::shapes_2d { gfx::VBO vbo; gfx::VAO vao; - Square(std::shared_ptr shader_program, std::vector vertices, std::vector indicies) : + Square(std::shared_ptr shader_program, Texture& texture, std::vector vertices, std::vector indicies) : super(nullptr), shader_program(shader_program), vertices(vertices), indicies(indicies), ebo(gfx::VBO(GL_ELEMENT_ARRAY_BUFFER, false)), vbo(gfx::VBO(GL_ARRAY_BUFFER, false)), - vao(gfx::VAO()) { + texture(texture) { vao.bind(); vbo.buffer(vertices.data(), 0, sizeof(Vertex) * vertices.size()); @@ -65,6 +66,8 @@ namespace simpleengine::shapes_2d { } virtual void render(std::shared_ptr target) override { + texture.bind(); + glUseProgram(*shader_program); vao.bind(); diff --git a/include/simpleengine/shapes/2d/triangle.h b/include/simpleengine/shapes/2d/triangle.h index 2b5004b..a34c4cb 100644 --- a/include/simpleengine/shapes/2d/triangle.h +++ b/include/simpleengine/shapes/2d/triangle.h @@ -15,10 +15,11 @@ #include "../../renderable.h" #include "../../vertex.h" - #include "../../gfx/vbo.h" #include "../../gfx/vao.h" -#include "simpleengine/gfx/vao.h" +#include "../../gfx/shader.h" +#include "../../gfx/texture.h" +#include "../../optional.h" #include @@ -27,64 +28,52 @@ namespace simpleengine::shapes_2d { private: using super = simpleengine::Renderable; private: - std::shared_ptr shader_program; + gfx::Shader shader; // This only stores the shader program + nonstd::optional texture; public: std::vector vertices; gfx::VBO vbo; gfx::VAO vao; - Triangle(std::shared_ptr shader_program, std::vector vertices) : super(nullptr), - shader_program(shader_program), vertices(vertices), vbo(gfx::VBO(GL_ARRAY_BUFFER, false)), - vao(gfx::VAO()) { - + Triangle(gfx::Shader shader, std::vector vertices) : super(nullptr), + shader(shader), vertices(vertices), vbo(gfx::VBO(GL_ARRAY_BUFFER, false)), texture(nonstd::nullopt) { vao.bind(); vbo.buffer(vertices.data(), 0, sizeof(Vertex) * vertices.size()); - /* vao.enable_attrib(vbo, 0, 3, GL_FLOAT, sizeof(Vertex), offsetof(Vertex, position)); + vao.enable_attrib(vbo, 0, 3, GL_FLOAT, sizeof(Vertex), offsetof(Vertex, position)); vao.enable_attrib(vbo, 1, 3, GL_FLOAT, sizeof(Vertex), offsetof(Vertex, color)); - vao.enable_attrib(vbo, 2, 2, GL_FLOAT, sizeof(Vertex), offsetof(Vertex, tex_coord)); */ - - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, position)); - glEnableVertexAttribArray(0); - - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, color)); - glEnableVertexAttribArray(1); - - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, tex_coord)); - glEnableVertexAttribArray(2); + vao.enable_attrib(vbo, 2, 2, GL_FLOAT, sizeof(Vertex), offsetof(Vertex, tex_coord)); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); + } - /* glCreateVertexArrays(1, &vao); - glBindVertexArray(vao); + Triangle(std::shared_ptr shader_program, std::vector vertices) : + Triangle(gfx::Shader(shader_program), vertices) { - glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size(), vertices.data(), GL_STATIC_DRAW); - - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, position)); - glEnableVertexAttribArray(0); - - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, color)); - glEnableVertexAttribArray(1); - - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, tex_coord)); - glEnableVertexAttribArray(2); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); */ } virtual ~Triangle() = default; - + + void set_texture(Texture texture) { + this->texture = texture; + } + virtual void update(const float& delta_time) override { } virtual void render(std::shared_ptr target) override { - glUseProgram(*shader_program); + shader.use(); + // If theres a texture set, tell the fragment shader that and bind to the texture for drawing. + if (texture.has_value()) { + shader.setUniformInt("texture_is_set", true, false); + texture.value().bind(); + } else { + shader.setUniformInt("texture_is_set", false, false); + } + vao.bind(); glDrawArrays(GL_TRIANGLES, 0, vertices.size()); } diff --git a/src/gfx/shader.cpp b/src/gfx/shader.cpp new file mode 100644 index 0000000..ec84711 --- /dev/null +++ b/src/gfx/shader.cpp @@ -0,0 +1,343 @@ +#include "gfx/shader.h" + +#include +#include + +namespace simpleengine::gfx { + Shader::Shader(std::shared_ptr program) : program(program) { + + } + + Shader::Shader(std::shared_ptr program, GLuint shader) : program(program), shader(shader) { + + } + + Shader Shader::from_source(const ShaderType& type, std::string& shader_source) { + Shader shd = Shader::from_source(std::make_shared(glCreateProgram()), type, shader_source); + + shd.link(); + shd.delete_shader(); + + return shd; + } + + Shader Shader::from_source(std::shared_ptr program, const ShaderType& type, std::string& shader_source) { + Shader shd; + shd.program = program; + shd.shader = glCreateShader(type); + + const GLchar* vert_src = shader_source.c_str(); + glShaderSource(shd.shader, 1, &vert_src, NULL); + glCompileShader(shd.shader); + + GLint success = false; + glGetShaderiv(shd.shader, GL_COMPILE_STATUS, &success); + + if (!success) { + char log[512]; + glGetShaderInfoLog(shd.shader, 512, NULL, log); + + std::cerr << "Failed to load shader from source:" << std::endl << log << std::endl; + throw ShaderException("Failed to compile shader!"); + } + + glAttachShader(*shd.program, shd.shader); + + return shd; + } + + Shader Shader::from_filepath(const ShaderType& type, const std::string& shader_path) { + Shader shd = Shader::from_filepath(std::make_shared(glCreateProgram()), type, shader_path); + + shd.link(); + shd.delete_shader(); + + return shd; + } + + Shader Shader::from_filepath(std::shared_ptr program, const ShaderType& type, + const std::string& shader_path) { + std::ifstream fstream(shader_path, std::ios::in); + + if (!fstream.is_open()) { + std::cerr << "Failed to open shader file: " << shader_path << std::endl; + throw ShaderException("Failed to open shader file!"); + } + + std::stringstream ss; + { + std::string str; + while (std::getline(fstream, str)) + { + ss << str << std::endl; + } + } + std::string ss_str = ss.str(); + + return Shader::from_source(type, ss_str); + } + + Shader::~Shader() { + delete_shader(); + } + + void Shader::link() { + glLinkProgram(*program); + + GLint success = false; + glGetProgramiv(*program, GL_LINK_STATUS, &success); + + if (!success) { + std::cerr << "Failed to link shader program!" << std::endl; + throw ShaderException("Failed to link shader program!"); + } + } + + void Shader::delete_shader() { + glDeleteShader(shader); + } + + void Shader::use() const { + glUseProgram(*program); + } + + void Shader::unuse() { + glUseProgram(0); + } + + GLfloat Shader::getUniformFloat(GLint location) const { + use(); + + GLfloat fl; + glGetUniformfv(*program, location, &fl); + + return fl; + } + + GLfloat Shader::getUniformFloat(const char* uniform_name) const { + int location = glGetUniformLocation(*program, uniform_name); + return getUniformFloat(location); + } + + GLint Shader::getUniformInt(GLint location) const { + use(); + + GLint _int; + glGetUniformiv(*program, location, &_int); + + return _int; + } + + GLint Shader::getUniformInt(const char* uniform_name) const { + int location = glGetUniformLocation(*program, uniform_name); + return getUniformInt(location); + } + + GLuint Shader::getUniformUInt(GLint location) const { + use(); + + GLuint _uint; + glGetUniformuiv(*program, location, &_uint); + + return _uint; + } + + GLuint Shader::getUniformUInt(const char* uniform_name) const { + int location = glGetUniformLocation(*program, uniform_name); + return getUniformUInt(location); + } + + GLdouble Shader::getUniformDouble(GLint location) const { + use(); + + GLdouble dbl; + glGetUniformdv(*program, location, &dbl); + + return dbl; + } + + GLdouble Shader::getUniformDouble(const char* uniform_name) const { + int location = glGetUniformLocation(*program, uniform_name); + return getUniformDouble(location); + } + + void Shader::setUniformFloat(GLint location, GLfloat fl, bool bind_shader) { + if (bind_shader) { + use(); + } + glUniform1f(location, fl); + if (bind_shader) { + unuse(); + } + } + + void Shader::setUniformFloat(const char* uniform_name, GLfloat fl, bool bind_shader) { + int location = glGetUniformLocation(*program, uniform_name); + setUniformFloat(location, fl, bind_shader); + } + + void Shader::setUniformFloatVec2(GLint location, glm::vec2 vec, bool bind_shader) { + if (bind_shader) { + use(); + } + glUniform2f(location, vec.x, vec.y); + if (bind_shader) { + unuse(); + } + } + + void Shader::setUniformFloatVec2(const char* uniform_name, glm::vec2 vec, bool bind_shader) { + int location = glGetUniformLocation(*program, uniform_name); + setUniformFloatVec2(location, vec, bind_shader); + } + + void Shader::setUniformFloatVec3(GLint location, glm::vec3 vec, bool bind_shader) { + if (bind_shader) { + use(); + } + glUniform3f(location, vec.x, vec.y, vec.z); + if (bind_shader) { + unuse(); + } + } + + void Shader::setUniformFloatVec3(const char* uniform_name, glm::vec3 vec, bool bind_shader) { + int location = glGetUniformLocation(*program, uniform_name); + setUniformFloatVec3(location, vec, bind_shader); + } + + void Shader::setUniformFloatVec4(GLint location, glm::vec4 vec, bool bind_shader) { + if (bind_shader) { + use(); + } + glUniform4f(location, vec.x, vec.y, vec.z, vec.w); + if (bind_shader) { + unuse(); + } + } + + void Shader::setUniformFloatVec4(const char* uniform_name, glm::vec4 vec, bool bind_shader) { + int location = glGetUniformLocation(*program, uniform_name); + setUniformFloatVec4(location, vec, bind_shader); + } + + void Shader::setUniformInt(GLint location, GLint i, bool bind_shader) { + if (bind_shader) { + use(); + } + glUniform1i(location, i); + if (bind_shader) { + unuse(); + } + } + + void Shader::setUniformInt(const char* uniform_name, GLint i, bool bind_shader) { + int location = glGetUniformLocation(*program, uniform_name); + setUniformInt(location, i, bind_shader); + } + + void Shader::setUniformIntVec2(GLint location, glm::ivec2 vec, bool bind_shader) { + if (bind_shader) { + use(); + } + glUniform2i(location, vec.x, vec.y); + if (bind_shader) { + unuse(); + } + } + + void Shader::setUniformIntVec2(const char* uniform_name, glm::ivec2 vec, bool bind_shader) { + int location = glGetUniformLocation(*program, uniform_name); + setUniformIntVec2(location, vec, bind_shader); + } + + void Shader::setUniformIntVec3(GLint location, glm::ivec3 vec, bool bind_shader) { + if (bind_shader) { + use(); + } + glUniform3i(location, vec.x, vec.y, vec.z); + if (bind_shader) { + unuse(); + } + } + + void Shader::setUniformIntVec3(const char* uniform_name, glm::ivec3 vec, bool bind_shader) { + int location = glGetUniformLocation(*program, uniform_name); + setUniformIntVec3(location, vec, bind_shader); + } + + void Shader::setUniformIntVec4(GLint location, glm::ivec4 vec, bool bind_shader) { + if (bind_shader) { + use(); + } + glUniform4i(location, vec.x, vec.y, vec.z, vec.w); + if (bind_shader) { + unuse(); + } + } + + void Shader::setUniformIntVec4(const char* uniform_name, glm::ivec4 vec, bool bind_shader) { + int location = glGetUniformLocation(*program, uniform_name); + setUniformIntVec4(location, vec, bind_shader); + } + + void Shader::setUniformUInt(GLint location, GLuint ui, bool bind_shader) { + if (bind_shader) { + use(); + } + glUniform1ui(location, ui); + if (bind_shader) { + unuse(); + } + } + + void Shader::setUniformUInt(const char* uniform_name, GLuint ui, bool bind_shader) { + int location = glGetUniformLocation(*program, uniform_name); + setUniformUInt(location, ui, bind_shader); + } + + void Shader::setUniformUIntVec2(GLint location, glm::uvec2 vec, bool bind_shader) { + if (bind_shader) { + use(); + } + glUniform2ui(location, vec.x, vec.y); + if (bind_shader) { + unuse(); + } + } + + void Shader::setUniformUIntVec2(const char* uniform_name, glm::uvec2 vec, bool bind_shader) { + int location = glGetUniformLocation(*program, uniform_name); + setUniformUIntVec2(location, vec, bind_shader); + } + + void Shader::setUniformUIntVec3(GLint location, glm::uvec3 vec, bool bind_shader) { + if (bind_shader) { + use(); + } + glUniform3ui(location, vec.x, vec.y, vec.z); + if (bind_shader) { + unuse(); + } + } + + void Shader::setUniformUIntVec3(const char* uniform_name, glm::uvec3 vec, bool bind_shader) { + int location = glGetUniformLocation(*program, uniform_name); + setUniformUIntVec3(location, vec, bind_shader); + } + + void Shader::setUniformUIntVec4(GLint location, glm::uvec4 vec, bool bind_shader) { + if (bind_shader) { + use(); + } + glUniform4ui(location, vec.x, vec.y, vec.z, vec.w); + if (bind_shader) { + unuse(); + } + } + + void Shader::setUniformUIntVec4(const char* uniform_name, glm::uvec4 vec, bool bind_shader) { + int location = glGetUniformLocation(*program, uniform_name); + setUniformUIntVec4(location, vec, bind_shader); + } +} \ No newline at end of file