177 lines
4.5 KiB
C++
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 "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 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;
|
|
ICloseable* renderShader = nullptr;
|
|
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 { /*if (renderShader) 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
|
|
{
|
|
renderShader->Close();
|
|
renderShader = nullptr;
|
|
}
|
|
|
|
private:
|
|
void CheckShaderInitState() const
|
|
{
|
|
if (renderShader) throw std::runtime_error("Shader already initialized!");
|
|
}
|
|
};
|
|
}
|