feat(web): switch to implementation-first capability wave
This commit is contained in:
@@ -1578,6 +1578,7 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
|
||||
type == "unwrapUV" || type == "addMaterialSlot" || type == "removeMaterialSlot" ||
|
||||
type == "assignMaterialFaces" || type == "setMaterialPrincipled" ||
|
||||
type == "importImage" || type == "setMaterialImageNode" || type == "setShaderGraph" ||
|
||||
type == "setGeometryNodeGraph" || type == "setPhysicsSimulation" ||
|
||||
type == "insertObjectKeyframe" || type == "deleteObjectKeyframe" ||
|
||||
type == "setFCurveInterpolation" || type == "setActiveAction" || type == "setNLAStack" ||
|
||||
type == "setConstraint" || type == "setParent" || type == "createCollection" ||
|
||||
@@ -1667,6 +1668,16 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
|
||||
command.value("imageId", "").c_str(), command.value("usage", "").c_str(),
|
||||
command.value("uvMap", "").c_str(), main_error);
|
||||
}
|
||||
else if (type == "setGeometryNodeGraph") {
|
||||
const json graph = command.value("graph", json::object());
|
||||
applied = web_engine_blend_main_set_geometry_node_graph(
|
||||
engine->authoritative_main, command.value("meshId", "").c_str(), graph.dump().c_str(), main_error);
|
||||
}
|
||||
else if (type == "setPhysicsSimulation") {
|
||||
const json manifest = command.value("manifest", json::object());
|
||||
applied = web_engine_blend_main_set_physics_simulation(
|
||||
engine->authoritative_main, manifest.dump().c_str(), main_error);
|
||||
}
|
||||
else if (type == "setShaderGraph") {
|
||||
const json graph = command.value("graph", json::object());
|
||||
const std::string material_id = command.value("materialId", "");
|
||||
|
||||
@@ -96,6 +96,8 @@ struct WebBlendMainState {
|
||||
blender::Main *main = nullptr;
|
||||
blender::Scene *scene = nullptr;
|
||||
blender::ViewLayer *view_layer = nullptr;
|
||||
std::unordered_map<std::string, std::string> geometry_node_graph_overrides;
|
||||
std::string physics_simulation_override;
|
||||
};
|
||||
|
||||
namespace {
|
||||
@@ -4296,6 +4298,21 @@ bool web_engine_blend_main_geometry_node_graphs_json(WebBlendMainState *state,
|
||||
graph["graphHash"] = web_engine_sha256_hex(graph.dump());
|
||||
graphs.push_back(std::move(graph));
|
||||
}
|
||||
for (const auto &[graph_id, graph_text] : state->geometry_node_graph_overrides) {
|
||||
if (graphs.size() >= max_graphs) {
|
||||
error = "GN_GRAPH_BUDGET_EXCEEDED: Geometry Node graph count exceeds 4096";
|
||||
return false;
|
||||
}
|
||||
json graph = json::parse(graph_text);
|
||||
bool already_present = false;
|
||||
for (const json &existing : graphs) {
|
||||
if (existing.value("id", "") == graph_id) {
|
||||
already_present = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!already_present) graphs.push_back(std::move(graph));
|
||||
}
|
||||
geometry_node_graphs_json = graphs.dump();
|
||||
return true;
|
||||
}
|
||||
@@ -4305,6 +4322,37 @@ bool web_engine_blend_main_geometry_node_graphs_json(WebBlendMainState *state,
|
||||
}
|
||||
}
|
||||
|
||||
bool web_engine_blend_main_set_geometry_node_graph(WebBlendMainState *state,
|
||||
const char *mesh_id,
|
||||
const char *graph_json,
|
||||
std::string &error)
|
||||
{
|
||||
if (state == nullptr || state->main == nullptr || mesh_id == nullptr || graph_json == nullptr ||
|
||||
find_mesh_object(state->main, mesh_id) == nullptr)
|
||||
{
|
||||
error = "GN_INVALID_GRAPH: Geometry Node target mesh is unavailable";
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const json graph = json::parse(graph_json);
|
||||
const std::string graph_id = graph.value("id", "");
|
||||
if (graph.value("schemaVersion", 0) != 1 || graph_id.empty() ||
|
||||
!graph.contains("nodes") || !graph["nodes"].is_array() ||
|
||||
!graph.contains("links") || !graph["links"].is_array() ||
|
||||
graph["nodes"].size() > 4096 || graph["links"].size() > 16384)
|
||||
{
|
||||
error = "GN_INVALID_GRAPH: Geometry Node graph schema or bounds are invalid";
|
||||
return false;
|
||||
}
|
||||
state->geometry_node_graph_overrides[graph_id] = graph.dump();
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception &exception) {
|
||||
error = std::string("GN_INVALID_GRAPH: Geometry Node graph JSON is invalid: ") + exception.what();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool web_engine_blend_main_physics_simulation_json(WebBlendMainState *state,
|
||||
std::string &physics_json,
|
||||
std::string &error)
|
||||
@@ -4313,6 +4361,10 @@ bool web_engine_blend_main_physics_simulation_json(WebBlendMainState *state,
|
||||
error = "PHYSICS_MANIFEST_INVALID: authoritative Main is not open";
|
||||
return false;
|
||||
}
|
||||
if (!state->physics_simulation_override.empty()) {
|
||||
physics_json = state->physics_simulation_override;
|
||||
return true;
|
||||
}
|
||||
#ifdef WITH_WEB
|
||||
/* Legacy particle systems are metadata-only in the Web runtime. Their desktop modifier chain
|
||||
* can contain file-space pointers that are unsafe for the physics manifest walker. */
|
||||
@@ -4431,6 +4483,40 @@ bool web_engine_blend_main_physics_simulation_json(WebBlendMainState *state,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool web_engine_blend_main_set_physics_simulation(WebBlendMainState *state,
|
||||
const char *manifest_json,
|
||||
std::string &error)
|
||||
{
|
||||
if (state == nullptr || state->main == nullptr || manifest_json == nullptr) {
|
||||
error = "PHYSICS_MANIFEST_INVALID: authoritative Main is not open";
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const json manifest = json::parse(manifest_json);
|
||||
if (manifest.value("schemaVersion", 0) != 1 || !manifest.contains("systems") ||
|
||||
!manifest["systems"].is_array() || manifest["systems"].size() > 4096)
|
||||
{
|
||||
error = "PHYSICS_MANIFEST_INVALID: physics manifest schema or system budget is invalid";
|
||||
return false;
|
||||
}
|
||||
for (const json &system : manifest["systems"]) {
|
||||
const std::string owner_id = system.value("ownerObjectId", "");
|
||||
if (!system.is_object() || owner_id.empty() || find_object(state->main, owner_id.c_str()) == nullptr ||
|
||||
!system.contains("settings") || !system["settings"].is_object())
|
||||
{
|
||||
error = "PHYSICS_MANIFEST_INVALID: physics system owner or settings are invalid";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
state->physics_simulation_override = manifest.dump();
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception &exception) {
|
||||
error = std::string("PHYSICS_MANIFEST_INVALID: physics manifest JSON is invalid: ") + exception.what();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool web_engine_blend_main_particle_settings_json(WebBlendMainState *state,
|
||||
std::string &particle_settings_json,
|
||||
std::string &error)
|
||||
|
||||
@@ -380,9 +380,16 @@ bool web_engine_blend_main_grease_pencils_json(WebBlendMainState *state,
|
||||
bool web_engine_blend_main_geometry_node_graphs_json(WebBlendMainState *state,
|
||||
std::string &geometry_node_graphs_json,
|
||||
std::string &error);
|
||||
bool web_engine_blend_main_set_geometry_node_graph(WebBlendMainState *state,
|
||||
const char *mesh_id,
|
||||
const char *graph_json,
|
||||
std::string &error);
|
||||
bool web_engine_blend_main_physics_simulation_json(WebBlendMainState *state,
|
||||
std::string &physics_json,
|
||||
std::string &error);
|
||||
bool web_engine_blend_main_set_physics_simulation(WebBlendMainState *state,
|
||||
const char *manifest_json,
|
||||
std::string &error);
|
||||
bool web_engine_blend_main_particle_settings_json(WebBlendMainState *state,
|
||||
std::string &particle_settings_json,
|
||||
std::string &error);
|
||||
|
||||
Reference in New Issue
Block a user