Files
OpenVulkano/openVulkanoCpp/Scene/Shader/Shader.hpp
2024-08-21 13:33:15 +02:00

177 lines
4.5 KiB
C++

/*
* 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 "Base/Render/RenderResource.hpp"
#include "VertexInputDescription.hpp"
#include "ShaderProgramType.hpp"
#include "DescriptorInputDescription.hpp"
#include "PushConstant.hpp"
#include <string>
#include <stdexcept>
namespace OpenVulkano::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
};
enum class CompareOp : uint32_t
{
NEVER = 0,
LESS = 1,
EQUAL = 2,
LESS_OR_EQUAL = 3,
GREATER = 4,
NOT_EQUAL = 5,
GREATER_OR_EQUAL = 6,
ALWAYS = 7
};
struct ShaderProgram
{
ShaderProgramType type;
std::string name;
ShaderProgram(ShaderProgramType type, const std::string& name) : type(type), name(name) {}
ShaderProgram(const ShaderProgram& program) = default;
ShaderProgram(ShaderProgram&& program) noexcept : 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";
}
};
class Shader final : public RenderResourceHolder<Shader>, public ICloseable
{
public:
std::vector<ShaderProgram> shaderPrograms{};
std::vector<VertexInputDescription> vertexInputDescriptions{};
std::vector<std::vector<DescriptorSetLayoutBinding>> descriptorSets;
std::vector<PushConstantRange> pushConstantRanges;
Topology topology = Topology::TRIANGLE_LIST;
CullMode cullMode = CullMode::BACK;
CompareOp depthCompareOp = CompareOp::LESS;
bool alphaBlend = false; // TODO allow fine control over blending
bool depthTest = true;
bool depthWrite = true;
bool dynamicViewport = true; // If disabled the swapchains fullscreen viewport will always be used, regardless of framebuffer or viewport
Shader() = default;
~Shader() override { Shader::Close(); }
Shader& AddShaderProgram(const ShaderProgram& shaderProgram)
{
CheckShaderInitState();
shaderPrograms.push_back(shaderProgram);
return *this;
}
Shader& AddShaderProgram(ShaderProgram&& shaderProgram)
{
CheckShaderInitState();
shaderPrograms.push_back(std::move(shaderProgram));
return *this;
}
template<typename ...ARGS>
Shader& AddShaderProgram(ARGS&&... args)
{
CheckShaderInitState();
shaderPrograms.emplace_back(std::forward<ARGS>(args)...);
return *this;
}
#pragma clang diagnostic push
#pragma ide diagnostic ignored "LoopDoesntUseConditionVariableInspection"
Shader& AddVertexInputDescription(const VertexInputDescription& inputDescription, int bindingId = -1)
{
CheckShaderInitState();
if (bindingId < 0) bindingId = static_cast<int>(vertexInputDescriptions.size());
while (bindingId > static_cast<int>(vertexInputDescriptions.size()))
{
vertexInputDescriptions.emplace_back(0, 0);
}
if (bindingId == static_cast<int>(vertexInputDescriptions.size()))
{
vertexInputDescriptions.emplace_back(bindingId, inputDescription);
}
else
{
vertexInputDescriptions[bindingId] = inputDescription;
}
return *this;
}
int AddDescriptorSetLayoutBinding(const DescriptorSetLayoutBinding& binding, int setId = -1)
{
CheckShaderInitState();
if (setId < 0) setId = static_cast<int>(descriptorSets.size() + 2);
if (setId < 2) throw std::runtime_error("Cant bind set id 0 or 1! They are used for node and camera!");
setId -= 2;
while (setId >= static_cast<int>(descriptorSets.size()))
{
descriptorSets.emplace_back();
}
descriptorSets[setId].push_back(binding);
return setId + 2;
}
#pragma clang diagnostic pop
void AddPushConstantRange(const PushConstantRange& pushConstantRange)
{
pushConstantRanges.push_back(pushConstantRange);
}
void Close() override
{
if (HasRenderResource())
GetRenderResource().Release();
}
private:
void CheckShaderInitState() const
{
if (HasRenderResource()) throw std::runtime_error("Shader already initialized!");
}
};
}