Advance N-015 through N-018 bounded workflows

This commit is contained in:
mes123456
2026-08-12 17:14:27 -04:00
parent 86136139e2
commit d54d5dd913
30 changed files with 662 additions and 59 deletions

View File

@@ -829,6 +829,13 @@ bool refresh_scene_from_main(EngineState &engine,
return false;
}
snapshot["greasePencils"] = json::parse(grease_pencils_json);
std::string physics_json;
if (!web_engine_blend_main_physics_simulation_json(
engine.authoritative_main, physics_json, error))
{
return false;
}
snapshot["physicsSimulation"] = json::parse(physics_json);
if (!active_object_id.empty()) snapshot["activeObjectId"] = active_object_id;
engine.blend_bytes.assign(reinterpret_cast<const char *>(bytes.data()), bytes.size());
engine.packed_assets = parsed.packed_assets;
@@ -1125,6 +1132,15 @@ EMSCRIPTEN_KEEPALIVE int web_engine_open_blend(const int handle,
return last_error_code;
}
opened_snapshot["greasePencils"] = json::parse(grease_pencils_json);
std::string physics_json;
if (!web_engine_blend_main_physics_simulation_json(
authoritative_main, physics_json, main_error))
{
web_engine_blend_main_free(authoritative_main);
set_error(WEB_ENGINE_BLEND_READ_FAILED, main_error.c_str());
return last_error_code;
}
opened_snapshot["physicsSimulation"] = json::parse(physics_json);
}
catch (const std::exception &exception) {
web_engine_blend_main_free(authoritative_main);
@@ -1173,6 +1189,13 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
const json command = json::parse(reinterpret_cast<const char *>(data),
reinterpret_cast<const char *>(data) + length);
const std::string type = command.value("type", "");
if (command.contains("baseRevision") &&
(!command["baseRevision"].is_number_unsigned() ||
command["baseRevision"].get<uint64_t>() != engine->revision))
{
set_error(WEB_ENGINE_INVALID_ARGUMENT, "REVISION_CONFLICT: command base revision does not match the current SceneIR");
return last_error_code;
}
const std::string previous_snapshot = engine->scene_snapshot.empty() ?
std::string(empty_scene_snapshot_json()) :
engine->scene_snapshot;

View File

@@ -3913,6 +3913,11 @@ json scene_ir_from_blend(const ParsedBlend &blend,
} // namespace
std::string web_engine_sha256_hex(const std::string &value)
{
return sha256_hex(value);
}
WebBlendReadResult web_engine_read_blend_scene_ir(const uint8_t *data,
const uint32_t length,
const uint64_t revision)

View File

@@ -16,3 +16,5 @@ struct WebBlendReadResult {
WebBlendReadResult web_engine_read_blend_scene_ir(const uint8_t *data,
uint32_t length,
uint64_t revision);
std::string web_engine_sha256_hex(const std::string &value);

View File

@@ -1,4 +1,5 @@
#include "web_engine_main_state.h"
#include "web_engine_blend_reader.h"
#include <algorithm>
#include <array>
@@ -60,7 +61,10 @@
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_world_types.h"
#include "DNA_userdef_enums.h"
@@ -3641,6 +3645,122 @@ bool web_engine_blend_main_grease_pencils_json(WebBlendMainState *state,
return true;
}
bool web_engine_blend_main_physics_simulation_json(WebBlendMainState *state,
std::string &physics_json,
std::string &error)
{
if (state == nullptr || state->main == nullptr) {
error = "PHYSICS_MANIFEST_INVALID: authoritative Main is not open";
return false;
}
constexpr size_t max_systems = 4096;
auto canonical_number = [](const float value) -> json {
return std::isfinite(value) && std::trunc(value) == value ? json(int64_t(value)) : json(value);
};
json systems = json::array();
json collider_ids = json::array();
for (const Object &object : state->main->objects) {
for (const ModifierData *modifier = static_cast<const ModifierData *>(object.modifiers.first);
modifier != nullptr;
modifier = modifier->next)
{
if (modifier->type == eModifierType_Collision) {
collider_ids.push_back("object:" + id_name(object.id));
break;
}
}
}
auto append_system = [&](const std::string &id,
const char *family,
const Object &object,
json settings,
json dependencies = json::array()) -> bool {
if (systems.size() >= max_systems) {
error = "PHYSICS_BUDGET_EXCEEDED: Physics system count exceeds the 4096 system budget";
return false;
}
systems.push_back({{"id", id},
{"family", family},
{"ownerObjectId", "object:" + id_name(object.id)},
{"settingsHash", web_engine_sha256_hex(settings.dump())},
{"settings", std::move(settings)},
{"dependencyIds", std::move(dependencies)}});
return true;
};
for (const Object &object : state->main->objects) {
const std::string object_name = id_name(object.id);
if (object.rigidbody_object != nullptr) {
const RigidBodyOb &body = *object.rigidbody_object;
if (!append_system("physics:rigid-body:" + object_name,
"RIGID_BODY",
object,
{{"type", int(body.type)},
{"shape", int(body.shape)},
{"flags", int(body.flag)},
{"mass", canonical_number(body.mass)},
{"friction", canonical_number(body.friction)},
{"restitution", canonical_number(body.restitution)},
{"margin", canonical_number(body.margin)},
{"linearDamping", canonical_number(body.lin_damping)},
{"angularDamping", canonical_number(body.ang_damping)}})) return false;
}
if (object.soft != nullptr) {
const SoftBody &soft = *object.soft;
if (!append_system("physics:soft-body:" + object_name,
"SOFT_BODY",
object,
{{"nodeMass", canonical_number(soft.nodemass)},
{"gravity", canonical_number(soft.grav)},
{"mediaFriction", canonical_number(soft.mediafrict)},
{"physicsSpeed", canonical_number(soft.physics_speed)},
{"goalSpring", canonical_number(soft.goalspring)},
{"goalFriction", canonical_number(soft.goalfrict)},
{"solverFlags", int(soft.solverflags)}},
collider_ids)) return false;
}
for (const ModifierData *modifier = static_cast<const ModifierData *>(object.modifiers.first);
modifier != nullptr;
modifier = modifier->next)
{
const std::string suffix = object_name + ":" + std::to_string(modifier->persistent_uid);
json settings = {{"name", modifier->name},
{"persistentUid", modifier->persistent_uid},
{"enabled", bool(modifier->mode & eModifierMode_Realtime)},
{"showRender", bool(modifier->mode & eModifierMode_Render)}};
if (modifier->type == eModifierType_Cloth) {
if (!append_system("physics:cloth:" + suffix, "CLOTH", object, std::move(settings), collider_ids)) return false;
}
else if (modifier->type == eModifierType_Fluid) {
const FluidModifierData &fluid = *reinterpret_cast<const FluidModifierData *>(modifier);
settings["modifierType"] = int(fluid.type);
if (!append_system("physics:fluid:" + suffix, "FLUID", object, std::move(settings))) return false;
}
else if (modifier->type == eModifierType_DynamicPaint) {
const DynamicPaintModifierData &paint = *reinterpret_cast<const DynamicPaintModifierData *>(modifier);
settings["modifierType"] = int(paint.type);
if (!append_system("physics:dynamic-paint:" + suffix, "DYNAMIC_PAINT", object, std::move(settings))) return false;
}
else if (modifier->type == eModifierType_ParticleSystem) {
const ParticleSystemModifierData &particle = *reinterpret_cast<const ParticleSystemModifierData *>(modifier);
const bool hair = particle.psys != nullptr && particle.psys->part != nullptr && particle.psys->part->type == PART_HAIR;
if (particle.psys != nullptr) {
settings["seed"] = particle.psys->seed;
settings["particleCount"] = particle.psys->totpart;
if (particle.psys->part != nullptr) {
settings["particleType"] = int(particle.psys->part->type);
settings["physicsType"] = int(particle.psys->part->phystype);
}
}
if (!append_system("physics:" + std::string(hair ? "hair:" : "particle:") + suffix,
hair ? "HAIR" : "PARTICLE", object, std::move(settings))) return false;
}
}
}
physics_json = json({{"schemaVersion", 1}, {"systems", std::move(systems)}}).dump();
return true;
}
bool web_engine_blend_main_create_grease_pencil_layer(WebBlendMainState *state,
const char *data_id,
const char *name,

View File

@@ -348,6 +348,9 @@ bool web_engine_blend_main_set_metaball_elements(WebBlendMainState *state,
bool web_engine_blend_main_grease_pencils_json(WebBlendMainState *state,
std::string &grease_pencils_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_create_grease_pencil_layer(WebBlendMainState *state,
const char *data_id,
const char *name,