/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once #include "Base/ICloseable.hpp" #include "Base/Utils.hpp" #include "VertexInputDescription.hpp" #include #include namespace openVulkanoCpp::Scene { enum class CullMode : uint32_t { NONE = 0, FRONT, BACK, FRONT_AND_BACK }; enum class Topology : uint32_t { POINT_LIST = 0, LINE_LIST, LINE_STRIPE, TRIANGLE_LIST, TRIANGLE_STRIP, TRIANGLE_FAN, LINE_LIST_WITH_ADJACENCY, LINE_STRIP_WITH_ADJACENCY, TRIANGLE_LIST_WITH_ADJACENCY, TRIANGLE_STRIP_WITH_ADJACENCY, PATCH_LIST }; class ShaderProgramType { static constexpr std::string_view FILE_EXTENSIONS_OPENGL[] = { ".vert", ".tesc", ".tese", ".geom", ".frag", ".comp", ".mesh", ".task", ".rgen", ".rahit", ".rchit", ".rmiss", ".rint", ".rcall", ".glsl" }; public: enum Type : uint32_t { VERTEX = 1, TESSELLATION_CONTROL = 2, TESSELLATION_EVALUATION = 4, GEOMETRY = 8, FRAGMENT = 16, COMPUTE = 32, // Mesh shader MESH_TASK = 0x40, MESH_MESH = 0x80, // Raytracing RAY_GEN = 0x100, RAY_ANY_HIT = 0x200, RAY_CLOSEST_HIT = 0x400, RAY_MISS = 0x800, RAY_INTERSECTION = 0x1000, RAY_CALLABLE = 0x2000, ALL_GRAPHICS = 0x0000001F }; ShaderProgramType(Type type) : m_type(type) {} [[nodiscard]] constexpr std::string_view GetExtensionOpenGL() const { return FILE_EXTENSIONS_OPENGL[GetId()]; } [[nodiscard]] constexpr uint32_t GetId() const { if (m_type == ALL_GRAPHICS) return 14; return Utils::Log2OfPow2(static_cast(m_type)); } [[nodiscard]] bool operator ==(Type rhs) const { return m_type == rhs; } [[nodiscard]] bool operator !=(Type rhs) const { return m_type != rhs; } [[nodiscard]] operator uint32_t() const { return m_type; } private: Type m_type; }; struct ShaderProgram { ShaderProgramType type; std::string name; ShaderProgram(ShaderProgramType type, const std::string& name) : type(type), name(name) {} ShaderProgram(const ShaderProgram& program) : type(program.type), name(program.name) {} ShaderProgram(ShaderProgram&& program) : type(program.type), name(std::move(program.name)) {} [[nodiscard]] std::string GetShaderNameOpenGL() const { std::string oglName; std::string_view ext = type.GetExtensionOpenGL(); oglName.reserve(name.size() + ext.size()); return oglName.append(name).append(ext); } [[nodiscard]] std::string GetShaderNameVulkan() const { return GetShaderNameOpenGL() + ".spv"; } }; struct Shader final : public virtual ICloseable { std::vector shaderPrograms{}; std::vector vertexInputDescriptions{}; Topology topology = Topology::TRIANGLE_LIST; CullMode cullMode = CullMode::BACK; ICloseable* renderShader = nullptr; bool alphaBlend = false; // TODO allow fine control over blending Shader() = default; ~Shader() override { if (renderShader) Shader::Close(); } Shader& AddShaderProgram(const ShaderProgram& shaderProgram) { if (renderShader) throw std::runtime_error("Shader already initialized!"); shaderPrograms.push_back(shaderProgram); return *this; } Shader& AddShaderProgram(ShaderProgram&& shaderProgram) { if (renderShader) throw std::runtime_error("Shader already initialized!"); shaderPrograms.push_back(std::move(shaderProgram)); return *this; } template Shader& AddShaderProgram(ARGS&&... args) { if (renderShader) throw std::runtime_error("Shader already initialized!"); shaderPrograms.emplace_back(std::forward(args)...); return *this; } Shader& AddVertexInputDescription(const VertexInputDescription& inputDescription, int bindingId = -1) { if (renderShader) throw std::runtime_error("Shader already initialized!"); if (bindingId < 0) bindingId = vertexInputDescriptions.size(); if (bindingId > vertexInputDescriptions.size()) { vertexInputDescriptions.emplace_back(0, 0); } if (bindingId == vertexInputDescriptions.size()) { vertexInputDescriptions.emplace_back(bindingId, inputDescription); } else { vertexInputDescriptions[bindingId] = inputDescription; } return *this; } void Close() override { renderShader->Close(); renderShader = nullptr; } }; }