feat(web): continue source-backed implementation waves
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled

This commit is contained in:
mes123456
2026-08-29 05:46:53 +08:00
parent e9b9d343a1
commit 81113159dc
180 changed files with 12316 additions and 82 deletions

View File

@@ -1585,7 +1585,7 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
type == "moveObjectToCollection" || type == "renameId" || type == "joinObjects" ||
type == "separateMeshFaces" || type == "applyObjectTransform" || type == "setObjectOrigin" ||
type == "setCurveControlPoints" || type == "setCurveHandle" || type == "setCurveTopology" || type == "setCurveSplines" || type == "setSurfaceTopology" || type == "setFontBody" ||
type == "setFontProperties" || type == "setFontAdvanced" || type == "importVFont" || type == "setFontLinks" || type == "setVolumeProperties" || type == "deleteNonMeshData" ||
type == "setFontProperties" || type == "setFontAdvanced" || type == "importVFont" || type == "setFontLinks" || type == "setTextSource" || type == "setVolumeProperties" || type == "deleteNonMeshData" ||
type == "setMetaballElements" || type == "createGreasePencilLayer" ||
type == "removeGreasePencilLayer" || type == "moveGreasePencilLayer" ||
type == "moveGreasePencilFrame" ||
@@ -1994,6 +1994,11 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
applied = main_error.empty() && web_engine_blend_main_set_font_links(
engine->authoritative_main, command.value("dataId", "").c_str(), font_ids, main_error);
}
else if (type == "setTextSource") {
applied = web_engine_blend_main_set_text_source(
engine->authoritative_main, command.value("dataId", "").c_str(),
command.value("source", "").c_str(), main_error);
}
else if (type == "setVolumeProperties") {
WebVolumePropertiesEdit properties;
properties.source_path = command.value("sourcePath", "");

View File

@@ -32,6 +32,7 @@
#include "BKE_material.hh"
#include "BKE_mesh.h"
#include "BKE_mesh.hh"
#include "BKE_modifier.hh"
#include "BKE_node.hh"
#include "BKE_node_legacy_types.hh"
#include "BKE_node_runtime.hh"
@@ -46,6 +47,7 @@
#include "BKE_volume.hh"
#include "BKE_fcurve.hh"
#include "BKE_image.hh"
#include "BKE_idprop.hh"
#include "ANIM_action.hh"
#include "ANIM_fcurve.hh"
@@ -169,6 +171,22 @@ bool write_text(Main *main, const char *name, const std::string &contents)
return true;
}
bool write_id_string(ID &id, const char *name, const std::string &contents)
{
if (name == nullptr || contents.size() > 16 * 1024 * 1024) return false;
IDProperty *group = IDP_EnsureProperties(&id);
if (group == nullptr) return false;
if (IDProperty *existing = IDP_GetPropertyFromGroup_null(group, name)) {
IDP_FreeFromGroup(group, existing);
}
IDProperty *property = bke::idprop::create(name, contents.c_str()).release();
if (property == nullptr || !IDP_AddToGroup(group, property)) {
if (property != nullptr) IDP_FreeProperty(property);
return false;
}
return true;
}
void load_persisted_geometry_overrides(WebBlendMainState *state)
{
if (state == nullptr || state->main == nullptr) return;
@@ -3964,6 +3982,28 @@ bool web_engine_blend_main_set_font_links(WebBlendMainState *state,
return true;
}
bool web_engine_blend_main_set_text_source(WebBlendMainState *state,
const char *data_id,
const char *source,
std::string &error)
{
if (state == nullptr || state->main == nullptr || data_id == nullptr || source == nullptr ||
strncmp(data_id, "text:", 5) != 0 || strlen(source) > 1024 * 1024)
{
error = "NON_MESH_PROPERTY_INVALID: Text source must be a local text data-block within the 1 MiB budget";
return false;
}
Text *text = find_text(state->main, data_id + 5);
if (text == nullptr || text->id.lib != nullptr) {
error = "NON_MESH_DATA_UNSUPPORTED: Text data-block was not found or is linked read-only";
return false;
}
BKE_text_clear(text);
BKE_text_write(text, source, int(strlen(source)));
text->flags |= TXT_ISDIRTY;
return true;
}
bool web_engine_blend_main_set_volume_properties(WebBlendMainState *state,
const char *data_id,
const WebVolumePropertiesEdit &properties,
@@ -4428,6 +4468,53 @@ bool web_engine_blend_main_set_geometry_node_graph(WebBlendMainState *state,
error = "GN_INVALID_GRAPH: Geometry Node graph could not be persisted in Main";
return false;
}
/* Materialize a native GeometryNodeTree datablock as the durable owner of
* this graph. The bounded JSON remains the transport representation, while
* future node-family slices can populate the tree incrementally. */
bNodeTree *native_tree = nullptr;
for (bNodeTree &candidate : state->main->nodetrees) {
if (id_name(candidate.id) == graph_id) {
native_tree = &candidate;
break;
}
}
if (native_tree == nullptr) {
native_tree = bke::node_tree_add_tree(state->main, graph_id, "GeometryNodeTree");
}
if (native_tree == nullptr) {
state->geometry_node_graph_overrides.erase(graph_id);
persist_geometry_overrides(state);
error = "GN_INVALID_GRAPH: Blender could not create a GeometryNodeTree datablock";
return false;
}
Object *target_object = find_mesh_object(state->main, mesh_id);
NodesModifierData *nodes_modifier = nullptr;
if (target_object != nullptr) {
nodes_modifier = reinterpret_cast<NodesModifierData *>(
BKE_modifiers_findby_type(target_object, eModifierType_Nodes));
if (nodes_modifier == nullptr) {
nodes_modifier = reinterpret_cast<NodesModifierData *>(BKE_modifier_new(eModifierType_Nodes));
if (nodes_modifier == nullptr) {
error = "GN_INVALID_GRAPH: Blender could not create a Geometry Nodes modifier";
return false;
}
STRNCPY_UTF8(nodes_modifier->modifier.name, "Web Geometry Nodes");
BKE_modifier_unique_name(&target_object->modifiers, &nodes_modifier->modifier);
BKE_modifiers_persistent_uid_init(*target_object, nodes_modifier->modifier);
BLI_addtail(&target_object->modifiers, nodes_modifier);
}
if (nodes_modifier->node_group != native_tree) {
if (nodes_modifier->node_group != nullptr) id_us_min(&nodes_modifier->node_group->id);
nodes_modifier->node_group = native_tree;
id_us_plus(&native_tree->id);
}
target_object->id.recalc |= ID_RECALC_GEOMETRY;
if (!write_id_string(target_object->id, "web_geometry_node_graph", graph_text)) {
error = "GN_INVALID_GRAPH: Geometry Node graph metadata could not be written to Object";
return false;
}
}
native_tree->id.recalc |= ID_RECALC_NTREE_OUTPUT;
return true;
}
catch (const std::exception &exception) {
@@ -4596,6 +4683,15 @@ bool web_engine_blend_main_set_physics_simulation(WebBlendMainState *state,
error = "PHYSICS_MANIFEST_INVALID: physics manifest could not be persisted in Main";
return false;
}
for (const json &system : manifest["systems"]) {
const std::string owner_id = system.value("ownerObjectId", "");
if (Object *owner = find_object(state->main, owner_id.c_str())) {
if (!write_id_string(owner->id, "web_physics_manifest", manifest_text)) {
error = "PHYSICS_MANIFEST_INVALID: physics metadata could not be written to Object";
return false;
}
}
}
state->physics_simulation_override = manifest_text;
return true;
}

View File

@@ -366,6 +366,10 @@ bool web_engine_blend_main_set_font_links(WebBlendMainState *state,
const char *data_id,
const std::array<std::string, 4> &font_ids,
std::string &error);
bool web_engine_blend_main_set_text_source(WebBlendMainState *state,
const char *data_id,
const char *source,
std::string &error);
bool web_engine_blend_main_set_volume_properties(WebBlendMainState *state,
const char *data_id,
const WebVolumePropertiesEdit &properties,