feat(web): continue scene pipeline authoring wave
This commit is contained in:
@@ -1592,7 +1592,7 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
|
||||
type == "insertGreasePencilFrame" || type == "removeGreasePencilFrame" ||
|
||||
type == "setGreasePencilStrokes" || type == "setVertexColors" ||
|
||||
type == "setVertexWeights" || type == "setCameraProperties" || type == "setLightProperties" ||
|
||||
type == "setWorldProperties" || type == "setSceneProperties" || type == "setSceneRenderSettings" || type == "setSceneAudioSettings" || type == "setSceneUnitSettings" ||
|
||||
type == "setWorldProperties" || type == "setSceneProperties" || type == "setSceneRenderSettings" || type == "setSceneAudioSettings" || type == "setSceneUnitSettings" || type == "setSceneTimelineSettings" || type == "setScenePipelineSettings" ||
|
||||
type == "setSculptMeshAttributes" ||
|
||||
type == "sculptStroke") {
|
||||
if (!engine->authoritative_commands || engine->authoritative_main == nullptr) {
|
||||
@@ -2196,7 +2196,7 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
|
||||
command.value("normalize", false), command.value("limit", 0u), command.value("mirror", false),
|
||||
command.value("mirrorAxis", 0), command.value("mirrorTolerance", 1e-4f), main_error);
|
||||
}
|
||||
else if (type == "setCameraProperties" || type == "setLightProperties" || type == "setWorldProperties" || type == "setSceneProperties" || type == "setSceneRenderSettings" || type == "setSceneAudioSettings" || type == "setSceneUnitSettings")
|
||||
else if (type == "setCameraProperties" || type == "setLightProperties" || type == "setWorldProperties" || type == "setSceneProperties" || type == "setSceneRenderSettings" || type == "setSceneAudioSettings" || type == "setSceneUnitSettings" || type == "setSceneTimelineSettings" || type == "setScenePipelineSettings")
|
||||
{
|
||||
const json properties = command.value("properties", json::object());
|
||||
if (type == "setSceneProperties") {
|
||||
@@ -2219,6 +2219,16 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
|
||||
engine->authoritative_main, command.value("dataId", "").c_str(),
|
||||
properties.dump().c_str(), main_error);
|
||||
}
|
||||
else if (type == "setSceneTimelineSettings") {
|
||||
applied = web_engine_blend_main_set_scene_timeline_settings(
|
||||
engine->authoritative_main, command.value("dataId", "").c_str(),
|
||||
properties.dump().c_str(), main_error);
|
||||
}
|
||||
else if (type == "setScenePipelineSettings") {
|
||||
applied = web_engine_blend_main_set_scene_pipeline_settings(
|
||||
engine->authoritative_main, command.value("dataId", "").c_str(),
|
||||
properties.dump().c_str(), main_error);
|
||||
}
|
||||
else {
|
||||
applied = web_engine_blend_main_set_render_properties(
|
||||
engine->authoritative_main, command.value("dataId", "").c_str(),
|
||||
|
||||
@@ -5255,6 +5255,19 @@ json scene_ir_from_blend(const ParsedBlend &blend,
|
||||
{"frameStart", frame_start},
|
||||
{"frameEnd", frame_end},
|
||||
{"outputPath", read_string(*blend.sdna, *render, "pic")}};
|
||||
scene["timelineSettings"] = {{"fps", read_integer(*blend.sdna, *render, "frs_sec").value_or(24)},
|
||||
{"fpsBase", read_float(*blend.sdna, *render, "frs_sec_base").value_or(1.0f)},
|
||||
{"frameStep", read_integer(*blend.sdna, *render, "frame_step").value_or(1)},
|
||||
{"usePreviewRange", (read_integer(*blend.sdna, *render, "flag").value_or(0) & SCER_PRV_RANGE) != 0},
|
||||
{"previewStart", read_integer(*blend.sdna, *render, "psfra").value_or(frame_start)},
|
||||
{"previewEnd", read_integer(*blend.sdna, *render, "pefra").value_or(frame_end)}};
|
||||
const int64_t scene_mode = read_integer(*blend.sdna, *render, "scemode").value_or(0);
|
||||
const int64_t render_mode = read_integer(*blend.sdna, *render, "mode").value_or(0);
|
||||
scene["pipelineSettings"] = {{"useCompositor", (scene_mode & R_DOCOMP) != 0},
|
||||
{"useSequencer", (scene_mode & R_DOSEQ) != 0},
|
||||
{"noOverwrite", (render_mode & R_NO_OVERWRITE) != 0},
|
||||
{"saveOutput", (render_mode & R_SAVE_OUTPUT) != 0},
|
||||
{"alphaPremultiplied", read_integer(*blend.sdna, *render, "alphamode").value_or(0) == R_ALPHAPREMUL}};
|
||||
const int64_t render_flags = read_integer(*blend.sdna, *render, "flag").value_or(0);
|
||||
if ((render_flags & SCER_PRV_RANGE) != 0) {
|
||||
scene["previewRange"] = {{"start", read_integer(*blend.sdna, *render, "psfra").value_or(frame_start)},
|
||||
|
||||
@@ -5984,6 +5984,135 @@ bool web_engine_blend_main_set_scene_unit_settings(WebBlendMainState *state,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool web_engine_blend_main_set_scene_timeline_settings(WebBlendMainState *state,
|
||||
const char *target_id,
|
||||
const char *properties_json,
|
||||
std::string &error)
|
||||
{
|
||||
if (state == nullptr || state->main == nullptr || target_id == nullptr || properties_json == nullptr) {
|
||||
error = "RENDER_PROPERTY_INVALID: scene timeline target is missing";
|
||||
return false;
|
||||
}
|
||||
Scene *scene = find_scene(state->main, target_id);
|
||||
if (scene == nullptr || scene->id.lib != nullptr) {
|
||||
error = "LINKED_DATA_MUTATION_BLOCKED: Scene is not editable";
|
||||
return false;
|
||||
}
|
||||
const json properties = json::parse(properties_json, nullptr, false);
|
||||
if (!properties.is_object() || properties.empty()) {
|
||||
error = "RENDER_PROPERTY_INVALID: scene timeline settings must be a non-empty object";
|
||||
return false;
|
||||
}
|
||||
const std::unordered_set<std::string> allowed = {"fps", "fpsBase", "frameStep", "usePreviewRange", "previewStart", "previewEnd"};
|
||||
for (const auto &[key, value] : properties.items()) {
|
||||
(void)value;
|
||||
if (!allowed.contains(key)) {
|
||||
error = "RENDER_PROPERTY_INVALID: unsupported scene timeline property " + key;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const auto read_int = [&](const char *key, int minimum, int maximum, int &target) {
|
||||
if (!properties.contains(key)) return true;
|
||||
if (!properties[key].is_number_integer()) {
|
||||
error = std::string("RENDER_PROPERTY_INVALID: ") + key + " must be an integer";
|
||||
return false;
|
||||
}
|
||||
const int64_t value = properties[key].get<int64_t>();
|
||||
if (value < minimum || value > maximum) {
|
||||
error = std::string("RENDER_PROPERTY_INVALID: ") + key + " is outside the bounded range";
|
||||
return false;
|
||||
}
|
||||
target = int(value);
|
||||
return true;
|
||||
};
|
||||
int fps = scene->r.frs_sec;
|
||||
if (!read_int("fps", 1, 1000, fps) ||
|
||||
!read_int("frameStep", 1, 1000, scene->r.frame_step) ||
|
||||
!read_int("previewStart", -1000000, 1000000, scene->r.psfra) ||
|
||||
!read_int("previewEnd", -1000000, 1000000, scene->r.pefra)) {
|
||||
return false;
|
||||
}
|
||||
if (properties.contains("fpsBase")) {
|
||||
if (!properties["fpsBase"].is_number()) {
|
||||
error = "RENDER_PROPERTY_INVALID: fpsBase must be numeric";
|
||||
return false;
|
||||
}
|
||||
const float fps_base = properties["fpsBase"].get<float>();
|
||||
if (!std::isfinite(fps_base) || fps_base < 0.001f || fps_base > 100.0f) {
|
||||
error = "RENDER_PROPERTY_INVALID: fpsBase is outside the bounded range";
|
||||
return false;
|
||||
}
|
||||
scene->r.frs_sec_base = fps_base;
|
||||
}
|
||||
if (scene->r.pefra < scene->r.psfra) {
|
||||
error = "RENDER_PROPERTY_INVALID: previewEnd must not precede previewStart";
|
||||
return false;
|
||||
}
|
||||
scene->r.frs_sec = short(fps);
|
||||
if (properties.contains("usePreviewRange")) {
|
||||
if (!properties["usePreviewRange"].is_boolean()) {
|
||||
error = "RENDER_PROPERTY_INVALID: usePreviewRange must be boolean";
|
||||
return false;
|
||||
}
|
||||
if (properties["usePreviewRange"].get<bool>()) scene->r.flag |= SCER_PRV_RANGE;
|
||||
else scene->r.flag &= ~SCER_PRV_RANGE;
|
||||
}
|
||||
scene->id.recalc |= ID_RECALC_PARAMETERS;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool web_engine_blend_main_set_scene_pipeline_settings(WebBlendMainState *state,
|
||||
const char *target_id,
|
||||
const char *properties_json,
|
||||
std::string &error)
|
||||
{
|
||||
if (state == nullptr || state->main == nullptr || target_id == nullptr || properties_json == nullptr) {
|
||||
error = "RENDER_PROPERTY_INVALID: scene pipeline target is missing";
|
||||
return false;
|
||||
}
|
||||
Scene *scene = find_scene(state->main, target_id);
|
||||
if (scene == nullptr || scene->id.lib != nullptr) {
|
||||
error = "LINKED_DATA_MUTATION_BLOCKED: Scene is not editable";
|
||||
return false;
|
||||
}
|
||||
const json properties = json::parse(properties_json, nullptr, false);
|
||||
if (!properties.is_object() || properties.empty()) {
|
||||
error = "RENDER_PROPERTY_INVALID: scene pipeline settings must be a non-empty object";
|
||||
return false;
|
||||
}
|
||||
const std::unordered_set<std::string> allowed = {"useCompositor", "useSequencer", "noOverwrite", "saveOutput", "alphaPremultiplied"};
|
||||
for (const auto &[key, value] : properties.items()) {
|
||||
(void)value;
|
||||
if (!allowed.contains(key)) {
|
||||
error = "RENDER_PROPERTY_INVALID: unsupported scene pipeline property " + key;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const auto read_flag = [&](const char *key, int &target, int flag) {
|
||||
if (!properties.contains(key)) return true;
|
||||
if (!properties[key].is_boolean()) {
|
||||
error = std::string("RENDER_PROPERTY_INVALID: ") + key + " must be boolean";
|
||||
return false;
|
||||
}
|
||||
if (properties[key].get<bool>()) target |= flag;
|
||||
else target &= ~flag;
|
||||
return true;
|
||||
};
|
||||
if (!read_flag("useCompositor", scene->r.scemode, R_DOCOMP) ||
|
||||
!read_flag("useSequencer", scene->r.scemode, R_DOSEQ) ||
|
||||
!read_flag("noOverwrite", scene->r.mode, R_NO_OVERWRITE) ||
|
||||
!read_flag("saveOutput", scene->r.mode, R_SAVE_OUTPUT)) return false;
|
||||
if (properties.contains("alphaPremultiplied")) {
|
||||
if (!properties["alphaPremultiplied"].is_boolean()) {
|
||||
error = "RENDER_PROPERTY_INVALID: alphaPremultiplied must be boolean";
|
||||
return false;
|
||||
}
|
||||
scene->r.alphamode = properties["alphaPremultiplied"].get<bool>() ? R_ALPHAPREMUL : R_ADDSKY;
|
||||
}
|
||||
scene->id.recalc |= ID_RECALC_PARAMETERS;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool web_engine_blend_main_write(WebBlendMainState *state,
|
||||
std::vector<uint8_t> &bytes,
|
||||
std::string &error)
|
||||
|
||||
@@ -532,6 +532,14 @@ bool web_engine_blend_main_set_scene_unit_settings(WebBlendMainState *state,
|
||||
const char *target_id,
|
||||
const char *properties_json,
|
||||
std::string &error);
|
||||
bool web_engine_blend_main_set_scene_timeline_settings(WebBlendMainState *state,
|
||||
const char *target_id,
|
||||
const char *properties_json,
|
||||
std::string &error);
|
||||
bool web_engine_blend_main_set_scene_pipeline_settings(WebBlendMainState *state,
|
||||
const char *target_id,
|
||||
const char *properties_json,
|
||||
std::string &error);
|
||||
bool web_engine_blend_main_write(WebBlendMainState *state,
|
||||
std::vector<uint8_t> &bytes,
|
||||
std::string &error);
|
||||
|
||||
Reference in New Issue
Block a user