载入中...
搜索中...
未找到
ShaderScriptBindings.cpp
浏览该文件的文档.
2#include "graphics/Graphics.h"
3#include "graphics/Shader.h"
8
9#include <simplesquirrel/simplesquirrel.hpp>
10#include <cstring>
11#include <exception>
12#include <memory>
13#include <vector>
14
15namespace eve::graphics {
16namespace {
17Result<std::vector<uint32_t>> shaderWords(ssq::Array array) {
18 std::vector<uint32_t> words;
19 words.reserve(array.size());
20 for (size_t i = 0; i < array.size(); ++i) {
21 if (array.get<ssq::Object>(i).getType() != ssq::Type::INTEGER)
22 return Result<std::vector<uint32_t>>::failure(
23 Diagnostic::error(DiagnosticCode::InvalidArgument, "SPIR-V words must be integers"));
24 const auto word = array.get<SQInteger>(i);
25 if (word < 0 || static_cast<uint64_t>(word) > UINT32_MAX)
26 return Result<std::vector<uint32_t>>::failure(
27 Diagnostic::error(DiagnosticCode::InvalidArgument, "SPIR-V words must be unsigned 32-bit integers"));
28 words.push_back(static_cast<uint32_t>(word));
29 }
30 return Result<std::vector<uint32_t>>::success(std::move(words));
31}
32
33} // namespace
34namespace detail {
36 try {
37 auto* fs = filesystem::Filesystem::create();
38 std::unique_ptr<filesystem::FileData> bytes(fs->read(path));
39 if (!bytes || bytes->getSize() < 20 || bytes->getSize() % 4 != 0)
41 DiagnosticCode::ParseError, "SPIR-V must contain a complete word-aligned header", path));
42 std::vector<std::uint32_t> words(bytes->getSize() / 4);
43 std::memcpy(words.data(), bytes->getData(), bytes->getSize());
44 if (words[0] != 0x07230203)
46 DiagnosticCode::ParseError, "SPIR-V magic mismatch", path));
47 return Result<std::vector<std::uint32_t>>::success(std::move(words));
48 } catch (const std::exception& error) {
49 return Result<std::vector<std::uint32_t>>::failure(
51 }
52}
53
54} // namespace detail
55namespace {
56// The existing Graphics factory owns the shader; this adapter only borrows it.
57ResultRef<Shader> loadMeshShader(Graphics& graphics, const std::string& vertex,
58 const std::string& fragment) {
59 if (graphics.getBackendName() != "vulkan")
61 DiagnosticCode::Unsupported, "SPIR-V mesh shaders require the Vulkan backend", "backend"));
62 if (fragment.empty())
64 DiagnosticCode::InvalidArgument, "fragment path must not be empty", "fragment"));
65 std::vector<std::uint32_t> vert;
66 if (!vertex.empty()) {
67 auto decoded = detail::readShaderStageFile(vertex);
68 if (!decoded) return ResultRef<Shader>::failure(decoded.status());
69 vert = std::move(decoded).takeValue();
70 }
71 auto frag = detail::readShaderStageFile(fragment);
72 if (!frag) return ResultRef<Shader>::failure(frag.status());
73 try {
74 auto* shader = graphics.newMeshShaderFromSpv(vert, frag.value());
75 if (!shader)
77 DiagnosticCode::Failed, "Mesh shader allocation failed", "shader"));
78 return ResultRef<Shader>::success(std::ref(*shader));
79 } catch (const std::exception& error) {
82 }
83}
84} // namespace
85
86void exposeShaderScriptBindings(ssq::Table& table, ssq::Class& cls) {
88 const auto vm = table.getHandle();
89 cls.addFunc(
90 "replaceShaderFromSpv", [vm](Graphics* graphics, Shader* shader, ssq::Array vertex, ssq::Array fragment) {
91 if (!graphics || !shader)
94 "graphics and shader must not be null")));
95 auto vert = shaderWords(vertex);
96 if (!vert.ok()) return eve::script::projectResult(vm, Result<void>::failure(vert.status()));
97 auto frag = shaderWords(fragment);
98 if (!frag.ok()) return eve::script::projectResult(vm, Result<void>::failure(frag.status()));
99 return eve::script::projectResult(vm, graphics->replaceShaderFromSpv(*shader, vert.value(), frag.value()));
100 });
101 cls.addFunc("replaceShaderFromGlsl",
102 [vm](Graphics* self, Shader* shader, const std::string& vertex,
103 const std::string& fragment) {
104 if (!self || !shader)
108 "graphics and shader must not be null", "shader", {},
109 "graphics.shader_reload.binding")));
111 vm, self->replaceShaderFromGlsl(*shader, vertex, fragment));
112 });
113 cls.addFunc("replaceShaderFromWgsl",
114 [vm](Graphics* self, Shader* shader, const std::string& vertex,
115 const std::string& fragment) {
116 if (!self || !shader)
120 "graphics and shader must not be null", "shader", {},
121 "graphics.shader_reload.binding")));
123 vm, self->replaceShaderFromWgsl(*shader, vertex, fragment));
124 });
125
126
127 cls.addFunc("configureMeshShaderSurface",
128 [vm](Graphics* self, Shader* shader, const std::string& name, bool depthWrite, bool doubleSided) {
130 if (name == "alpha")
132 else if (name == "premultiplied")
134 else if (name == "additive")
136 else if (name == "multiply")
138 else if (name != "opaque")
141 "Unknown mesh blend mode", "blend")));
142 if (!self || !shader)
145 "Expected graphics and shader", "shader")));
147 vm, self->configureMeshShaderSurface(*shader, blend, depthWrite, doubleSided));
148 });
149 cls.addFunc("configureMeshShaderRaster", [vm](Graphics* self, Shader* shader, const std::string& compare,
150 float constantBias, float slopeBias, int colorMask) {
152 if (compare == "less")
153 state.depthCompare = MeshDepthCompare::Less;
154 else if (compare == "lessEqual")
155 state.depthCompare = MeshDepthCompare::LessEqual;
156 else if (compare == "always")
157 state.depthCompare = MeshDepthCompare::Always;
158 else
159 colorMask = -1;
160 if (!self || !shader || colorMask < 0 || colorMask > 15)
163 "Invalid shader, depth comparison or RGBA mask",
164 "shader.raster")));
165 state.depthBiasConstant = constantBias;
166 state.depthBiasSlope = slopeBias;
167 state.colorWriteMask = static_cast<std::uint8_t>(colorMask);
169 });
170 cls.addFunc("loadMeshShaderSpv", [vm](Graphics* self, const std::string& vertex,
171 const std::string& fragment) {
172 auto result = loadMeshShader(*self, vertex, fragment);
173 if (!result) return eve::script::projectStatusResult(vm, result.status());
174 auto projected = eve::script::projectStatusResult(vm, result.status());
175 projected.set("value", &result.value().get());
177 projected.set("ownership", std::string("borrowed-from-graphics"));
178 return projected;
179 });
180}
181} // namespace eve::graphics
Vocabulary aliases for nullable and checked borrowed references.
Vec3 projected
Definition CaveMesh.cpp:122
HSQUIRRELVM vm
Definition ECS.cpp:20
HSQOBJECT cls
Definition ECS.cpp:21
vk::ShaderModule vert
vk::ShaderModule frag
float blend
std::uint64_t bytes
std::string name
bool doubleSided
std::string error
Definition Package.cpp:60
std::string path
Definition PlayHost.cpp:110
int detail
Shader * shader
The single Squirrel projection for common Result, Status and Value.
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
virtual Result< void > replaceShaderFromGlsl(Shader &shader, const std::string &vertGlsl, const std::string &fragGlsl)=0
Compile GLSL and transactionally replace an existing shader.
virtual eve::Result< void > configureMeshShaderRaster(Shader &shader, const MeshShaderRasterState &state)
Transactionally configure an owned ordinary mesh shader's raster state.
Definition Graphics.h:1847
virtual eve::Result< void > configureMeshShaderSurface(Shader &, BlendMode, bool, bool)
Prepare a custom mesh shader's blend, depth and culling state.
Definition Graphics.h:1830
virtual Result< void > replaceShaderFromSpv(Shader &shader, const std::vector< uint32_t > &vertSpv, const std::vector< uint32_t > &fragSpv)=0
Transactionally replace an existing shader with SPIR-V stages.
virtual Result< void > replaceShaderFromWgsl(Shader &shader, const std::string &vertWgsl, const std::string &fragWgsl)=0
Transactionally replace an existing shader with WGSL stages.
Custom GPU program.
Definition Shader.h:39
std::string word
void exposeShaderResourceBindings(ssq::Table &table, ssq::Class &cls)
Expose shader resource bindings.
Result< std::vector< std::uint32_t > > readShaderStageFile(const std::string &path)
Reads shader stage file.
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
Definition Animation.h:25
void exposeShaderScriptBindings(ssq::Table &table, ssq::Class &cls)
Register shader loading and binary replacement on the VM owner thread. Borrows both tables for this c...
void markResultHasValue(ssq::Table &result)
Declare that a projected table received a payload the caller attached itself.
ssq::Table projectStatusResult(HSQUIRRELVM vm, const Status &status)
Project a checked native status that carries no payload.
ssq::Table projectResult(HSQUIRRELVM vm, Result< void > &&result)
Consume and project a void native Result using the common schema.
BlendMode
Render-neutral 2D blend mode shared by graphics-facing modules.
Definition RenderTypes.h:11
Value snapshot of custom mesh rasterization state, independent of blending/culling.