Complete internal submodule smoke closure
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-09-07 12:58:28 +08:00
parent f87a72732c
commit b940b8bac8
30 changed files with 4176 additions and 17 deletions

View File

@@ -128,6 +128,7 @@ target_link_options(web_engine PRIVATE
"-sUSE_FREETYPE=1"
"-sENVIRONMENT=web,node,worker"
"-sALLOW_MEMORY_GROWTH=1"
"-sNO_DISABLE_EXCEPTION_CATCHING=1"
"-sINITIAL_MEMORY=67108864"
"-sMAXIMUM_MEMORY=2147483648"
"-sSTACK_SIZE=8388608"

View File

@@ -1744,6 +1744,9 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
type == "assignMaterialFaces" || type == "setMaterialPrincipled" ||
type == "importImage" || type == "setMaterialImageNode" || type == "setShaderGraph" ||
type == "setGeometryNodeGraph" || type == "setPhysicsSimulation" ||
type == "setRigidBodySettings" || type == "setClothSettings" ||
type == "setFluidSettings" || type == "setParticleCache" ||
type == "setSimulationPlayback" ||
type == "insertObjectKeyframe" || type == "deleteObjectKeyframe" ||
type == "createAction" || type == "removeAction" || type == "setKeyframe" || type == "setFCurveKeyframes" ||
type == "setDriverExpression" || type == "setActionGroups" || type == "setKeyingSet" || type == "bakeAnimation" || type == "setTimelineMarkers" ||
@@ -1764,7 +1767,8 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
type == "setGreasePencilStrokes" || type == "setGreasePencilDrawing" ||
type == "setGreasePencilMaterial" || type == "setGreasePencilSelection" ||
type == "setGreasePencilInterpolate" || type == "setVertexColors" ||
type == "setVertexWeights" || type == "setCameraProperties" || type == "setLightProperties" ||
type == "setVertexWeights" || type == "setCameraProperties" || type == "setCameraView" ||
type == "setLightProperties" || type == "setRenderPasses" ||
type == "setWorldProperties" || type == "renderFrame" || type == "renderAnimation" || type == "setSceneProperties" || type == "setSceneRenderSettings" || type == "setSceneAudioSettings" || type == "setSceneUnitSettings" || type == "setSceneTimelineSettings" || type == "setScenePipelineSettings" || type == "setSceneBindings" || type == "setSceneViewLayerSettings" || type == "setSceneCollectionSettings" || type == "setSceneBorderSettings" || type == "setSceneSimplifySettings" || type == "setSceneColorManagement" || type == "setSceneImageFormat" || type == "setSceneMotionBlur" || type == "setSceneHairSettings" || type == "setSceneCompositorSettings" || type == "setScenePerformanceSettings" || type == "setSceneSamplingSettings" || type == "setSceneMultiviewSettings" || type == "setSceneStampSettings" || type == "setSceneLineSettings" || type == "setSceneViewLayerPassSettings" || type == "setSceneViewLayerAOVs" || type == "setSceneViewLayerLightgroups" || type == "setTrackingMarkers" || type == "setTrackingSolve" || type == "setMaskSpline" || type == "setMaskPoint" || type == "clearObjectTransform" || type == "createObjectData" || type == "setObjectSelection" || type == "setCollectionVisibility" || type == "setObjectLightgroup" || type == "setWorldLightgroup" || type == "setLightLinking" ||
type == "setSculptMeshAttributes" ||
type == "sculptStroke") {
@@ -1885,6 +1889,23 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
applied = web_engine_blend_main_set_physics_simulation(
engine->authoritative_main, manifest.dump().c_str(), main_error);
}
else if (type == "setRigidBodySettings" || type == "setClothSettings" ||
type == "setFluidSettings" || type == "setParticleCache")
{
const std::string family = type == "setRigidBodySettings" ?
command.value("family", "RIGID_BODY") :
type == "setClothSettings" ? "CLOTH" :
type == "setFluidSettings" ? "FLUID" : "PARTICLE";
const json settings = command.value("settings", json::object());
applied = web_engine_blend_main_patch_physics_settings(
engine->authoritative_main, command.value("objectId", "").c_str(), family.c_str(),
settings.dump().c_str(), main_error);
}
else if (type == "setSimulationPlayback") {
const json settings = command.value("settings", json::object());
applied = web_engine_blend_main_set_simulation_playback(
engine->authoritative_main, settings.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", "");

View File

@@ -5832,6 +5832,11 @@ std::string web_engine_sha256_hex(const std::string &value)
return sha256_hex(value);
}
std::string web_engine_modifier_type_name(const int64_t type)
{
return modifier_type_name(type);
}
WebBlendReadResult web_engine_read_blend_scene_ir(const uint8_t *data,
const uint32_t length,
const uint64_t revision)

View File

@@ -18,3 +18,4 @@ WebBlendReadResult web_engine_read_blend_scene_ir(const uint8_t *data,
uint64_t revision);
std::string web_engine_sha256_hex(const std::string &value);
std::string web_engine_modifier_type_name(int64_t type);

View File

@@ -138,6 +138,7 @@ template<typename T> struct WebListWrapper {
#include "SEQ_add.hh"
#include "SEQ_edit.hh"
#include "SEQ_relations.hh"
#include "SEQ_sequencer.hh"
#include "SEQ_utils.hh"
@@ -662,6 +663,7 @@ constexpr char WEB_ENGINE_GEOMETRY_OVERRIDE_PROPERTY[] = "web_geometry_node_grap
constexpr char WEB_ENGINE_GEOMETRY_GRAPH_PROPERTY[] = "web_geometry_node_graph";
constexpr char WEB_ENGINE_PHYSICS_OVERRIDE_TEXT[] = "WBV2 Physics Simulation Override";
constexpr char WEB_ENGINE_PHYSICS_OVERRIDE_PROPERTY[] = "web_physics_simulation_override";
constexpr char WEB_ENGINE_PHYSICS_PLAYBACK_PROPERTY[] = "web_physics_simulation_playback";
constexpr char WEB_ENGINE_MEDIA_RETENTION_TEXT[] = "WBV2 Media Datablock Retention";
std::string text_contents(Text &text)
@@ -1869,7 +1871,9 @@ bool web_engine_blend_main_add_modifier(WebBlendMainState *state,
ModifierType type = eModifierType_None;
for (int candidate = eModifierType_None + 1; candidate < NUM_MODIFIER_TYPES; candidate++) {
const ModifierTypeInfo *info = BKE_modifier_get_info(ModifierType(candidate));
if (info != nullptr && STREQ(info->idname, modifier_type)) {
if (info != nullptr && (STREQ(info->idname, modifier_type) ||
web_engine_modifier_type_name(candidate) == modifier_type))
{
type = ModifierType(candidate);
break;
}
@@ -7710,6 +7714,126 @@ bool web_engine_blend_main_set_physics_simulation(WebBlendMainState *state,
}
}
bool web_engine_blend_main_patch_physics_settings(WebBlendMainState *state,
const char *owner_object_id,
const char *family,
const char *settings_json,
std::string &error)
{
if (state == nullptr || state->main == nullptr || owner_object_id == nullptr || family == nullptr ||
settings_json == nullptr)
{
error = "PHYSICS_MANIFEST_INVALID: physics settings require an open Main, owner, family and settings";
return false;
}
try {
Object *owner = find_object(state->main, owner_object_id);
const std::string family_name(family);
const std::array<const char *, 7> families = {
"RIGID_BODY", "SOFT_BODY", "CLOTH", "FLUID", "DYNAMIC_PAINT", "PARTICLE", "HAIR"};
const json patch = json::parse(settings_json);
if (owner == nullptr || std::find(families.begin(), families.end(), family_name) == families.end() ||
!patch.is_object() || patch.empty() || patch.size() > 256 || patch.dump().size() > 64 * 1024)
{
error = "PHYSICS_MANIFEST_INVALID: physics owner, family or settings are invalid";
return false;
}
for (const auto &[key, value] : patch.items()) {
if (key.empty() || key.size() > 128 ||
!(value.is_null() || value.is_boolean() || value.is_string() ||
(value.is_number() && std::isfinite(value.get<double>()))))
{
error = "PHYSICS_MANIFEST_INVALID: physics settings must contain bounded scalar values";
return false;
}
}
std::string manifest_json;
if (!web_engine_blend_main_physics_simulation_json(state, manifest_json, error)) return false;
json manifest = json::parse(manifest_json);
json *target = nullptr;
for (json &system : manifest["systems"]) {
const std::string system_family = system.value("family", "");
const bool family_matches = system_family == family_name ||
(family_name == "PARTICLE" && system_family == "HAIR");
if (family_matches && system.value("ownerObjectId", "") == owner_object_id) {
target = &system;
break;
}
}
if (target == nullptr) {
std::string slug = family_name;
std::transform(slug.begin(), slug.end(), slug.begin(), [](const unsigned char character) {
return character == '_' ? '-' : char(std::tolower(character));
});
manifest["systems"].push_back({{"id", "physics:" + slug + ":" + id_name(owner->id)},
{"family", family_name},
{"ownerObjectId", owner_object_id},
{"settingsHash", std::string(64, '0')},
{"settings", json::object()},
{"dependencyIds", json::array()}});
target = &manifest["systems"].back();
}
json &settings = (*target)["settings"];
for (const auto &[key, value] : patch.items()) settings[key] = value;
(*target)["settingsHash"] = web_engine_sha256_hex(settings.dump());
target->erase("cache");
return web_engine_blend_main_set_physics_simulation(state, manifest.dump().c_str(), error);
}
catch (const std::exception &exception) {
error = std::string("PHYSICS_MANIFEST_INVALID: physics settings JSON is invalid: ") + exception.what();
return false;
}
}
bool web_engine_blend_main_set_simulation_playback(WebBlendMainState *state,
const char *settings_json,
std::string &error)
{
if (state == nullptr || state->scene == nullptr || settings_json == nullptr) {
error = "PHYSICS_PLAYBACK_INVALID: simulation playback requires an open Main and settings";
return false;
}
try {
const json settings = json::parse(settings_json);
if (!settings.is_object() || settings.empty()) {
error = "PHYSICS_PLAYBACK_INVALID: simulation playback settings are empty";
return false;
}
const std::array<const char *, 4> allowed = {"frame", "playing", "direction", "reset"};
for (const auto &[key, value] : settings.items()) {
if (std::find(allowed.begin(), allowed.end(), key) == allowed.end()) {
error = "PHYSICS_PLAYBACK_INVALID: simulation playback contains an unsupported setting";
return false;
}
}
if ((settings.contains("frame") && (!settings["frame"].is_number_integer() ||
settings["frame"].get<int64_t>() < -1000000 ||
settings["frame"].get<int64_t>() > 1000000)) ||
(settings.contains("playing") && !settings["playing"].is_boolean()) ||
(settings.contains("reset") && !settings["reset"].is_boolean()) ||
(settings.contains("direction") && (!settings["direction"].is_number_integer() ||
std::abs(settings["direction"].get<int>()) != 1)))
{
error = "PHYSICS_PLAYBACK_INVALID: simulation playback settings are outside the bounded range";
return false;
}
const bool reset = settings.value("reset", false);
const int frame = reset ? state->scene->r.sfra : settings.value("frame", state->scene->r.cfra);
if (!web_engine_blend_main_set_frame(state, frame, error)) return false;
if (!write_id_string(state->scene->id, WEB_ENGINE_PHYSICS_PLAYBACK_PROPERTY, settings.dump())) {
error = "PHYSICS_PLAYBACK_INVALID: simulation playback metadata could not be persisted";
return false;
}
state->scene->id.recalc |= ID_RECALC_PARAMETERS;
return true;
}
catch (const std::exception &exception) {
error = std::string("PHYSICS_PLAYBACK_INVALID: simulation playback 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)

View File

@@ -636,6 +636,14 @@ bool web_engine_blend_main_physics_simulation_json(WebBlendMainState *state,
bool web_engine_blend_main_set_physics_simulation(WebBlendMainState *state,
const char *manifest_json,
std::string &error);
bool web_engine_blend_main_patch_physics_settings(WebBlendMainState *state,
const char *owner_object_id,
const char *family,
const char *settings_json,
std::string &error);
bool web_engine_blend_main_set_simulation_playback(WebBlendMainState *state,
const char *settings_json,
std::string &error);
bool web_engine_blend_main_particle_settings_json(WebBlendMainState *state,
std::string &particle_settings_json,
std::string &error);