Advance N-015 through N-018 bounded workflows
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user