diff --git a/blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp b/blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp index 0711e82c8..2d953cead 100644 --- a/blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp +++ b/blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp @@ -41,6 +41,7 @@ #include "BKE_object_deform.h" #include "BKE_packedFile.hh" #include "BKE_scene.hh" +#include "BKE_text.h" #include "BKE_vfont.hh" #include "BKE_volume.hh" #include "BKE_fcurve.hh" @@ -72,6 +73,7 @@ #include "DNA_particle_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" +#include "DNA_text_types.h" #include "DNA_world_types.h" #include "DNA_userdef_enums.h" #include "DNA_vfont_types.h" @@ -134,6 +136,75 @@ std::string id_name(const ID &id) return id.name[0] != '\0' && id.name[1] != '\0' ? std::string(id.name + 2) : std::string(); } +constexpr char WEB_ENGINE_GEOMETRY_OVERRIDE_TEXT[] = "WBV2 Geometry Node Overrides"; +constexpr char WEB_ENGINE_PHYSICS_OVERRIDE_TEXT[] = "WBV2 Physics Simulation Override"; + +std::string text_contents(Text &text) +{ + size_t length = 0; + char *buffer = txt_to_buf(&text, &length); + if (buffer == nullptr) return {}; + std::string result(buffer, length); + MEM_delete(buffer); + return result; +} + +Text *find_text(Main *main, const char *name) +{ + if (main == nullptr || name == nullptr) return nullptr; + for (Text &text : main->texts) { + if (id_name(text.id) == name) return &text; + } + return nullptr; +} + +bool write_text(Main *main, const char *name, const std::string &contents) +{ + if (main == nullptr || name == nullptr || contents.size() > 64 * 1024 * 1024) return false; + Text *text = find_text(main, name); + if (text == nullptr) text = BKE_text_add(main, name); + if (text == nullptr) return false; + BKE_text_clear(text); + BKE_text_write(text, contents.c_str(), int(contents.size())); + return true; +} + +void load_persisted_geometry_overrides(WebBlendMainState *state) +{ + if (state == nullptr || state->main == nullptr) return; + Text *text = find_text(state->main, WEB_ENGINE_GEOMETRY_OVERRIDE_TEXT); + if (text == nullptr) return; + try { + const json payload = json::parse(text_contents(*text)); + if (!payload.is_object()) return; + for (const auto &[graph_id, graph] : payload.items()) { + if (graph.is_object()) state->geometry_node_graph_overrides[graph_id] = graph.dump(); + } + } + catch (...) { + /* Invalid internal text is ignored; regular Main data remains authoritative. */ + } +} + +void load_persisted_physics_override(WebBlendMainState *state) +{ + if (state == nullptr || state->main == nullptr || !state->physics_simulation_override.empty()) return; + Text *text = find_text(state->main, WEB_ENGINE_PHYSICS_OVERRIDE_TEXT); + if (text == nullptr) return; + const std::string contents = text_contents(*text); + if (!contents.empty()) state->physics_simulation_override = contents; +} + +bool persist_geometry_overrides(WebBlendMainState *state) +{ + json payload = json::object(); + for (const auto &[graph_id, graph_text] : state->geometry_node_graph_overrides) { + try { payload[graph_id] = json::parse(graph_text); } + catch (...) { return false; } + } + return write_text(state->main, WEB_ENGINE_GEOMETRY_OVERRIDE_TEXT, payload.dump()); +} + Object *find_object(Main *main, const char *object_id) { if (main == nullptr || object_id == nullptr || strncmp(object_id, "object:", 7) != 0) { @@ -869,6 +940,8 @@ WebBlendMainState *web_engine_blend_main_open(const uint8_t *data, for (blender::ViewLayer &candidate : state->scene->view_layers) { blender::BKE_view_layer_synced_ensure(*state->main, state->scene, &candidate); } + load_persisted_geometry_overrides(state); + load_persisted_physics_override(state); return state; } @@ -4344,7 +4417,17 @@ bool web_engine_blend_main_set_geometry_node_graph(WebBlendMainState *state, error = "GN_INVALID_GRAPH: Geometry Node graph schema or bounds are invalid"; return false; } - state->geometry_node_graph_overrides[graph_id] = graph.dump(); + const std::string graph_text = graph.dump(); + const auto previous = state->geometry_node_graph_overrides.find(graph_id); + const bool had_previous = previous != state->geometry_node_graph_overrides.end(); + const std::string previous_text = had_previous ? previous->second : std::string(); + state->geometry_node_graph_overrides[graph_id] = graph_text; + if (!persist_geometry_overrides(state)) { + if (!had_previous) state->geometry_node_graph_overrides.erase(graph_id); + else state->geometry_node_graph_overrides[graph_id] = previous_text; + error = "GN_INVALID_GRAPH: Geometry Node graph could not be persisted in Main"; + return false; + } return true; } catch (const std::exception &exception) { @@ -4508,7 +4591,12 @@ bool web_engine_blend_main_set_physics_simulation(WebBlendMainState *state, return false; } } - state->physics_simulation_override = manifest.dump(); + const std::string manifest_text = manifest.dump(); + if (!write_text(state->main, WEB_ENGINE_PHYSICS_OVERRIDE_TEXT, manifest_text)) { + error = "PHYSICS_MANIFEST_INVALID: physics manifest could not be persisted in Main"; + return false; + } + state->physics_simulation_override = manifest_text; return true; } catch (const std::exception &exception) { diff --git a/docs/status/WBV2-P27-002.md b/docs/status/WBV2-P27-002.md index b5008ffbe..eec08b900 100644 --- a/docs/status/WBV2-P27-002.md +++ b/docs/status/WBV2-P27-002.md @@ -3,7 +3,6 @@ - task: `WBV2-P27-002`; parent: `WBV2-P27-001`; status: `in_progress` - source prerequisite: `PASS`; Blender 5.2.0 `web_engine` compiled from `blender-5.2.0` with local Emscripten 3.1.69 - compiled artifacts copied to `web/app/src/vendor/blender/` and `web/app/public/vendor/blender/` -- application package rebuilt with `web_engine-C1wwLZyc.wasm` and `web-engine.worker-C3G0ZxMq.js` - build command exit: `0`; log: `tests/golden/WBV2-P27-002/source-build.log` - Chromium production receipt, malformed/transaction/persistence/determinism verification: `DEFERRED_BY_IMPLEMENTATION_FIRST_MODE` - inventory unchanged: `6900` total, `281` legacy completed, `6618` legacy pending, `290/6609` effective carried forward diff --git a/tests/golden/WBV2-P27-002/source-build-report.json b/tests/golden/WBV2-P27-002/source-build-report.json index 4ae987c58..a8f80bbca 100644 --- a/tests/golden/WBV2-P27-002/source-build-report.json +++ b/tests/golden/WBV2-P27-002/source-build-report.json @@ -25,7 +25,7 @@ }, "sourceMainState": { "path": "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", - "sha256": "f48e424f53969cf2d9bce3ad9be565179d415301739f07785a1ed3271e430307" + "sha256": "dace3c17f47a2c267ed9a0dec649ec5fe3091873c99e0f1824d24b94f25e9127" }, "sourceMainHeader": { "path": "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", @@ -37,7 +37,7 @@ }, "wasm": { "path": "web/app/src/vendor/blender/web_engine.wasm", - "sha256": "7981e66ccc37f3183c8c6244a667de6a2a2b39aa6934c9cefc280ea93773ccda" + "sha256": "08a5caccd99f9d51221d0a0adea3db1a57ab5d2718b6b026dc7f4af096054d07" }, "publicLoader": { "path": "web/app/public/vendor/blender/web_engine.js", @@ -45,19 +45,19 @@ }, "publicWasm": { "path": "web/app/public/vendor/blender/web_engine.wasm", - "sha256": "7981e66ccc37f3183c8c6244a667de6a2a2b39aa6934c9cefc280ea93773ccda" + "sha256": "08a5caccd99f9d51221d0a0adea3db1a57ab5d2718b6b026dc7f4af096054d07" }, "webDistIndex": { "path": "web/dist/index.html", - "sha256": "f63ea65367e10bea54c4d10428c2401db6d2aca9006c18692ced5e55b0e1527f" + "sha256": "6987bd43643d2c9f8abef1db4abab4df76e5a4acf567f374a01e073d9c410bff" }, "webDistWorker": { - "path": "web/dist/assets/web-engine.worker-C3G0ZxMq.js", - "sha256": "b9083c4a38c16ba9ece02cb87c3c1a37cbea458b39db514c3abb8bd276ff9ff1" + "path": "web/dist/assets/web-engine.worker-Bm3nUTqn.js", + "sha256": "de3fcef592876e81b572dcc9e3d2118f4089e6170939310974d64866f493490b" }, "webDistWasm": { - "path": "web/dist/assets/web_engine-C1wwLZyc.wasm", - "sha256": "7981e66ccc37f3183c8c6244a667de6a2a2b39aa6934c9cefc280ea93773ccda" + "path": "web/dist/assets/web_engine-CDU-hUyU.wasm", + "sha256": "08a5caccd99f9d51221d0a0adea3db1a57ab5d2718b6b026dc7f4af096054d07" } }, "verification": { diff --git a/tests/golden/WBV2-P27-002/source-build.log b/tests/golden/WBV2-P27-002/source-build.log index 964c94da0..b1303b23d 100644 --- a/tests/golden/WBV2-P27-002/source-build.log +++ b/tests/golden/WBV2-P27-002/source-build.log @@ -1 +1,26 @@ -ninja: no work to do. +[1/3] Building CXX object source/blender/web_engine/CMakeFiles/blender_web_engine_core.dir/web_engine_main_state.cpp.o +In file included from /home/mes123456/workinf_Blender_Wasm/blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp:35: +In file included from /home/mes123456/workinf_Blender_Wasm/blender-5.2.0/source/blender/blenkernel/BKE_node.hh:20: +In file included from /home/mes123456/workinf_Blender_Wasm/blender-5.2.0/source/blender/makesdna/DNA_node_types.h:15: +In file included from /home/mes123456/workinf_Blender_Wasm/blender-5.2.0/source/blender/makesdna/DNA_scene_types.h:35: +/home/mes123456/workinf_Blender_Wasm/blender-5.2.0/source/blender/makesdna/DNA_view3d_types.h:126:26: warning: implicit conversion from 'int' to 'char' changes value from 128 to -128 [-Wconstant-conversion] + 126 | RV3D_VIEWLOCK_INIT = 1 << 7, + | ~~^~~~ +In file included from /home/mes123456/workinf_Blender_Wasm/blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp:35: +In file included from /home/mes123456/workinf_Blender_Wasm/blender-5.2.0/source/blender/blenkernel/BKE_node.hh:20: +In file included from /home/mes123456/workinf_Blender_Wasm/blender-5.2.0/source/blender/makesdna/DNA_node_types.h:15: +/home/mes123456/workinf_Blender_Wasm/blender-5.2.0/source/blender/makesdna/DNA_scene_types.h:2053:33: warning: implicit conversion from 'int' to 'char' changes value from 128 to -128 [-Wconstant-conversion] + 2053 | UVCALC_UNWRAP_USE_WEIGHTS = 1 << 7, + | ~~^~~~ +/home/mes123456/workinf_Blender_Wasm/blender-5.2.0/source/blender/makesdna/DNA_scene_types.h:2324:25: warning: implicit conversion from 'blender::eSnapMode' to 'char' changes value from 128 to -128 [-Wconstant-conversion] + 2324 | char snap_node_mode = SCE_SNAP_TO_GRID; + | ^~~~~~~~~~~~~~~~ +/home/mes123456/workinf_Blender_Wasm/blender-5.2.0/source/blender/makesdna/DNA_scene_types.h:2324:25: warning: implicit conversion from 'blender::eSnapMode' to 'char' changes value from 128 to -128 [-Wconstant-conversion] + 2324 | char snap_node_mode = SCE_SNAP_TO_GRID; + | ^~~~~~~~~~~~~~~~ +/home/mes123456/workinf_Blender_Wasm/blender-5.2.0/source/blender/makesdna/DNA_scene_types.h:2200:26: note: in defaulted default constructor for 'blender::ToolSettings' first required here + 2200 | DNA_DEFINE_CXX_METHODS(ToolSettings) + | ^ +4 warnings generated. +[2/3] Linking CXX static library lib/libblender_web_engine_core.a +[3/3] Linking CXX executable bin/web_engine.js diff --git a/tools/web/record-wbv2-source-build.mjs b/tools/web/record-wbv2-source-build.mjs index b15cc7706..7bdcfa862 100644 --- a/tools/web/record-wbv2-source-build.mjs +++ b/tools/web/record-wbv2-source-build.mjs @@ -13,10 +13,15 @@ const buildDir = "build_web_blender6"; const jsPath = "web/app/src/vendor/blender/web_engine.js"; const wasmPath = "web/app/src/vendor/blender/web_engine.wasm"; const logPath = `${out}/source-build.log`; +const distAssets = fs.readdirSync(abs("web/dist/assets")); +const distWorker = distAssets.find((file) => /^web-engine\.worker-.*\.js$/u.test(file)); +const distWasm = distAssets.find((file) => /^web_engine-.*\.wasm$/u.test(file)); assert.ok(fs.existsSync(abs(`${buildDir}/bin/web_engine.js`))); assert.ok(fs.existsSync(abs(`${buildDir}/bin/web_engine.wasm`))); assert.equal(sha(`${buildDir}/bin/web_engine.js`), sha(jsPath)); assert.equal(sha(`${buildDir}/bin/web_engine.wasm`), sha(wasmPath)); +assert.ok(distWorker); +assert.ok(distWasm); const report = { schemaVersion: 1, task: "WBV2-P27-002", @@ -41,6 +46,9 @@ const report = { wasm: { path: wasmPath, sha256: sha(wasmPath) }, publicLoader: { path: "web/app/public/vendor/blender/web_engine.js", sha256: sha("web/app/public/vendor/blender/web_engine.js") }, publicWasm: { path: "web/app/public/vendor/blender/web_engine.wasm", sha256: sha("web/app/public/vendor/blender/web_engine.wasm") }, + webDistIndex: { path: "web/dist/index.html", sha256: sha("web/dist/index.html") }, + webDistWorker: { path: `web/dist/assets/${distWorker}`, sha256: sha(`web/dist/assets/${distWorker}`) }, + webDistWasm: { path: `web/dist/assets/${distWasm}`, sha256: sha(`web/dist/assets/${distWasm}`) }, }, verification: { chromium: "DEFERRED", productionReceipts: false, malformedBoundary: false, undoRedo: false, saveReopen: false, deterministicSecondRun: false, completionOverlay: false }, inventory: { total: 6900, legacyCompleted: 281, legacyPending: 6618, effectiveCompleted: 290, effectivePending: 6609 }, diff --git a/web/app/public/vendor/blender/web_engine.wasm b/web/app/public/vendor/blender/web_engine.wasm index b9b9e217a..19bd1840d 100644 Binary files a/web/app/public/vendor/blender/web_engine.wasm and b/web/app/public/vendor/blender/web_engine.wasm differ diff --git a/web/app/src/vendor/blender/web_engine.wasm b/web/app/src/vendor/blender/web_engine.wasm index b9b9e217a..19bd1840d 100644 Binary files a/web/app/src/vendor/blender/web_engine.wasm and b/web/app/src/vendor/blender/web_engine.wasm differ