fix(web): synchronize WebEngine WASM with Blender sources
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 11:33:34 +08:00
parent e3677bd2a1
commit d5e736b80d
20 changed files with 423 additions and 134 deletions

View File

@@ -22,6 +22,24 @@ extern bool web_engine_blend_main_set_sequencer_strip_modifiers(WebBlendMainStat
extern bool web_engine_blend_main_set_sequencer_transitions(WebBlendMainState *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_sequencer_color_balance(WebBlendMainState *, const char *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_compositor_node_graph(WebBlendMainState *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_create_action(WebBlendMainState *, const char *, const char *, std::string &, std::string &);
extern bool web_engine_blend_main_remove_action(WebBlendMainState *, const char *, std::string &);
extern bool web_engine_blend_main_set_keyframe(WebBlendMainState *, const char *, const char *, int, const char *, const char *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_fcurve_keyframes(WebBlendMainState *, const char *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_driver_expression(WebBlendMainState *, const char *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_action_groups(WebBlendMainState *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_keying_set(WebBlendMainState *, const char *, const char *, const char *, bool, std::string &);
extern bool web_engine_blend_main_bake_animation(WebBlendMainState *, const char *, int, int, int, std::string &);
extern bool web_engine_blend_main_set_timeline_markers(WebBlendMainState *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_render_passes(WebBlendMainState *, const char *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_camera_view(WebBlendMainState *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_tracking_markers(WebBlendMainState *, const char *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_tracking_solve(WebBlendMainState *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_mask_spline(WebBlendMainState *, const char *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_mask_point(WebBlendMainState *, const char *, const char *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_light_linking(WebBlendMainState *, const char *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_list_macros(std::string &, std::string &);
extern bool web_engine_blend_main_prepare_macro(WebBlendMainState *, const char *, const char *, std::string &, std::string &);
bool web_engine_blend_main_set_sequencer_strips(WebBlendMainState *state,
const char *scene_id,
@@ -1306,15 +1324,6 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
set_error(WEB_ENGINE_BLEND_WRITE_FAILED, history_error.c_str());
return last_error_code;
}
extern bool web_engine_blend_main_create_action(WebBlendMainState *, const char *, const char *, std::string &, std::string &);
extern bool web_engine_blend_main_remove_action(WebBlendMainState *, const char *, std::string &);
extern bool web_engine_blend_main_set_keyframe(WebBlendMainState *, const char *, const char *, int, const char *, const char *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_fcurve_keyframes(WebBlendMainState *, const char *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_driver_expression(WebBlendMainState *, const char *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_action_groups(WebBlendMainState *, const char *, const char *, std::string &);
extern bool web_engine_blend_main_set_keying_set(WebBlendMainState *, const char *, const char *, const char *, bool, std::string &);
extern bool web_engine_blend_main_bake_animation(WebBlendMainState *, const char *, int, int, int, std::string &);
extern bool web_engine_blend_main_set_timeline_markers(WebBlendMainState *, const char *, const char *, std::string &);
if (type == "setFrame") {
if (!engine->authoritative_commands || engine->authoritative_main == nullptr) {
set_error(WEB_ENGINE_NOT_IMPLEMENTED,
@@ -2773,14 +2782,12 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
{
const json properties = command.value("properties", json::object());
if (type == "setRenderPasses") {
extern bool web_engine_blend_main_set_render_passes(WebBlendMainState *, const char *, const char *, const char *, std::string &);
applied = web_engine_blend_main_set_render_passes(engine->authoritative_main,
command.value("dataId", "").c_str(),
command.value("layerName", "").c_str(),
command.value("passes", json::object()).dump().c_str(), main_error);
}
else if (type == "setCameraView") {
extern bool web_engine_blend_main_set_camera_view(WebBlendMainState *, const char *, const char *, std::string &);
const json camera = command.value("cameraObjectId", json(nullptr));
const std::string camera_id = camera.is_null() ? std::string() : camera.is_string() ? camera.get<std::string>() : std::string("\x01");
applied = camera_id != "\x01" && web_engine_blend_main_set_camera_view(engine->authoritative_main,
@@ -2908,27 +2915,23 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
command.value("layerName", "").c_str(), command.value("lightgroups", json::array()).dump().c_str(), main_error);
}
else if (type == "setTrackingMarkers") {
extern bool web_engine_blend_main_set_tracking_markers(WebBlendMainState *, const char *, const char *, const char *, std::string &);
applied = web_engine_blend_main_set_tracking_markers(engine->authoritative_main,
command.value("clipId", "").c_str(),
command.value("trackId", "").c_str(),
command.value("markers", json::array()).dump().c_str(), main_error);
}
else if (type == "setTrackingSolve") {
extern bool web_engine_blend_main_set_tracking_solve(WebBlendMainState *, const char *, const char *, std::string &);
applied = web_engine_blend_main_set_tracking_solve(engine->authoritative_main,
command.value("clipId", "").c_str(),
command.value("solve", json::object()).dump().c_str(), main_error);
}
else if (type == "setMaskSpline") {
extern bool web_engine_blend_main_set_mask_spline(WebBlendMainState *, const char *, const char *, const char *, std::string &);
applied = web_engine_blend_main_set_mask_spline(engine->authoritative_main,
command.value("maskId", "").c_str(),
command.value("layerId", "").c_str(),
command.value("spline", json::object()).dump().c_str(), main_error);
}
else if (type == "setMaskPoint") {
extern bool web_engine_blend_main_set_mask_point(WebBlendMainState *, const char *, const char *, const char *, const char *, std::string &);
applied = web_engine_blend_main_set_mask_point(engine->authoritative_main,
command.value("maskId", "").c_str(),
command.value("layerId", "").c_str(),
@@ -2985,7 +2988,6 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
engine->authoritative_main, command.value("dataId", "").c_str(), name.c_str(), main_error);
}
else if (type == "setLightLinking") {
extern bool web_engine_blend_main_set_light_linking(WebBlendMainState *, const char *, const char *, const char *, std::string &);
const json lightgroup = command.value("lightgroup", json(nullptr));
const std::string name = lightgroup.is_null() ? std::string() : lightgroup.is_string() ? lightgroup.get<std::string>() : std::string("\x01");
const std::string target = command.value("target", "");
@@ -3031,13 +3033,6 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
}
}
bool web_engine_blend_main_list_macros(std::string &catalog_json, std::string &error);
bool web_engine_blend_main_prepare_macro(WebBlendMainState *state,
const char *macro_id,
const char *properties_json,
std::string &plan_json,
std::string &error);
/* Stable JSON facade for Worker-to-WASM calls. Binary-only transfers retain their
* dedicated ABI, while stateful commands and JSON reports use this entrypoint. */
EMSCRIPTEN_KEEPALIVE int web_engine_call_json(const int handle,

View File

@@ -47,6 +47,8 @@
#include "BLF_api.hh"
#include "IMB_imbuf.hh"
#include "DEG_depsgraph.hh"
#include "DEG_depsgraph_build.hh"
#include "DEG_depsgraph_query.hh"
@@ -94,6 +96,7 @@ void initialize_blender_runtime()
fn::multi_function::register_common_functions();
BKE_idtype_init();
BKE_appdir_init();
IMB_init();
BKE_modifier_init();
BKE_callback_global_init();
BLI_task_scheduler_init();

View File

@@ -10,11 +10,14 @@
* make those boundaries explicit; they never fabricate evaluated geometry.
*/
#include <algorithm>
#include <memory>
#include <optional>
#include "BKE_image.hh"
#include "BKE_node.hh"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
@@ -36,6 +39,7 @@
#include "RE_texture.h"
#include "rna_internal.hh"
#include "SEQ_relations.hh"
#include "SEQ_add.hh"
#include "SEQ_modifier.hh"
#include "SEQ_sequencer.hh"
#include "SEQ_iterator.hh"
@@ -340,12 +344,77 @@ VectorSet<Strip *> query_all_strips_recursive(const ListBaseT<Strip> *seqbase)
void relations_check_uids_unique_and_report(const Scene * /*scene*/) {}
Editing *editing_ensure(Scene *scene)
{
if (scene == nullptr) return nullptr;
if (scene->ed == nullptr) scene->ed = MEM_new<Editing>("Web sequencer editing");
return scene->ed;
}
void add_load_data_init(LoadData *load_data, const char *name, const char *path, int start_frame, int channel)
{
if (load_data == nullptr) return;
*load_data = LoadData{};
load_data->start_frame = start_frame;
load_data->channel = channel;
if (name != nullptr) STRNCPY(load_data->name, name);
if (path != nullptr) STRNCPY(load_data->path, path);
}
static Strip *web_add_strip(ListBaseT<Strip> *seqbase, LoadData *load_data, StripType type)
{
if (seqbase == nullptr || load_data == nullptr) return nullptr;
Strip *strip = MEM_new<Strip>("Web sequencer strip");
strip->type = type;
strip->start = load_data->start_frame;
strip->channel = load_data->channel;
strip->len = std::max(1, load_data->image.length);
strip->data = MEM_new<StripData>("Web sequencer strip data");
BLI_addtail(seqbase, strip);
return strip;
}
Strip *add_scene_strip(Scene *, ListBaseT<Strip> *seqbase, LoadData *load_data)
{
Strip *strip = web_add_strip(seqbase, load_data, STRIP_TYPE_SCENE);
if (strip != nullptr) strip->scene = load_data->scene;
return strip;
}
Strip *add_movie_strip(Main *, Scene *, ListBaseT<Strip> *seqbase, LoadData *load_data) { return web_add_strip(seqbase, load_data, STRIP_TYPE_MOVIE); }
Strip *add_image_strip(Main *, Scene *, ListBaseT<Strip> *seqbase, LoadData *load_data) { return web_add_strip(seqbase, load_data, STRIP_TYPE_IMAGE); }
Strip *add_sound_strip(Main *, Scene *, ListBaseT<Strip> *seqbase, LoadData *load_data) { return web_add_strip(seqbase, load_data, STRIP_TYPE_SOUND); }
Strip *add_meta_strip(Scene *, ListBaseT<Strip> *seqbase, LoadData *load_data) { return web_add_strip(seqbase, load_data, STRIP_TYPE_META); }
Strip *add_effect_strip(Scene *, ListBaseT<Strip> *seqbase, LoadData *load_data)
{
Strip *strip = web_add_strip(seqbase, load_data, load_data->effect.type);
if (strip != nullptr) { strip->input1 = load_data->effect.input1; strip->input2 = load_data->effect.input2; }
return strip;
}
void edit_strip_name_set(Scene *, Strip *strip, const char *name) { if (strip != nullptr && name != nullptr) STRNCPY(strip->name, name); }
void edit_update_muting(Editing *) {}
void edit_flag_for_removal(Scene *, ListBaseT<Strip> *, Strip *) {}
static void web_free_strips(ListBaseT<Strip> *seqbase)
{
for (Strip *strip = static_cast<Strip *>(seqbase->first); strip != nullptr;) {
Strip *next = strip->next;
web_free_strips(&strip->seqbase);
BLI_remlink(seqbase, strip);
MEM_SAFE_DELETE(strip->data);
MEM_delete(strip);
strip = next;
}
}
void edit_remove_flagged_strips(Scene *, ListBaseT<Strip> *seqbase) { if (seqbase != nullptr) web_free_strips(seqbase); }
} // namespace seq
/* ----------------------- Nodes / editor boundaries ------------------- */
namespace nodes {
void node_tree_shader_default(const bContext *, Main *, ID *) {}
const std::shared_ptr<const GeometryNodesLazyFunctionGraphInfo> &
ensure_geometry_nodes_lazy_function_graph(const bNodeTree & /*tree*/)
{

View File

@@ -99,6 +99,7 @@
#include "DNA_volume_types.h"
#include "BLI_listbase_iterator.hh"
#include "BLI_listbase_wrapper.hh"
#include "BLI_listbase.h"
#include "BLI_color.hh"
#include "BLI_math_matrix.h"
@@ -107,6 +108,28 @@
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#ifdef LISTBASE_FOREACH
# undef LISTBASE_FOREACH
#endif
#ifdef LISTBASE_FOREACH_MUTABLE
# undef LISTBASE_FOREACH_MUTABLE
#endif
template<typename T> struct WebListWrapper {
blender::ListBase *list;
struct Iterator {
T *item;
Iterator &operator++() { item = reinterpret_cast<T *>(reinterpret_cast<blender::Link *>(item)->next); return *this; }
bool operator!=(const Iterator &other) const { return item != other.item; }
T *operator*() const { return item; }
};
explicit WebListWrapper(blender::ListBase *value) : list(value) {}
Iterator begin() const { return {reinterpret_cast<T *>(list->first)}; }
Iterator end() const { return {nullptr}; }
};
#define LISTBASE_FOREACH(type, var, list) \
for (type var : WebListWrapper<std::remove_pointer_t<type>>(list))
#define LISTBASE_FOREACH_MUTABLE(type, var, list) LISTBASE_FOREACH(type, var, list)
#include "MEM_guardedalloc.h"
#include "bmesh.hh"
@@ -258,14 +281,14 @@ bool web_operator_number3(const json &value, std::vector<float> &output)
bool web_operator_object_exists(WebBlendMainState *state, const std::string &object_id)
{
if (state == nullptr || state->main == nullptr || object_id.empty()) return false;
LISTBASE_FOREACH (Object *, object, &state->main->objects) {
for (Object *object : WebListWrapper<Object>(&state->main->objects)) {
const std::string name = id_name(object->id);
if (object_id == name || object_id == "object:" + name) return true;
}
return false;
}
bool web_engine_blend_main_list_operators(std::string &catalog_json, std::string &error)
bool web_engine_blend_main_list_operators_impl(std::string &catalog_json, std::string &error)
{
try {
catalog_json = web_operator_catalog_json().dump();
@@ -539,7 +562,7 @@ json web_macro_source(const WebMacroSpec &spec)
{"evidence", "bounded WebEngine macro plan source"}}});
}
bool web_engine_blend_main_list_macros(std::string &catalog_json, std::string &error)
bool web_engine_blend_main_list_macros_impl(std::string &catalog_json, std::string &error)
{
try {
const json operator_catalog = web_operator_catalog_json();
@@ -577,7 +600,7 @@ bool web_engine_blend_main_list_macros(std::string &catalog_json, std::string &e
}
}
bool web_engine_blend_main_prepare_macro(WebBlendMainState *state,
bool web_engine_blend_main_prepare_macro_impl(WebBlendMainState *state,
const char *macro_id,
const char *properties_json,
std::string &plan_json,
@@ -1611,6 +1634,25 @@ json geometry_socket_json(const bNodeSocket &socket, const eNodeSocketInOut dire
} // namespace
bool web_engine_blend_main_list_operators(std::string &catalog_json, std::string &error)
{
return web_engine_blend_main_list_operators_impl(catalog_json, error);
}
bool web_engine_blend_main_list_macros(std::string &catalog_json, std::string &error)
{
return web_engine_blend_main_list_macros_impl(catalog_json, error);
}
bool web_engine_blend_main_prepare_macro(WebBlendMainState *state,
const char *macro_id,
const char *properties_json,
std::string &plan_json,
std::string &error)
{
return web_engine_blend_main_prepare_macro_impl(state, macro_id, properties_json, plan_json, error);
}
bool web_engine_blend_main_prepare_operator(WebBlendMainState *state,
const char *operator_id,
const char *properties_json,
@@ -1824,7 +1866,14 @@ bool web_engine_blend_main_add_modifier(WebBlendMainState *state,
error = "meshId or modifierType was not found in editable authoritative Main";
return false;
}
const eModifierType type = BKE_modifiertype_from_idname(modifier_type);
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)) {
type = ModifierType(candidate);
break;
}
}
if (type == eModifierType_None) {
error = "modifierType is not supported by Blender metadata";
return false;
@@ -1836,7 +1885,7 @@ bool web_engine_blend_main_add_modifier(WebBlendMainState *state,
}
if (name != nullptr && name[0] != '\0') STRNCPY_UTF8(modifier->name, name);
BKE_modifier_unique_name(&object->modifiers, modifier);
BKE_modifiers_persistent_uid_init(*object, modifier);
BKE_modifiers_persistent_uid_init(*object, *modifier);
BLI_addtail(&object->modifiers, modifier);
object->id.recalc |= ID_RECALC_GEOMETRY;
modifier_uuid = std::string(object->id.name + 2) + ":" + std::to_string(modifier->persistent_uid);
@@ -1930,10 +1979,10 @@ bool web_engine_blend_main_set_modifier_parameters(WebBlendMainState *state,
for (ModifierData &modifier : object->modifiers) {
if (modifier.persistent_uid != uid) continue;
PointerRNA pointer;
RNA_pointer_create(&object->id, &RNA_Modifier, &modifier, &pointer);
pointer = RNA_pointer_create_id_subdata(object->id, RNA_Modifier, &modifier);
for (auto it = parameters.begin(); it != parameters.end(); ++it) {
PropertyRNA *property = RNA_struct_find_property(&pointer, it.key().c_str());
if (property == nullptr || RNA_property_is_readonly(&pointer, property)) {
if (property == nullptr || !RNA_property_editable(&pointer, property)) {
error = "modifier parameter is not editable in Blender metadata: " + it.key();
return false;
}
@@ -1959,7 +2008,7 @@ bool web_engine_blend_main_set_modifier_parameters(WebBlendMainState *state,
int enum_value = 0;
if (value.is_number_integer()) enum_value = value.get<int>();
else if (value.is_string()) {
if (!RNA_property_enum_value_from_identifier(&pointer, property, value.get<std::string>().c_str(), &enum_value)) {
if (!RNA_property_enum_value(nullptr, &pointer, property, value.get<std::string>().c_str(), &enum_value)) {
error = "modifier enum parameter has an unknown value: " + it.key();
return false;
}
@@ -2000,10 +2049,11 @@ static ID *web_rna_find_id(WebBlendMainState *state, const char *type_filter, co
{
if (state == nullptr || state->main == nullptr || name == nullptr || name[0] == '\0') return nullptr;
ID *found = nullptr;
ID *id = nullptr;
FOREACH_MAIN_ID_BEGIN (state->main, id) {
if (id->name[0] == '\0' || !STREQ(id->name + 2, name)) continue;
PointerRNA pointer;
RNA_id_pointer_create(id, &pointer);
pointer = RNA_id_pointer_create(id);
const char *identifier = RNA_struct_identifier(pointer.type);
if (type_filter != nullptr && type_filter[0] != '\0' &&
(identifier == nullptr || !STREQ(identifier, type_filter))) continue;
@@ -2044,7 +2094,7 @@ static bool web_rna_read_value(PointerRNA *pointer, PropertyRNA *property, json
static bool web_rna_set_value(PointerRNA *pointer, PropertyRNA *property, const json &value, std::string &error)
{
if (web_rna_property_blocked(property) || RNA_property_is_readonly(pointer, property)) {
if (web_rna_property_blocked(property) || !RNA_property_editable(pointer, property)) {
error = "RNA property is readonly, context-only, or contains an unsupported pointer";
return false;
}
@@ -2072,7 +2122,7 @@ static bool web_rna_set_value(PointerRNA *pointer, PropertyRNA *property, const
int enum_value = 0;
if (item.is_number_integer()) enum_value = item.get<int>();
else if (item.is_string()) {
if (!RNA_property_enum_value_from_identifier(pointer, property, item.get<std::string>().c_str(), &enum_value)) return false;
if (!RNA_property_enum_value(nullptr, pointer, property, item.get<std::string>().c_str(), &enum_value)) return false;
}
else return false;
RNA_property_enum_set(pointer, property, enum_value);
@@ -2105,9 +2155,10 @@ bool web_engine_blend_main_list_rna_data_blocks(WebBlendMainState *state,
if (state == nullptr || state->main == nullptr) { error = "RNA reflection requires an authoritative Main"; return false; }
json data_blocks = json::array();
int count = 0;
ID *id = nullptr;
FOREACH_MAIN_ID_BEGIN (state->main, id) {
PointerRNA pointer;
RNA_id_pointer_create(id, &pointer);
pointer = RNA_id_pointer_create(id);
const char *identifier = RNA_struct_identifier(pointer.type);
if (identifier == nullptr || (type_filter != nullptr && type_filter[0] != '\0' && !STREQ(identifier, type_filter))) continue;
const bool editable = id->lib == nullptr;
@@ -2130,9 +2181,9 @@ bool web_engine_blend_main_read_rna_properties(WebBlendMainState *state,
ID *id = web_rna_find_id(state, type_filter, name);
if (id == nullptr) { error = "RNA data-block was not found in authoritative Main"; return false; }
PointerRNA pointer;
RNA_id_pointer_create(id, &pointer);
pointer = RNA_id_pointer_create(id);
json properties = json::array();
PropertyRNA *iterator_property = RNA_struct_iterator_property(&pointer);
PropertyRNA *iterator_property = RNA_struct_iterator_property(pointer.type);
CollectionPropertyIterator iterator;
RNA_property_collection_begin(&pointer, iterator_property, &iterator);
for (; iterator.valid && static_cast<int>(properties.size()) < std::clamp(limit, 1, 1024); RNA_property_collection_next(&iterator)) {
@@ -2142,7 +2193,7 @@ bool web_engine_blend_main_read_rna_properties(WebBlendMainState *state,
{"name", RNA_property_ui_name(property)},
{"type", RNA_property_type(property) == PROP_BOOLEAN ? "BOOLEAN" : RNA_property_type(property) == PROP_INT ? "INT" : RNA_property_type(property) == PROP_FLOAT ? "FLOAT" : RNA_property_type(property) == PROP_STRING ? "STRING" : "ENUM"},
{"arrayLength", std::max(1, RNA_property_array_length(&pointer, property))},
{"readonly", RNA_property_is_readonly(&pointer, property)}};
{"readonly", !RNA_property_editable(&pointer, property)}};
const char *description = RNA_property_ui_description(property);
if (description != nullptr && description[0] != '\0') entry["description"] = description;
json value;
@@ -2164,7 +2215,7 @@ bool web_engine_blend_main_set_rna_property(WebBlendMainState *state,
ID *id = web_rna_find_id(state, type_filter, name);
if (id == nullptr || id->lib != nullptr || property_name == nullptr || value_json == nullptr) { error = "RNA data-block is missing or linked and cannot be edited"; return false; }
PointerRNA pointer;
RNA_id_pointer_create(id, &pointer);
pointer = RNA_id_pointer_create(id);
PropertyRNA *property = RNA_struct_find_property(&pointer, property_name);
if (property == nullptr) { error = "RNA property was not found in Blender metadata"; return false; }
json value;
@@ -2186,7 +2237,7 @@ bool web_engine_blend_main_read_rna_property_schema(WebBlendMainState *state,
return false;
}
PointerRNA pointer;
RNA_id_pointer_create(id, &pointer);
pointer = RNA_id_pointer_create(id);
PropertyRNA *property = RNA_struct_find_property(&pointer, property_name);
if (property == nullptr || (web_rna_property_blocked(property) && RNA_property_type(property) != PROP_COLLECTION)) {
error = "RNA property is unsupported, context-only, or contains a pointer";
@@ -2207,7 +2258,7 @@ bool web_engine_blend_main_read_rna_property_schema(WebBlendMainState *state,
{"name", RNA_property_ui_name(property)},
{"type", type_name},
{"arrayLength", std::max(1, RNA_property_array_length(&pointer, property))},
{"readonly", RNA_property_is_readonly(&pointer, property)}};
{"readonly", !RNA_property_editable(&pointer, property)}};
const char *description = RNA_property_ui_description(property);
if (description != nullptr && description[0] != '\0') schema["description"] = description;
if (type == PROP_COLLECTION) schema["collection"] = json{{"nestedPath", property_name}};
@@ -2228,7 +2279,7 @@ bool web_engine_blend_main_set_rna_array_property(WebBlendMainState *state,
return false;
}
PointerRNA pointer;
RNA_id_pointer_create(id, &pointer);
pointer = RNA_id_pointer_create(id);
PropertyRNA *property = RNA_struct_find_property(&pointer, property_name);
if (property == nullptr || RNA_property_array_length(&pointer, property) <= 1) {
error = "RNA property is not a bounded array";
@@ -2262,7 +2313,7 @@ bool web_engine_blend_main_set_rna_enum_property(WebBlendMainState *state,
return false;
}
PointerRNA pointer;
RNA_id_pointer_create(id, &pointer);
pointer = RNA_id_pointer_create(id);
PropertyRNA *property = RNA_struct_find_property(&pointer, property_name);
if (property == nullptr || RNA_property_type(property) != PROP_ENUM) {
error = "RNA property is not an enum";
@@ -2349,7 +2400,7 @@ bool web_engine_blend_main_read_rna_collection(WebBlendMainState *state,
start = end + 1;
}
PointerRNA pointer;
RNA_id_pointer_create(id, &pointer);
pointer = RNA_id_pointer_create(id);
json items;
if (!web_rna_read_collection_path(&pointer, segments, 0, limit, items, error)) return false;
result_json = json{{"path", path_value}, {"items", items}}.dump();
@@ -3113,7 +3164,7 @@ bool web_engine_blend_main_sculpt_stroke(WebBlendMainState *state,
}
MutableSpan<float3> positions = mesh->vert_positions_for_write();
const std::optional<VArraySpan<float>> mask = mesh->attributes().lookup<float>(".sculpt_mask", bke::AttrDomain::Point);
const VArray<float> mask = mesh->attributes().lookup<float>(".sculpt_mask", bke::AttrDomain::Point).varray;
std::vector<std::vector<int>> neighbors;
if (brush == "SMOOTH") {
neighbors.resize(size_t(mesh->verts_num));
@@ -3140,7 +3191,7 @@ bool web_engine_blend_main_sculpt_stroke(WebBlendMainState *state,
const float distance = std::sqrt(dx * dx + dy * dy + dz * dz);
if (distance >= sample.radius) continue;
const float falloff = (1.0f - distance / sample.radius);
const float mask_factor = !mask ? 1.0f : std::max(0.0f, 1.0f - (*mask)[vertex]);
const float mask_factor = !mask ? 1.0f : std::max(0.0f, 1.0f - mask[vertex]);
const float influence = sample.strength * sample.pressure * falloff * falloff * mask_factor;
if (influence == 0.0f) continue;
if (brush == "SMOOTH") {
@@ -3230,7 +3281,7 @@ bool web_engine_blend_main_create_primitive(WebBlendMainState *state,
return false;
}
Mesh *mesh = static_cast<Mesh *>(object->data);
Mesh *mesh = reinterpret_cast<Mesh *>(object->data);
BMeshCreateParams create_params{};
BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default, &create_params);
float matrix[4][4];
@@ -4072,10 +4123,10 @@ bool web_engine_blend_main_remove_action(WebBlendMainState *state,
error = "removeAction requires an editable Action";
return false;
}
for (Object *object : state->main->objects) {
if (object->adt != nullptr && object->adt->action == action) {
animrig::unassign_action(object->id);
object->id.recalc |= ID_RECALC_ANIMATION | ID_RECALC_TRANSFORM;
for (Object &object : state->main->objects) {
if (object.adt != nullptr && object.adt->action == action) {
animrig::unassign_action(object.id);
object.id.recalc |= ID_RECALC_ANIMATION | ID_RECALC_TRANSFORM;
}
}
BKE_id_delete(state->main, &action->id);
@@ -4279,7 +4330,7 @@ bool web_engine_blend_main_set_driver_expression(WebBlendMainState *state,
error = "setDriverExpression requires an editable FCurve and bounded expression";
return false;
}
if (fcurve->driver == nullptr) fcurve->driver = static_cast<ChannelDriver *>(MEM_callocN(sizeof(ChannelDriver), "Web FCurve driver"));
if (fcurve->driver == nullptr) fcurve->driver = MEM_new<ChannelDriver>("Web FCurve driver");
if (fcurve->driver == nullptr) { error = "Blender could not allocate an FCurve driver"; return false; }
BLI_strncpy(fcurve->driver->expression, expression, sizeof(fcurve->driver->expression));
fcurve->driver->type = DRIVER_TYPE_PYTHON;
@@ -4304,14 +4355,17 @@ bool web_engine_blend_main_set_action_groups(WebBlendMainState *state,
const std::string name = entry["name"].get<std::string>();
if (name.empty() || name.size() > 63 || entry["paths"].size() > 4096) { error = "setActionGroups group is invalid"; return false; }
bActionGroup *group = static_cast<bActionGroup *>(BLI_findstring(&action->groups, name.c_str(), offsetof(bActionGroup, name)));
if (group == nullptr) group = BKE_action_group_add(action, name.c_str());
if (group == nullptr) {
group = MEM_new<bActionGroup>("Web Action group");
STRNCPY(group->name, name.c_str());
BLI_addtail(&action->groups, group);
}
if (group == nullptr) { error = "Blender could not allocate an Action group"; return false; }
for (const json &path_entry : entry["paths"]) {
if (!path_entry.is_string()) { error = "setActionGroups path is invalid"; return false; }
FCurve *fcurve = web_find_action_fcurve(action, path_entry.get<std::string>().c_str());
if (fcurve == nullptr) { error = "Action group FCurve channel was not found"; return false; }
BKE_action_groups_remove_channel(action, fcurve);
BKE_action_groups_add_channel(action, group, fcurve);
fcurve->grp = group;
}
}
action->id.recalc |= ID_RECALC_ANIMATION;
@@ -4340,20 +4394,20 @@ bool web_engine_blend_main_set_keying_set(WebBlendMainState *state,
keying_set = candidate;
LISTBASE_FOREACH_MUTABLE (KS_Path *, path, &candidate->paths) {
BLI_remlink(&candidate->paths, path);
MEM_SAFE_FREE(path->rna_path);
MEM_freeN(path);
if (path->rna_path != nullptr) MEM_delete_void(static_cast<void *>(path->rna_path));
MEM_delete(path);
}
break;
}
if (keying_set == nullptr) {
keying_set = static_cast<KeyingSet *>(MEM_callocN(sizeof(KeyingSet), "Web Keying Set"));
keying_set = MEM_new<KeyingSet>("Web Keying Set");
BLI_strncpy(keying_set->name, name, sizeof(keying_set->name));
BLI_strncpy(keying_set->idname, name, sizeof(keying_set->idname));
BLI_addtail(&scene->keyingsets, keying_set);
}
for (const json &entry : paths) {
if (!entry.is_object() || !entry.contains("path") || !entry["path"].is_string()) { error = "setKeyingSet path is invalid"; return false; }
KS_Path *path = static_cast<KS_Path *>(MEM_callocN(sizeof(KS_Path), "Web Keying Set Path"));
KS_Path *path = MEM_new<KS_Path>("Web Keying Set Path");
path->rna_path = BLI_strdup(entry["path"].get<std::string>().c_str());
path->array_index = entry.value("arrayIndex", -1);
path->id = &scene->id;
@@ -4387,19 +4441,19 @@ bool web_engine_blend_main_set_timeline_markers(WebBlendMainState *state,
if (!markers.is_array() || markers.size() > 10000) { error = "setTimelineMarkers marker array is invalid"; return false; }
LISTBASE_FOREACH_MUTABLE (TimeMarker *, marker, &scene->markers) {
BLI_remlink(&scene->markers, marker);
MEM_freeN(marker);
MEM_delete(marker);
}
for (const json &entry : markers) {
if (!entry.is_object() || !entry.contains("frame") || !entry["frame"].is_number_integer() || !entry.contains("name") || !entry["name"].is_string()) {
error = "setTimelineMarkers marker entry is invalid";
return false;
}
TimeMarker *marker = static_cast<TimeMarker *>(MEM_callocN(sizeof(TimeMarker), "Web timeline marker"));
TimeMarker *marker = MEM_new<TimeMarker>("Web timeline marker");
marker->frame = entry["frame"].get<int>();
BLI_strncpy(marker->name, entry["name"].get<std::string>().c_str(), sizeof(marker->name));
BLI_addtail(&scene->markers, marker);
}
scene->id.recalc |= ID_RECALC_COPY_ON_WRITE;
scene->id.recalc |= ID_RECALC_SYNC_TO_EVAL;
return true;
}
@@ -5911,8 +5965,8 @@ bool web_engine_blend_main_set_curve_bevel(WebBlendMainState *state,
}
if (bevel_depth >= 0.0f) curve->bevel_radius = bevel_depth;
if (bevel_resolution >= 0) curve->bevresol = short(bevel_resolution);
if (bevel_factor_start >= 0.0f) curve->bevel_factor_start = bevel_factor_start;
if (bevel_factor_end >= 0.0f) curve->bevel_factor_end = bevel_factor_end;
if (bevel_factor_start >= 0.0f) curve->bevfac1 = bevel_factor_start;
if (bevel_factor_end >= 0.0f) curve->bevfac2 = bevel_factor_end;
curve->id.recalc |= ID_RECALC_GEOMETRY;
for (Object &object : state->main->objects) {
if (object.data == &curve->id) object.id.recalc |= ID_RECALC_GEOMETRY;
@@ -5949,7 +6003,7 @@ bool web_engine_blend_main_set_curve_taper(WebBlendMainState *state,
curve->taperobj = taper_object;
if (curve->taperobj != nullptr) id_us_plus(&curve->taperobj->id);
}
if (taper_radius_mode >= 0) curve->taper_radius_mode = short(taper_radius_mode);
if (taper_radius_mode >= 0) curve->taper_radius_mode = eCurveTaperRadiusMode(taper_radius_mode);
curve->id.recalc |= ID_RECALC_GEOMETRY;
for (Object &object : state->main->objects) {
if (object.data == &curve->id) object.id.recalc |= ID_RECALC_GEOMETRY;
@@ -5967,7 +6021,7 @@ bool web_engine_blend_main_convert_curve_type(WebBlendMainState *state,
if (error.empty()) error = "NON_MESH_DATA_UNSUPPORTED: Curve data-block was not found";
return false;
}
short object_type = 0;
ObjectType object_type = OB_EMPTY;
if (STREQ(target_type, "CURVE")) object_type = OB_CURVES_LEGACY;
else if (STREQ(target_type, "SURFACE")) object_type = OB_SURF;
else {
@@ -6541,7 +6595,7 @@ static void web_armature_tag_update(WebBlendMainState *state, bArmature *armatur
BKE_armature_where_is(armature);
armature->id.recalc |= ID_RECALC_GEOMETRY;
for (Object &candidate : state->main->objects) {
if (candidate.type == OB_ARMATURE && candidate.data == armature) {
if (candidate.type == OB_ARMATURE && candidate.data == &armature->id) {
BKE_pose_rebuild(state->main, &candidate, armature, true);
candidate.id.recalc |= ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM;
}
@@ -6556,7 +6610,7 @@ static Bone *web_armature_add_bone(bArmature *armature,
float roll,
bool connected)
{
Bone *bone = static_cast<Bone *>(MEM_callocN(sizeof(Bone), "WebEngine armature edit bone"));
Bone *bone = MEM_new<Bone>("WebEngine armature edit bone");
BLI_strncpy(bone->name, name, sizeof(bone->name));
bone->parent = parent;
bone->roll = roll;
@@ -6631,13 +6685,11 @@ bool web_engine_blend_main_set_armature_bones(
}
}
bArmature *armature = static_cast<bArmature *>(object->data);
while (Bone *bone = static_cast<Bone *>(armature->bonebase.first)) {
BKE_armature_bone_free(armature, bone);
}
bArmature *armature = reinterpret_cast<bArmature *>(object->data);
BKE_armature_bonelist_free(&armature->bonebase, false);
std::vector<Bone *> created(bones.size(), nullptr);
for (size_t index = 0; index < bones.size(); index++) {
Bone *bone = static_cast<Bone *>(MEM_callocN(sizeof(Bone), "WebEngine armature bone"));
Bone *bone = MEM_new<Bone>("WebEngine armature bone");
BLI_strncpy(bone->name, bones[index].name.c_str(), sizeof(bone->name));
bone->roll = bones[index].roll;
bone->weight = 1.0f;
@@ -6663,7 +6715,7 @@ bool web_engine_blend_main_set_armature_bones(
BKE_armature_where_is(armature);
armature->id.recalc |= ID_RECALC_GEOMETRY;
for (Object &candidate : state->main->objects) {
if (candidate.type == OB_ARMATURE && candidate.data == armature) {
if (candidate.type == OB_ARMATURE && candidate.data == &armature->id) {
BKE_pose_rebuild(state->main, &candidate, armature, true);
candidate.id.recalc |= ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM;
}
@@ -6693,7 +6745,7 @@ bool web_engine_blend_main_set_pose_bone_transform(WebBlendMainState *state,
for (int axis = 0; axis < 3; axis++) {
channel->loc[axis] = translation[axis];
channel->eul[axis] = rotation_euler[axis];
channel->size[axis] = scale[axis];
channel->scale[axis] = scale[axis];
}
object->id.recalc |= ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM;
return true;
@@ -6712,7 +6764,7 @@ bool web_engine_blend_main_armature_edit_operations(
error = "ARMATURE_EDIT_INVALID: armature and a bounded operation batch are required";
return false;
}
bArmature *armature = static_cast<bArmature *>(object->data);
bArmature *armature = reinterpret_cast<bArmature *>(object->data);
BKE_armature_where_is(armature);
auto finite_vec = [](const std::array<float, 3> &value) {
return std::all_of(value.begin(), value.end(), [](float component) { return std::isfinite(component); });
@@ -6740,7 +6792,9 @@ bool web_engine_blend_main_armature_edit_operations(
error = "ARMATURE_EDIT_INVALID: DELETE bone was not found";
return false;
}
BKE_armature_bone_free(armature, bone);
BKE_armature_bonelist_free(&bone->childbase, false);
BLI_remlink(bone->parent != nullptr ? &bone->parent->childbase : &armature->bonebase, bone);
MEM_delete(bone);
}
else if (operation.operation == "RENAME") {
if (bone == nullptr || !valid_name(operation.name) ||
@@ -6794,7 +6848,7 @@ bool web_engine_blend_main_set_bone_roll(WebBlendMainState *state,
{
Object *object = find_object(state != nullptr ? state->main : nullptr, object_id);
bArmature *armature = object != nullptr && object->type == OB_ARMATURE ?
static_cast<bArmature *>(object->data) : nullptr;
reinterpret_cast<bArmature *>(object->data) : nullptr;
Bone *bone = armature != nullptr ? web_armature_find_bone(&armature->bonebase, bone_name) : nullptr;
if (bone == nullptr || !std::isfinite(roll)) {
error = "ARMATURE_ROLL_INVALID: armature bone was not found or roll is not finite";
@@ -6812,7 +6866,7 @@ bool web_engine_blend_main_set_bone_symmetry(WebBlendMainState *state,
{
Object *object = find_object(state != nullptr ? state->main : nullptr, object_id);
bArmature *armature = object != nullptr && object->type == OB_ARMATURE ?
static_cast<bArmature *>(object->data) : nullptr;
reinterpret_cast<bArmature *>(object->data) : nullptr;
if (armature == nullptr) {
error = "ARMATURE_NOT_FOUND: object must identify an armature object";
return false;
@@ -6831,7 +6885,7 @@ bool web_engine_blend_main_set_bone_parenting(WebBlendMainState *state,
{
Object *object = find_object(state != nullptr ? state->main : nullptr, object_id);
bArmature *armature = object != nullptr && object->type == OB_ARMATURE ?
static_cast<bArmature *>(object->data) : nullptr;
reinterpret_cast<bArmature *>(object->data) : nullptr;
Bone *bone = armature != nullptr ? web_armature_find_bone(&armature->bonebase, bone_name) : nullptr;
Bone *parent = armature != nullptr && parent_name != nullptr && parent_name[0] != '\0' ?
web_armature_find_bone(&armature->bonebase, parent_name) : nullptr;
@@ -6887,7 +6941,7 @@ bool web_engine_blend_main_set_pose_constraint(WebBlendMainState *state,
error = "POSE_CONSTRAINT_INVALID: constraint to remove was not found";
return false;
}
BKE_constraint_remove(&channel->constraints, constraint);
BKE_constraint_remove_ex(&channel->constraints, object, constraint);
object->id.recalc |= ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM;
return true;
}
@@ -6906,11 +6960,11 @@ bool web_engine_blend_main_set_pose_constraint(WebBlendMainState *state,
return false;
}
if (constraint != nullptr && constraint->type != type->second) {
BKE_constraint_remove(&channel->constraints, constraint);
BKE_constraint_remove_ex(&channel->constraints, object, constraint);
constraint = nullptr;
}
if (constraint == nullptr) {
constraint = BKE_constraint_add_for_pose(object, channel, edit.constraint_name.c_str(), type->second);
constraint = BKE_constraint_add_for_pose(object, channel, edit.constraint_name.c_str(), eBConstraint_Types(type->second));
}
Object **target_slot = nullptr;
char *subtarget = nullptr;
@@ -10335,14 +10389,14 @@ bool web_engine_blend_main_create_object_data(WebBlendMainState *state,
return false;
}
const std::string type(object_type);
int blender_type = OB_EMPTY;
ObjectType blender_type = OB_EMPTY;
ID *data = nullptr;
if (type == "CAMERA") {
blender_type = OB_CAMERA;
data = &BKE_camera_add(state->main, name)->id;
}
else if (type == "LIGHT") {
blender_type = OB_LIGHT;
blender_type = OB_LAMP;
data = &BKE_light_add(state->main, name)->id;
}
else if (type == "ARMATURE") {
@@ -10382,13 +10436,13 @@ bool web_engine_blend_main_set_object_selection(WebBlendMainState *state,
error = "LINKED_DATA_MUTATION_BLOCKED: Object selection target is not editable";
return false;
}
BKE_view_layer_synced_ensure(state->scene, state->view_layer);
BKE_view_layer_synced_ensure(*state->main, state->scene, state->view_layer);
Base *base = BKE_view_layer_base_find(state->view_layer, object);
if (base == nullptr) {
error = "OBJECT_EDITOR_INVALID: Object is not available in the active ViewLayer";
return false;
}
BKE_base_select(base, selected ? BA_SELECT : BA_DESELECT);
SET_FLAG_FROM_TEST(base->flag, selected, BASE_SELECTED);
if (active) state->view_layer->basact = base;
else if (!selected && state->view_layer->basact == base) state->view_layer->basact = nullptr;
return true;