Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
World3DShaderAssets.cpp
Go to the documentation of this file.
2
3#include <SDL3/SDL.h>
4
5#include <fstream>
6#include <iterator>
7#include <utility>
8#include <vector>
9
10namespace monopoly::engine
11{
12 namespace
13 {
14 struct ShaderAssetChoice
15 {
17 const char* suffix{};
18 const char* entrypoint{};
19 bool text{};
20 };
21
22 std::expected<ShaderAssetChoice, World3DShaderError>
24 {
25 if (!device)
26 return std::unexpected(World3DShaderError{
27 World3DShaderErrorCode::MissingDevice, {}, "missing SDL GPU device"});
28
29 const auto formats = SDL_GetGPUShaderFormats(device);
31 return ShaderAssetChoice{SDL_GPU_SHADERFORMAT_DXIL, ".dxil", "main", false};
33 return ShaderAssetChoice{SDL_GPU_SHADERFORMAT_MSL, ".msl", "main0", true};
35 return ShaderAssetChoice{SDL_GPU_SHADERFORMAT_SPIRV, ".spv", "main", false};
37 return std::unexpected(World3DShaderError{
39 "SPIR-V World3D texture shader has not been regenerated; refusing the stale untextured asset"});
40
41 return std::unexpected(World3DShaderError{
43 "device exposes no current generated World3D shader format"});
44 }
45
46 std::expected<std::vector<Uint8>, World3DShaderError>
47 readShader(const std::filesystem::path& path, bool text)
48 {
49 if (!std::filesystem::exists(path))
50 return std::unexpected(World3DShaderError{
51 World3DShaderErrorCode::MissingAsset, path, "shader asset does not exist"});
52
53 std::ifstream stream(path, std::ios::binary);
54 if (!stream)
55 return std::unexpected(World3DShaderError{
56 World3DShaderErrorCode::ReadFailed, path, "shader asset could not be opened"});
57
58 std::vector<Uint8> bytes{
59 std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>()};
60 if (!stream.eof() && stream.fail())
61 return std::unexpected(World3DShaderError{
62 World3DShaderErrorCode::ReadFailed, path, "shader asset read failed"});
63 if (text) bytes.push_back(0);
64 return bytes;
65 }
66 std::expected<SDL_GPUShader*, World3DShaderError> createShader(
67 SDL_GPUDevice* device,
68 const std::filesystem::path& path,
69 const ShaderAssetChoice& choice,
71 {
72 auto bytes = readShader(path, choice.text);
73 if (!bytes) return std::unexpected(bytes.error());
74
76 info.code_size = choice.text ? bytes->size() - 1U : bytes->size();
77 info.code = bytes->data();
78 info.entrypoint = choice.entrypoint;
79 info.format = choice.format;
80 info.stage = stage;
81 info.num_uniform_buffers = 1;
82 info.num_samplers = stage == SDL_GPU_SHADERSTAGE_FRAGMENT ? (modernPBR ? 7U : 1U) : 0U;
83
85 if (!shader)
86 return std::unexpected(World3DShaderError{
88 return shader;
89 }
90 }
91
96
98 {
99 *this = std::move(other);
100 }
102 {
103 if (this == &other) return *this;
104 reset();
105 device_ = std::exchange(other.device_, nullptr);
106 vertex_ = std::exchange(other.vertex_, nullptr);
107 fragment_ = std::exchange(other.fragment_, nullptr);
108 format_ = std::exchange(other.format_, SDL_GPU_SHADERFORMAT_INVALID);
109 entrypoint_ = std::exchange(other.entrypoint_, "main");
110 return *this;
111 }
112
114 {
115 if (device_ && fragment_) SDL_ReleaseGPUShader(device_, fragment_);
116 if (device_ && vertex_) SDL_ReleaseGPUShader(device_, vertex_);
117 fragment_ = nullptr;
118 vertex_ = nullptr;
119 device_ = nullptr;
121 entrypoint_ = "main";
122 }
123
124 std::expected<World3DShaderSet, World3DShaderError> World3DShaderSet::load(
125 SDL_GPUDevice* device, const std::filesystem::path& shaderDirectory,
126 bool modernPBR)
127 {
128 auto choice = chooseFormat(device, modernPBR);
129 if (!choice) return std::unexpected(choice.error());
130
131 const std::string name = modernPBR ? "ModernPBR" : "World3D";
132 const auto vertexPath = shaderDirectory / (name + ".vert" + choice->suffix);
133 const auto fragmentPath = shaderDirectory / (name + ".frag" + choice->suffix);
135 if (!vertex) return std::unexpected(vertex.error());
136
138 if (!fragment)
139 {
141 return std::unexpected(fragment.error());
142 }
143
144 World3DShaderSet result;
145 result.device_ = device;
146 result.vertex_ = *vertex;
147 result.fragment_ = *fragment;
148 result.format_ = choice->format;
149 result.entrypoint_ = choice->entrypoint;
150 return result;
151 }
152}
const char * name
std::string_view text
std::vector< std::byte > bytes
unsigned index
std::string path
CardTag other
const char * entrypoint
SDL_GPUShaderFormat format
const char * suffix
static std::expected< World3DShaderSet, World3DShaderError > load(SDL_GPUDevice *device, const std::filesystem::path &shaderDirectory, bool modernPBR=false)
World3DShaderSet & operator=(const World3DShaderSet &)=delete
SDL_GPUShader * vertex() const noexcept
SDL_GPUShader * fragment() const noexcept