Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/alembic/intern/abc_curves.cc20
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc210
-rw-r--r--source/blender/alembic/intern/abc_exporter.h11
-rw-r--r--source/blender/alembic/intern/abc_mesh.cc38
-rw-r--r--source/blender/alembic/intern/abc_object.cc102
-rw-r--r--source/blender/alembic/intern/abc_object.h31
-rw-r--r--source/blender/alembic/intern/abc_transform.cc32
-rw-r--r--source/blender/alembic/intern/abc_transform.h6
-rw-r--r--source/blender/alembic/intern/abc_util.cc352
-rw-r--r--source/blender/alembic/intern/abc_util.h95
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc476
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c1
-rw-r--r--source/blender/blenkernel/BKE_appdir.h4
-rw-r--r--source/blender/blenkernel/BKE_blender.h2
-rw-r--r--source/blender/blenkernel/BKE_blendfile.h1
-rw-r--r--source/blender/blenkernel/BKE_cloth.h6
-rw-r--r--source/blender/blenkernel/BKE_idprop.h13
-rw-r--r--source/blender/blenkernel/BKE_library.h2
-rw-r--r--source/blender/blenkernel/BKE_library_query.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h2
-rw-r--r--source/blender/blenkernel/intern/appdir.c173
-rw-r--r--source/blender/blenkernel/intern/blender.c38
-rw-r--r--source/blender/blenkernel/intern/blendfile.c32
-rw-r--r--source/blender/blenkernel/intern/cloth.c37
-rw-r--r--source/blender/blenkernel/intern/customdata.c55
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c2
-rw-r--r--source/blender/blenkernel/intern/idprop.c182
-rw-r--r--source/blender/blenkernel/intern/library_query.c119
-rw-r--r--source/blender/blenkernel/intern/library_remap.c30
-rw-r--r--source/blender/blenkernel/intern/node.c2
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c17
-rw-r--r--source/blender/blenlib/BLI_hash.h66
-rw-r--r--source/blender/blenlib/BLI_listbase.h1
-rw-r--r--source/blender/blenlib/BLI_path_util.h27
-rw-r--r--source/blender/blenlib/intern/listbase.c34
-rw-r--r--source/blender/blenlib/intern/path_util.c173
-rw-r--r--source/blender/blenlib/intern/task.c53
-rw-r--r--source/blender/blenloader/CMakeLists.txt6
-rw-r--r--source/blender/blenloader/intern/readfile.c1011
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c12
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c13
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c56
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c6
-rw-r--r--source/blender/collada/AnimationImporter.cpp2
-rw-r--r--source/blender/collada/ArmatureExporter.cpp70
-rw-r--r--source/blender/collada/ArmatureImporter.cpp60
-rw-r--r--source/blender/collada/ControllerExporter.cpp115
-rw-r--r--source/blender/collada/ExportSettings.h3
-rw-r--r--source/blender/collada/ImportSettings.h1
-rw-r--r--source/blender/collada/TransformReader.cpp23
-rw-r--r--source/blender/collada/TransformReader.h5
-rw-r--r--source/blender/collada/TransformWriter.cpp7
-rw-r--r--source/blender/collada/TransformWriter.h3
-rw-r--r--source/blender/collada/collada.cpp11
-rw-r--r--source/blender/collada/collada.h9
-rw-r--r--source/blender/collada/collada_internal.cpp12
-rw-r--r--source/blender/collada/collada_internal.h6
-rw-r--r--source/blender/collada/collada_utils.cpp224
-rw-r--r--source/blender/collada/collada_utils.h15
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc57
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.h4
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc23
-rw-r--r--source/blender/editors/curve/editcurve.c3
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c17
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c27
-rw-r--r--source/blender/editors/include/UI_interface.h4
-rw-r--r--source/blender/editors/interface/interface.c6
-rw-r--r--source/blender/editors/interface/interface_anim.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c55
-rw-r--r--source/blender/editors/interface/interface_intern.h3
-rw-r--r--source/blender/editors/interface/interface_layout.c57
-rw-r--r--source/blender/editors/interface/interface_regions.c47
-rw-r--r--source/blender/editors/interface/interface_templates.c5
-rw-r--r--source/blender/editors/interface/interface_utils.c10
-rw-r--r--source/blender/editors/interface/interface_widgets.c22
-rw-r--r--source/blender/editors/io/io_collada.c46
-rw-r--r--source/blender/editors/mesh/meshtools.c4
-rw-r--r--source/blender/editors/object/object_modifier.c5
-rw-r--r--source/blender/editors/object/object_relations.c29
-rw-r--r--source/blender/editors/render/render_shading.c2
-rw-r--r--source/blender/editors/screen/glutil.c8
-rw-r--r--source/blender/editors/screen/screen_ops.c27
-rw-r--r--source/blender/editors/sound/sound_ops.c2
-rw-r--r--source/blender/editors/space_clip/clip_utils.c5
-rw-r--r--source/blender/editors/space_file/fsmenu.c13
-rw-r--r--source/blender/editors/space_node/drawnode.c24
-rw-r--r--source/blender/editors/space_node/node_add.c16
-rw-r--r--source/blender/editors/space_node/node_buttons.c11
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c51
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c3
-rw-r--r--source/blender/editors/space_view3d/drawobject.c11
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c21
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c2
-rw-r--r--source/blender/editors/transform/transform_manipulator.c120
-rw-r--r--source/blender/editors/transform/transform_orientations.c2
-rw-r--r--source/blender/editors/transform/transform_snap_object.c5
-rw-r--r--source/blender/gpu/GPU_material.h5
-rw-r--r--source/blender/gpu/intern/gpu_basic_shader.c4
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c6
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c4
-rw-r--r--source/blender/gpu/intern/gpu_compositing.c4
-rw-r--r--source/blender/gpu/intern/gpu_draw.c36
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c6
-rw-r--r--source/blender/gpu/intern/gpu_material.c29
-rw-r--r--source/blender/gpu/intern/gpu_shader.c1
-rw-r--r--source/blender/gpu/intern/gpu_texture.c14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl10
-rw-r--r--source/blender/imbuf/intern/colormanagement.c2
-rw-r--r--source/blender/makesdna/DNA_ID.h2
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h4
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h1
-rw-r--r--source/blender/makesdna/DNA_object_types.h2
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h13
-rw-r--r--source/blender/makesrna/RNA_access.h2
-rw-r--r--source/blender/makesrna/RNA_define.h1
-rw-r--r--source/blender/makesrna/RNA_types.h2
-rw-r--r--source/blender/makesrna/intern/makesrna.c2
-rw-r--r--source/blender/makesrna/intern/rna_ID.c6
-rw-r--r--source/blender/makesrna/intern/rna_access.c84
-rw-r--r--source/blender/makesrna/intern/rna_action.c3
-rw-r--r--source/blender/makesrna/intern/rna_animation.c3
-rw-r--r--source/blender/makesrna/intern/rna_define.c13
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c3
-rw-r--r--source/blender/makesrna/intern/rna_internal.h1
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c14
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c1
-rw-r--r--source/blender/makesrna/intern/rna_object.c4
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c37
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c123
-rw-r--r--source/blender/makesrna/intern/rna_ui.c1
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c42
-rw-r--r--source/blender/makesrna/intern/rna_wm.c1
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c2
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c4
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_object_info.c12
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp51
-rw-r--r--source/blender/physics/intern/implicit.h10
-rw-r--r--source/blender/physics/intern/implicit_blender.c34
-rw-r--r--source/blender/python/generic/idprop_py_api.c440
-rw-r--r--source/blender/python/intern/bpy_props.c169
-rw-r--r--source/blender/python/intern/bpy_props.h4
-rw-r--r--source/blender/python/intern/bpy_rna.c44
-rw-r--r--source/blender/python/intern/bpy_rna.h1
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c20
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h2
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h4
-rw-r--r--source/blender/render/intern/include/render_types.h2
-rw-r--r--source/blender/render/intern/source/render_texture.c61
-rw-r--r--source/blender/render/intern/source/renderdatabase.c9
-rw-r--r--source/blender/render/intern/source/shadeoutput.c10
-rw-r--r--source/blender/windowmanager/CMakeLists.txt4
-rw-r--r--source/blender/windowmanager/intern/wm.c2
-rw-r--r--source/blender/windowmanager/intern/wm_files.c263
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c2
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c7
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c56
-rw-r--r--source/blender/windowmanager/intern/wm_window.c73
-rw-r--r--source/blender/windowmanager/wm_files.h3
-rw-r--r--source/blender/windowmanager/wm_window.h2
165 files changed, 4220 insertions, 2449 deletions
diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc
index 0542255d84b..28e75db2862 100644
--- a/source/blender/alembic/intern/abc_curves.cc
+++ b/source/blender/alembic/intern/abc_curves.cc
@@ -205,6 +205,7 @@ void AbcCurveReader::readObjectData(Main *bmain, float time)
cu->flag |= CU_DEFORM_FILL | CU_3D;
cu->actvert = CU_ACT_NONE;
+ cu->resolu = 1;
m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_object_name.c_str());
m_object->data = cu;
@@ -250,13 +251,18 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
nu->pntsv = 1;
nu->flag |= CU_SMOOTH;
- nu->orderu = num_verts;
-
- if (smp.getType() == Alembic::AbcGeom::kCubic) {
- nu->orderu = 3;
- }
- else if (orders && orders->size() > i) {
- nu->orderu = static_cast<short>((*orders)[i] - 1);
+ switch (smp.getType()) {
+ case Alembic::AbcGeom::kCubic:
+ nu->orderu = 4;
+ break;
+ case Alembic::AbcGeom::kVariableOrder:
+ if (orders && orders->size() > i) {
+ nu->orderu = static_cast<short>((*orders)[i]);
+ }
+ break;
+ case Alembic::AbcGeom::kLinear:
+ default:
+ nu->orderu = 2;
}
if (periodicity == Alembic::AbcGeom::kNonPeriodic) {
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
index 61e7712150f..ef3196cb15d 100644
--- a/source/blender/alembic/intern/abc_exporter.cc
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -66,6 +66,7 @@ using Alembic::Abc::OBox3dProperty;
ExportSettings::ExportSettings()
: scene(NULL)
+ , logger()
, selected_only(false)
, visible_layers_only(false)
, renderable_only(false)
@@ -123,14 +124,32 @@ static bool object_is_shape(Object *ob)
}
}
-static bool export_object(const ExportSettings * const settings, Object *ob)
+
+/**
+ * Returns whether this object should be exported into the Alembic file.
+ *
+ * @param settings export settings, used for options like 'selected only'.
+ * @param ob the object in question.
+ * @param is_duplicated normally false; true when the object is instanced
+ * into the scene by a dupli-object (e.g. part of a
+ * dupligroup). This ignores selection and layer
+ * visibility, and assumes that the dupli-object itself
+ * (e.g. the group-instantiating empty) is exported.
+ */
+static bool export_object(const ExportSettings * const settings, Object *ob,
+ bool is_duplicated)
{
- if (settings->selected_only && !parent_selected(ob)) {
- return false;
- }
+ if (!is_duplicated) {
+ /* These two tests only make sense when the object isn't being instanced
+ * into the scene. When it is, its exportability is determined by
+ * its dupli-object and the DupliObject::no_draw property. */
+ if (settings->selected_only && !parent_selected(ob)) {
+ return false;
+ }
- if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) {
- return false;
+ if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) {
+ return false;
+ }
}
if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) {
@@ -153,11 +172,13 @@ AbcExporter::AbcExporter(Scene *scene, const char *filename, ExportSettings &set
AbcExporter::~AbcExporter()
{
- std::map<std::string, AbcTransformWriter*>::iterator it, e;
- for (it = m_xforms.begin(), e = m_xforms.end(); it != e; ++it) {
- delete it->second;
+ /* Free xforms map */
+ m_xforms_type::iterator it_x, e_x;
+ for (it_x = m_xforms.begin(), e_x = m_xforms.end(); it_x != e_x; ++it_x) {
+ delete it_x->second;
}
+ /* Free shapes vector */
for (int i = 0, e = m_shapes.size(); i != e; ++i) {
delete m_shapes[i];
}
@@ -269,13 +290,7 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_writer->archive(), m_trans_sampling_index);
- if (m_settings.flatten_hierarchy) {
- createTransformWritersFlat();
- }
- else {
- createTransformWritersHierarchy(bmain->eval_ctx);
- }
-
+ createTransformWritersHierarchy(bmain->eval_ctx);
createShapeWriters(bmain->eval_ctx);
/* Make a list of frames to export. */
@@ -322,7 +337,7 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
continue;
}
- std::map<std::string, AbcTransformWriter *>::iterator xit, xe;
+ m_xforms_type::iterator xit, xe;
for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) {
xit->second->write();
}
@@ -346,34 +361,16 @@ void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx)
while (base) {
Object *ob = base->object;
- if (export_object(&m_settings, ob)) {
- switch (ob->type) {
- case OB_LAMP:
- case OB_LATTICE:
- case OB_MBALL:
- case OB_SPEAKER:
- /* We do not export transforms for objects of these classes. */
- break;
-
- default:
- exploreTransform(eval_ctx, ob, ob->parent, NULL);
- }
- }
-
- base = base->next;
- }
-}
+ switch (ob->type) {
+ case OB_LAMP:
+ case OB_LATTICE:
+ case OB_MBALL:
+ case OB_SPEAKER:
+ /* We do not export transforms for objects of these classes. */
+ break;
-void AbcExporter::createTransformWritersFlat()
-{
- Base *base = static_cast<Base *>(m_scene->base.first);
-
- while (base) {
- Object *ob = base->object;
-
- if (export_object(&m_settings, ob) && object_is_shape(ob)) {
- std::string name = get_id_name(ob);
- m_xforms[name] = new AbcTransformWriter(ob, m_writer->archive().getTop(), 0, m_trans_sampling_index, m_settings);
+ default:
+ exploreTransform(eval_ctx, ob, ob->parent);
}
base = base->next;
@@ -382,8 +379,13 @@ void AbcExporter::createTransformWritersFlat()
void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent)
{
+ /* If an object isn't exported itself, its duplilist shouldn't be
+ * exported either. */
+ if (!export_object(&m_settings, ob, dupliObParent != NULL)) {
+ return;
+ }
- if (export_object(&m_settings, ob) && object_is_shape(ob)) {
+ if (object_is_shape(ob)) {
createTransformWriter(ob, parent, dupliObParent);
}
@@ -394,68 +396,91 @@ void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Obje
Object *dupli_ob = NULL;
Object *dupli_parent = NULL;
- while (link) {
+ for (; link; link = link->next) {
+ /* This skips things like custom bone shapes. */
+ if (m_settings.renderable_only && link->no_draw) {
+ continue;
+ }
+
if (link->type == OB_DUPLIGROUP) {
dupli_ob = link->ob;
dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob;
exploreTransform(eval_ctx, dupli_ob, dupli_parent, ob);
}
-
- link = link->next;
}
}
free_object_duplilist(lb);
}
-void AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent)
+AbcTransformWriter * AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent)
{
- const std::string name = get_object_dag_path_name(ob, dupliObParent);
-
/* An object should not be its own parent, or we'll get infinite loops. */
BLI_assert(ob != parent);
BLI_assert(ob != dupliObParent);
- /* check if we have already created a transform writer for this object */
- if (getXForm(name) != NULL){
- std::cerr << "xform " << name << " already exists\n";
- return;
+ std::string name;
+ if (m_settings.flatten_hierarchy) {
+ name = get_id_name(ob);
+ }
+ else {
+ name = get_object_dag_path_name(ob, dupliObParent);
}
- AbcTransformWriter *parent_xform = NULL;
+ /* check if we have already created a transform writer for this object */
+ AbcTransformWriter *my_writer = getXForm(name);
+ if (my_writer != NULL){
+ return my_writer;
+ }
- if (parent) {
- const std::string parentname = get_object_dag_path_name(parent, dupliObParent);
- parent_xform = getXForm(parentname);
+ AbcTransformWriter *parent_writer = NULL;
+ Alembic::Abc::OObject alembic_parent;
- if (!parent_xform) {
- if (parent->parent) {
- createTransformWriter(parent, parent->parent, dupliObParent);
+ if (m_settings.flatten_hierarchy || parent == NULL) {
+ /* Parentless objects still have the "top object" as parent
+ * in Alembic. */
+ alembic_parent = m_writer->archive().getTop();
+ }
+ else {
+ /* Since there are so many different ways to find parents (as evident
+ * in the number of conditions below), we can't really look up the
+ * parent by name. We'll just call createTransformWriter(), which will
+ * return the parent's AbcTransformWriter pointer. */
+ if (parent->parent) {
+ if (parent == dupliObParent) {
+ parent_writer = createTransformWriter(parent, parent->parent, NULL);
+ }
+ else {
+ parent_writer = createTransformWriter(parent, parent->parent, dupliObParent);
}
- else if (parent == dupliObParent) {
- if (dupliObParent->parent == NULL) {
- createTransformWriter(parent, NULL, NULL);
- }
- else {
- createTransformWriter(parent, dupliObParent->parent, dupliObParent->parent);
- }
+ }
+ else if (parent == dupliObParent) {
+ if (dupliObParent->parent == NULL) {
+ parent_writer = createTransformWriter(parent, NULL, NULL);
}
else {
- createTransformWriter(parent, dupliObParent, dupliObParent);
+ parent_writer = createTransformWriter(parent, dupliObParent->parent, dupliObParent->parent);
}
-
- parent_xform = getXForm(parentname);
}
- }
+ else {
+ parent_writer = createTransformWriter(parent, dupliObParent, dupliObParent);
+ }
- if (parent_xform) {
- m_xforms[name] = new AbcTransformWriter(ob, parent_xform->alembicXform(), parent_xform, m_trans_sampling_index, m_settings);
- m_xforms[name]->setParent(parent);
+ BLI_assert(parent_writer);
+ alembic_parent = parent_writer->alembicXform();
}
- else {
- m_xforms[name] = new AbcTransformWriter(ob, m_writer->archive().getTop(), NULL, m_trans_sampling_index, m_settings);
+
+ my_writer = new AbcTransformWriter(ob, alembic_parent, parent_writer,
+ m_trans_sampling_index, m_settings);
+
+ /* When flattening, the matrix of the dupliobject has to be added. */
+ if (m_settings.flatten_hierarchy && dupliObParent) {
+ my_writer->m_proxy_from = dupliObParent;
}
+
+ m_xforms[name] = my_writer;
+ return my_writer;
}
void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx)
@@ -472,19 +497,28 @@ void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx)
void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent)
{
- ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
-
+ /* If an object isn't exported itself, its duplilist shouldn't be
+ * exported either. */
+ if (!export_object(&m_settings, ob, dupliObParent != NULL)) {
+ return;
+ }
+
createShapeWriter(ob, dupliObParent);
+ ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
+
if (lb) {
- DupliObject *dupliob = static_cast<DupliObject *>(lb->first);
+ DupliObject *link = static_cast<DupliObject *>(lb->first);
- while (dupliob) {
- if (dupliob->type == OB_DUPLIGROUP) {
- exploreObject(eval_ctx, dupliob->ob, ob);
+ for (; link; link = link->next) {
+ /* This skips things like custom bone shapes. */
+ if (m_settings.renderable_only && link->no_draw) {
+ continue;
}
- dupliob = dupliob->next;
+ if (link->type == OB_DUPLIGROUP) {
+ exploreObject(eval_ctx, link->ob, ob);
+ }
}
}
@@ -497,10 +531,6 @@ void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
return;
}
- if (!export_object(&m_settings, ob)) {
- return;
- }
-
std::string name;
if (m_settings.flatten_hierarchy) {
@@ -513,7 +543,7 @@ void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
AbcTransformWriter *xform = getXForm(name);
if (!xform) {
- std::cerr << __func__ << ": xform " << name << " is NULL\n";
+ ABC_LOG(m_settings.logger) << __func__ << ": xform " << name << " is NULL\n";
return;
}
diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h
index b0eb8e185d6..73b7af280d9 100644
--- a/source/blender/alembic/intern/abc_exporter.h
+++ b/source/blender/alembic/intern/abc_exporter.h
@@ -28,6 +28,8 @@
#include <set>
#include <vector>
+#include "abc_util.h"
+
class AbcObjectWriter;
class AbcTransformWriter;
class ArchiveWriter;
@@ -41,6 +43,7 @@ struct ExportSettings {
ExportSettings();
Scene *scene;
+ SimpleLogger logger;
bool selected_only;
bool visible_layers_only;
@@ -86,7 +89,10 @@ class AbcExporter {
ArchiveWriter *m_writer;
- std::map<std::string, AbcTransformWriter *> m_xforms;
+ /* mapping from name to transform writer */
+ typedef std::map<std::string, AbcTransformWriter *> m_xforms_type;
+ m_xforms_type m_xforms;
+
std::vector<AbcObjectWriter *> m_shapes;
public:
@@ -103,8 +109,7 @@ private:
void getFrameSet(double step, std::set<double> &frames);
void createTransformWritersHierarchy(EvaluationContext *eval_ctx);
- void createTransformWritersFlat();
- void createTransformWriter(Object *ob, Object *parent, Object *dupliObParent);
+ AbcTransformWriter * createTransformWriter(Object *ob, Object *parent, Object *dupliObParent);
void exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent = NULL);
void exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent);
void createShapeWriters(EvaluationContext *eval_ctx);
diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc
index 5a57e43326a..79b891dbcd4 100644
--- a/source/blender/alembic/intern/abc_mesh.cc
+++ b/source/blender/alembic/intern/abc_mesh.cc
@@ -897,19 +897,31 @@ static void *add_customdata_cb(void *user_data, const char *name, int data_type)
{
DerivedMesh *dm = static_cast<DerivedMesh *>(user_data);
CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
- void *cd_ptr = NULL;
-
- if (ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) {
- cd_ptr = CustomData_get_layer_named(dm->getLoopDataLayout(dm), cd_data_type, name);
-
- if (cd_ptr == NULL) {
- cd_ptr = CustomData_add_layer_named(dm->getLoopDataLayout(dm),
- cd_data_type,
- CD_DEFAULT,
- NULL,
- dm->getNumLoops(dm),
- name);
- }
+ void *cd_ptr;
+ CustomData *loopdata;
+ int numloops;
+
+ /* unsupported custom data type -- don't do anything. */
+ if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) {
+ return NULL;
+ }
+
+ loopdata = dm->getLoopDataLayout(dm);
+ cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name);
+ if (cd_ptr != NULL) {
+ /* layer already exists, so just return it. */
+ return cd_ptr;
+ }
+
+ /* create a new layer, taking care to construct the hopefully-soon-to-be-removed
+ * CD_MTEXPOLY layer too, with the same name. */
+ numloops = dm->getNumLoops(dm);
+ cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT,
+ NULL, numloops, name);
+ if (cd_data_type == CD_MLOOPUV) {
+ CustomData_add_layer_named(dm->getPolyDataLayout(dm),
+ CD_MTEXPOLY, CD_DEFAULT,
+ NULL, numloops, name);
}
return cd_ptr;
diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc
index a5b8af542fc..c8716d55218 100644
--- a/source/blender/alembic/intern/abc_object.cc
+++ b/source/blender/alembic/intern/abc_object.cc
@@ -91,7 +91,7 @@ Imath::Box3d AbcObjectWriter::bounds()
if (!bb) {
if (this->m_object->type != OB_CAMERA) {
- std::cerr << "Boundbox is null!\n";
+ ABC_LOG(m_settings.logger) << "Bounding box is null!\n";
}
return Imath::Box3d();
@@ -127,6 +127,7 @@ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings
, m_min_time(std::numeric_limits<chrono_t>::max())
, m_max_time(std::numeric_limits<chrono_t>::min())
, m_refcount(0)
+ , parent_reader(NULL)
{
m_name = object.getFullName();
std::vector<std::string> parts;
@@ -214,7 +215,7 @@ Imath::M44d get_matrix(const IXformSchema &schema, const float time)
return s0.getMatrix();
}
-void AbcObjectReader::readObjectMatrix(const float time)
+void AbcObjectReader::setupObjectTransform(const float time)
{
bool is_constant = false;
@@ -236,49 +237,88 @@ void AbcObjectReader::readObjectMatrix(const float time)
}
}
-void AbcObjectReader::read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant)
+Alembic::AbcGeom::IXform AbcObjectReader::xform()
{
- IXform ixform;
- bool has_alembic_parent = false;
-
/* Check that we have an empty object (locator, bone head/tail...). */
if (IXform::matches(m_iobject.getMetaData())) {
- ixform = IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
-
- /* See comment below. */
- has_alembic_parent = m_iobject.getParent().getParent().valid();
+ return IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
}
- /* Check that we have an object with actual data. */
- else if (IXform::matches(m_iobject.getParent().getMetaData())) {
- ixform = IXform(m_iobject.getParent(), Alembic::AbcGeom::kWrapExisting);
-
- /* This is a bit hackish, but we need to make sure that extra
- * transformations added to the matrix (rotation/scale) are only applied
- * to root objects. The way objects and their hierarchy are created will
- * need to be revisited at some point but for now this seems to do the
- * trick.
- *
- * Explanation of the trick:
- * The first getParent() will return this object's transformation matrix.
- * The second getParent() will get the parent of the transform, but this
- * might be the archive root ('/') which is valid, so we go passed it to
- * make sure that there is no parent.
- */
- has_alembic_parent = m_iobject.getParent().getParent().getParent().valid();
+
+ /* Check that we have an object with actual data, in which case the
+ * parent Alembic object should contain the transform. */
+ IObject abc_parent = m_iobject.getParent();
+
+ /* The archive's top object can be recognised by not having a parent. */
+ if (abc_parent.getParent()
+ && IXform::matches(abc_parent.getMetaData())) {
+ return IXform(abc_parent, Alembic::AbcGeom::kWrapExisting);
}
+
/* Should not happen. */
- else {
+ std::cerr << "AbcObjectReader::xform(): "
+ << "unable to find IXform for Alembic object '"
+ << m_iobject.getFullName() << "'\n";
+ BLI_assert(false);
+
+ return IXform();
+}
+
+void AbcObjectReader::read_matrix(float r_mat[4][4], const float time,
+ const float scale, bool &is_constant)
+{
+ IXform ixform = xform();
+ if (!ixform) {
return;
}
- const IXformSchema &schema(ixform.getSchema());
-
+ const IXformSchema & schema(ixform.getSchema());
if (!schema.valid()) {
+ std::cerr << "Alembic object " << ixform.getFullName()
+ << " has an invalid schema." << std::endl;
return;
}
+ bool has_alembic_parent;
+ IObject ixform_parent = ixform.getParent();
+ if (!ixform_parent.getParent()) {
+ /* The archive top object certainly is not a transform itself, so handle
+ * it as "no parent". */
+ has_alembic_parent = false;
+ }
+ else {
+ has_alembic_parent = ixform_parent && schema.getInheritsXforms();
+
+ if (has_alembic_parent && m_object->parent == NULL) {
+ /* TODO Sybren: This happened in some files. I think I solved it,
+ * but I'll leave this check in here anyway until we've tested it
+ * more thoroughly. Better than crashing on a null parent anyway. */
+ std::cerr << "Alembic object " << m_iobject.getFullName()
+ << " with transform " << ixform.getFullName()
+ << " has an Alembic parent but no parent Blender object."
+ << std::endl;
+ has_alembic_parent = false;
+ }
+ }
+
const Imath::M44d matrix = get_matrix(schema, time);
- convert_matrix(matrix, m_object, mat, scale, has_alembic_parent);
+ convert_matrix(matrix, m_object, r_mat);
+
+ if (has_alembic_parent) {
+ /* In this case, the matrix in Alembic is in local coordinates, so
+ * convert to world matrix. To prevent us from reading and accumulating
+ * all parent matrices in the Alembic file, we assume that the Blender
+ * parent object is already updated for the current timekey, and use its
+ * world matrix. */
+ BLI_assert(m_object->parent);
+ mul_m4_m4m4(r_mat, m_object->parent->obmat, r_mat);
+ }
+ else {
+ /* Only apply scaling to root objects, parenting will propagate it. */
+ float scale_mat[4][4];
+ scale_m4_fl(scale_mat, scale);
+ scale_mat[3][3] = scale; /* scale translations too */
+ mul_m4_m4m4(r_mat, r_mat, scale_mat);
+ }
is_constant = schema.isConstant();
}
diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h
index 0f733e67d3f..d5344533b55 100644
--- a/source/blender/alembic/intern/abc_object.h
+++ b/source/blender/alembic/intern/abc_object.h
@@ -117,15 +117,7 @@ struct ImportSettings {
template <typename Schema>
static bool has_animations(Schema &schema, ImportSettings *settings)
{
- if (settings->is_sequence) {
- return true;
- }
-
- if (!schema.isConstant()) {
- return true;
- }
-
- return false;
+ return settings->is_sequence || !schema.isConstant();
}
/* ************************************************************************** */
@@ -152,15 +144,30 @@ protected:
int m_refcount;
public:
+ AbcObjectReader *parent_reader;
+
+public:
explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
virtual ~AbcObjectReader();
const Alembic::Abc::IObject &iobject() const;
+ typedef std::vector<AbcObjectReader *> ptr_vector;
+
+ /**
+ * Returns the transform of this object. This can be the Alembic object
+ * itself (in case of an Empty) or it can be the parent Alembic object.
+ */
+ virtual Alembic::AbcGeom::IXform xform();
+
Object *object() const;
void object(Object *ob);
+ const std::string & name() const { return m_name; }
+ const std::string & object_name() const { return m_object_name; }
+ const std::string & data_name() const { return m_data_name; }
+
virtual bool valid() const = 0;
virtual void readObjectData(Main *bmain, float time) = 0;
@@ -173,7 +180,8 @@ public:
return dm;
}
- void readObjectMatrix(const float time);
+ /** Reads the object matrix and sets up an object transform if animated. */
+ void setupObjectTransform(const float time);
void addCacheModifier();
@@ -184,7 +192,8 @@ public:
void incref();
void decref();
- void read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant);
+ void read_matrix(float r_mat[4][4], const float time,
+ const float scale, bool &is_constant);
};
Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time);
diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc
index 2c6ef09326c..6e218cac429 100644
--- a/source/blender/alembic/intern/abc_transform.cc
+++ b/source/blender/alembic/intern/abc_transform.cc
@@ -62,9 +62,9 @@ AbcTransformWriter::AbcTransformWriter(Object *ob,
unsigned int time_sampling,
ExportSettings &settings)
: AbcObjectWriter(NULL, ob, time_sampling, settings, parent)
+ , m_proxy_from(NULL)
{
m_is_animated = hasAnimation(m_object);
- m_parent = NULL;
if (!m_is_animated) {
time_sampling = 0;
@@ -72,6 +72,9 @@ AbcTransformWriter::AbcTransformWriter(Object *ob,
m_xform = OXform(abc_parent, get_id_name(m_object), time_sampling);
m_schema = m_xform.getSchema();
+
+ /* Blender objects can't have a parent without inheriting the transform. */
+ m_inherits_xform = parent != NULL;
}
void AbcTransformWriter::do_write()
@@ -86,27 +89,29 @@ void AbcTransformWriter::do_write()
return;
}
- float mat[4][4];
- create_transform_matrix(m_object, mat);
+ float yup_mat[4][4];
+ create_transform_matrix(m_object, yup_mat,
+ m_inherits_xform ? ABC_MATRIX_LOCAL : ABC_MATRIX_WORLD,
+ m_proxy_from);
/* Only apply rotation to root camera, parenting will propagate it. */
- if (m_object->type == OB_CAMERA && !has_parent_camera(m_object)) {
+ if (m_object->type == OB_CAMERA && (!m_inherits_xform || !has_parent_camera(m_object))) {
float rot_mat[4][4];
axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2);
- mul_m4_m4m4(mat, mat, rot_mat);
+ mul_m4_m4m4(yup_mat, yup_mat, rot_mat);
}
- if (!m_object->parent) {
+ if (!m_object->parent || !m_inherits_xform) {
/* Only apply scaling to root objects, parenting will propagate it. */
float scale_mat[4][4];
scale_m4_fl(scale_mat, m_settings.global_scale);
- mul_m4_m4m4(mat, mat, scale_mat);
- mul_v3_fl(mat[3], m_settings.global_scale);
+ scale_mat[3][3] = m_settings.global_scale; /* also scale translation */
+ mul_m4_m4m4(yup_mat, yup_mat, scale_mat);
}
- m_matrix = convert_matrix(mat);
-
+ m_matrix = convert_matrix(yup_mat);
m_sample.setMatrix(m_matrix);
+ m_sample.setInheritsXforms(m_inherits_xform);
m_schema.set(m_sample);
}
@@ -133,6 +138,10 @@ bool AbcTransformWriter::hasAnimation(Object * /*ob*/) const
AbcEmptyReader::AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
: AbcObjectReader(object, settings)
{
+ /* Empties have no data. It makes the import of Alembic files easier to
+ * understand when we name the empty after its name in Alembic. */
+ m_object_name = object.getName();
+
Alembic::AbcGeom::IXform xform(object, Alembic::AbcGeom::kWrapExisting);
m_schema = xform.getSchema();
@@ -146,6 +155,7 @@ bool AbcEmptyReader::valid() const
void AbcEmptyReader::readObjectData(Main *bmain, float /*time*/)
{
- m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_data_name.c_str());
+ m_object = BKE_object_add_only_object(bmain, OB_EMPTY,
+ m_object_name.c_str());
m_object->data = NULL;
}
diff --git a/source/blender/alembic/intern/abc_transform.h b/source/blender/alembic/intern/abc_transform.h
index 6a3aae216f2..59388e155dc 100644
--- a/source/blender/alembic/intern/abc_transform.h
+++ b/source/blender/alembic/intern/abc_transform.h
@@ -37,8 +37,11 @@ class AbcTransformWriter : public AbcObjectWriter {
Alembic::Abc::M44d m_matrix;
bool m_is_animated;
- Object *m_parent;
bool m_visible;
+ bool m_inherits_xform;
+
+public:
+ Object *m_proxy_from;
public:
AbcTransformWriter(Object *ob,
@@ -49,7 +52,6 @@ public:
Alembic::AbcGeom::OXform &alembicXform() { return m_xform;}
virtual Imath::Box3d bounds();
- void setParent(Object *p) { m_parent = p; }
private:
virtual void do_write();
diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc
index 50fa43a3491..67d2d3b1eb2 100644
--- a/source/blender/alembic/intern/abc_util.cc
+++ b/source/blender/alembic/intern/abc_util.cc
@@ -41,7 +41,7 @@ extern "C" {
#include "PIL_time.h"
}
-std::string get_id_name(Object *ob)
+std::string get_id_name(const Object * const ob)
{
if (!ob) {
return "";
@@ -50,7 +50,7 @@ std::string get_id_name(Object *ob)
return get_id_name(&ob->id);
}
-std::string get_id_name(ID *id)
+std::string get_id_name(const ID * const id)
{
std::string name(id->name + 2);
std::replace(name.begin(), name.end(), ' ', '_');
@@ -60,7 +60,7 @@ std::string get_id_name(ID *id)
return name;
}
-std::string get_object_dag_path_name(Object *ob, Object *dupli_parent)
+std::string get_object_dag_path_name(const Object * const ob, Object *dupli_parent)
{
std::string name = get_id_name(ob);
@@ -132,15 +132,28 @@ void split(const std::string &s, const char delim, std::vector<std::string> &tok
}
}
-/* Create a rotation matrix for each axis from euler angles.
- * Euler angles are swaped to change coordinate system. */
-static void create_rotation_matrix(
+void create_swapped_rotation_matrix(
float rot_x_mat[3][3], float rot_y_mat[3][3],
- float rot_z_mat[3][3], const float euler[3], const bool to_yup)
+ float rot_z_mat[3][3], const float euler[3],
+ AbcAxisSwapMode mode)
{
const float rx = euler[0];
- const float ry = (to_yup) ? euler[2] : -euler[2];
- const float rz = (to_yup) ? -euler[1] : euler[1];
+ float ry;
+ float rz;
+
+ /* Apply transformation */
+ switch(mode) {
+ case ABC_ZUP_FROM_YUP:
+ ry = -euler[2];
+ rz = euler[1];
+ break;
+ case ABC_YUP_FROM_ZUP:
+ ry = euler[2];
+ rz = -euler[1];
+ break;
+ default:
+ BLI_assert(false);
+ }
unit_m3(rot_x_mat);
unit_m3(rot_y_mat);
@@ -162,58 +175,70 @@ static void create_rotation_matrix(
rot_z_mat[1][1] = cos(rz);
}
-/* Recompute transform matrix of object in new coordinate system
- * (from Y-Up to Z-Up). */
-void create_transform_matrix(float r_mat[4][4])
+/* Convert matrix from Z=up to Y=up or vice versa. Use yup_mat = zup_mat for in-place conversion. */
+void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode)
{
- float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], transform_mat[4][4];
+ float dst_rot[3][3], src_rot[3][3], dst_scale_mat[4][4];
float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
- float loc[3], scale[3], euler[3];
+ float src_trans[3], dst_scale[3], src_scale[3], euler[3];
- zero_v3(loc);
- zero_v3(scale);
+ zero_v3(src_trans);
+ zero_v3(dst_scale);
+ zero_v3(src_scale);
zero_v3(euler);
- unit_m3(rot);
- unit_m3(rot_mat);
- unit_m4(scale_mat);
- unit_m4(transform_mat);
- unit_m4(invmat);
+ unit_m3(src_rot);
+ unit_m3(dst_rot);
+ unit_m4(dst_scale_mat);
- /* Compute rotation matrix. */
+ /* We assume there is no sheer component and no homogeneous scaling component. */
+ BLI_assert(fabs(src_mat[0][3]) < 2 * FLT_EPSILON);
+ BLI_assert(fabs(src_mat[1][3]) < 2 * FLT_EPSILON);
+ BLI_assert(fabs(src_mat[2][3]) < 2 * FLT_EPSILON);
+ BLI_assert(fabs(src_mat[3][3] - 1.0f) < 2 * FLT_EPSILON);
- /* Extract location, rotation, and scale from matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, r_mat);
+ /* Extract translation, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(src_trans, src_rot, src_scale, src_mat);
/* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
+ mat3_to_eulO(euler, ROT_MODE_XZY, src_rot);
/* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, false);
+ create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, mode);
/* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+ mul_m3_m3m3(dst_rot, dst_rot, rot_z_mat);
+ mul_m3_m3m3(dst_rot, dst_rot, rot_y_mat);
+ mul_m3_m3m3(dst_rot, dst_rot, rot_x_mat);
- /* Add rotation matrix to transformation matrix. */
- copy_m4_m3(transform_mat, rot_mat);
+ mat3_to_eulO(euler, ROT_MODE_XZY, dst_rot);
- /* Add translation to transformation matrix. */
- copy_zup_from_yup(transform_mat[3], loc);
+ /* Start construction of dst_mat from rotation matrix */
+ unit_m4(dst_mat);
+ copy_m4_m3(dst_mat, dst_rot);
- /* Create scale matrix. */
- scale_mat[0][0] = scale[0];
- scale_mat[1][1] = scale[2];
- scale_mat[2][2] = scale[1];
+ /* Apply translation */
+ switch(mode) {
+ case ABC_ZUP_FROM_YUP:
+ copy_zup_from_yup(dst_mat[3], src_trans);
+ break;
+ case ABC_YUP_FROM_ZUP:
+ copy_yup_from_zup(dst_mat[3], src_trans);
+ break;
+ default:
+ BLI_assert(false);
+ }
- /* Add scale to transformation matrix. */
- mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
+ /* Apply scale matrix. Swaps y and z, but does not
+ * negate like translation does. */
+ dst_scale[0] = src_scale[0];
+ dst_scale[1] = src_scale[2];
+ dst_scale[2] = src_scale[1];
- copy_m4_m4(r_mat, transform_mat);
+ size_to_mat4(dst_scale_mat, dst_scale);
+ mul_m4_m4m4(dst_mat, dst_mat, dst_scale_mat);
}
-void convert_matrix(const Imath::M44d &xform, Object *ob,
- float r_mat[4][4], float scale, bool has_alembic_parent)
+void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4])
{
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
@@ -227,207 +252,32 @@ void convert_matrix(const Imath::M44d &xform, Object *ob,
mul_m4_m4m4(r_mat, r_mat, cam_to_yup);
}
- create_transform_matrix(r_mat);
-
- if (ob->parent) {
- mul_m4_m4m4(r_mat, ob->parent->obmat, r_mat);
- }
- /* TODO(kevin) */
- else if (!has_alembic_parent) {
- /* Only apply scaling to root objects, parenting will propagate it. */
- float scale_mat[4][4];
- scale_m4_fl(scale_mat, scale);
- mul_m4_m4m4(r_mat, r_mat, scale_mat);
- mul_v3_fl(r_mat[3], scale);
- }
+ copy_m44_axis_swap(r_mat, r_mat, ABC_ZUP_FROM_YUP);
}
-/* Recompute transform matrix of object in new coordinate system (from Z-Up to Y-Up). */
-void create_transform_matrix(Object *obj, float transform_mat[4][4])
+/* Recompute transform matrix of object in new coordinate system
+ * (from Z-Up to Y-Up). */
+void create_transform_matrix(Object *obj, float r_yup_mat[4][4], AbcMatrixMode mode,
+ Object *proxy_from)
{
- float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], mat[4][4];
- float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
- float loc[3], scale[3], euler[3];
-
- zero_v3(loc);
- zero_v3(scale);
- zero_v3(euler);
- unit_m3(rot);
- unit_m3(rot_mat);
- unit_m4(scale_mat);
- unit_m4(transform_mat);
- unit_m4(invmat);
- unit_m4(mat);
-
- /* get local matrix. */
- if (obj->parent) {
- invert_m4_m4(invmat, obj->parent->obmat);
- mul_m4_m4m4(mat, invmat, obj->obmat);
+ float zup_mat[4][4];
+
+ /* get local or world matrix. */
+ if (mode == ABC_MATRIX_LOCAL && obj->parent) {
+ /* Note that this produces another matrix than the local matrix, due to
+ * constraints and modifiers as well as the obj->parentinv matrix. */
+ invert_m4_m4(obj->parent->imat, obj->parent->obmat);
+ mul_m4_m4m4(zup_mat, obj->parent->imat, obj->obmat);
}
else {
- copy_m4_m4(mat, obj->obmat);
+ copy_m4_m4(zup_mat, obj->obmat);
}
- /* Compute rotation matrix. */
- switch (obj->rotmode) {
- case ROT_MODE_AXISANGLE:
- {
- /* Get euler angles from axis angle rotation. */
- axis_angle_to_eulO(euler, ROT_MODE_XYZ, obj->rotAxis, obj->rotAngle);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
-
- /* Extract location and scale from matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- break;
- }
- case ROT_MODE_QUAT:
- {
- float q[4];
- copy_v4_v4(q, obj->quat);
-
- /* Swap axis. */
- q[2] = obj->quat[3];
- q[3] = -obj->quat[2];
-
- /* Compute rotation matrix from quaternion. */
- quat_to_mat3(rot_mat, q);
-
- /* Extract location and scale from matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- break;
- }
- case ROT_MODE_XYZ:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
-
- break;
- }
- case ROT_MODE_XZY:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_XZY, rot);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
-
- break;
- }
- case ROT_MODE_YXZ:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_YXZ, rot);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
-
- break;
- }
- case ROT_MODE_YZX:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_YZX, rot);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
-
- break;
- }
- case ROT_MODE_ZXY:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_ZXY, rot);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
-
- break;
- }
- case ROT_MODE_ZYX:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_ZYX, rot);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
-
- break;
- }
+ if (proxy_from) {
+ mul_m4_m4m4(zup_mat, proxy_from->obmat, zup_mat);
}
- /* Add rotation matrix to transformation matrix. */
- copy_m4_m3(transform_mat, rot_mat);
-
- /* Add translation to transformation matrix. */
- copy_yup_from_zup(transform_mat[3], loc);
-
- /* Create scale matrix. */
- scale_mat[0][0] = scale[0];
- scale_mat[1][1] = scale[2];
- scale_mat[2][2] = scale[1];
-
- /* Add scale to transformation matrix. */
- mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
+ copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP);
}
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
@@ -520,7 +370,10 @@ AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSe
reader = new AbcCurveReader(object, settings);
}
else {
- assert(false);
+ std::cerr << "Alembic: unknown how to handle objects of schema "
+ << md.get("schemaObjTitle")
+ << ", skipping object "
+ << object.getFullName() << std::endl;
}
return reader;
@@ -537,3 +390,32 @@ ScopeTimer::~ScopeTimer()
{
fprintf(stderr, "%s: %fs\n", m_message, PIL_check_seconds_timer() - m_start);
}
+
+/* ********************** */
+
+bool SimpleLogger::empty()
+{
+ return ((size_t)m_stream.tellp()) == 0ul;
+}
+
+std::string SimpleLogger::str() const
+{
+ return m_stream.str();
+}
+
+void SimpleLogger::clear()
+{
+ m_stream.clear();
+ m_stream.str("");
+}
+
+std::ostringstream &SimpleLogger::stream()
+{
+ return m_stream;
+}
+
+std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger)
+{
+ os << logger.str();
+ return os;
+}
diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h
index 85ba4d5c9c7..74d0faf97d3 100644
--- a/source/blender/alembic/intern/abc_util.h
+++ b/source/blender/alembic/intern/abc_util.h
@@ -32,6 +32,11 @@
# define ABC_INLINE static inline
#endif
+/**
+ * @brief The CacheReader struct is only used for anonymous pointers,
+ * to interface between C and C++ code. This library only creates
+ * pointers to AbcObjectReader (or subclasses thereof).
+ */
struct CacheReader {
int unused;
};
@@ -44,16 +49,21 @@ struct ImportSettings;
struct ID;
struct Object;
-std::string get_id_name(ID *id);
-std::string get_id_name(Object *ob);
-std::string get_object_dag_path_name(Object *ob, Object *dupli_parent);
+std::string get_id_name(const ID * const id);
+std::string get_id_name(const Object * const ob);
+std::string get_object_dag_path_name(const Object * const ob, Object *dupli_parent);
bool object_selected(Object *ob);
bool parent_selected(Object *ob);
Imath::M44d convert_matrix(float mat[4][4]);
-void create_transform_matrix(float r_mat[4][4]);
-void create_transform_matrix(Object *obj, float transform_mat[4][4]);
+
+typedef enum {
+ ABC_MATRIX_WORLD = 1,
+ ABC_MATRIX_LOCAL = 2,
+} AbcMatrixMode;
+void create_transform_matrix(Object *obj, float r_transform_mat[4][4],
+ AbcMatrixMode mode, Object *proxy_from);
void split(const std::string &s, const char delim, std::vector<std::string> &tokens);
@@ -64,8 +74,7 @@ bool begins_with(const TContainer &input, const TContainer &match)
&& std::equal(match.begin(), match.end(), input.begin());
}
-void convert_matrix(const Imath::M44d &xform, Object *ob,
- float r_mat[4][4], float scale, bool has_alembic_parent = false);
+void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4]);
template <typename Schema>
void get_min_max_time_ex(const Schema &schema, chrono_t &min, chrono_t &max)
@@ -118,34 +127,54 @@ AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSe
ABC_INLINE void copy_zup_from_yup(float zup[3], const float yup[3])
{
+ const float old_yup1 = yup[1]; /* in case zup == yup */
zup[0] = yup[0];
zup[1] = -yup[2];
- zup[2] = yup[1];
+ zup[2] = old_yup1;
}
ABC_INLINE void copy_zup_from_yup(short zup[3], const short yup[3])
{
+ const short old_yup1 = yup[1]; /* in case zup == yup */
zup[0] = yup[0];
zup[1] = -yup[2];
- zup[2] = yup[1];
+ zup[2] = old_yup1;
}
/* Copy from Z-up to Y-up. */
ABC_INLINE void copy_yup_from_zup(float yup[3], const float zup[3])
{
+ const float old_zup1 = zup[1]; /* in case yup == zup */
yup[0] = zup[0];
yup[1] = zup[2];
- yup[2] = -zup[1];
+ yup[2] = -old_zup1;
}
ABC_INLINE void copy_yup_from_zup(short yup[3], const short zup[3])
{
+ const short old_zup1 = zup[1]; /* in case yup == zup */
yup[0] = zup[0];
yup[1] = zup[2];
- yup[2] = -zup[1];
+ yup[2] = -old_zup1;
}
+/* Names are given in (dst, src) order, just like
+ * the parameters of copy_m44_axis_swap() */
+typedef enum {
+ ABC_ZUP_FROM_YUP = 1,
+ ABC_YUP_FROM_ZUP = 2,
+} AbcAxisSwapMode;
+
+/* Create a rotation matrix for each axis from euler angles.
+ * Euler angles are swaped to change coordinate system. */
+void create_swapped_rotation_matrix(
+ float rot_x_mat[3][3], float rot_y_mat[3][3],
+ float rot_z_mat[3][3], const float euler[3],
+ AbcAxisSwapMode mode);
+
+void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode);
+
/* *************************** */
#undef ABC_DEBUG_TIME
@@ -165,4 +194,48 @@ public:
# define SCOPE_TIMER(message)
#endif
+/* *************************** */
+
+/**
+ * Utility class whose purpose is to more easily log related informations. An
+ * instance of the SimpleLogger can be created in any context, and will hold a
+ * copy of all the strings passed to its output stream.
+ *
+ * Different instances of the class may be accessed from different threads,
+ * although accessing the same instance from different threads will lead to race
+ * conditions.
+ */
+class SimpleLogger {
+ std::ostringstream m_stream;
+
+public:
+ /**
+ * Check whether or not the SimpleLogger's stream is empty.
+ */
+ bool empty();
+
+ /**
+ * Return a copy of the string contained in the SimpleLogger's stream.
+ */
+ std::string str() const;
+
+ /**
+ * Remove the bits set on the SimpleLogger's stream and clear its string.
+ */
+ void clear();
+
+ /**
+ * Return a reference to the SimpleLogger's stream, in order to e.g. push
+ * content into it.
+ */
+ std::ostringstream &stream();
+};
+
+#define ABC_LOG(logger) logger.stream()
+
+/**
+ * Pass the content of the logger's stream to the specified std::ostream.
+ */
+std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger);
+
#endif /* __ABC_UTIL_H__ */
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index dc5146a26e0..0de0d1a1ab6 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -21,6 +21,7 @@
*/
#include "../ABC_alembic.h"
+#include <boost/foreach.hpp>
#include <Alembic/AbcMaterial/IMaterial.h>
@@ -120,91 +121,62 @@ ABC_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive)
/* NOTE: this function is similar to visit_objects below, need to keep them in
* sync. */
-static void gather_objects_paths(const IObject &object, ListBase *object_paths)
+static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
{
if (!object.valid()) {
- return;
+ return false;
}
- for (int i = 0; i < object.getNumChildren(); ++i) {
- IObject child = object.getChild(i);
- if (!child.valid()) {
- continue;
- }
+ size_t children_claiming_this_object = 0;
+ size_t num_children = object.getNumChildren();
- bool get_path = false;
+ for (size_t i = 0; i < num_children; ++i) {
+ bool child_claims_this_object = gather_objects_paths(object.getChild(i), object_paths);
+ children_claiming_this_object += child_claims_this_object ? 1 : 0;
+ }
- const MetaData &md = child.getMetaData();
+ const MetaData &md = object.getMetaData();
+ bool get_path = false;
+ bool parent_is_part_of_this_object = false;
- if (IXform::matches(md)) {
- /* Check whether or not this object is a Maya locator, which is
- * similar to empties used as parent object in Blender. */
- if (has_property(child.getProperties(), "locator")) {
- get_path = true;
- }
- else {
- /* Avoid creating an empty object if the child of this transform
- * is not a transform (that is an empty). */
- if (child.getNumChildren() == 1) {
- if (IXform::matches(child.getChild(0).getMetaData())) {
- get_path = true;
- }
-#if 0
- else {
- std::cerr << "Skipping " << child.getFullName() << '\n';
- }
-#endif
- }
- else {
- get_path = true;
- }
- }
- }
- else if (IPolyMesh::matches(md)) {
- get_path = true;
- }
- else if (ISubD::matches(md)) {
- get_path = true;
- }
- else if (INuPatch::matches(md)) {
-#ifdef USE_NURBS
- get_path = true;
-#endif
- }
- else if (ICamera::matches(md)) {
- get_path = true;
- }
- else if (IPoints::matches(md)) {
- get_path = true;
- }
- else if (IMaterial::matches(md)) {
- /* Pass for now. */
- }
- else if (ILight::matches(md)) {
- /* Pass for now. */
- }
- else if (IFaceSet::matches(md)) {
- /* Pass, those are handled in the mesh reader. */
- }
- else if (ICurves::matches(md)) {
+ if (!object.getParent()) {
+ /* The root itself is not an object we should import. */
+ }
+ else if (IXform::matches(md)) {
+ if (has_property(object.getProperties(), "locator")) {
get_path = true;
}
else {
- assert(false);
+ get_path = children_claiming_this_object == 0;
}
- if (get_path) {
- AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
- MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
-
- BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX);
+ /* Transforms are never "data" for their parent. */
+ parent_is_part_of_this_object = false;
+ }
+ else {
+ /* These types are "data" for their parent. */
+ get_path =
+ IPolyMesh::matches(md) ||
+ ISubD::matches(md) ||
+#ifdef USE_NURBS
+ INuPatch::matches(md) ||
+#endif
+ ICamera::matches(md) ||
+ IPoints::matches(md) ||
+ ICurves::matches(md);
+ parent_is_part_of_this_object = get_path;
+ }
- BLI_addtail(object_paths, abc_path);
- }
+ if (get_path) {
+ void *abc_path_void = MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath");
+ AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(abc_path_void);
- gather_objects_paths(child, object_paths);
+ BLI_strncpy(abc_path->path, object.getFullName().c_str(), PATH_MAX);
+ BLI_addtail(object_paths, abc_path);
}
+
+ return parent_is_part_of_this_object;
}
AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths)
@@ -301,10 +273,10 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
}
}
catch (const std::exception &e) {
- std::cerr << "Abc Export error: " << e.what() << '\n';
+ ABC_LOG(data->settings.logger) << "Abc Export error: " << e.what() << '\n';
}
catch (...) {
- std::cerr << "Abc Export error\n";
+ ABC_LOG(data->settings.logger) << "Abc Export: unknown error...\n";
}
}
@@ -316,6 +288,11 @@ static void export_endjob(void *customdata)
BLI_delete(data->filename, false, false);
}
+ if (!data->settings.logger.empty()) {
+ std::cerr << data->settings.logger;
+ WM_report(RPT_ERROR, "Errors occured during the export, look in the console to know more...");
+ }
+
G.is_rendering = false;
BKE_spacedata_draw_locks(false);
}
@@ -331,6 +308,22 @@ void ABC_export(
job->bmain = CTX_data_main(C);
BLI_strncpy(job->filename, filepath, 1024);
+ /* Alright, alright, alright....
+ *
+ * ExportJobData contains an ExportSettings containing a SimpleLogger.
+ *
+ * Since ExportJobData is a C-style struct dynamically allocated with
+ * MEM_mallocN (see above), its construtor is never called, therefore the
+ * ExportSettings constructor is not called which implies that the
+ * SimpleLogger one is not called either. SimpleLogger in turn does not call
+ * the constructor of its data members which ultimately means that its
+ * std::ostringstream member has a NULL pointer. To be able to properly use
+ * the stream's operator<<, the pointer needs to be set, therefore we have
+ * to properly construct everything. And this is done using the placement
+ * new operator as here below. It seems hackish, but I'm too lazy to
+ * do bigger refactor and maybe there is a better way which does not involve
+ * hardcore refactoring. */
+ new (&job->settings) ExportSettings();
job->settings.scene = job->scene;
job->settings.frame_start = params->frame_start;
job->settings.frame_end = params->frame_end;
@@ -376,114 +369,208 @@ void ABC_export(
/* ********************** Import file ********************** */
-static void visit_object(const IObject &object,
- std::vector<AbcObjectReader *> &readers,
- GHash *parent_map,
- ImportSettings &settings)
+/**
+ * Generates an AbcObjectReader for this Alembic object and its children.
+ *
+ * \param object The Alembic IObject to visit.
+ * \param readers The created AbcObjectReader * will be appended to this vector.
+ * \param settings Import settings, not used directly but passed to the
+ * AbcObjectReader subclass constructors.
+ * \param r_assign_as_parent Return parameter, contains a list of reader
+ * pointers, whose parent pointer should still be set.
+ * This is filled when this call to visit_object() didn't create
+ * a reader that should be the parent.
+ * \return A pair of boolean and reader pointer. The boolean indicates whether
+ * this IObject claims its parent as part of the same object
+ * (for example an IPolyMesh object would claim its parent, as the mesh
+ * is interpreted as the object's data, and the parent IXform as its
+ * Blender object). The pointer is the AbcObjectReader that represents
+ * the IObject parameter.
+ *
+ * NOTE: this function is similar to gather_object_paths above, need to keep
+ * them in sync. */
+static std::pair<bool, AbcObjectReader *> visit_object(
+ const IObject &object,
+ AbcObjectReader::ptr_vector &readers,
+ ImportSettings &settings,
+ AbcObjectReader::ptr_vector &r_assign_as_parent)
{
+ const std::string & full_name = object.getFullName();
+
if (!object.valid()) {
- return;
+ std::cerr << " - "
+ << full_name
+ << ": object is invalid, skipping it and all its children.\n";
+ return std::make_pair(false, static_cast<AbcObjectReader *>(NULL));
}
- for (int i = 0; i < object.getNumChildren(); ++i) {
- IObject child = object.getChild(i);
+ /* The interpretation of data by the children determine the role of this
+ * object. This is especially important for Xform objects, as they can be
+ * either part of a Blender object or a Blender object (Empty) themselves.
+ */
+ size_t children_claiming_this_object = 0;
+ size_t num_children = object.getNumChildren();
+ AbcObjectReader::ptr_vector claiming_child_readers;
+ AbcObjectReader::ptr_vector nonclaiming_child_readers;
+ AbcObjectReader::ptr_vector assign_as_parent;
+ for (size_t i = 0; i < num_children; ++i) {
+ const IObject ichild = object.getChild(i);
- if (!child.valid()) {
- continue;
+ /* TODO: When we only support C++11, use std::tie() instead. */
+ std::pair<bool, AbcObjectReader *> child_result;
+ child_result = visit_object(ichild, readers, settings, assign_as_parent);
+
+ bool child_claims_this_object = child_result.first;
+ AbcObjectReader *child_reader = child_result.second;
+
+ if (child_reader == NULL) {
+ BLI_assert(!child_claims_this_object);
+ }
+ else {
+ if (child_claims_this_object) {
+ claiming_child_readers.push_back(child_reader);
+ } else {
+ nonclaiming_child_readers.push_back(child_reader);
+ }
}
- AbcObjectReader *reader = NULL;
+ children_claiming_this_object += child_claims_this_object ? 1 : 0;
+ }
+ BLI_assert(children_claiming_this_object == claiming_child_readers.size());
- const MetaData &md = child.getMetaData();
+ AbcObjectReader *reader = NULL;
+ const MetaData &md = object.getMetaData();
+ bool parent_is_part_of_this_object = false;
- if (IXform::matches(md)) {
- bool create_xform = false;
+ if (!object.getParent()) {
+ /* The root itself is not an object we should import. */
+ }
+ else if (IXform::matches(md)) {
+ bool create_empty;
- /* Check whether or not this object is a Maya locator, which is
- * similar to empties used as parent object in Blender. */
- if (has_property(child.getProperties(), "locator")) {
- create_xform = true;
- }
- else {
- /* Avoid creating an empty object if the child of this transform
- * is not a transform (that is an empty). */
- if (child.getNumChildren() == 1) {
- if (IXform::matches(child.getChild(0).getMetaData())) {
- create_xform = true;
- }
-#if 0
- else {
- std::cerr << "Skipping " << child.getFullName() << '\n';
- }
-#endif
- }
- else {
- create_xform = true;
- }
- }
+ /* An xform can either be a Blender Object (if it contains a mesh, for
+ * example), but it can also be an Empty. Its correct translation to
+ * Blender's data model depends on its children. */
- if (create_xform) {
- reader = new AbcEmptyReader(child, settings);
- }
+ /* Check whether or not this object is a Maya locator, which is
+ * similar to empties used as parent object in Blender. */
+ if (has_property(object.getProperties(), "locator")) {
+ create_empty = true;
}
- else if (IPolyMesh::matches(md)) {
- reader = new AbcMeshReader(child, settings);
+ else {
+ create_empty = claiming_child_readers.empty();
}
- else if (ISubD::matches(md)) {
- reader = new AbcSubDReader(child, settings);
+
+ if (create_empty) {
+ reader = new AbcEmptyReader(object, settings);
}
- else if (INuPatch::matches(md)) {
+ }
+ else if (IPolyMesh::matches(md)) {
+ reader = new AbcMeshReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else if (ISubD::matches(md)) {
+ reader = new AbcSubDReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else if (INuPatch::matches(md)) {
#ifdef USE_NURBS
- /* TODO(kevin): importing cyclic NURBS from other software crashes
- * at the moment. This is due to the fact that NURBS in other
- * software have duplicated points which causes buffer overflows in
- * Blender. Need to figure out exactly how these points are
- * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
- * Until this is fixed, disabling NURBS reading. */
- reader = new AbcNurbsReader(child, settings);
+ /* TODO(kevin): importing cyclic NURBS from other software crashes
+ * at the moment. This is due to the fact that NURBS in other
+ * software have duplicated points which causes buffer overflows in
+ * Blender. Need to figure out exactly how these points are
+ * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
+ * Until this is fixed, disabling NURBS reading. */
+ reader = new AbcNurbsReader(object, settings);
+ parent_is_part_of_this_object = true;
#endif
+ }
+ else if (ICamera::matches(md)) {
+ reader = new AbcCameraReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else if (IPoints::matches(md)) {
+ reader = new AbcPointsReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else if (IMaterial::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (ILight::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (IFaceSet::matches(md)) {
+ /* Pass, those are handled in the mesh reader. */
+ }
+ else if (ICurves::matches(md)) {
+ reader = new AbcCurveReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else {
+ std::cerr << "Alembic object " << full_name
+ << " is of unsupported schema type '"
+ << object.getMetaData().get("schemaObjTitle") << "'"
+ << std::endl;
+ }
+
+ if (reader) {
+ /* We have created a reader, which should imply that this object is
+ * not claimed as part of any child Alembic object. */
+ BLI_assert(claiming_child_readers.empty());
+
+ readers.push_back(reader);
+ reader->incref();
+
+ AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
+ MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
+ BLI_strncpy(abc_path->path, full_name.c_str(), PATH_MAX);
+ BLI_addtail(&settings.cache_file->object_paths, abc_path);
+
+ /* We can now assign this reader as parent for our children. */
+ if (nonclaiming_child_readers.size() + assign_as_parent.size() > 0) {
+ /* TODO: When we only support C++11, use for (a: b) instead. */
+ BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) {
+ child_reader->parent_reader = reader;
+ }
+ BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) {
+ child_reader->parent_reader = reader;
+ }
}
- else if (ICamera::matches(md)) {
- reader = new AbcCameraReader(child, settings);
- }
- else if (IPoints::matches(md)) {
- reader = new AbcPointsReader(child, settings);
- }
- else if (IMaterial::matches(md)) {
- /* Pass for now. */
- }
- else if (ILight::matches(md)) {
- /* Pass for now. */
- }
- else if (IFaceSet::matches(md)) {
- /* Pass, those are handled in the mesh reader. */
- }
- else if (ICurves::matches(md)) {
- reader = new AbcCurveReader(child, settings);
+ }
+ else if (object.getParent()) {
+ if (claiming_child_readers.size() > 0) {
+ /* The first claiming child will serve just fine as parent to
+ * our non-claiming children. Since all claiming children share
+ * the same XForm, it doesn't really matter which one we pick. */
+ AbcObjectReader *claiming_child = claiming_child_readers[0];
+ BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) {
+ child_reader->parent_reader = claiming_child;
+ }
+ BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) {
+ child_reader->parent_reader = claiming_child;
+ }
+ /* Claiming children should have our parent set as their parent. */
+ BOOST_FOREACH(AbcObjectReader *child_reader, claiming_child_readers) {
+ r_assign_as_parent.push_back(child_reader);
+ }
}
else {
- assert(false);
- }
-
- if (reader) {
- readers.push_back(reader);
- reader->incref();
-
- AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
- MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
-
- BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX);
-
- BLI_addtail(&settings.cache_file->object_paths, abc_path);
-
- /* Cast to `void *` explicitly to avoid compiler errors because it
- * is a `const char *` which the compiler cast to `const void *`
- * instead of the expected `void *`. */
- BLI_ghash_insert(parent_map, (void *)child.getFullName().c_str(), reader);
+ /* This object isn't claimed by any child, and didn't produce
+ * a reader. Odd situation, could be the top Alembic object, or
+ * an unsupported Alembic schema. Delegate to our parent. */
+ BOOST_FOREACH(AbcObjectReader *child_reader, claiming_child_readers) {
+ r_assign_as_parent.push_back(child_reader);
+ }
+ BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) {
+ r_assign_as_parent.push_back(child_reader);
+ }
+ BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) {
+ r_assign_as_parent.push_back(child_reader);
+ }
}
-
- visit_object(child, readers, parent_map, settings);
}
+
+ return std::make_pair(parent_is_part_of_this_object, reader);
}
enum {
@@ -498,7 +585,6 @@ struct ImportJobData {
char filename[1024];
ImportSettings settings;
- GHash *parent_map;
std::vector<AbcObjectReader *> readers;
short *stop;
@@ -575,11 +661,12 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
*data->do_update = true;
*data->progress = 0.05f;
- data->parent_map = BLI_ghash_str_new("alembic parent ghash");
-
/* Parse Alembic Archive. */
+ AbcObjectReader::ptr_vector assign_as_parent;
+ visit_object(archive->getTop(), data->readers, data->settings, assign_as_parent);
- visit_object(archive->getTop(), data->readers, data->parent_map, data->settings);
+ /* There shouldn't be any orphans. */
+ BLI_assert(assign_as_parent.size() == 0);
if (G.is_break) {
data->was_cancelled = true;
@@ -603,13 +690,16 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
if (reader->valid()) {
reader->readObjectData(data->bmain, 0.0f);
- reader->readObjectMatrix(0.0f);
min_time = std::min(min_time, reader->minTime());
max_time = std::max(max_time, reader->maxTime());
}
+ else {
+ std::cerr << "Object " << reader->name() << " in Alembic file "
+ << data->filename << " is invalid.\n";
+ }
- *data->progress = 0.1f + 0.6f * (++i / size);
+ *data->progress = 0.1f + 0.3f * (++i / size);
*data->do_update = true;
if (G.is_break) {
@@ -627,45 +717,31 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
CFRA = SFRA;
}
else if (min_time < max_time) {
- SFRA = static_cast<int>(min_time * FPS);
- EFRA = static_cast<int>(max_time * FPS);
+ SFRA = static_cast<int>(round(min_time * FPS));
+ EFRA = static_cast<int>(round(max_time * FPS));
CFRA = SFRA;
}
}
- /* Setup parentship. */
-
- i = 0;
+ /* Setup parenthood. */
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
const AbcObjectReader *reader = *iter;
- const AbcObjectReader *parent_reader = NULL;
- const IObject &iobject = reader->iobject();
-
- IObject parent = iobject.getParent();
+ const AbcObjectReader *parent_reader = reader->parent_reader;
+ Object *ob = reader->object();
- if (!IXform::matches(iobject.getHeader())) {
- /* In the case of an non XForm node, the parent is the transform
- * matrix of the data itself, so we get the its grand parent.
- */
-
- /* Special case with object only containing a mesh and some strands,
- * we want both objects to be parented to the same object. */
- if (!is_mesh_and_strands(parent)) {
- parent = parent.getParent();
- }
+ if (parent_reader == NULL) {
+ ob->parent = NULL;
}
-
- parent_reader = reinterpret_cast<AbcObjectReader *>(
- BLI_ghash_lookup(data->parent_map, parent.getFullName().c_str()));
-
- if (parent_reader) {
- Object *parent = parent_reader->object();
-
- if (parent != NULL && reader->object() != parent) {
- Object *ob = reader->object();
- ob->parent = parent;
- }
+ else {
+ ob->parent = parent_reader->object();
}
+ }
+
+ /* Setup transformations and constraints. */
+ i = 0;
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ AbcObjectReader *reader = *iter;
+ reader->setupObjectTransform(0.0f);
*data->progress = 0.7f + 0.3f * (++i / size);
*data->do_update = true;
@@ -690,10 +766,9 @@ static void import_endjob(void *user_data)
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
Object *ob = (*iter)->object();
- if (ob->data) {
- BKE_libblock_free_us(data->bmain, ob->data);
- ob->data = NULL;
- }
+ /* It's possible that cancellation occured between the creation of
+ * the reader and the creation of the Blender object. */
+ if (ob == NULL) continue;
BKE_libblock_free_us(data->bmain, ob);
}
@@ -723,10 +798,6 @@ static void import_endjob(void *user_data)
}
}
- if (data->parent_map) {
- BLI_ghash_free(data->parent_map, NULL, NULL);
- }
-
switch (data->error_code) {
default:
case ABC_NO_ERROR:
@@ -760,7 +831,6 @@ void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence
job->settings.sequence_len = sequence_len;
job->settings.offset = offset;
job->settings.validate_meshes = validate_meshes;
- job->parent_map = NULL;
job->error_code = ABC_NO_ERROR;
job->was_cancelled = false;
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index aa7d539538b..bbbabfb8ba2 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -135,6 +135,7 @@ void blf_glyph_cache_clear(FontBLF *font)
while ((gc = BLI_pophead(&font->cache))) {
blf_glyph_cache_free(gc);
}
+ font->glyph_cache = NULL;
}
void blf_glyph_cache_free(GlyphCacheBLF *gc)
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index 077fe2a629c..ac8f861fa56 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -27,11 +27,15 @@
/* note on naming: typical _get() suffix is omitted here,
* since its the main purpose of the API. */
const char *BKE_appdir_folder_default(void);
+const char *BKE_appdir_folder_id_ex(const int folder_id, const char *subfolder, char *path, size_t path_len);
const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder);
const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder);
const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder);
const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, const bool do_check);
+bool BKE_appdir_app_template_any(void);
+bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len);
+
/* Initialize path to program executable */
void BKE_appdir_program_path_init(const char *argv0);
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 62a15bae153..d55926ffb1e 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -52,6 +52,8 @@ void BKE_blender_userdef_set_data(struct UserDef *userdef);
void BKE_blender_userdef_free_data(struct UserDef *userdef);
void BKE_blender_userdef_refresh(void);
+void BKE_blender_userdef_set_app_template(struct UserDef *userdef);
+
/* set this callback when a UI is running */
void BKE_blender_callback_test_break_set(void (*func)(void));
int BKE_blender_test_break(void);
diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h
index 75978120051..ac58451e412 100644
--- a/source/blender/blenkernel/BKE_blendfile.h
+++ b/source/blender/blenkernel/BKE_blendfile.h
@@ -50,6 +50,7 @@ bool BKE_blendfile_read_from_memory(
bool BKE_blendfile_read_from_memfile(
struct bContext *C, struct MemFile *memfile,
struct ReportList *reports, int skip_flag);
+void BKE_blendfile_read_make_empty(struct bContext *C);
struct UserDef *BKE_blendfile_userdef_read(
const char *filepath, struct ReportList *reports);
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 36330242f18..6c517bd02df 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -136,9 +136,6 @@ typedef struct ClothSpring {
float restlen; /* The original length of the spring. */
int type; /* types defined in BKE_cloth.h ("springType") */
int flags; /* defined in BKE_cloth.h, e.g. deactivated due to tearing */
- float dfdx[3][3];
- float dfdv[3][3];
- float f[3];
float stiffness; /* stiffness factor from the vertex groups */
float editrestlen;
@@ -240,9 +237,6 @@ void bvhselftree_update_from_cloth(struct ClothModifierData *clmd, bool moving);
// needed for button_object.c
void cloth_clear_cache (struct Object *ob, struct ClothModifierData *clmd, float framenr );
-// needed for cloth.c
-int cloth_add_spring (struct ClothModifierData *clmd, unsigned int indexA, unsigned int indexB, float restlength, int spring_type);
-
void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3], const float dir_new[3]);
////////////////////////////////////////////////
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index 5b10d7ebc06..ab8728faedb 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -60,8 +60,6 @@ typedef union IDPropertyTemplate {
IDProperty *IDP_NewIDPArray(const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
IDProperty *IDP_CopyIDPArray(const IDProperty *array) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void IDP_FreeIDPArray(IDProperty *prop);
-
/* shallow copies item */
void IDP_SetIndexArray(struct IDProperty *prop, int index, struct IDProperty *item) ATTR_NONNULL();
struct IDProperty *IDP_GetIndexArray(struct IDProperty *prop, int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -81,8 +79,8 @@ void IDP_ConcatString(struct IDProperty *str1, struct IDProperty *append) ATTR_N
void IDP_FreeString(struct IDProperty *prop) ATTR_NONNULL();
/*-------- ID Type -------*/
-void IDP_LinkID(struct IDProperty *prop, ID *id);
-void IDP_UnlinkID(struct IDProperty *prop);
+
+typedef void(*IDPWalkFunc)(void *userData, IDProperty *idp);
/*-------- Group Functions -------*/
@@ -112,11 +110,12 @@ bool IDP_EqualsProperties(struct IDProperty *prop1, struct IDProperty *prop2) AT
struct IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void IDP_FreeProperty_ex(struct IDProperty *prop, const bool do_id_user);
void IDP_FreeProperty(struct IDProperty *prop);
void IDP_ClearProperty(IDProperty *prop);
-void IDP_UnlinkProperty(struct IDProperty *prop);
+void IDP_RelinkProperty(struct IDProperty *prop);
#define IDP_Int(prop) ((prop)->data.val)
#define IDP_Array(prop) ((prop)->data.pointer)
@@ -134,11 +133,15 @@ void IDP_UnlinkProperty(struct IDProperty *prop);
# define IDP_IDPArray(prop) _Generic((prop), \
IDProperty *: ((IDProperty *) (prop)->data.pointer), \
const IDProperty *: ((const IDProperty *) (prop)->data.pointer))
+# define IDP_Id(prop) _Generic((prop), \
+ IDProperty *: ((ID *) (prop)->data.pointer), \
+ const IDProperty *: ((const ID *) (prop)->data.pointer))
#else
# define IDP_Float(prop) (*(float *)&(prop)->data.val)
# define IDP_Double(prop) (*(double *)&(prop)->data.val)
# define IDP_String(prop) ((char *) (prop)->data.pointer)
# define IDP_IDPArray(prop) ((IDProperty *) (prop)->data.pointer)
+# define IDP_Id(prop) ((ID *) (prop)->data.pointer)
#endif
#ifndef NDEBUG
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 72ae2cf4efa..6649cfbb585 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -66,7 +66,7 @@ struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_
void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL();
void BKE_libblock_free_ex(struct Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user) ATTR_NONNULL();
void BKE_libblock_free_us(struct Main *bmain, void *idv) ATTR_NONNULL();
-void BKE_libblock_free_data(struct Main *bmain, struct ID *id) ATTR_NONNULL();
+void BKE_libblock_free_data(struct Main *bmain, struct ID *id, const bool do_id_user) ATTR_NONNULL();
void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id);
diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index 1258e2fa72e..68bf9f43fe1 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -87,7 +87,7 @@ void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const
int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used);
-bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used);
+bool BKE_library_id_can_use_idtype(struct ID *id_owner, const short id_type_used);
bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv);
bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 546f0d97c2b..193f1154c54 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -49,7 +49,7 @@
#include "RNA_types.h"
/* not very important, but the stack solver likes to know a maximum */
-#define MAX_SOCKET 64
+#define MAX_SOCKET 512
struct bContext;
struct bNode;
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index f2f0a92d8b3..43fd47981b1 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -114,18 +114,26 @@ static char *blender_version_decimal(const int ver)
* Concatenates path_base, (optional) path_sep and (optional) folder_name into targetpath,
* returning true if result points to a directory.
*/
-static bool test_path(char *targetpath, const char *path_base, const char *path_sep, const char *folder_name)
+static bool test_path(
+ char *targetpath, size_t targetpath_len,
+ const char *path_base, const char *path_sep, const char *folder_name)
{
char tmppath[FILE_MAX];
- if (path_sep) BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep);
- else BLI_strncpy(tmppath, path_base, sizeof(tmppath));
+ if (path_sep) {
+ BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep);
+ }
+ else {
+ BLI_strncpy(tmppath, path_base, sizeof(tmppath));
+ }
/* rare cases folder_name is omitted (when looking for ~/.config/blender/2.xx dir only) */
- if (folder_name)
- BLI_make_file_string("/", targetpath, tmppath, folder_name);
- else
- BLI_strncpy(targetpath, tmppath, sizeof(tmppath));
+ if (folder_name) {
+ BLI_join_dirfile(targetpath, targetpath_len, tmppath, folder_name);
+ }
+ else {
+ BLI_strncpy(targetpath, tmppath, targetpath_len);
+ }
/* FIXME: why is "//" on front of tmppath expanded to "/" (by BLI_join_dirfile)
* if folder_name is specified but not otherwise? */
@@ -179,7 +187,9 @@ static bool test_env_path(char *path, const char *envvar)
* \param ver To construct name of version-specific directory within bprogdir
* \return true if such a directory exists.
*/
-static bool get_path_local(char *targetpath, const char *folder_name, const char *subfolder_name, const int ver)
+static bool get_path_local(
+ char *targetpath, size_t targetpath_len,
+ const char *folder_name, const char *subfolder_name, const int ver)
{
char relfolder[FILE_MAX];
@@ -201,11 +211,12 @@ static bool get_path_local(char *targetpath, const char *folder_name, const char
/* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */
#ifdef __APPLE__
- static char osx_resourses[FILE_MAX]; /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */
+ /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */
+ static char osx_resourses[FILE_MAX];
sprintf(osx_resourses, "%s../Resources", bprogdir);
- return test_path(targetpath, osx_resourses, blender_version_decimal(ver), relfolder);
+ return test_path(targetpath, targetpath_len, osx_resourses, blender_version_decimal(ver), relfolder);
#else
- return test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder);
+ return test_path(targetpath, targetpath_len, bprogdir, blender_version_decimal(ver), relfolder);
#endif
}
@@ -219,7 +230,7 @@ static bool is_portable_install(void)
const int ver = BLENDER_VERSION;
char path[FILE_MAX];
- return get_path_local(path, "config", NULL, ver);
+ return get_path_local(path, sizeof(path), "config", NULL, ver);
}
/**
@@ -233,20 +244,22 @@ static bool is_portable_install(void)
* \param ver Blender version, used to construct a subdirectory name
* \return true if it was able to construct such a path.
*/
-static bool get_path_user(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver)
+static bool get_path_user(
+ char *targetpath, size_t targetpath_len, const char *folder_name, const char *subfolder_name,
+ const char *envvar, const int ver)
{
char user_path[FILE_MAX];
const char *user_base_path;
/* for portable install, user path is always local */
- if (is_portable_install())
- return get_path_local(targetpath, folder_name, subfolder_name, ver);
-
+ if (is_portable_install()) {
+ return get_path_local(targetpath, targetpath_len, folder_name, subfolder_name, ver);
+ }
user_path[0] = '\0';
if (test_env_path(user_path, envvar)) {
if (subfolder_name) {
- return test_path(targetpath, user_path, NULL, subfolder_name);
+ return test_path(targetpath, targetpath_len, user_path, NULL, subfolder_name);
}
else {
BLI_strncpy(targetpath, user_path, FILE_MAX);
@@ -266,10 +279,10 @@ static bool get_path_user(char *targetpath, const char *folder_name, const char
#endif
if (subfolder_name) {
- return test_path(targetpath, user_path, folder_name, subfolder_name);
+ return test_path(targetpath, targetpath_len, user_path, folder_name, subfolder_name);
}
else {
- return test_path(targetpath, user_path, NULL, folder_name);
+ return test_path(targetpath, targetpath_len, user_path, NULL, folder_name);
}
}
@@ -283,7 +296,9 @@ static bool get_path_user(char *targetpath, const char *folder_name, const char
* \param ver Blender version, used to construct a subdirectory name
* \return true if it was able to construct such a path.
*/
-static bool get_path_system(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver)
+static bool get_path_system(
+ char *targetpath, size_t targetpath_len, const char *folder_name, const char *subfolder_name,
+ const char *envvar, const int ver)
{
char system_path[FILE_MAX];
const char *system_base_path;
@@ -307,13 +322,13 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha
/* try CWD/release/folder_name */
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
- if (test_path(targetpath, cwd, "release", relfolder)) {
+ if (test_path(targetpath, targetpath_len, cwd, "release", relfolder)) {
return true;
}
}
/* try EXECUTABLE_DIR/release/folder_name */
- if (test_path(targetpath, bprogdir, "release", relfolder))
+ if (test_path(targetpath, targetpath_len, bprogdir, "release", relfolder))
return true;
/* end developer overrides */
@@ -324,7 +339,7 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha
if (test_env_path(system_path, envvar)) {
if (subfolder_name) {
- return test_path(targetpath, system_path, NULL, subfolder_name);
+ return test_path(targetpath, targetpath_len, system_path, NULL, subfolder_name);
}
else {
BLI_strncpy(targetpath, system_path, FILE_MAX);
@@ -345,57 +360,63 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha
if (subfolder_name) {
/* try $BLENDERPATH/folder_name/subfolder_name */
- return test_path(targetpath, system_path, folder_name, subfolder_name);
+ return test_path(targetpath, targetpath_len, system_path, folder_name, subfolder_name);
}
else {
/* try $BLENDERPATH/folder_name */
- return test_path(targetpath, system_path, NULL, folder_name);
+ return test_path(targetpath, targetpath_len, system_path, NULL, folder_name);
}
}
-/* get a folder out of the 'folder_id' presets for paths */
-/* returns the path if found, NULL string if not */
-const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder)
+/**
+ * Get a folder out of the 'folder_id' presets for paths.
+ * returns the path if found, NULL string if not
+ *
+ * \param subfolder: The name of a directory to check for,
+ * this may contain path separators but must resolve to a directory, checked with #BLI_is_dir.
+ */
+const char *BKE_appdir_folder_id_ex(
+ const int folder_id, const char *subfolder,
+ char *path, size_t path_len)
{
const int ver = BLENDER_VERSION;
- static char path[FILE_MAX] = "";
-
+
switch (folder_id) {
case BLENDER_DATAFILES: /* general case */
- if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
- if (get_path_local(path, "datafiles", subfolder, ver)) break;
- if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
+ if (get_path_user(path, path_len, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
+ if (get_path_local(path, path_len, "datafiles", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
return NULL;
case BLENDER_USER_DATAFILES:
- if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
+ if (get_path_user(path, path_len, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
return NULL;
case BLENDER_SYSTEM_DATAFILES:
- if (get_path_local(path, "datafiles", subfolder, ver)) break;
- if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
+ if (get_path_local(path, path_len, "datafiles", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
return NULL;
case BLENDER_USER_AUTOSAVE:
- if (get_path_user(path, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
+ if (get_path_user(path, path_len, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
return NULL;
case BLENDER_USER_CONFIG:
- if (get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break;
+ if (get_path_user(path, path_len, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break;
return NULL;
case BLENDER_USER_SCRIPTS:
- if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break;
+ if (get_path_user(path, path_len, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break;
return NULL;
case BLENDER_SYSTEM_SCRIPTS:
- if (get_path_local(path, "scripts", subfolder, ver)) break;
- if (get_path_system(path, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break;
+ if (get_path_local(path, path_len, "scripts", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break;
return NULL;
case BLENDER_SYSTEM_PYTHON:
- if (get_path_local(path, "python", subfolder, ver)) break;
- if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break;
+ if (get_path_local(path, path_len, "python", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break;
return NULL;
default:
@@ -406,6 +427,13 @@ const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder)
return path;
}
+const char *BKE_appdir_folder_id(
+ const int folder_id, const char *subfolder)
+{
+ static char path[FILE_MAX] = "";
+ return BKE_appdir_folder_id_ex(folder_id, subfolder, path, sizeof(path));
+}
+
/**
* Returns the path to a folder in the user area without checking that it actually exists first.
*/
@@ -416,16 +444,16 @@ const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *su
switch (folder_id) {
case BLENDER_USER_DATAFILES:
- get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver);
+ get_path_user(path, sizeof(path), "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver);
break;
case BLENDER_USER_CONFIG:
- get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver);
+ get_path_user(path, sizeof(path), "config", subfolder, "BLENDER_USER_CONFIG", ver);
break;
case BLENDER_USER_AUTOSAVE:
- get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver);
+ get_path_user(path, sizeof(path), "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver);
break;
case BLENDER_USER_SCRIPTS:
- get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver);
+ get_path_user(path, sizeof(path), "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver);
break;
default:
BLI_assert(0);
@@ -469,13 +497,13 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con
bool ok;
switch (folder_id) {
case BLENDER_RESOURCE_PATH_USER:
- ok = get_path_user(path, NULL, NULL, NULL, ver);
+ ok = get_path_user(path, sizeof(path), NULL, NULL, NULL, ver);
break;
case BLENDER_RESOURCE_PATH_LOCAL:
- ok = get_path_local(path, NULL, NULL, ver);
+ ok = get_path_local(path, sizeof(path), NULL, NULL, ver);
break;
case BLENDER_RESOURCE_PATH_SYSTEM:
- ok = get_path_system(path, NULL, NULL, NULL, ver);
+ ok = get_path_system(path, sizeof(path), NULL, NULL, NULL, ver);
break;
default:
path[0] = '\0'; /* in case do_check is false */
@@ -655,6 +683,48 @@ bool BKE_appdir_program_python_search(
return is_found;
}
+static const char *app_template_directory_search[2] = {
+ "startup" SEP_STR "bl_app_templates_user",
+ "startup" SEP_STR "bl_app_templates_system",
+};
+
+static const int app_template_directory_id[2] = {
+ BLENDER_USER_SCRIPTS,
+ BLENDER_SYSTEM_SCRIPTS,
+};
+
+/**
+ * Return true if templates exist
+ */
+bool BKE_appdir_app_template_any(void)
+{
+ char temp_dir[FILE_MAX];
+ for (int i = 0; i < 2; i++) {
+ if (BKE_appdir_folder_id_ex(
+ app_template_directory_id[i], app_template_directory_search[i],
+ temp_dir, sizeof(temp_dir)))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len)
+{
+ for (int i = 0; i < 2; i++) {
+ char subdir[FILE_MAX];
+ BLI_join_dirfile(subdir, sizeof(subdir), app_template_directory_search[i], app_template);
+ if (BKE_appdir_folder_id_ex(
+ app_template_directory_id[i], subdir,
+ path, path_len))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
/**
* Gets the temp directory when blender first runs.
* If the default path is not found, use try $TEMP
@@ -713,7 +783,8 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
BLI_add_slash(fullname);
#ifdef WIN32
if (userdir && userdir != fullname) {
- BLI_strncpy(userdir, fullname, maxlen); /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
+ /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
+ BLI_strncpy(userdir, fullname, maxlen);
}
#endif
}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index f661f18fbc0..ceb641073e0 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -238,6 +238,44 @@ void BKE_blender_userdef_refresh(void)
}
+/**
+ * Write U from userdef.
+ * This function defines which settings a template will override for the user preferences.
+ */
+void BKE_blender_userdef_set_app_template(UserDef *userdef)
+{
+ /* TODO:
+ * - keymaps
+ * - various minor settings (add as needed).
+ */
+
+#define LIST_OVERRIDE(id) { \
+ BLI_freelistN(&U.id); \
+ BLI_movelisttolist(&U.id, &userdef->id); \
+} ((void)0)
+
+#define MEMCPY_OVERRIDE(id) \
+ memcpy(U.id, userdef->id, sizeof(U.id));
+
+ /* for some types we need custom free functions */
+ userdef_free_addons(&U);
+ userdef_free_keymaps(&U);
+
+ LIST_OVERRIDE(uistyles);
+ LIST_OVERRIDE(uifonts);
+ LIST_OVERRIDE(themes);
+ LIST_OVERRIDE(addons);
+ LIST_OVERRIDE(user_keymaps);
+
+ MEMCPY_OVERRIDE(light);
+
+ MEMCPY_OVERRIDE(font_path_ui);
+ MEMCPY_OVERRIDE(font_path_ui_mono);
+
+#undef LIST_OVERRIDE
+#undef MEMCPY_OVERRIDE
+}
+
/* ***************** testing for break ************* */
static void (*blender_test_break_cb)(void) = NULL;
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 5725a12e3d4..a521d671ea4 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -356,8 +356,10 @@ int BKE_blendfile_read(
BlendFileData *bfd;
int retval = BKE_BLENDFILE_READ_OK;
- if (strstr(filepath, BLENDER_STARTUP_FILE) == NULL) /* don't print user-pref loading */
- printf("read blend: %s\n", filepath);
+ /* don't print user-pref loading */
+ if (strstr(filepath, BLENDER_STARTUP_FILE) == NULL) {
+ printf("Read blend: %s\n", filepath);
+ }
bfd = BLO_read_from_file(filepath, reports, skip_flags);
if (bfd) {
@@ -424,6 +426,32 @@ bool BKE_blendfile_read_from_memfile(
return (bfd != NULL);
}
+/**
+ * Utility to make a file 'empty' used for startup to optionally give an empty file.
+ * Handy for tests.
+ */
+void BKE_blendfile_read_make_empty(bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+
+ ListBase *lbarray[MAX_LIBARRAY];
+ ID *id;
+ int a;
+
+ a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ id = lbarray[a]->first;
+ if (id != NULL) {
+ if (ELEM(GS(id->name), ID_SCE, ID_SCR, ID_WM)) {
+ continue;
+ }
+ while ((id = lbarray[a]->first)) {
+ BKE_libblock_delete(bmain, id);
+ }
+ }
+ }
+}
+
/* only read the userdef from a .blend */
UserDef *BKE_blendfile_userdef_read(const char *filepath, ReportList *reports)
{
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 28ef3f6f248..ee0fde1ea61 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -869,12 +869,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
return 0;
}
- for ( i = 0; i < dm->getNumVerts(dm); i++) {
- if ((!(cloth->verts[i].flags & CLOTH_VERT_FLAG_PINNED)) && (cloth->verts[i].goal > ALMOST_ZERO)) {
- cloth_add_spring (clmd, i, i, 0.0, CLOTH_SPRING_TYPE_GOAL);
- }
- }
-
// init our solver
BPH_cloth_solver_init(ob, clmd);
@@ -944,37 +938,6 @@ BLI_INLINE void spring_verts_ordered_set(ClothSpring *spring, int v0, int v1)
}
}
-// be careful: implicit solver has to be resettet when using this one!
-// --> only for implicit handling of this spring!
-int cloth_add_spring(ClothModifierData *clmd, unsigned int indexA, unsigned int indexB, float restlength, int spring_type)
-{
- Cloth *cloth = clmd->clothObject;
- ClothSpring *spring = NULL;
-
- if (cloth) {
- // TODO: look if this spring is already there
-
- spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
-
- if (!spring)
- return 0;
-
- spring->ij = indexA;
- spring->kl = indexB;
- spring->restlen = restlength;
- spring->type = spring_type;
- spring->flags = 0;
- spring->stiffness = 0;
-
- cloth->numsprings++;
-
- BLI_linklist_prepend ( &cloth->springs, spring );
-
- return 1;
- }
- return 0;
-}
-
static void cloth_free_edgelist(LinkNodePair *edgelist, unsigned int mvert_num)
{
if (edgelist) {
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index c9f0b8ec9ca..7c3f0ac630d 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -33,14 +33,10 @@
/** \file blender/blenkernel/intern/customdata.c
* \ingroup bke
*/
-
-
-#include <math.h>
-#include <string.h>
-#include <assert.h>
#include "MEM_guardedalloc.h"
+#include "DNA_customdata_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_ID.h"
@@ -62,20 +58,16 @@
#include "BKE_mesh_remap.h"
#include "BKE_multires.h"
-#include "data_transfer_intern.h"
-
#include "bmesh.h"
-#include <math.h>
-#include <string.h>
+/* only for customdata_data_transfer_interp_normal_normals */
+#include "data_transfer_intern.h"
/* number of layers to add when growing a CustomData object */
#define CUSTOMDATA_GROW 5
/* ensure typemap size is ok */
-BLI_STATIC_ASSERT(sizeof(((CustomData *)NULL)->typemap) /
- sizeof(((CustomData *)NULL)->typemap[0]) == CD_NUMTYPES,
- "size mismatch");
+BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "size mismatch");
/********************* Layer type information **********************/
@@ -805,18 +797,15 @@ static void layerInterp_mloopcol(
const float *sub_weights, int count, void *dest)
{
MLoopCol *mc = dest;
- int i;
- const float *sub_weight;
struct {
float a;
float r;
float g;
float b;
- } col;
- col.a = col.r = col.g = col.b = 0;
+ } col = {0};
- sub_weight = sub_weights;
- for (i = 0; i < count; ++i) {
+ const float *sub_weight = sub_weights;
+ for (int i = 0; i < count; ++i) {
float weight = weights ? weights[i] : 1;
const MLoopCol *src = sources[i];
if (sub_weights) {
@@ -833,19 +822,16 @@ static void layerInterp_mloopcol(
col.a += src->a * weight;
}
}
-
+
+
/* Subdivide smooth or fractal can cause problems without clamping
* although weights should also not cause this situation */
- CLAMP(col.a, 0.0f, 255.0f);
- CLAMP(col.r, 0.0f, 255.0f);
- CLAMP(col.g, 0.0f, 255.0f);
- CLAMP(col.b, 0.0f, 255.0f);
- /* delay writing to the destination incase dest is in sources */
- mc->r = (int)col.r;
- mc->g = (int)col.g;
- mc->b = (int)col.b;
- mc->a = (int)col.a;
+ /* also delay writing to the destination incase dest is in sources */
+ mc->r = CLAMPIS(iroundf(col.r), 0, 255);
+ mc->g = CLAMPIS(iroundf(col.g), 0, 255);
+ mc->b = CLAMPIS(iroundf(col.b), 0, 255);
+ mc->a = CLAMPIS(iroundf(col.a), 0, 255);
}
static int layerMaxNum_mloopcol(void)
@@ -1068,15 +1054,10 @@ static void layerInterp_mcol(
/* Subdivide smooth or fractal can cause problems without clamping
* although weights should also not cause this situation */
- CLAMP(col[j].a, 0.0f, 255.0f);
- CLAMP(col[j].r, 0.0f, 255.0f);
- CLAMP(col[j].g, 0.0f, 255.0f);
- CLAMP(col[j].b, 0.0f, 255.0f);
-
- mc[j].a = (int)col[j].a;
- mc[j].r = (int)col[j].r;
- mc[j].g = (int)col[j].g;
- mc[j].b = (int)col[j].b;
+ mc[j].a = CLAMPIS(iroundf(col[j].a), 0, 255);
+ mc[j].r = CLAMPIS(iroundf(col[j].r), 0, 255);
+ mc[j].g = CLAMPIS(iroundf(col[j].g), 0, 255);
+ mc[j].b = CLAMPIS(iroundf(col[j].b), 0, 255);
}
}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 678dc92a5f2..302e55a1f5a 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -3053,7 +3053,7 @@ void DAG_id_type_tag(Main *bmain, short idtype)
DAG_id_type_tag(bmain, ID_SCE);
}
- bmain->id_tag_update[BKE_idcode_to_index(idtype)] = 1;
+ atomic_fetch_and_or_uint8((uint8_t*)&bmain->id_tag_update[BKE_idcode_to_index(idtype)], 1);
}
int DAG_id_type_tagged(Main *bmain, short idtype)
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index b2641b110f8..074a9a12fe0 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -117,31 +117,35 @@ IDProperty *IDP_CopyIDPArray(const IDProperty *array)
return narray;
}
-void IDP_FreeIDPArray(IDProperty *prop)
+static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
{
int i;
BLI_assert(prop->type == IDP_IDPARRAY);
for (i = 0; i < prop->len; i++)
- IDP_FreeProperty(GETPROP(prop, i));
+ IDP_FreeProperty_ex(GETPROP(prop, i), do_id_user);
if (prop->data.pointer)
MEM_freeN(prop->data.pointer);
}
-/*shallow copies item*/
+/* shallow copies item */
void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
{
IDProperty *old;
BLI_assert(prop->type == IDP_IDPARRAY);
+ if (index >= prop->len || index < 0)
+ return;
+
old = GETPROP(prop, index);
- if (index >= prop->len || index < 0) return;
- if (item != old) IDP_FreeProperty(old);
-
- memcpy(GETPROP(prop, index), item, sizeof(IDProperty));
+ if (item != old) {
+ IDP_FreeProperty(old);
+
+ memcpy(old, item, sizeof(IDProperty));
+ }
}
IDProperty *IDP_GetIndexArray(IDProperty *prop, int index)
@@ -433,22 +437,24 @@ void IDP_FreeString(IDProperty *prop)
/* -------------------------------------------------------------------- */
-/* ID Type (not in use yet) */
+/* ID Type */
-/** \name IDProperty ID API (unused)
+/** \name IDProperty ID API
* \{ */
-void IDP_LinkID(IDProperty *prop, ID *id)
-{
- if (prop->data.pointer)
- id_us_min(((ID *)prop->data.pointer));
- prop->data.pointer = id;
- id_us_plus(id);
-}
-void IDP_UnlinkID(IDProperty *prop)
+static IDProperty *IDP_CopyID(const IDProperty *prop)
{
- id_us_min(((ID *)prop->data.pointer));
+ IDProperty *newp;
+
+ BLI_assert(prop->type == IDP_ID);
+ newp = idp_generic_copy(prop);
+
+ newp->data.pointer = prop->data.pointer;
+ id_us_plus(IDP_Id(newp));
+
+ return newp;
}
+
/** \} */
@@ -499,14 +505,9 @@ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
break;
default:
{
- IDProperty *tmp = other;
- IDProperty *copy = IDP_CopyProperty(prop);
-
- BLI_insertlinkafter(&dest->data.group, other, copy);
- BLI_remlink(&dest->data.group, tmp);
-
- IDP_FreeProperty(tmp);
- MEM_freeN(tmp);
+ BLI_insertlinkreplace(&dest->data.group, other, IDP_CopyProperty(prop));
+ IDP_FreeProperty(other);
+ MEM_freeN(other);
break;
}
}
@@ -526,11 +527,9 @@ void IDP_SyncGroupTypes(IDProperty *dst, const IDProperty *src, const bool do_ar
if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) ||
(do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) && (prop_src->len != prop_dst->len)))
{
- IDP_FreeFromGroup(dst, prop_dst);
- prop_dst = IDP_CopyProperty(prop_src);
-
- dst->len++;
- BLI_insertlinkbefore(&dst->data.group, prop_dst_next, prop_dst);
+ BLI_insertlinkreplace(&dst->data.group, prop_dst, IDP_CopyProperty(prop_src));
+ IDP_FreeProperty(prop_dst);
+ MEM_freeN(prop_dst);
}
else if (prop_dst->type == IDP_GROUP) {
IDP_SyncGroupTypes(prop_dst, prop_src, do_arraylen);
@@ -555,11 +554,7 @@ void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
for (prop = src->data.group.first; prop; prop = prop->next) {
for (loop = dest->data.group.first; loop; loop = loop->next) {
if (STREQ(loop->name, prop->name)) {
- IDProperty *copy = IDP_CopyProperty(prop);
-
- BLI_insertlinkafter(&dest->data.group, loop, copy);
-
- BLI_remlink(&dest->data.group, loop);
+ BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop));
IDP_FreeProperty(loop);
MEM_freeN(loop);
break;
@@ -586,9 +581,7 @@ void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop
BLI_assert(prop_exist == IDP_GetPropertyFromGroup(group, prop->name));
if ((prop_exist = IDP_GetPropertyFromGroup(group, prop->name))) {
- BLI_insertlinkafter(&group->data.group, prop_exist, prop);
-
- BLI_remlink(&group->data.group, prop_exist);
+ BLI_insertlinkreplace(&group->data.group, prop_exist, prop);
IDP_FreeProperty(prop_exist);
MEM_freeN(prop_exist);
}
@@ -719,13 +712,13 @@ IDProperty *IDP_GetPropertyTypeFromGroup(IDProperty *prop, const char *name, con
* This is because all ID Property freeing functions free only direct data (not the ID Property
* struct itself), but for Groups the child properties *are* considered
* direct data. */
-static void IDP_FreeGroup(IDProperty *prop)
+static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
{
IDProperty *loop;
BLI_assert(prop->type == IDP_GROUP);
for (loop = prop->data.group.first; loop; loop = loop->next) {
- IDP_FreeProperty(loop);
+ IDP_FreeProperty_ex(loop, do_id_user);
}
BLI_freelistN(&prop->data.group);
}
@@ -742,12 +735,51 @@ IDProperty *IDP_CopyProperty(const IDProperty *prop)
switch (prop->type) {
case IDP_GROUP: return IDP_CopyGroup(prop);
case IDP_STRING: return IDP_CopyString(prop);
+ case IDP_ID: return IDP_CopyID(prop);
case IDP_ARRAY: return IDP_CopyArray(prop);
case IDP_IDPARRAY: return IDP_CopyIDPArray(prop);
default: return idp_generic_copy(prop);
}
}
+/* Updates ID pointers after an object has been copied */
+/* TODO Nuke this once its only user has been correctly converted to use generic ID management from BKE_library! */
+void IDP_RelinkProperty(struct IDProperty *prop)
+{
+ if (!prop)
+ return;
+
+ switch (prop->type) {
+ case IDP_GROUP:
+ {
+ for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ IDP_RelinkProperty(loop);
+ }
+ break;
+ }
+ case IDP_IDPARRAY:
+ {
+ IDProperty *idp_array = IDP_Array(prop);
+ for (int i = 0; i < prop->len; i++) {
+ IDP_RelinkProperty(&idp_array[i]);
+ }
+ break;
+ }
+ case IDP_ID:
+ {
+ ID *id = IDP_Id(prop);
+ if (id && id->newid) {
+ id_us_min(IDP_Id(prop));
+ prop->data.pointer = id->newid;
+ id_us_plus(IDP_Id(prop));
+ }
+ break;
+ }
+ default:
+ break; /* Nothing to do for other IDProp types. */
+ }
+}
+
/**
* Get the Group property that contains the id properties for ID id. Set create_if_needed
* to create the Group property and attach it to id if it doesn't exist; otherwise
@@ -844,6 +876,8 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is
return false;
return true;
}
+ case IDP_ID:
+ return (IDP_Id(prop1) == IDP_Id(prop2));
default:
/* should never get here */
BLI_assert(0);
@@ -867,17 +901,19 @@ bool IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
* The union is simple to use; see the top of this header file for its definition.
* An example of using this function:
*
- * IDPropertyTemplate val;
- * IDProperty *group, *idgroup, *color;
- * group = IDP_New(IDP_GROUP, val, "group1"); //groups don't need a template.
+ * \code{.c}
+ * IDPropertyTemplate val;
+ * IDProperty *group, *idgroup, *color;
+ * group = IDP_New(IDP_GROUP, val, "group1"); //groups don't need a template.
*
- * val.array.len = 4
- * val.array.type = IDP_FLOAT;
- * color = IDP_New(IDP_ARRAY, val, "color1");
+ * val.array.len = 4
+ * val.array.type = IDP_FLOAT;
+ * color = IDP_New(IDP_ARRAY, val, "color1");
*
- * idgroup = IDP_GetProperties(some_id, 1);
- * IDP_AddToGroup(idgroup, color);
- * IDP_AddToGroup(idgroup, group);
+ * idgroup = IDP_GetProperties(some_id, 1);
+ * IDP_AddToGroup(idgroup, color);
+ * IDP_AddToGroup(idgroup, group);
+ * \endcode
*
* Note that you MUST either attach the id property to an id property group with
* IDP_AddToGroup or MEM_freeN the property, doing anything else might result in
@@ -897,7 +933,7 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
*(float *)&prop->data.val = val->f;
break;
case IDP_DOUBLE:
- prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty double");
*(double *)&prop->data.val = val->d;
break;
case IDP_ARRAY:
@@ -917,6 +953,7 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
prop->len = prop->totallen = val->array.len;
break;
}
+ printf("%s: bad array type.\n",__func__);
return NULL;
}
case IDP_STRING:
@@ -963,6 +1000,14 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
/* heh I think all needed values are set properly by calloc anyway :) */
break;
}
+ case IDP_ID:
+ {
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty datablock");
+ prop->data.pointer = (void *)val->id;
+ prop->type = IDP_ID;
+ id_us_plus(IDP_Id(prop));
+ break;
+ }
default:
{
prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
@@ -977,11 +1022,10 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
}
/**
- * \note this will free all child properties of list arrays and groups!
- * Also, note that this does NOT unlink anything! Plus it doesn't free
- * the actual struct IDProperty struct either.
+ * \note This will free allocated data, all child properties of arrays and groups, and unlink IDs!
+ * But it does not free the actual IDProperty struct itself.
*/
-void IDP_FreeProperty(IDProperty *prop)
+void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user)
{
switch (prop->type) {
case IDP_ARRAY:
@@ -991,14 +1035,24 @@ void IDP_FreeProperty(IDProperty *prop)
IDP_FreeString(prop);
break;
case IDP_GROUP:
- IDP_FreeGroup(prop);
+ IDP_FreeGroup(prop, do_id_user);
break;
case IDP_IDPARRAY:
- IDP_FreeIDPArray(prop);
+ IDP_FreeIDPArray(prop, do_id_user);
+ break;
+ case IDP_ID:
+ if (do_id_user) {
+ id_us_min(IDP_Id(prop));
+ }
break;
}
}
+void IDP_FreeProperty(IDProperty *prop)
+{
+ IDP_FreeProperty_ex(prop, true);
+}
+
void IDP_ClearProperty(IDProperty *prop)
{
IDP_FreeProperty(prop);
@@ -1006,18 +1060,4 @@ void IDP_ClearProperty(IDProperty *prop)
prop->len = prop->totallen = 0;
}
-/**
- * Unlinks any struct IDProperty<->ID linkage that might be going on.
- *
- * \note currently unused
- */
-void IDP_UnlinkProperty(IDProperty *prop)
-{
- switch (prop->type) {
- case IDP_ID:
- IDP_UnlinkID(prop);
- break;
- }
-}
-
/** \} */
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index 9685f1f5af6..0616c614848 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -33,6 +33,7 @@
#include "DNA_actuator_types.h"
#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
@@ -70,10 +71,12 @@
#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_fcurve.h"
+#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
+#include "BKE_node.h"
#include "BKE_particle.h"
#include "BKE_rigidbody.h"
#include "BKE_sca.h"
@@ -82,7 +85,9 @@
#define FOREACH_FINALIZE _finalize
-#define FOREACH_FINALIZE_VOID FOREACH_FINALIZE: (void)0
+#define FOREACH_FINALIZE_VOID \
+ if (0) { goto FOREACH_FINALIZE; } \
+ FOREACH_FINALIZE: ((void)0)
#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, _cb_flag) \
CHECK_TYPE(id_pp, ID **); \
@@ -140,6 +145,37 @@ typedef struct LibraryForeachIDData {
BLI_LINKSTACK_DECLARE(ids_todo, ID *);
} LibraryForeachIDData;
+static void library_foreach_idproperty_ID_link(LibraryForeachIDData *data, IDProperty *prop, int flag)
+{
+ if (!prop)
+ return;
+
+ switch (prop->type) {
+ case IDP_GROUP:
+ {
+ for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ library_foreach_idproperty_ID_link(data, loop, flag);
+ }
+ break;
+ }
+ case IDP_IDPARRAY:
+ {
+ IDProperty *loop = IDP_Array(prop);
+ for (int i = 0; i < prop->len; i++) {
+ library_foreach_idproperty_ID_link(data, &loop[i], flag);
+ }
+ break;
+ }
+ case IDP_ID:
+ FOREACH_CALLBACK_INVOKE_ID(data, prop->data.pointer, flag);
+ break;
+ default:
+ break; /* Nothing to do here with other types of IDProperties... */
+ }
+
+ FOREACH_FINALIZE_VOID;
+}
+
static void library_foreach_rigidbodyworldSceneLooper(
struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cb_flag)
{
@@ -265,6 +301,17 @@ static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint)
FOREACH_FINALIZE_VOID;
}
+static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone)
+{
+ library_foreach_idproperty_ID_link(data, bone->prop, IDWALK_CB_USER);
+
+ for (Bone *curbone = bone->childbase.first; curbone; curbone = curbone->next) {
+ library_foreach_bone(data, curbone);
+ }
+
+ FOREACH_FINALIZE_VOID;
+}
+
static void library_foreach_ID_as_subdata_link(
ID **id_pp, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data)
{
@@ -337,6 +384,8 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
continue;
}
+ library_foreach_idproperty_ID_link(&data, id->properties, IDWALK_CB_USER);
+
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
library_foreach_animationData(&data, adt);
@@ -402,6 +451,7 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
CALLBACK_INVOKE(seq->clip, IDWALK_CB_USER);
CALLBACK_INVOKE(seq->mask, IDWALK_CB_USER);
CALLBACK_INVOKE(seq->sound, IDWALK_CB_USER);
+ library_foreach_idproperty_ID_link(&data, seq->prop, IDWALK_CB_USER);
for (SequenceModifierData *smd = seq->modifiers.first; smd; smd = smd->next) {
CALLBACK_INVOKE(smd->mask_id, IDWALK_CB_USER);
}
@@ -515,6 +565,7 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
data.cb_flag |= proxy_cb_flag;
for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) {
+ library_foreach_idproperty_ID_link(&data, pchan->prop, IDWALK_CB_USER);
CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER);
BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, &data);
}
@@ -554,6 +605,16 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
break;
}
+ case ID_AR:
+ {
+ bArmature *arm = (bArmature *)id;
+
+ for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) {
+ library_foreach_bone(&data, bone);
+ }
+ break;
+ }
+
case ID_ME:
{
Mesh *mesh = (Mesh *) id;
@@ -736,9 +797,27 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
{
bNodeTree *ntree = (bNodeTree *) id;
bNode *node;
+ bNodeSocket *sock;
+
CALLBACK_INVOKE(ntree->gpd, IDWALK_CB_USER);
+
for (node = ntree->nodes.first; node; node = node->next) {
CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER);
+
+ library_foreach_idproperty_ID_link(&data, node->prop, IDWALK_CB_USER);
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
+ }
+ for (sock = node->outputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
+ }
+ }
+
+ for (sock = ntree->inputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
+ }
+ for (sock = ntree->outputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
}
break;
}
@@ -898,7 +977,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
case ID_VF:
case ID_TXT:
case ID_SO:
- case ID_AR:
case ID_GD:
case ID_WM:
case ID_PAL:
@@ -948,9 +1026,25 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
*/
/* XXX This has to be fully rethink, basing check on ID type is not really working anymore (and even worth once
* IDProps will support ID pointers), we'll have to do some quick checks on IDs themselves... */
-bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used)
+bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
{
- if (id_type_can_have_animdata(id_type_owner)) {
+ /* any type of ID can be used in custom props. */
+ if (id_owner->properties) {
+ return true;
+ }
+
+ const short id_type_owner = GS(id_owner->name);
+
+ /* IDProps of armature bones and nodes, and bNode->id can use virtually any type of ID. */
+ if (ELEM(id_type_owner, ID_NT, ID_AR)) {
+ return true;
+ }
+
+ if (ntreeFromID(id_owner)) {
+ return true;
+ }
+
+ if (BKE_animdata_from_id(id_owner)) {
return true; /* AnimationData can use virtually any kind of datablocks, through drivers especially. */
}
@@ -959,8 +1053,7 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id
return ELEM(id_type_used, ID_LI);
case ID_SCE:
return (ELEM(id_type_used, ID_OB, ID_WO, ID_SCE, ID_MC, ID_MA, ID_GR, ID_TXT,
- ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT) ||
- BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT));
case ID_OB:
/* Could be the following, but simpler to just always say 'yes' here. */
#if 0
@@ -977,13 +1070,13 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id
case ID_MB:
return ELEM(id_type_used, ID_MA);
case ID_MA:
- return (ELEM(id_type_used, ID_TE, ID_GR) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_TE, ID_GR));
case ID_TE:
- return (ELEM(id_type_used, ID_IM, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_IM, ID_OB));
case ID_LT:
return ELEM(id_type_used, ID_KE);
case ID_LA:
- return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_TE));
case ID_CA:
return ELEM(id_type_used, ID_OB);
case ID_KE:
@@ -991,7 +1084,7 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id
case ID_SCR:
return ELEM(id_type_used, ID_SCE);
case ID_WO:
- return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_TE));
case ID_SPK:
return ELEM(id_type_used, ID_SO);
case ID_GR:
@@ -1012,7 +1105,7 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id
case ID_MSK:
return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */
case ID_LS:
- return (ELEM(id_type_used, ID_TE, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_TE, ID_OB));
case ID_IM:
case ID_VF:
case ID_TXT:
@@ -1118,7 +1211,7 @@ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
while (i-- && !is_defined) {
ID *id_curr = lb_array[i]->first;
- if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) {
+ if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) {
continue;
}
@@ -1170,7 +1263,7 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
while (i-- && !is_defined) {
ID *id_curr = lb_array[i]->first;
- if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) {
+ if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) {
continue;
}
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index b6f4621a0b3..d14e0cf0b65 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -448,20 +448,16 @@ ATTR_NONNULL(1) static void libblock_remap_data(
* objects actually using given old_id... sounds rather unlikely currently, though, so this will do for now. */
while (i--) {
- ID *id_curr = lb_array[i]->first;
-
- if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(old_id->name))) {
- continue;
- }
-
- for (; id_curr; id_curr = id_curr->next) {
- /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
- * the user count handling...
- * XXX No more true (except for debug usage of those skipping counters). */
- r_id_remap_data->id = id_curr;
- libblock_remap_data_preprocess(r_id_remap_data);
- BKE_library_foreach_ID_link(
- NULL, id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
+ for (ID *id_curr = lb_array[i]->first; id_curr; id_curr = id_curr->next) {
+ if (BKE_library_id_can_use_idtype(id_curr, GS(old_id->name))) {
+ /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
+ * the user count handling...
+ * XXX No more true (except for debug usage of those skipping counters). */
+ r_id_remap_data->id = id_curr;
+ libblock_remap_data_preprocess(r_id_remap_data);
+ BKE_library_foreach_ID_link(
+ NULL, id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
+ }
}
}
}
@@ -723,10 +719,10 @@ void BKE_libblock_relink_to_newid(ID *id)
BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0);
}
-void BKE_libblock_free_data(Main *UNUSED(bmain), ID *id)
+void BKE_libblock_free_data(Main *UNUSED(bmain), ID *id, const bool do_id_user)
{
if (id->properties) {
- IDP_FreeProperty(id->properties);
+ IDP_FreeProperty_ex(id->properties, do_id_user);
MEM_freeN(id->properties);
}
}
@@ -876,7 +872,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b
BLI_remlink(lb, id);
- BKE_libblock_free_data(bmain, id);
+ BKE_libblock_free_data(bmain, id, do_id_user);
BKE_main_unlock(bmain);
MEM_freeN(id);
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 3f3b4896653..f3223e31b17 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -1828,7 +1828,7 @@ void ntreeFreeTree(bNodeTree *ntree)
if (tntree == ntree)
break;
if (tntree == NULL) {
- BKE_libblock_free_data(G.main, &ntree->id);
+ BKE_libblock_free_data(G.main, &ntree->id, true);
}
}
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index e3b801b3193..eb7abc2f004 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -64,6 +64,7 @@
#include "BLI_strict_flags.h"
+#include "BLI_hash.h"
/* Dupli-Geometry */
@@ -180,6 +181,22 @@ static DupliObject *make_dupli(const DupliContext *ctx,
if (ob->type == OB_MBALL)
dob->no_draw = true;
+ /* random number */
+ /* the logic here is designed to match Cycles */
+ dob->random_id = BLI_hash_string(dob->ob->id.name + 2);
+
+ if (dob->persistent_id[0] != INT_MAX) {
+ for(i = 0; i < MAX_DUPLI_RECUR*2; i++)
+ dob->random_id = BLI_hash_int_2d(dob->random_id, (unsigned int)dob->persistent_id[i]);
+ }
+ else {
+ dob->random_id = BLI_hash_int_2d(dob->random_id, 0);
+ }
+
+ if (ctx->object != ob) {
+ dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->object->id.name + 2));
+ }
+
return dob;
}
diff --git a/source/blender/blenlib/BLI_hash.h b/source/blender/blenlib/BLI_hash.h
new file mode 100644
index 00000000000..551143f5d72
--- /dev/null
+++ b/source/blender/blenlib/BLI_hash.h
@@ -0,0 +1,66 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_HASH_H__
+#define __BLI_HASH_H__
+
+/** \file BLI_hash.h
+ * \ingroup bli
+ */
+
+static inline unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
+{
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+ unsigned int a, b, c;
+
+ a = b = c = 0xdeadbeef + (2 << 2) + 13;
+ a += kx;
+ b += ky;
+
+ c ^= b; c -= rot(b,14);
+ a ^= c; a -= rot(c,11);
+ b ^= a; b -= rot(a,25);
+ c ^= b; c -= rot(b,16);
+ a ^= c; a -= rot(c,4);
+ b ^= a; b -= rot(a,14);
+ c ^= b; c -= rot(b,24);
+
+ return c;
+
+#undef rot
+}
+
+static inline unsigned int BLI_hash_string(const char *str)
+{
+ unsigned int i = 0, c;
+
+ while((c = *str++))
+ i = i * 37 + c;
+
+ return i;
+}
+
+static inline unsigned int BLI_hash_int(unsigned int k)
+{
+ return BLI_hash_int_2d(k, 0);
+}
+
+#endif // __BLI_HASH_H__
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index 96349a7b066..00e761b81bc 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -67,6 +67,7 @@ void *BLI_poptail(ListBase *listbase) ATTR_NONNULL(1);
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1);
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1);
+void BLI_insertlinkreplace(ListBase *listbase, void *v_l_src, void *v_l_dst) ATTR_NONNULL(1, 2, 3);
void BLI_listbase_sort(struct ListBase *listbase, int (*cmp)(const void *, const void *)) ATTR_NONNULL(1, 2);
void BLI_listbase_sort_r(ListBase *listbase, int (*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1, 2);
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index baa1f792018..b6a55d34d14 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -39,14 +39,6 @@ extern "C" {
struct ListBase;
-#ifdef WIN32
-#define SEP '\\'
-#define ALTSEP '/'
-#else
-#define SEP '/'
-#define ALTSEP '\\'
-#endif
-
void BLI_setenv(const char *env, const char *val) ATTR_NONNULL(1);
void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1);
@@ -60,7 +52,13 @@ void BLI_path_append(char *__restrict dst, const size_t maxlen,
const char *__restrict file) ATTR_NONNULL();
void BLI_join_dirfile(char *__restrict string, const size_t maxlen,
const char *__restrict dir, const char *__restrict file) ATTR_NONNULL();
+size_t BLI_path_join(
+ char *__restrict dst, const size_t dst_len,
+ const char *path_first, ...) ATTR_NONNULL(1, 3) ATTR_SENTINEL(0);
const char *BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+bool BLI_path_name_at_index(
+ const char *__restrict path, const int index,
+ int *__restrict r_offset, int *__restrict r_len) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
#if 0
typedef enum bli_rebase_state {
@@ -83,7 +81,6 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen);
#endif
bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *name);
-void BLI_getlastdir(const char *dir, char *last, const size_t maxlen);
bool BLI_testextensie(const char *str, const char *ext) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
bool BLI_testextensie_n(const char *str, ...) ATTR_NONNULL(1) ATTR_SENTINEL(0);
bool BLI_testextensie_array(const char *str, const char **ext_array) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
@@ -143,6 +140,18 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
# define FILE_MAX 1024
#endif
+#ifdef WIN32
+# define SEP '\\'
+# define ALTSEP '/'
+# define SEP_STR "\\"
+# define ALTSEP_STR "/"
+#else
+# define SEP '/'
+# define ALTSEP '\\'
+# define SEP_STR "/"
+# define ALTSEP_STR "\\"
+#endif
+
/* Parent and current dir helpers. */
#define FILENAME_PARENT ".."
#define FILENAME_CURRENT "."
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index c9bf4976ae8..6cb7b7d8e3e 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -342,6 +342,40 @@ void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
}
}
+
+/**
+ * Insert a link in place of another, without changing it's position in the list.
+ *
+ * Puts `vnewlink` in the position of `vreplacelink`, removing `vreplacelink`.
+ * - `vreplacelink` *must* be in the list.
+ * - `vnewlink` *must not* be in the list.
+ */
+void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
+{
+ Link *l_old = vreplacelink;
+ Link *l_new = vnewlink;
+
+ /* update adjacent links */
+ if (l_old->next != NULL) {
+ l_old->next->prev = l_new;
+ }
+ if (l_old->prev != NULL) {
+ l_old->prev->next = l_new;
+ }
+
+ /* set direct links */
+ l_new->next = l_old->next;
+ l_new->prev = l_old->prev;
+
+ /* update list */
+ if (listbase->first == l_old) {
+ listbase->first = l_new;
+ }
+ if (listbase->last == l_old) {
+ listbase->last = l_new;
+ }
+}
+
/**
* Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move
* item if new position would exceed list (could optionally move to head/tail).
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 6644e6605a1..7b765cfa939 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -1167,30 +1167,6 @@ bool BLI_path_program_search(
}
/**
- * Copies into *last the part of *dir following the second-last slash.
- */
-void BLI_getlastdir(const char *dir, char *last, const size_t maxlen)
-{
- const char *s = dir;
- const char *lslash = NULL;
- const char *prevslash = NULL;
- while (*s) {
- if ((*s == '\\') || (*s == '/')) {
- prevslash = lslash;
- lslash = s;
- }
- s++;
- }
- if (prevslash) {
- BLI_strncpy(last, prevslash + 1, maxlen);
- }
- else {
- BLI_strncpy(last, dir, maxlen);
- }
-}
-
-
-/**
* Sets the specified environment variable to the specified value,
* and clears it if val == NULL.
*/
@@ -1615,6 +1591,90 @@ void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__r
}
/**
+ * Join multiple strings into a path, ensuring only a single path separator between each,
+ * and trailing slash is kept.
+ *
+ * \note If you want a trailing slash, add ``SEP_STR`` as the last path argument,
+ * duplicate slashes will be cleaned up.
+ */
+size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path, ...)
+{
+ if (UNLIKELY(dst_len == 0)) {
+ return 0;
+ }
+ const size_t dst_last = dst_len - 1;
+ size_t ofs = BLI_strncpy_rlen(dst, path, dst_len);
+
+ if (ofs == dst_last) {
+ return ofs;
+ }
+
+ /* remove trailing slashes, unless there are _only_ trailing slashes
+ * (allow "//" as the first argument). */
+ bool has_trailing_slash = false;
+ if (ofs != 0) {
+ size_t len = ofs;
+ while ((len != 0) && ELEM(path[len - 1], SEP, ALTSEP)) {
+ len -= 1;
+ }
+ if (len != 0) {
+ ofs = len;
+ }
+ has_trailing_slash = (path[len] != '\0');
+ }
+
+ va_list args;
+ va_start(args, path);
+ while ((path = (const char *) va_arg(args, const char *))) {
+ has_trailing_slash = false;
+ const char *path_init = path;
+ while (ELEM(path[0], SEP, ALTSEP)) {
+ path++;
+ }
+ size_t len = strlen(path);
+ if (len != 0) {
+ while ((len != 0) && ELEM(path[len - 1], SEP, ALTSEP)) {
+ len -= 1;
+ }
+
+ if (len != 0) {
+ /* the very first path may have a slash at the end */
+ if (ofs && !ELEM(dst[ofs - 1], SEP, ALTSEP)) {
+ dst[ofs++] = SEP;
+ if (ofs == dst_last) {
+ break;
+ }
+ }
+ has_trailing_slash = (path[len] != '\0');
+ if (ofs + len >= dst_last) {
+ len = dst_last - ofs;
+ }
+ memcpy(&dst[ofs], path, len);
+ ofs += len;
+ if (ofs == dst_last) {
+ break;
+ }
+ }
+ }
+ else {
+ has_trailing_slash = (path_init != path);
+ }
+ }
+ va_end(args);
+
+ if (has_trailing_slash) {
+ if ((ofs != dst_last) && (ofs != 0) && (ELEM(dst[ofs - 1], SEP, ALTSEP) == 0)) {
+ dst[ofs++] = SEP;
+ }
+ }
+
+ BLI_assert(ofs <= dst_last);
+ dst[ofs] = '\0';
+
+ return ofs;
+}
+
+/**
* like pythons os.path.basename()
*
* \return The pointer into \a path string immediately after last slash,
@@ -1626,6 +1686,71 @@ const char *BLI_path_basename(const char *path)
return filename ? filename + 1 : path;
}
+/**
+ * Get an element of the path at an index, eg:
+ * "/some/path/file.txt" where an index of...
+ * - 0 or -3: "some"
+ * - 1 or -2: "path"
+ * - 2 or -1: "file.txt"
+ *
+ * Ignores multiple slashes at any point in the path (including start/end).
+ */
+bool BLI_path_name_at_index(const char *path, const int index, int *r_offset, int *r_len)
+{
+ if (index >= 0) {
+ int index_step = 0;
+ int prev = -1;
+ int i = 0;
+ while (true) {
+ const char c = path[i];
+ if (ELEM(c, SEP, ALTSEP, '\0')) {
+ if (prev + 1 != i) {
+ prev += 1;
+ if (index_step == index) {
+ *r_offset = prev;
+ *r_len = i - prev;
+ /* printf("!!! %d %d\n", start, end); */
+ return true;
+ }
+ index_step += 1;
+ }
+ if (c == '\0') {
+ break;
+ }
+ prev = i;
+ }
+ i += 1;
+ }
+ return false;
+ }
+ else {
+ /* negative number, reverse where -1 is the last element */
+ int index_step = -1;
+ int prev = strlen(path);
+ int i = prev - 1;
+ while (true) {
+ const char c = i >= 0 ? path[i] : '\0';
+ if (ELEM(c, SEP, ALTSEP, '\0')) {
+ if (prev - 1 != i) {
+ i += 1;
+ if (index_step == index) {
+ *r_offset = i;
+ *r_len = prev - i;
+ return true;
+ }
+ index_step -= 1;
+ }
+ if (c == '\0') {
+ break;
+ }
+ prev = i;
+ }
+ i -= 1;
+ }
+ return false;
+ }
+}
+
/* UNUSED */
#if 0
/**
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index 17e20f8fa18..eb4e6e91aee 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -162,6 +162,16 @@ struct TaskPool {
*/
int thread_id;
+ /* For the pools which are created from non-main thread which is not a
+ * scheduler worker thread we can't re-use any of scheduler's threads TLS
+ * and have to use our own one.
+ */
+ bool use_local_tls;
+ TaskThreadLocalStorage local_tls;
+#ifndef NDEBUG
+ pthread_t creator_thread_id;
+#endif
+
#ifdef DEBUG_STATS
TaskMemPoolStats *mempool_stats;
#endif
@@ -202,13 +212,25 @@ BLI_INLINE void task_data_free(Task *task, const int thread_id)
}
}
+BLI_INLINE void initialize_task_tls(TaskThreadLocalStorage *tls)
+{
+ memset(tls, 0, sizeof(TaskThreadLocalStorage));
+}
+
BLI_INLINE TaskThreadLocalStorage *get_task_tls(TaskPool *pool,
const int thread_id)
{
TaskScheduler *scheduler = pool->scheduler;
BLI_assert(thread_id >= 0);
BLI_assert(thread_id <= scheduler->num_threads);
+ if (pool->use_local_tls && thread_id == 0) {
+ BLI_assert(pool->thread_id == 0);
+ BLI_assert(!BLI_thread_is_main());
+ BLI_assert(pthread_equal(pthread_self(), pool->creator_thread_id));
+ return &pool->local_tls;
+ }
if (thread_id == 0) {
+ BLI_assert(BLI_thread_is_main());
return &scheduler->task_threads[pool->thread_id].tls;
}
return &scheduler->task_threads[thread_id].tls;
@@ -252,6 +274,9 @@ static void task_free(TaskPool *pool, Task *task, const int thread_id)
task_data_free(task, thread_id);
BLI_assert(thread_id >= 0);
BLI_assert(thread_id <= pool->scheduler->num_threads);
+ if (thread_id == 0) {
+ BLI_assert(pool->use_local_tls || BLI_thread_is_main());
+ }
TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
TaskMemPool *task_mempool = &tls->task_mempool;
if (task_mempool->num_tasks < MEMPOOL_SIZE - 1) {
@@ -424,9 +449,12 @@ TaskScheduler *BLI_task_scheduler_create(int num_threads)
num_threads = 1;
}
- scheduler->task_threads = MEM_callocN(sizeof(TaskThread) * (num_threads + 1),
+ scheduler->task_threads = MEM_mallocN(sizeof(TaskThread) * (num_threads + 1),
"TaskScheduler task threads");
+ /* Initialize TLS for main thread. */
+ initialize_task_tls(&scheduler->task_threads[0].tls);
+
pthread_key_create(&scheduler->tls_id_key, NULL);
/* launch threads that will be waiting for work */
@@ -440,6 +468,7 @@ TaskScheduler *BLI_task_scheduler_create(int num_threads)
TaskThread *thread = &scheduler->task_threads[i + 1];
thread->scheduler = scheduler;
thread->id = i + 1;
+ initialize_task_tls(&thread->tls);
if (pthread_create(&scheduler->threads[i], NULL, task_scheduler_thread_run, thread) != 0) {
fprintf(stderr, "TaskScheduler failed to launch thread %d/%d\n", i, num_threads);
@@ -572,6 +601,7 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler,
pool->num_suspended = 0;
pool->suspended_queue.first = pool->suspended_queue.last = NULL;
pool->run_in_background = is_background;
+ pool->use_local_tls = false;
BLI_mutex_init(&pool->num_mutex);
BLI_condition_init(&pool->num_cond);
@@ -584,13 +614,18 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler,
}
else {
TaskThread *thread = pthread_getspecific(scheduler->tls_id_key);
- /* NOTE: It is possible that pool is created from non-main thread
- * which isn't a scheduler thread. In this case pthread's TLS will
- * be NULL and we can safely consider thread id 0 for the main
- * thread of this pool (the one which does wort_and_wait()).
- */
if (thread == NULL) {
+ /* NOTE: Task pool is created from non-main thread which is not
+ * managed by the task scheduler. We identify ourselves as thread ID
+ * 0 but we do not use scheduler's TLS storage and use our own
+ * instead to avoid any possible threading conflicts.
+ */
pool->thread_id = 0;
+ pool->use_local_tls = true;
+#ifndef NDEBUG
+ pool->creator_thread_id = pthread_self();
+#endif
+ initialize_task_tls(&pool->local_tls);
}
else {
pool->thread_id = thread->id;
@@ -670,6 +705,10 @@ void BLI_task_pool_free(TaskPool *pool)
MEM_freeN(pool->mempool_stats);
#endif
+ if (pool->use_local_tls) {
+ free_task_tls(&pool->local_tls);
+ }
+
MEM_freeN(pool);
BLI_end_threaded_malloc();
@@ -743,9 +782,7 @@ void BLI_task_pool_work_and_wait(TaskPool *pool)
BLI_condition_notify_all(&scheduler->queue_cond);
BLI_mutex_unlock(&scheduler->queue_mutex);
-
}
- pool->is_suspended = false;
}
pool->do_work = true;
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 8cb9ef837b2..3d2e8a306de 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -69,6 +69,12 @@ if(WITH_BUILDINFO)
add_definitions(-DWITH_BUILDINFO)
endif()
+if(WITH_PYTHON)
+ if(WITH_PYTHON_SECURITY)
+ add_definitions(-DWITH_PYTHON_SECURITY)
+ endif()
+endif()
+
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index fb80585dc2a..2900f9e4fc4 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -129,6 +129,7 @@
#include "BKE_library_idmap.h"
#include "BKE_library_query.h"
#include "BKE_idcode.h"
+#include "BKE_idprop.h"
#include "BKE_material.h"
#include "BKE_main.h" // for Main
#include "BKE_mesh.h" // for ME_ defines (patching)
@@ -2001,7 +2002,7 @@ static void test_pointer_array(FileData *fd, void **mat)
/* ************ READ ID Properties *************** */
static void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, FileData *fd);
-static void IDP_LibLinkProperty(IDProperty *prop, int switch_endian, FileData *fd);
+static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd);
static void IDP_DirectLinkIDPArray(IDProperty *prop, int switch_endian, FileData *fd)
{
@@ -2132,10 +2133,39 @@ static void _IDP_DirectLinkGroup_OrFree(IDProperty **prop, int switch_endian, Fi
}
}
-/* stub function */
-static void IDP_LibLinkProperty(IDProperty *UNUSED(prop), int UNUSED(switch_endian), FileData *UNUSED(fd))
+static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd)
{
- /* Should we do something here, prop should be ensured to be non-NULL first... */
+ if (!prop)
+ return;
+
+ switch (prop->type) {
+ case IDP_ID: /* PointerProperty */
+ {
+ void *newaddr = newlibadr_us(fd, NULL, IDP_Id(prop));
+ if (IDP_Id(prop) && !newaddr && G.debug) {
+ printf("Error while loading \"%s\". Data not found in file!\n", prop->name);
+ }
+ prop->data.pointer = newaddr;
+ break;
+ }
+ case IDP_IDPARRAY: /* CollectionProperty */
+ {
+ IDProperty *idp_array = IDP_IDPArray(prop);
+ for (int i = 0; i < prop->len; i++) {
+ IDP_LibLinkProperty(&(idp_array[i]), fd);
+ }
+ break;
+ }
+ case IDP_GROUP: /* PointerProperty */
+ {
+ for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ IDP_LibLinkProperty(loop, fd);
+ }
+ break;
+ }
+ default:
+ break; /* Nothing to do for other IDProps. */
+ }
}
/* ************ READ IMAGE PREVIEW *************** */
@@ -2192,19 +2222,19 @@ static void direct_link_curvemapping(FileData *fd, CurveMapping *cumap)
/* library brush linking after fileread */
static void lib_link_brush(FileData *fd, Main *main)
{
- Brush *brush;
-
/* only link ID pointers */
- for (brush = main->brush.first; brush; brush = brush->id.next) {
+ for (Brush *brush = main->brush.first; brush; brush = brush->id.next) {
if (brush->id.tag & LIB_TAG_NEED_LINK) {
- brush->id.tag &= ~LIB_TAG_NEED_LINK;
-
+ IDP_LibLinkProperty(brush->id.properties, fd);
+
/* brush->(mask_)mtex.obj is ignored on purpose? */
brush->mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mtex.tex);
brush->mask_mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mask_mtex.tex);
brush->clone.image = newlibadr(fd, brush->id.lib, brush->clone.image);
brush->toggle_brush = newlibadr(fd, brush->id.lib, brush->toggle_brush);
brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve);
+
+ brush->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -2227,13 +2257,13 @@ static void direct_link_brush(FileData *fd, Brush *brush)
}
/* ************ READ Palette *************** */
-static void lib_link_palette(FileData *UNUSED(fd), Main *main)
+static void lib_link_palette(FileData *fd, Main *main)
{
- Palette *palette;
-
/* only link ID pointers */
- for (palette = main->palettes.first; palette; palette = palette->id.next) {
+ for (Palette *palette = main->palettes.first; palette; palette = palette->id.next) {
if (palette->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(palette->id.properties, fd);
+
palette->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -2245,13 +2275,13 @@ static void direct_link_palette(FileData *fd, Palette *palette)
link_list(fd, &palette->colors);
}
-static void lib_link_paint_curve(FileData *UNUSED(fd), Main *main)
+static void lib_link_paint_curve(FileData *fd, Main *main)
{
- PaintCurve *pc;
-
/* only link ID pointers */
- for (pc = main->paintcurves.first; pc; pc = pc->id.next) {
+ for (PaintCurve *pc = main->paintcurves.first; pc; pc = pc->id.next) {
if (pc->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(pc->id.properties, fd);
+
pc->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -2503,15 +2533,12 @@ static void direct_link_fcurves(FileData *fd, ListBase *list)
static void lib_link_action(FileData *fd, Main *main)
{
- bAction *act;
- bActionChannel *chan;
-
- for (act = main->action.first; act; act = act->id.next) {
+ for (bAction *act = main->action.first; act; act = act->id.next) {
if (act->id.tag & LIB_TAG_NEED_LINK) {
- act->id.tag &= ~LIB_TAG_NEED_LINK;
+ IDP_LibLinkProperty(act->id.properties, fd);
// XXX deprecated - old animation system <<<
- for (chan=act->chanbase.first; chan; chan=chan->next) {
+ for (bActionChannel *chan = act->chanbase.first; chan; chan = chan->next) {
chan->ipo = newlibadr_us(fd, act->id.lib, chan->ipo);
lib_link_constraint_channels(fd, &act->id, &chan->constraintChannels);
}
@@ -2524,6 +2551,8 @@ static void lib_link_action(FileData *fd, Main *main)
marker->camera = newlibadr(fd, act->id.lib, marker->camera);
}
}
+
+ act->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -2710,26 +2739,20 @@ static void direct_link_animdata(FileData *fd, AnimData *adt)
static void lib_link_cachefiles(FileData *fd, Main *bmain)
{
- CacheFile *cache_file;
-
/* only link ID pointers */
- for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
+ for (CacheFile *cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
if (cache_file->id.tag & LIB_TAG_NEED_LINK) {
- cache_file->id.tag &= ~LIB_TAG_NEED_LINK;
- }
-
- BLI_listbase_clear(&cache_file->object_paths);
- cache_file->handle = NULL;
- cache_file->handle_mutex = NULL;
-
- if (cache_file->adt) {
+ IDP_LibLinkProperty(cache_file->id.properties, fd);
lib_link_animdata(fd, &cache_file->id, cache_file->adt);
+
+ cache_file->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
static void direct_link_cachefile(FileData *fd, CacheFile *cache_file)
{
+ BLI_listbase_clear(&cache_file->object_paths);
cache_file->handle = NULL;
cache_file->handle_mutex = NULL;
@@ -2753,19 +2776,13 @@ static void direct_link_motionpath(FileData *fd, bMotionPath *mpath)
/* ************ READ NODE TREE *************** */
-static void lib_link_node_socket(FileData *fd, ID *UNUSED(id), bNodeSocket *sock)
-{
- /* Link ID Properties -- and copy this comment EXACTLY for easy finding
- * of library blocks that implement this.*/
- IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
-}
-
/* Single node tree (also used for material/scene trees), ntree is not NULL */
static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
{
bNode *node;
bNodeSocket *sock;
+ IDP_LibLinkProperty(ntree->id.properties, fd);
lib_link_animdata(fd, &ntree->id, ntree->adt);
ntree->gpd = newlibadr_us(fd, id->lib, ntree->gpd);
@@ -2773,32 +2790,35 @@ static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
for (node = ntree->nodes.first; node; node = node->next) {
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- IDP_LibLinkProperty(node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(node->prop, fd);
- node->id= newlibadr_us(fd, id->lib, node->id);
+ node->id = newlibadr_us(fd, id->lib, node->id);
- for (sock = node->inputs.first; sock; sock = sock->next)
- lib_link_node_socket(fd, id, sock);
- for (sock = node->outputs.first; sock; sock = sock->next)
- lib_link_node_socket(fd, id, sock);
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ IDP_LibLinkProperty(sock->prop, fd);
+ }
+ for (sock = node->outputs.first; sock; sock = sock->next) {
+ IDP_LibLinkProperty(sock->prop, fd);
+ }
}
- for (sock = ntree->inputs.first; sock; sock = sock->next)
- lib_link_node_socket(fd, id, sock);
- for (sock = ntree->outputs.first; sock; sock = sock->next)
- lib_link_node_socket(fd, id, sock);
+ for (sock = ntree->inputs.first; sock; sock = sock->next) {
+ IDP_LibLinkProperty(sock->prop, fd);
+ }
+ for (sock = ntree->outputs.first; sock; sock = sock->next) {
+ IDP_LibLinkProperty(sock->prop, fd);
+ }
}
/* library ntree linking after fileread */
static void lib_link_nodetree(FileData *fd, Main *main)
{
- bNodeTree *ntree;
-
/* only link ID pointers */
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
+ for (bNodeTree *ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
if (ntree->id.tag & LIB_TAG_NEED_LINK) {
- ntree->id.tag &= ~LIB_TAG_NEED_LINK;
lib_link_ntree(fd, &ntree->id, ntree);
+
+ ntree->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3291,6 +3311,8 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose)
pchan->bone = BLI_ghash_lookup(bone_hash, pchan->name);
+ IDP_LibLinkProperty(pchan->prop, fd);
+
pchan->custom = newlibadr_us(fd, arm->id.lib, pchan->custom);
if (UNLIKELY(pchan->bone == NULL)) {
rebuild = true;
@@ -3311,13 +3333,26 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose)
}
}
+static void lib_link_bones(FileData *fd, Bone *bone)
+{
+ IDP_LibLinkProperty(bone->prop, fd);
+
+ for (Bone *curbone = bone->childbase.first; curbone; curbone = curbone->next) {
+ lib_link_bones(fd, curbone);
+ }
+}
+
static void lib_link_armature(FileData *fd, Main *main)
{
- bArmature *arm;
-
- for (arm = main->armature.first; arm; arm = arm->id.next) {
+ for (bArmature *arm = main->armature.first; arm; arm = arm->id.next) {
if (arm->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(arm->id.properties, fd);
lib_link_animdata(fd, &arm->id, arm->adt);
+
+ for (Bone *curbone = arm->bonebase.first; curbone; curbone = curbone->next) {
+ lib_link_bones(fd, curbone);
+ }
+
arm->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -3362,14 +3397,13 @@ static void direct_link_armature(FileData *fd, bArmature *arm)
static void lib_link_camera(FileData *fd, Main *main)
{
- Camera *ca;
-
- for (ca = main->camera.first; ca; ca = ca->id.next) {
+ for (Camera *ca = main->camera.first; ca; ca = ca->id.next) {
if (ca->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(ca->id.properties, fd);
lib_link_animdata(fd, &ca->id, ca->adt);
ca->ipo = newlibadr_us(fd, ca->id.lib, ca->ipo); // XXX deprecated - old animation system
-
+
ca->dof_ob = newlibadr(fd, ca->id.lib, ca->dof_ob);
ca->id.tag &= ~LIB_TAG_NEED_LINK;
@@ -3388,16 +3422,13 @@ static void direct_link_camera(FileData *fd, Camera *ca)
static void lib_link_lamp(FileData *fd, Main *main)
{
- Lamp *la;
- MTex *mtex;
- int a;
-
- for (la = main->lamp.first; la; la = la->id.next) {
+ for (Lamp *la = main->lamp.first; la; la = la->id.next) {
if (la->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(la->id.properties, fd);
lib_link_animdata(fd, &la->id, la->adt);
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = la->mtex[a];
+ for (int a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex = la->mtex[a];
if (mtex) {
mtex->tex = newlibadr_us(fd, la->id.lib, mtex->tex);
mtex->object = newlibadr(fd, la->id.lib, mtex->object);
@@ -3454,17 +3485,11 @@ void blo_do_versions_key_uidgen(Key *key)
static void lib_link_key(FileData *fd, Main *main)
{
- Key *key;
-
- for (key = main->key.first; key; key = key->id.next) {
- /*check if we need to generate unique ids for the shapekeys*/
- if (!key->uidgen) {
- blo_do_versions_key_uidgen(key);
- }
-
+ for (Key *key = main->key.first; key; key = key->id.next) {
BLI_assert((key->id.tag & LIB_TAG_EXTERN) == 0);
if (key->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(key->id.properties, fd);
lib_link_animdata(fd, &key->id, key->adt);
key->ipo = newlibadr_us(fd, key->id.lib, key->ipo); // XXX deprecated - old animation system
@@ -3527,15 +3552,14 @@ static void direct_link_key(FileData *fd, Key *key)
static void lib_link_mball(FileData *fd, Main *main)
{
- MetaBall *mb;
- int a;
-
- for (mb = main->mball.first; mb; mb = mb->id.next) {
+ for (MetaBall *mb = main->mball.first; mb; mb = mb->id.next) {
if (mb->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(mb->id.properties, fd);
lib_link_animdata(fd, &mb->id, mb->adt);
- for (a = 0; a < mb->totcol; a++)
+ for (int a = 0; a < mb->totcol; a++) {
mb->mat[a] = newlibadr_us(fd, mb->id.lib, mb->mat[a]);
+ }
mb->ipo = newlibadr_us(fd, mb->id.lib, mb->ipo); // XXX deprecated - old animation system
@@ -3564,18 +3588,15 @@ static void direct_link_mball(FileData *fd, MetaBall *mb)
static void lib_link_world(FileData *fd, Main *main)
{
- World *wrld;
- MTex *mtex;
- int a;
-
- for (wrld = main->world.first; wrld; wrld = wrld->id.next) {
+ for (World *wrld = main->world.first; wrld; wrld = wrld->id.next) {
if (wrld->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(wrld->id.properties, fd);
lib_link_animdata(fd, &wrld->id, wrld->adt);
wrld->ipo = newlibadr_us(fd, wrld->id.lib, wrld->ipo); // XXX deprecated - old animation system
- for (a=0; a < MAX_MTEX; a++) {
- mtex = wrld->mtex[a];
+ for (int a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex = wrld->mtex[a];
if (mtex) {
mtex->tex = newlibadr_us(fd, wrld->id.lib, mtex->tex);
mtex->object = newlibadr(fd, wrld->id.lib, mtex->object);
@@ -3616,12 +3637,12 @@ static void direct_link_world(FileData *fd, World *wrld)
/* ************ READ VFONT ***************** */
-static void lib_link_vfont(FileData *UNUSED(fd), Main *main)
+static void lib_link_vfont(FileData *fd, Main *main)
{
- VFont *vf;
-
- for (vf = main->vfont.first; vf; vf = vf->id.next) {
+ for (VFont *vf = main->vfont.first; vf; vf = vf->id.next) {
if (vf->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(vf->id.properties, fd);
+
vf->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -3636,12 +3657,12 @@ static void direct_link_vfont(FileData *fd, VFont *vf)
/* ************ READ TEXT ****************** */
-static void lib_link_text(FileData *UNUSED(fd), Main *main)
+static void lib_link_text(FileData *fd, Main *main)
{
- Text *text;
-
- for (text = main->text.first; text; text = text->id.next) {
+ for (Text *text = main->text.first; text; text = text->id.next) {
if (text->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(text->id.properties, fd);
+
text->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -3690,11 +3711,9 @@ static void direct_link_text(FileData *fd, Text *text)
static void lib_link_image(FileData *fd, Main *main)
{
- Image *ima;
-
- for (ima = main->image.first; ima; ima = ima->id.next) {
+ for (Image *ima = main->image.first; ima; ima = ima->id.next) {
if (ima->id.tag & LIB_TAG_NEED_LINK) {
- IDP_LibLinkProperty(ima->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(ima->id.properties, fd);
ima->id.tag &= ~LIB_TAG_NEED_LINK;
}
@@ -3759,15 +3778,14 @@ static void direct_link_image(FileData *fd, Image *ima)
static void lib_link_curve(FileData *fd, Main *main)
{
- Curve *cu;
- int a;
-
- for (cu = main->curve.first; cu; cu = cu->id.next) {
+ for (Curve *cu = main->curve.first; cu; cu = cu->id.next) {
if (cu->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(cu->id.properties, fd);
lib_link_animdata(fd, &cu->id, cu->adt);
- for (a = 0; a < cu->totcol; a++)
+ for (int a = 0; a < cu->totcol; a++) {
cu->mat[a] = newlibadr_us(fd, cu->id.lib, cu->mat[a]);
+ }
cu->bevobj = newlibadr(fd, cu->id.lib, cu->bevobj);
cu->taperobj = newlibadr(fd, cu->id.lib, cu->taperobj);
@@ -3852,10 +3870,9 @@ static void direct_link_curve(FileData *fd, Curve *cu)
static void lib_link_texture(FileData *fd, Main *main)
{
- Tex *tex;
-
- for (tex = main->tex.first; tex; tex = tex->id.next) {
+ for (Tex *tex = main->tex.first; tex; tex = tex->id.next) {
if (tex->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(tex->id.properties, fd);
lib_link_animdata(fd, &tex->id, tex->adt);
tex->ima = newlibadr_us(fd, tex->id.lib, tex->ima);
@@ -3931,23 +3948,20 @@ static void direct_link_texture(FileData *fd, Tex *tex)
static void lib_link_material(FileData *fd, Main *main)
{
- Material *ma;
- MTex *mtex;
- int a;
-
- for (ma = main->mat.first; ma; ma = ma->id.next) {
+ for (Material *ma = main->mat.first; ma; ma = ma->id.next) {
if (ma->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(ma->id.properties, fd);
lib_link_animdata(fd, &ma->id, ma->adt);
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(ma->id.properties, fd);
ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo); // XXX deprecated - old animation system
ma->group = newlibadr_us(fd, ma->id.lib, ma->group);
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = ma->mtex[a];
+ for (int a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex = ma->mtex[a];
if (mtex) {
mtex->tex = newlibadr_us(fd, ma->id.lib, mtex->tex);
mtex->object = newlibadr(fd, ma->id.lib, mtex->object);
@@ -4078,14 +4092,11 @@ static void lib_link_partdeflect(FileData *fd, ID *id, PartDeflect *pd)
static void lib_link_particlesettings(FileData *fd, Main *main)
{
- ParticleSettings *part;
- ParticleDupliWeight *dw;
- MTex *mtex;
- int a;
-
- for (part = main->particle.first; part; part = part->id.next) {
+ for (ParticleSettings *part = main->particle.first; part; part = part->id.next) {
if (part->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(part->id.properties, fd);
lib_link_animdata(fd, &part->id, part->adt);
+
part->ipo = newlibadr_us(fd, part->id.lib, part->ipo); // XXX deprecated - old animation system
part->dup_ob = newlibadr(fd, part->id.lib, part->dup_ob);
@@ -4105,6 +4116,7 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
}
if (part->dupliweights.first && part->dup_group) {
+ ParticleDupliWeight *dw;
int index_ok = 0;
/* check for old files without indices (all indexes 0) */
if (BLI_listbase_is_single(&part->dupliweights)) {
@@ -4169,8 +4181,8 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
}
}
- for (a = 0; a < MAX_MTEX; a++) {
- mtex= part->mtex[a];
+ for (int a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex= part->mtex[a];
if (mtex) {
mtex->tex = newlibadr_us(fd, part->id.lib, mtex->tex);
mtex->object = newlibadr(fd, part->id.lib, mtex->object);
@@ -4404,7 +4416,7 @@ static void lib_link_mesh(FileData *fd, Main *main)
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- IDP_LibLinkProperty(me->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(me->id.properties, fd);
lib_link_animdata(fd, &me->id, me->adt);
/* this check added for python created meshes */
@@ -4677,10 +4689,9 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
static void lib_link_latt(FileData *fd, Main *main)
{
- Lattice *lt;
-
- for (lt = main->latt.first; lt; lt = lt->id.next) {
+ for (Lattice *lt = main->latt.first; lt; lt = lt->id.next) {
if (lt->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(lt->id.properties, fd);
lib_link_animdata(fd, &lt->id, lt->adt);
lt->ipo = newlibadr_us(fd, lt->id.lib, lt->ipo); // XXX deprecated - old animation system
@@ -4724,17 +4735,13 @@ static void lib_link_modifiers(FileData *fd, Object *ob)
static void lib_link_object(FileData *fd, Main *main)
{
- Object *ob;
- PartEff *paf;
- bSensor *sens;
- bController *cont;
- bActuator *act;
- void *poin;
- int warn=0, a;
-
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ bool warn = false;
+
+ for (Object *ob = main->object.first; ob; ob = ob->id.next) {
if (ob->id.tag & LIB_TAG_NEED_LINK) {
- IDP_LibLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ int a;
+
+ IDP_LibLinkProperty(ob->id.properties, fd);
lib_link_animdata(fd, &ob->id, ob->adt);
// XXX deprecated - old animation system <<<
@@ -4766,17 +4773,17 @@ static void lib_link_object(FileData *fd, Main *main)
}
ob->proxy_group = newlibadr(fd, ob->id.lib, ob->proxy_group);
- poin = ob->data;
+ void *poin = ob->data;
ob->data = newlibadr_us(fd, ob->id.lib, ob->data);
- if (ob->data==NULL && poin!=NULL) {
+ if (ob->data == NULL && poin != NULL) {
if (ob->id.lib)
printf("Can't find obdata of %s lib %s\n", ob->id.name + 2, ob->id.lib->name);
else
printf("Object %s lost data.\n", ob->id.name + 2);
ob->type = OB_EMPTY;
- warn = 1;
+ warn = true;
if (ob->pose) {
/* we can't call #BKE_pose_free() here because of library linking
@@ -4822,13 +4829,13 @@ static void lib_link_object(FileData *fd, Main *main)
lib_link_nlastrips(fd, &ob->id, &ob->nlastrips);
// >>> XXX deprecated - old animation system
- for (paf = ob->effect.first; paf; paf = paf->next) {
+ for (PartEff *paf = ob->effect.first; paf; paf = paf->next) {
if (paf->type == EFF_PARTICLE) {
paf->group = newlibadr_us(fd, ob->id.lib, paf->group);
}
}
- for (sens = ob->sensors.first; sens; sens = sens->next) {
+ for (bSensor *sens = ob->sensors.first; sens; sens = sens->next) {
for (a = 0; a < sens->totlinks; a++)
sens->links[a] = newglobadr(fd, sens->links[a]);
@@ -4839,7 +4846,7 @@ static void lib_link_object(FileData *fd, Main *main)
}
}
- for (cont = ob->controllers.first; cont; cont = cont->next) {
+ for (bController *cont = ob->controllers.first; cont; cont = cont->next) {
for (a=0; a < cont->totlinks; a++)
cont->links[a] = newglobadr(fd, cont->links[a]);
@@ -4851,86 +4858,117 @@ static void lib_link_object(FileData *fd, Main *main)
cont->totslinks = 0;
}
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_SOUND) {
- bSoundActuator *sa = act->data;
- sa->sound= newlibadr_us(fd, ob->id.lib, sa->sound);
- }
- else if (act->type == ACT_GAME) {
- /* bGameActuator *ga= act->data; */
- }
- else if (act->type == ACT_CAMERA) {
- bCameraActuator *ca = act->data;
- ca->ob= newlibadr(fd, ob->id.lib, ca->ob);
- }
- /* leave this one, it's obsolete but necessary to read for conversion */
- else if (act->type == ACT_ADD_OBJECT) {
- bAddObjectActuator *eoa = act->data;
- if (eoa) eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob);
- }
- else if (act->type == ACT_OBJECT) {
- bObjectActuator *oa = act->data;
- if (oa == NULL) {
- init_actuator(act);
+ for (bActuator *act = ob->actuators.first; act; act = act->next) {
+ switch (act->type) {
+ case ACT_SOUND:
+ {
+ bSoundActuator *sa = act->data;
+ sa->sound = newlibadr_us(fd, ob->id.lib, sa->sound);
+ break;
}
- else {
- oa->reference = newlibadr(fd, ob->id.lib, oa->reference);
+ case ACT_GAME:
+ /* bGameActuator *ga= act->data; */
+ break;
+ case ACT_CAMERA:
+ {
+ bCameraActuator *ca = act->data;
+ ca->ob = newlibadr(fd, ob->id.lib, ca->ob);
+ break;
}
- }
- else if (act->type == ACT_EDIT_OBJECT) {
- bEditObjectActuator *eoa = act->data;
- if (eoa == NULL) {
- init_actuator(act);
+ /* leave this one, it's obsolete but necessary to read for conversion */
+ case ACT_ADD_OBJECT:
+ {
+ bAddObjectActuator *eoa = act->data;
+ if (eoa)
+ eoa->ob = newlibadr(fd, ob->id.lib, eoa->ob);
+ break;
}
- else {
- eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob);
- eoa->me= newlibadr(fd, ob->id.lib, eoa->me);
+ case ACT_OBJECT:
+ {
+ bObjectActuator *oa = act->data;
+ if (oa == NULL) {
+ init_actuator(act);
+ }
+ else {
+ oa->reference = newlibadr(fd, ob->id.lib, oa->reference);
+ }
+ break;
}
- }
- else if (act->type == ACT_SCENE) {
- bSceneActuator *sa = act->data;
- sa->camera= newlibadr(fd, ob->id.lib, sa->camera);
- sa->scene= newlibadr(fd, ob->id.lib, sa->scene);
- }
- else if (act->type == ACT_ACTION) {
- bActionActuator *aa = act->data;
- aa->act= newlibadr_us(fd, ob->id.lib, aa->act);
- }
- else if (act->type == ACT_SHAPEACTION) {
- bActionActuator *aa = act->data;
- aa->act= newlibadr_us(fd, ob->id.lib, aa->act);
- }
- else if (act->type == ACT_PROPERTY) {
- bPropertyActuator *pa = act->data;
- pa->ob= newlibadr(fd, ob->id.lib, pa->ob);
- }
- else if (act->type == ACT_MESSAGE) {
- bMessageActuator *ma = act->data;
- ma->toObject= newlibadr(fd, ob->id.lib, ma->toObject);
- }
- else if (act->type == ACT_2DFILTER) {
- bTwoDFilterActuator *_2dfa = act->data;
- _2dfa->text= newlibadr(fd, ob->id.lib, _2dfa->text);
- }
- else if (act->type == ACT_PARENT) {
- bParentActuator *parenta = act->data;
- parenta->ob = newlibadr(fd, ob->id.lib, parenta->ob);
- }
- else if (act->type == ACT_STATE) {
- /* bStateActuator *statea = act->data; */
- }
- else if (act->type == ACT_ARMATURE) {
- bArmatureActuator *arma= act->data;
- arma->target= newlibadr(fd, ob->id.lib, arma->target);
- arma->subtarget= newlibadr(fd, ob->id.lib, arma->subtarget);
- }
- else if (act->type == ACT_STEERING) {
- bSteeringActuator *steeringa = act->data;
- steeringa->target = newlibadr(fd, ob->id.lib, steeringa->target);
- steeringa->navmesh = newlibadr(fd, ob->id.lib, steeringa->navmesh);
- }
- else if (act->type == ACT_MOUSE) {
- /* bMouseActuator *moa= act->data; */
+ case ACT_EDIT_OBJECT:
+ {
+ bEditObjectActuator *eoa = act->data;
+ if (eoa == NULL) {
+ init_actuator(act);
+ }
+ else {
+ eoa->ob = newlibadr(fd, ob->id.lib, eoa->ob);
+ eoa->me = newlibadr(fd, ob->id.lib, eoa->me);
+ }
+ break;
+ }
+ case ACT_SCENE:
+ {
+ bSceneActuator *sa = act->data;
+ sa->camera = newlibadr(fd, ob->id.lib, sa->camera);
+ sa->scene = newlibadr(fd, ob->id.lib, sa->scene);
+ break;
+ }
+ case ACT_ACTION:
+ {
+ bActionActuator *aa = act->data;
+ aa->act = newlibadr_us(fd, ob->id.lib, aa->act);
+ break;
+ }
+ case ACT_SHAPEACTION:
+ {
+ bActionActuator *aa = act->data;
+ aa->act = newlibadr_us(fd, ob->id.lib, aa->act);
+ break;
+ }
+ case ACT_PROPERTY:
+ {
+ bPropertyActuator *pa = act->data;
+ pa->ob = newlibadr(fd, ob->id.lib, pa->ob);
+ break;
+ }
+ case ACT_MESSAGE:
+ {
+ bMessageActuator *ma = act->data;
+ ma->toObject = newlibadr(fd, ob->id.lib, ma->toObject);
+ break;
+ }
+ case ACT_2DFILTER:
+ {
+ bTwoDFilterActuator *_2dfa = act->data;
+ _2dfa->text = newlibadr(fd, ob->id.lib, _2dfa->text);
+ break;
+ }
+ case ACT_PARENT:
+ {
+ bParentActuator *parenta = act->data;
+ parenta->ob = newlibadr(fd, ob->id.lib, parenta->ob);
+ break;
+ }
+ case ACT_STATE:
+ /* bStateActuator *statea = act->data; */
+ break;
+ case ACT_ARMATURE:
+ {
+ bArmatureActuator *arma= act->data;
+ arma->target = newlibadr(fd, ob->id.lib, arma->target);
+ arma->subtarget = newlibadr(fd, ob->id.lib, arma->subtarget);
+ break;
+ }
+ case ACT_STEERING:
+ {
+ bSteeringActuator *steeringa = act->data;
+ steeringa->target = newlibadr(fd, ob->id.lib, steeringa->target);
+ steeringa->navmesh = newlibadr(fd, ob->id.lib, steeringa->navmesh);
+ break;
+ }
+ case ACT_MOUSE:
+ /* bMouseActuator *moa = act->data; */
+ break;
}
}
@@ -5662,23 +5700,16 @@ static bool scene_validate_setscene__liblink(Scene *sce, const int totscene)
static void lib_link_scene(FileData *fd, Main *main)
{
- Scene *sce;
- Base *base, *next;
- Sequence *seq;
- SceneRenderLayer *srl;
- FreestyleModuleConfig *fmc;
- FreestyleLineSet *fls;
-
#ifdef USE_SETSCENE_CHECK
bool need_check_set = false;
int totscene = 0;
#endif
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (Scene *sce = main->scene.first; sce; sce = sce->id.next) {
if (sce->id.tag & LIB_TAG_NEED_LINK) {
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(sce->id.properties, fd);
lib_link_animdata(fd, &sce->id, sce->adt);
lib_link_keyingsets(fd, &sce->id, &sce->keyingsets);
@@ -5714,7 +5745,7 @@ static void lib_link_scene(FileData *fd, Main *main)
sce->toolsettings->particle.shape_object = newlibadr(fd, sce->id.lib, sce->toolsettings->particle.shape_object);
- for (base = sce->base.first; base; base = next) {
+ for (Base *next, *base = sce->base.first; base; base = next) {
next = base->next;
base->object = newlibadr_us(fd, sce->id.lib, base->object);
@@ -5728,8 +5759,11 @@ static void lib_link_scene(FileData *fd, Main *main)
}
}
+ Sequence *seq;
SEQ_BEGIN (sce->ed, seq)
{
+ IDP_LibLinkProperty(seq->prop, fd);
+
if (seq->ipo) seq->ipo = newlibadr_us(fd, sce->id.lib, seq->ipo); // XXX deprecated - old animation system
seq->scene_sound = NULL;
if (seq->scene) {
@@ -5793,13 +5827,13 @@ static void lib_link_scene(FileData *fd, Main *main)
composite_patch(sce->nodetree, sce);
}
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
+ for (SceneRenderLayer *srl = sce->r.layers.first; srl; srl = srl->next) {
srl->mat_override = newlibadr_us(fd, sce->id.lib, srl->mat_override);
srl->light_override = newlibadr_us(fd, sce->id.lib, srl->light_override);
- for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
+ for (FreestyleModuleConfig *fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
fmc->script = newlibadr(fd, sce->id.lib, fmc->script);
}
- for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
+ for (FreestyleLineSet *fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
fls->linestyle = newlibadr_us(fd, sce->id.lib, fls->linestyle);
fls->group = newlibadr_us(fd, sce->id.lib, fls->group);
}
@@ -5833,7 +5867,7 @@ static void lib_link_scene(FileData *fd, Main *main)
#ifdef USE_SETSCENE_CHECK
if (need_check_set) {
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (Scene *sce = main->scene.first; sce; sce = sce->id.next) {
if (sce->id.tag & LIB_TAG_NEED_LINK) {
sce->id.tag &= ~LIB_TAG_NEED_LINK;
if (!scene_validate_setscene__liblink(sce, totscene)) {
@@ -6243,8 +6277,10 @@ static void lib_link_windowmanager(FileData *fd, Main *main)
for (wm = main->wm.first; wm; wm = wm->id.next) {
if (wm->id.tag & LIB_TAG_NEED_LINK) {
- for (win = wm->windows.first; win; win = win->next)
+ /* Note: WM IDProperties are never written to file, hence no need to read/link them here. */
+ for (win = wm->windows.first; win; win = win->next) {
win->screen = newlibadr(fd, NULL, win->screen);
+ }
wm->id.tag &= ~LIB_TAG_NEED_LINK;
}
@@ -6256,13 +6292,12 @@ static void lib_link_windowmanager(FileData *fd, Main *main)
/* relink's grease pencil data's refs */
static void lib_link_gpencil(FileData *fd, Main *main)
{
- bGPdata *gpd;
-
- for (gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
+ for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
if (gpd->id.tag & LIB_TAG_NEED_LINK) {
- gpd->id.tag &= ~LIB_TAG_NEED_LINK;
-
+ IDP_LibLinkProperty(gpd->id.properties, fd);
lib_link_animdata(fd, &gpd->id, gpd->adt);
+
+ gpd->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -6324,12 +6359,11 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
* check lib pointers in call below */
static void lib_link_screen(FileData *fd, Main *main)
{
- bScreen *sc;
- ScrArea *sa;
-
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (bScreen *sc = main->screen.first; sc; sc = sc->id.next) {
if (sc->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(sc->id.properties, fd);
id_us_ensure_real(&sc->id);
+
sc->scene = newlibadr(fd, sc->id.lib, sc->scene);
/* this should not happen, but apparently it does somehow. Until we figure out the cause,
@@ -6340,178 +6374,205 @@ static void lib_link_screen(FileData *fd, Main *main)
sc->animtimer = NULL; /* saved in rare cases */
sc->scrubbing = false;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
-
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
sa->full = newlibadr(fd, sc->id.lib, sa->full);
- for (sl = sa->spacedata.first; sl; sl= sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D*) sl;
- BGpic *bgpic = NULL;
-
- v3d->camera= newlibadr(fd, sc->id.lib, v3d->camera);
- v3d->ob_centre= newlibadr(fd, sc->id.lib, v3d->ob_centre);
-
- /* should be do_versions but not easy adding into the listbase */
- if (v3d->bgpic) {
- v3d->bgpic = newlibadr(fd, sc->id.lib, v3d->bgpic);
- BLI_addtail(&v3d->bgpicbase, bgpic);
- v3d->bgpic = NULL;
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl= sl->next) {
+ switch (sl->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d = (View3D*) sl;
+ BGpic *bgpic = NULL;
+
+ v3d->camera= newlibadr(fd, sc->id.lib, v3d->camera);
+ v3d->ob_centre= newlibadr(fd, sc->id.lib, v3d->ob_centre);
+
+ /* should be do_versions but not easy adding into the listbase */
+ if (v3d->bgpic) {
+ v3d->bgpic = newlibadr(fd, sc->id.lib, v3d->bgpic);
+ BLI_addtail(&v3d->bgpicbase, bgpic);
+ v3d->bgpic = NULL;
+ }
+
+ for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
+ bgpic->ima = newlibadr_us(fd, sc->id.lib, bgpic->ima);
+ bgpic->clip = newlibadr_us(fd, sc->id.lib, bgpic->clip);
+ }
+ if (v3d->localvd) {
+ v3d->localvd->camera = newlibadr(fd, sc->id.lib, v3d->localvd->camera);
+ }
+ break;
}
-
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- bgpic->ima = newlibadr_us(fd, sc->id.lib, bgpic->ima);
- bgpic->clip = newlibadr_us(fd, sc->id.lib, bgpic->clip);
+ case SPACE_IPO:
+ {
+ SpaceIpo *sipo = (SpaceIpo *)sl;
+ bDopeSheet *ads = sipo->ads;
+
+ if (ads) {
+ ads->source = newlibadr(fd, sc->id.lib, ads->source);
+ ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
+ }
+ break;
}
- if (v3d->localvd) {
- v3d->localvd->camera = newlibadr(fd, sc->id.lib, v3d->localvd->camera);
+ case SPACE_BUTS:
+ {
+ SpaceButs *sbuts = (SpaceButs *)sl;
+ sbuts->pinid = newlibadr(fd, sc->id.lib, sbuts->pinid);
+ if (sbuts->pinid == NULL) {
+ sbuts->flag &= ~SB_PIN_CONTEXT;
+ }
+ break;
}
- }
- else if (sl->spacetype == SPACE_IPO) {
- SpaceIpo *sipo = (SpaceIpo *)sl;
- bDopeSheet *ads = sipo->ads;
-
- if (ads) {
- ads->source = newlibadr(fd, sc->id.lib, ads->source);
- ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
+ case SPACE_FILE:
+ break;
+ case SPACE_ACTION:
+ {
+ SpaceAction *saction = (SpaceAction *)sl;
+ bDopeSheet *ads = &saction->ads;
+
+ if (ads) {
+ ads->source = newlibadr(fd, sc->id.lib, ads->source);
+ ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
+ }
+
+ saction->action = newlibadr(fd, sc->id.lib, saction->action);
+ break;
}
- }
- else if (sl->spacetype == SPACE_BUTS) {
- SpaceButs *sbuts = (SpaceButs *)sl;
- sbuts->pinid = newlibadr(fd, sc->id.lib, sbuts->pinid);
- if (sbuts->pinid == NULL) {
- sbuts->flag &= ~SB_PIN_CONTEXT;
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ sima->image = newlibadr_real_us(fd, sc->id.lib, sima->image);
+ sima->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sima->mask_info.mask);
+
+ /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
+ * so fingers crossed this works fine!
+ */
+ sima->gpd = newlibadr_us(fd, sc->id.lib, sima->gpd);
+ break;
}
- }
- else if (sl->spacetype == SPACE_FILE) {
- ;
- }
- else if (sl->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)sl;
- bDopeSheet *ads = &saction->ads;
-
- if (ads) {
- ads->source = newlibadr(fd, sc->id.lib, ads->source);
- ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+
+ /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
+ * so fingers crossed this works fine!
+ */
+ sseq->gpd = newlibadr_us(fd, sc->id.lib, sseq->gpd);
+ break;
}
-
- saction->action = newlibadr(fd, sc->id.lib, saction->action);
- }
- else if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)sl;
-
- sima->image = newlibadr_real_us(fd, sc->id.lib, sima->image);
- sima->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sima->mask_info.mask);
-
- /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
- * so fingers crossed this works fine!
- */
- sima->gpd = newlibadr_us(fd, sc->id.lib, sima->gpd);
- }
- else if (sl->spacetype == SPACE_SEQ) {
- SpaceSeq *sseq = (SpaceSeq *)sl;
-
- /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
- * so fingers crossed this works fine!
- */
- sseq->gpd = newlibadr_us(fd, sc->id.lib, sseq->gpd);
+ case SPACE_NLA:
+ {
+ SpaceNla *snla= (SpaceNla *)sl;
+ bDopeSheet *ads= snla->ads;
+
+ if (ads) {
+ ads->source = newlibadr(fd, sc->id.lib, ads->source);
+ ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
+ }
+ break;
+ }
+ case SPACE_TEXT:
+ {
+ SpaceText *st= (SpaceText *)sl;
- }
- else if (sl->spacetype == SPACE_NLA) {
- SpaceNla *snla= (SpaceNla *)sl;
- bDopeSheet *ads= snla->ads;
-
- if (ads) {
- ads->source = newlibadr(fd, sc->id.lib, ads->source);
- ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
+ st->text= newlibadr(fd, sc->id.lib, st->text);
+ break;
}
- }
- else if (sl->spacetype == SPACE_TEXT) {
- SpaceText *st= (SpaceText *)sl;
-
- st->text= newlibadr(fd, sc->id.lib, st->text);
- }
- else if (sl->spacetype == SPACE_SCRIPT) {
- SpaceScript *scpt = (SpaceScript *)sl;
- /*scpt->script = NULL; - 2.45 set to null, better re-run the script */
- if (scpt->script) {
- scpt->script = newlibadr(fd, sc->id.lib, scpt->script);
+ case SPACE_SCRIPT:
+ {
+ SpaceScript *scpt = (SpaceScript *)sl;
+ /*scpt->script = NULL; - 2.45 set to null, better re-run the script */
if (scpt->script) {
- SCRIPT_SET_NULL(scpt->script);
+ scpt->script = newlibadr(fd, sc->id.lib, scpt->script);
+ if (scpt->script) {
+ SCRIPT_SET_NULL(scpt->script);
+ }
}
+ break;
}
- }
- else if (sl->spacetype == SPACE_OUTLINER) {
- SpaceOops *so= (SpaceOops *)sl;
- so->search_tse.id = newlibadr(fd, NULL, so->search_tse.id);
-
- if (so->treestore) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
+ case SPACE_OUTLINER:
+ {
+ SpaceOops *so= (SpaceOops *)sl;
+ so->search_tse.id = newlibadr(fd, NULL, so->search_tse.id);
+
+ if (so->treestore) {
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+
+ BLI_mempool_iternew(so->treestore, &iter);
+ while ((tselem = BLI_mempool_iterstep(&iter))) {
+ tselem->id = newlibadr(fd, NULL, tselem->id);
+ }
+ if (so->treehash) {
+ /* rebuild hash table, because it depends on ids too */
+ so->storeflag |= SO_TREESTORE_REBUILD;
+ }
+ }
+ break;
+ }
+ case SPACE_NODE:
+ {
+ SpaceNode *snode = (SpaceNode *)sl;
+ bNodeTreePath *path, *path_next;
+ bNodeTree *ntree;
+
+ /* node tree can be stored locally in id too, link this first */
+ snode->id = newlibadr(fd, sc->id.lib, snode->id);
+ snode->from = newlibadr(fd, sc->id.lib, snode->from);
+
+ ntree = snode->id ? ntreeFromID(snode->id) : NULL;
+ snode->nodetree = ntree ? ntree : newlibadr_us(fd, sc->id.lib, snode->nodetree);
+
+ for (path = snode->treepath.first; path; path = path->next) {
+ if (path == snode->treepath.first) {
+ /* first nodetree in path is same as snode->nodetree */
+ path->nodetree = snode->nodetree;
+ }
+ else
+ path->nodetree = newlibadr_us(fd, sc->id.lib, path->nodetree);
- BLI_mempool_iternew(so->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- tselem->id = newlibadr(fd, NULL, tselem->id);
+ if (!path->nodetree)
+ break;
}
- if (so->treehash) {
- /* rebuild hash table, because it depends on ids too */
- so->storeflag |= SO_TREESTORE_REBUILD;
+
+ /* remaining path entries are invalid, remove */
+ for (; path; path = path_next) {
+ path_next = path->next;
+
+ BLI_remlink(&snode->treepath, path);
+ MEM_freeN(path);
}
- }
- }
- else if (sl->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)sl;
- bNodeTreePath *path, *path_next;
- bNodeTree *ntree;
-
- /* node tree can be stored locally in id too, link this first */
- snode->id = newlibadr(fd, sc->id.lib, snode->id);
- snode->from = newlibadr(fd, sc->id.lib, snode->from);
-
- ntree = snode->id ? ntreeFromID(snode->id) : NULL;
- snode->nodetree = ntree ? ntree : newlibadr_us(fd, sc->id.lib, snode->nodetree);
-
- for (path = snode->treepath.first; path; path = path->next) {
- if (path == snode->treepath.first) {
- /* first nodetree in path is same as snode->nodetree */
- path->nodetree = snode->nodetree;
+
+ /* edittree is just the last in the path,
+ * set this directly since the path may have been shortened above */
+ if (snode->treepath.last) {
+ path = snode->treepath.last;
+ snode->edittree = path->nodetree;
}
- else
- path->nodetree = newlibadr_us(fd, sc->id.lib, path->nodetree);
-
- if (!path->nodetree)
- break;
+ else {
+ snode->edittree = NULL;
+ }
+ break;
}
-
- /* remaining path entries are invalid, remove */
- for (; path; path = path_next) {
- path_next = path->next;
-
- BLI_remlink(&snode->treepath, path);
- MEM_freeN(path);
+ case SPACE_CLIP:
+ {
+ SpaceClip *sclip = (SpaceClip *)sl;
+
+ sclip->clip = newlibadr_real_us(fd, sc->id.lib, sclip->clip);
+ sclip->secondary_clip = newlibadr_real_us(fd, sc->id.lib, sclip->secondary_clip);
+ sclip->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sclip->mask_info.mask);
+ break;
}
-
- /* edittree is just the last in the path,
- * set this directly since the path may have been shortened above */
- if (snode->treepath.last) {
- path = snode->treepath.last;
- snode->edittree = path->nodetree;
+ case SPACE_LOGIC:
+ {
+ SpaceLogic *slogic = (SpaceLogic *)sl;
+
+ slogic->gpd = newlibadr_us(fd, sc->id.lib, slogic->gpd);
+ break;
}
- else
- snode->edittree = NULL;
- }
- else if (sl->spacetype == SPACE_CLIP) {
- SpaceClip *sclip = (SpaceClip *)sl;
-
- sclip->clip = newlibadr_real_us(fd, sc->id.lib, sclip->clip);
- sclip->secondary_clip = newlibadr_real_us(fd, sc->id.lib, sclip->secondary_clip);
- sclip->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sclip->mask_info.mask);
- }
- else if (sl->spacetype == SPACE_LOGIC) {
- SpaceLogic *slogic = (SpaceLogic *)sl;
-
- slogic->gpd = newlibadr_us(fd, sc->id.lib, slogic->gpd);
+ default:
+ break;
}
}
}
@@ -7386,13 +7447,13 @@ static void fix_relpaths_library(const char *basepath, Main *main)
static void lib_link_speaker(FileData *fd, Main *main)
{
- Speaker *spk;
-
- for (spk = main->speaker.first; spk; spk = spk->id.next) {
+ for (Speaker *spk = main->speaker.first; spk; spk = spk->id.next) {
if (spk->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(spk->id.properties, fd);
lib_link_animdata(fd, &spk->id, spk->adt);
spk->sound = newlibadr_us(fd, spk->id.lib, spk->sound);
+
spk->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -7442,14 +7503,15 @@ static void direct_link_sound(FileData *fd, bSound *sound)
static void lib_link_sound(FileData *fd, Main *main)
{
- bSound *sound;
-
- for (sound = main->sound.first; sound; sound = sound->id.next) {
+ for (bSound *sound = main->sound.first; sound; sound = sound->id.next) {
if (sound->id.tag & LIB_TAG_NEED_LINK) {
- sound->id.tag &= ~LIB_TAG_NEED_LINK;
+ IDP_LibLinkProperty(sound->id.properties, fd);
+
sound->ipo = newlibadr_us(fd, sound->id.lib, sound->ipo); // XXX deprecated - old animation system
BKE_sound_load(main, sound);
+
+ sound->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -7464,17 +7526,13 @@ static void direct_link_group(FileData *fd, Group *group)
static void lib_link_group(FileData *fd, Main *main)
{
- Group *group;
- GroupObject *go;
- bool add_us;
-
- for (group = main->group.first; group; group = group->id.next) {
+ for (Group *group = main->group.first; group; group = group->id.next) {
if (group->id.tag & LIB_TAG_NEED_LINK) {
- group->id.tag &= ~LIB_TAG_NEED_LINK;
+ IDP_LibLinkProperty(group->id.properties, fd);
- add_us = false;
+ bool add_us = false;
- for (go = group->gobject.first; go; go = go->next) {
+ for (GroupObject *go = group->gobject.first; go; go = go->next) {
go->ob = newlibadr_real_us(fd, group->id.lib, go->ob);
if (go->ob) {
go->ob->flag |= OB_FROMGROUP;
@@ -7486,6 +7544,8 @@ static void lib_link_group(FileData *fd, Main *main)
id_us_ensure_real(&group->id);
}
BKE_group_object_unlink(group, NULL, NULL, NULL); /* removes NULL entries */
+
+ group->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -7608,13 +7668,11 @@ static void lib_link_movieCorrespondences(FileData *fd,
static void lib_link_movieclip(FileData *fd, Main *main)
{
- MovieClip *clip;
-
- for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ for (MovieClip *clip = main->movieclip.first; clip; clip = clip->id.next) {
if (clip->id.tag & LIB_TAG_NEED_LINK) {
MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
+ IDP_LibLinkProperty(clip->id.properties, fd);
lib_link_animdata(fd, &clip->id, clip->adt);
clip->gpd = newlibadr_us(fd, clip->id.lib, clip->gpd);
@@ -7623,7 +7681,7 @@ static void lib_link_movieclip(FileData *fd, Main *main)
lib_link_moviePlaneTracks(fd, clip, &tracking->plane_tracks);
lib_link_movieCorrespondences(fd, clip, &tracking->correspondences);
- for (object = tracking->objects.first; object; object = object->next) {
+ for (MovieTrackingObject *object = tracking->objects.first; object; object = object->next) {
lib_link_movieTracks(fd, clip, &object->tracks);
lib_link_moviePlaneTracks(fd, clip, &object->plane_tracks);
}
@@ -7700,16 +7758,12 @@ static void lib_link_mask_parent(FileData *fd, Mask *mask, MaskParent *parent)
static void lib_link_mask(FileData *fd, Main *main)
{
- Mask *mask;
-
- mask = main->mask.first;
- while (mask) {
+ for (Mask *mask = main->mask.first; mask; mask = mask->id.next) {
if (mask->id.tag & LIB_TAG_NEED_LINK) {
- MaskLayer *masklay;
-
+ IDP_LibLinkProperty(mask->id.properties, fd);
lib_link_animdata(fd, &mask->id, mask->adt);
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ for (MaskLayer *masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
MaskSpline *spline;
spline = masklay->splines.first;
@@ -7730,7 +7784,6 @@ static void lib_link_mask(FileData *fd, Main *main)
mask->id.tag &= ~LIB_TAG_NEED_LINK;
}
- mask = mask->id.next;
}
}
@@ -7738,18 +7791,13 @@ static void lib_link_mask(FileData *fd, Main *main)
static void lib_link_linestyle(FileData *fd, Main *main)
{
- FreestyleLineStyle *linestyle;
- LineStyleModifier *m;
- MTex *mtex;
- int a;
-
- linestyle = main->linestyle.first;
- while (linestyle) {
+ for (FreestyleLineStyle *linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) {
if (linestyle->id.tag & LIB_TAG_NEED_LINK) {
- linestyle->id.tag &= ~LIB_TAG_NEED_LINK;
+ LineStyleModifier *m;
- IDP_LibLinkProperty(linestyle->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(linestyle->id.properties, fd);
lib_link_animdata(fd, &linestyle->id, linestyle->adt);
+
for (m = linestyle->color_modifiers.first; m; m = m->next) {
switch (m->type) {
case LS_MODIFIER_DISTANCE_FROM_OBJECT:
@@ -7780,8 +7828,8 @@ static void lib_link_linestyle(FileData *fd, Main *main)
break;
}
}
- for (a=0; a < MAX_MTEX; a++) {
- mtex = linestyle->mtex[a];
+ for (int a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex = linestyle->mtex[a];
if (mtex) {
mtex->tex = newlibadr_us(fd, linestyle->id.lib, mtex->tex);
mtex->object = newlibadr(fd, linestyle->id.lib, mtex->object);
@@ -7791,8 +7839,9 @@ static void lib_link_linestyle(FileData *fd, Main *main)
lib_link_ntree(fd, &linestyle->id, linestyle->nodetree);
linestyle->nodetree->id.lib = linestyle->id.lib;
}
+
+ linestyle->id.tag &= ~LIB_TAG_NEED_LINK;
}
- linestyle = linestyle->id.next;
}
}
@@ -8463,12 +8512,13 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_screen(fd, main);
lib_link_scene(fd, main);
lib_link_object(fd, main);
+ lib_link_mesh(fd, main);
lib_link_curve(fd, main);
lib_link_mball(fd, main);
lib_link_material(fd, main);
lib_link_texture(fd, main);
lib_link_image(fd, main);
- lib_link_ipo(fd, main); // XXX deprecated... still needs to be maintained for version patches still
+ lib_link_ipo(fd, main); /* XXX deprecated... still needs to be maintained for version patches still */
lib_link_key(fd, main);
lib_link_world(fd, main);
lib_link_lamp(fd, main);
@@ -8481,7 +8531,7 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_armature(fd, main);
lib_link_action(fd, main);
lib_link_vfont(fd, main);
- lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */
+ lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */
lib_link_brush(fd, main);
lib_link_palette(fd, main);
lib_link_paint_curve(fd, main);
@@ -8492,9 +8542,7 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_gpencil(fd, main);
lib_link_cachefiles(fd, main);
- lib_link_mesh(fd, main); /* as last: tpage images with users at zero */
-
- lib_link_library(fd, main); /* only init users */
+ lib_link_library(fd, main); /* only init users */
}
static void direct_link_keymapitem(FileData *fd, wmKeyMapItem *kmi)
@@ -8914,6 +8962,31 @@ static void expand_constraint_channels(FileData *fd, Main *mainvar, ListBase *ch
}
}
+static void expand_idprops(FileData *fd, Main *mainvar, IDProperty *prop)
+{
+ if (!prop)
+ return;
+
+ switch (prop->type) {
+ case IDP_ID:
+ expand_doit(fd, mainvar, IDP_Id(prop));
+ break;
+ case IDP_IDPARRAY:
+ {
+ IDProperty *idp_array = IDP_IDPArray(prop);
+ for (int i = 0; i < prop->len; i++) {
+ expand_idprops(fd, mainvar, &idp_array[i]);
+ }
+ break;
+ }
+ case IDP_GROUP:
+ for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ expand_idprops(fd, mainvar, loop);
+ }
+ break;
+ }
+}
+
static void expand_fmodifiers(FileData *fd, Main *mainvar, ListBase *list)
{
FModifier *fcm;
@@ -9099,6 +9172,7 @@ static void expand_key(FileData *fd, Main *mainvar, Key *key)
static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
{
bNode *node;
+ bNodeSocket *sock;
if (ntree->adt)
expand_animdata(fd, mainvar, ntree->adt);
@@ -9107,10 +9181,22 @@ static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
expand_doit(fd, mainvar, ntree->gpd);
for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id && node->type != CMP_NODE_R_LAYERS)
+ if (node->id && node->type != CMP_NODE_R_LAYERS) {
expand_doit(fd, mainvar, node->id);
+ }
+
+ expand_idprops(fd, mainvar, node->prop);
+
+ for (sock = node->inputs.first; sock; sock = sock->next)
+ expand_doit(fd, mainvar, sock->prop);
+ for (sock = node->outputs.first; sock; sock = sock->next)
+ expand_doit(fd, mainvar, sock->prop);
}
+ for (sock = ntree->inputs.first; sock; sock = sock->next)
+ expand_doit(fd, mainvar, sock->prop);
+ for (sock = ntree->outputs.first; sock; sock = sock->next)
+ expand_doit(fd, mainvar, sock->prop);
}
static void expand_texture(FileData *fd, Main *mainvar, Tex *tex)
@@ -9328,17 +9414,6 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb)
}
}
-#if 0 /* Disabled as it doesn't actually do anything except recurse... */
-static void expand_bones(FileData *fd, Main *mainvar, Bone *bone)
-{
- Bone *curBone;
-
- for (curBone = bone->childbase.first; curBone; curBone=curBone->next) {
- expand_bones(fd, mainvar, curBone);
- }
-}
-#endif
-
static void expand_pose(FileData *fd, Main *mainvar, bPose *pose)
{
bPoseChannel *chan;
@@ -9348,24 +9423,28 @@ static void expand_pose(FileData *fd, Main *mainvar, bPose *pose)
for (chan = pose->chanbase.first; chan; chan = chan->next) {
expand_constraints(fd, mainvar, &chan->constraints);
+ expand_idprops(fd, mainvar, chan->prop);
expand_doit(fd, mainvar, chan->custom);
}
}
+static void expand_bones(FileData *fd, Main *mainvar, Bone *bone)
+{
+ expand_idprops(fd, mainvar, bone->prop);
+
+ for (Bone *curBone = bone->childbase.first; curBone; curBone = curBone->next) {
+ expand_bones(fd, mainvar, curBone);
+ }
+}
+
static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm)
-{
+{
if (arm->adt)
expand_animdata(fd, mainvar, arm->adt);
-
-#if 0 /* Disabled as this currently only recurses down the chain doing nothing */
- {
- Bone *curBone;
-
- for (curBone = arm->bonebase.first; curBone; curBone=curBone->next) {
- expand_bones(fd, mainvar, curBone);
- }
+
+ for (Bone *curBone = arm->bonebase.first; curBone; curBone = curBone->next) {
+ expand_bones(fd, mainvar, curBone);
}
-#endif
}
static void expand_object_expandModifiers(
@@ -9593,6 +9672,8 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
SEQ_BEGIN (sce->ed, seq)
{
+ expand_idprops(fd, mainvar, seq->prop);
+
if (seq->scene) expand_doit(fd, mainvar, seq->scene);
if (seq->scene_camera) expand_doit(fd, mainvar, seq->scene_camera);
if (seq->clip) expand_doit(fd, mainvar, seq->clip);
@@ -9750,6 +9831,8 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
id = lbarray[a]->first;
while (id) {
if (id->tag & LIB_TAG_NEED_EXPAND) {
+ expand_idprops(fd, mainvar, id->properties);
+
switch (GS(id->name)) {
case ID_OB:
expand_object(fd, mainvar, (Object *)id);
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 99d9e140481..e34f12b1cf9 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -68,6 +68,18 @@ void BLO_update_defaults_userpref_blend(void)
* but take care since some hardware has driver bugs here (T46962).
* Further hardware workarounds should be made in gpu_extensions.c */
U.glalphaclip = (1.0f / 255);
+
+ /* default so DPI is detected automatically */
+ U.dpi = 0;
+ U.ui_scale = 1.0f;
+
+#ifdef WITH_PYTHON_SECURITY
+ /* use alternative setting for security nuts
+ * otherwise we'd need to patch the binary blob - startup.blend.c */
+ U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
+#else
+ U.flag &= ~USER_SCRIPT_AUTOEXEC_DISABLE;
+#endif
}
/**
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index cee5450a37d..4fe14fdf5c9 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -2403,15 +2403,20 @@ static void bmesh_kernel_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separ
do {
LinkNode *n_orig = edges_separate->link;
do {
- BMEdge *e_orig = n_orig->link;
+ LinkNode *n_prev = n_orig;
LinkNode *n_step = n_orig->next;
+ BMEdge *e_orig = n_orig->link;
do {
BMEdge *e = n_step->link;
BLI_assert(e != e_orig);
- if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2)) {
- BM_edge_splice(bm, e_orig, e);
+ if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2) &&
+ BM_edge_splice(bm, e_orig, e))
+ {
+ /* don't visit again */
+ n_prev->next = n_step->next;
}
- } while ((n_step = n_step->next));
+ } while ((n_prev = n_step),
+ (n_step = n_step->next));
} while ((n_orig = n_orig->next) && n_orig->next);
} while ((edges_separate = edges_separate->next));
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index d92d0cbb469..e9fb6a28154 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -1512,23 +1512,6 @@ int BM_mesh_elem_count(BMesh *bm, const char htype)
}
}
-/**
- * Special case: Python uses custom-data layers to hold PyObject references.
- * These have to be kept in-place, else the PyObject's we point to, wont point back to us.
- *
- * \note ``ele_src`` Is a duplicate, so we don't need to worry about getting in a feedback loop.
- *
- * \note If there are other customdata layers which need this functionality, it should be generalized.
- * However #BM_mesh_remap is currently the only place where this is done.
- */
-static void bm_mesh_remap_cd_update(
- BMHeader *ele_dst, BMHeader *ele_src,
- const int cd_elem_pyptr)
-{
- void **pyptr_dst_p = BM_ELEM_CD_GET_VOID_P(((BMElem *)ele_dst), cd_elem_pyptr);
- void **pyptr_src_p = BM_ELEM_CD_GET_VOID_P(((BMElem *)ele_src), cd_elem_pyptr);
- *pyptr_dst_p = *pyptr_src_p;
-}
/**
* Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays
@@ -1570,6 +1553,8 @@ void BM_mesh_remap(
BMVert **verts_pool, *verts_copy, **vep;
int i, totvert = bm->totvert;
const unsigned int *new_idx;
+ /* Special case: Python uses custom - data layers to hold PyObject references.
+ * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */
const int cd_vert_pyptr = CustomData_get_offset(&bm->vdata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
@@ -1578,9 +1563,14 @@ void BM_mesh_remap(
/* Make a copy of all vertices. */
verts_pool = bm->vtable;
verts_copy = MEM_mallocN(sizeof(BMVert) * totvert, "BM_mesh_remap verts copy");
+ void **pyptrs = (cd_vert_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totvert, __func__) : NULL;
for (i = totvert, ve = verts_copy + totvert - 1, vep = verts_pool + totvert - 1; i--; ve--, vep--) {
*ve = **vep;
/* printf("*vep: %p, verts_pool[%d]: %p\n", *vep, i, verts_pool[i]);*/
+ if (cd_vert_pyptr != -1) {
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)ve), cd_vert_pyptr);
+ pyptrs[i] = *pyptr;
+ }
}
/* Copy back verts to their new place, and update old2new pointers mapping. */
@@ -1593,13 +1583,17 @@ void BM_mesh_remap(
/* printf("mapping vert from %d to %d (%p/%p to %p)\n", i, *new_idx, *vep, verts_pool[i], new_vep);*/
BLI_ghash_insert(vptr_map, *vep, new_vep);
if (cd_vert_pyptr != -1) {
- bm_mesh_remap_cd_update(&(*vep)->head, &new_vep->head, cd_vert_pyptr);
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_vep), cd_vert_pyptr);
+ *pyptr = pyptrs[*new_idx];
}
}
bm->elem_index_dirty |= BM_VERT;
bm->elem_table_dirty |= BM_VERT;
MEM_freeN(verts_copy);
+ if (pyptrs) {
+ MEM_freeN(pyptrs);
+ }
}
/* Remap Edges */
@@ -1607,6 +1601,8 @@ void BM_mesh_remap(
BMEdge **edges_pool, *edges_copy, **edp;
int i, totedge = bm->totedge;
const unsigned int *new_idx;
+ /* Special case: Python uses custom - data layers to hold PyObject references.
+ * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */
const int cd_edge_pyptr = CustomData_get_offset(&bm->edata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
@@ -1615,8 +1611,13 @@ void BM_mesh_remap(
/* Make a copy of all vertices. */
edges_pool = bm->etable;
edges_copy = MEM_mallocN(sizeof(BMEdge) * totedge, "BM_mesh_remap edges copy");
+ void **pyptrs = (cd_edge_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totedge, __func__) : NULL;
for (i = totedge, ed = edges_copy + totedge - 1, edp = edges_pool + totedge - 1; i--; ed--, edp--) {
*ed = **edp;
+ if (cd_edge_pyptr != -1) {
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)ed), cd_edge_pyptr);
+ pyptrs[i] = *pyptr;
+ }
}
/* Copy back verts to their new place, and update old2new pointers mapping. */
@@ -1629,13 +1630,17 @@ void BM_mesh_remap(
BLI_ghash_insert(eptr_map, *edp, new_edp);
/* printf("mapping edge from %d to %d (%p/%p to %p)\n", i, *new_idx, *edp, edges_pool[i], new_edp);*/
if (cd_edge_pyptr != -1) {
- bm_mesh_remap_cd_update(&(*edp)->head, &new_edp->head, cd_edge_pyptr);
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_edp), cd_edge_pyptr);
+ *pyptr = pyptrs[*new_idx];
}
}
bm->elem_index_dirty |= BM_EDGE;
bm->elem_table_dirty |= BM_EDGE;
MEM_freeN(edges_copy);
+ if (pyptrs) {
+ MEM_freeN(pyptrs);
+ }
}
/* Remap Faces */
@@ -1643,6 +1648,8 @@ void BM_mesh_remap(
BMFace **faces_pool, *faces_copy, **fap;
int i, totface = bm->totface;
const unsigned int *new_idx;
+ /* Special case: Python uses custom - data layers to hold PyObject references.
+ * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */
const int cd_poly_pyptr = CustomData_get_offset(&bm->pdata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
@@ -1651,8 +1658,13 @@ void BM_mesh_remap(
/* Make a copy of all vertices. */
faces_pool = bm->ftable;
faces_copy = MEM_mallocN(sizeof(BMFace) * totface, "BM_mesh_remap faces copy");
+ void **pyptrs = (cd_poly_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totface, __func__) : NULL;
for (i = totface, fa = faces_copy + totface - 1, fap = faces_pool + totface - 1; i--; fa--, fap--) {
*fa = **fap;
+ if (cd_poly_pyptr != -1) {
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)fa), cd_poly_pyptr);
+ pyptrs[i] = *pyptr;
+ }
}
/* Copy back verts to their new place, and update old2new pointers mapping. */
@@ -1664,7 +1676,8 @@ void BM_mesh_remap(
*new_fap = *fa;
BLI_ghash_insert(fptr_map, *fap, new_fap);
if (cd_poly_pyptr != -1) {
- bm_mesh_remap_cd_update(&(*fap)->head, &new_fap->head, cd_poly_pyptr);
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_fap), cd_poly_pyptr);
+ *pyptr = pyptrs[*new_idx];
}
}
@@ -1672,6 +1685,9 @@ void BM_mesh_remap(
bm->elem_table_dirty |= BM_FACE;
MEM_freeN(faces_copy);
+ if (pyptrs) {
+ MEM_freeN(pyptrs);
+ }
}
/* And now, fix all vertices/edges/faces/loops pointers! */
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index 723e0b168e0..e5c3ff7a088 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -1566,7 +1566,7 @@ void BM_mesh_calc_uvs_cone(
BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for ensuring the mesh has UVs */
- x = 0.0f;
+ x = 1.0f;
y = 1.0f - uv_height;
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
@@ -1580,7 +1580,7 @@ void BM_mesh_calc_uvs_cone(
switch (loop_index) {
case 0:
- x += uv_width;
+ /* Continue in the last position */
break;
case 1:
y += uv_height;
@@ -1598,8 +1598,6 @@ void BM_mesh_calc_uvs_cone(
luv->uv[0] = x;
luv->uv[1] = y;
}
-
- x += uv_width;
}
else {
/* top or bottom face - so unwrap it by transforming back to a circle and using the X/Y coords */
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index 3801c9300df..bd47ee0214d 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -1934,7 +1934,7 @@ Object *AnimationImporter::get_joint_object(COLLADAFW::Node *root, COLLADAFW::No
mul_m4_m4m4(mat, ipar, temp);
}
- TransformBase::decompose(mat, job->loc, NULL, job->quat, job->size);
+ bc_decompose(mat, job->loc, NULL, job->quat, job->size);
if (par_job) {
job->parent = par_job;
diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp
index 40065956ecb..9348f3b3285 100644
--- a/source/blender/collada/ArmatureExporter.cpp
+++ b/source/blender/collada/ArmatureExporter.cpp
@@ -256,47 +256,59 @@ void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW:
//bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
float mat[4][4];
+ float bone_rest_mat[4][4]; /* derived from bone->arm_mat */
+ float parent_rest_mat[4][4]; /* derived from bone->parent->arm_mat */
- if (bone->parent) {
- // get bone-space matrix from parent pose
- /*bPoseChannel *parchan = BKE_pose_channel_find_name(ob_arm->pose, bone->parent->name);
- float invpar[4][4];
- invert_m4_m4(invpar, parchan->pose_mat);
- mul_m4_m4m4(mat, invpar, pchan->pose_mat);*/
-
- float invpar[4][4];
- invert_m4_m4(invpar, bone->parent->arm_mat);
- mul_m4_m4m4(mat, invpar, bone->arm_mat);
+ bool has_restmat = bc_get_property_matrix(bone, "rest_mat", mat);
- }
- else {
+ if (!has_restmat) {
+
+ /* Have no restpose matrix stored, try old style <= Blender 2.78 */
- //copy_m4_m4(mat, pchan->pose_mat);
- //pose mat is object space
- //New change: export bone->arm_mat
- copy_m4_m4(mat, bone->arm_mat);
- }
+ bc_create_restpose_mat(this->export_settings, bone, bone_rest_mat, bone->arm_mat, true);
- // OPEN_SIM_COMPATIBILITY
- if (export_settings->open_sim) {
- // Remove rotations vs armature from transform
- // parent_rest_rot * mat * irest_rot
- float temp[4][4];
- copy_m4_m4(temp, bone->arm_mat);
- temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
- invert_m4(temp);
+ if (bone->parent) {
+ // get bone-space matrix from parent pose
+ /*bPoseChannel *parchan = BKE_pose_channel_find_name(ob_arm->pose, bone->parent->name);
+ float invpar[4][4];
+ invert_m4_m4(invpar, parchan->pose_mat);
+ mul_m4_m4m4(mat, invpar, pchan->pose_mat);*/
+ float invpar[4][4];
+ bc_create_restpose_mat(this->export_settings, bone->parent, parent_rest_mat, bone->parent->arm_mat, true);
- mul_m4_m4m4(mat, mat, temp);
+ invert_m4_m4(invpar, parent_rest_mat);
+ mul_m4_m4m4(mat, invpar, bone_rest_mat);
- if (bone->parent) {
- copy_m4_m4(temp, bone->parent->arm_mat);
+ }
+ else {
+ copy_m4_m4(mat, bone_rest_mat);
+ }
+
+ // OPEN_SIM_COMPATIBILITY
+ if (export_settings->open_sim) {
+ // Remove rotations vs armature from transform
+ // parent_rest_rot * mat * irest_rot
+ float temp[4][4];
+ copy_m4_m4(temp, bone_rest_mat);
temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
+ invert_m4(temp);
+
+ mul_m4_m4m4(mat, mat, temp);
+
+ if (bone->parent) {
+ copy_m4_m4(temp, parent_rest_mat);
+ temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
- mul_m4_m4m4(mat, temp, mat);
+ mul_m4_m4m4(mat, temp, mat);
+ }
}
}
+ if (this->export_settings->limit_precision)
+ bc_sanitize_mat(mat, 6);
+
TransformWriter::add_node_transform(node, mat, NULL);
+
}
std::string ArmatureExporter::get_controller_id(Object *ob_arm, Object *ob)
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index f4ce3992771..0ea8324ed7c 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -32,6 +32,7 @@
#include "COLLADAFWUniqueId.h"
+extern "C" {
#include "BKE_action.h"
#include "BKE_depsgraph.h"
#include "BKE_object.h"
@@ -39,7 +40,9 @@
#include "BLI_string.h"
#include "BLI_listbase.h"
#include "ED_armature.h"
+}
+#include "collada_utils.h"
#include "ArmatureImporter.h"
// use node name, or fall back to original id if not present (name is optional)
@@ -91,6 +94,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
{
float mat[4][4];
float joint_inv_bind_mat[4][4];
+ float joint_bind_mat[4][4];
int chain_length = 0;
//Checking if bone is already made.
@@ -114,7 +118,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
// get original world-space matrix
invert_m4_m4(mat, joint_inv_bind_mat);
-
+ copy_m4_m4(joint_bind_mat, mat);
// And make local to armature
Object *ob_arm = skin->BKE_armature_from_object();
if (ob_arm) {
@@ -130,18 +134,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
// create a bone even if there's no joint data for it (i.e. it has no influence)
if (!bone_is_skinned) {
- float obmat[4][4];
- // bone-space
- get_node_mat(obmat, node, NULL, NULL);
-
- // get world-space
- if (parent) {
- mul_m4_m4m4(mat, parent_mat, obmat);
- }
- else {
- copy_m4_m4(mat, obmat);
- }
-
+ get_node_mat(mat, node, NULL, NULL, parent_mat);
}
if (parent) bone->parent = parent;
@@ -157,10 +150,11 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
int use_connect = be.get_use_connect();
switch (use_connect) {
- case 1: bone->flag |= BONE_CONNECTED;
- break;
- case 0: bone->flag &= ~BONE_CONNECTED;
- case -1: break; // not defined
+ case 1: bone->flag |= BONE_CONNECTED;
+ break;
+ case -1:/* Connect type not specified */
+ case 0: bone->flag &= ~BONE_CONNECTED;
+ break;
}
if (be.has_roll()) {
@@ -173,6 +167,15 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
bone->roll = angle;
}
copy_v3_v3(bone->head, mat[3]);
+
+ if (bone_is_skinned)
+ {
+ float rest_mat[4][4];
+ get_node_mat(rest_mat, node, NULL, NULL, NULL);
+ bc_set_IDPropertyMatrix(bone, "bind_mat", joint_bind_mat);
+ bc_set_IDPropertyMatrix(bone, "rest_mat", rest_mat);
+ }
+
add_v3_v3v3(bone->tail, bone->head, tail); //tail must be non zero
/* find smallest bone length in armature (used later for leaf bone length) */
@@ -274,7 +277,6 @@ void ArmatureImporter::fix_parent_connect(bArmature *armature, Bone *bone)
}
-
void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone, int clip)
{
BoneExtensionMap &extended_bones = bone_extension_manager.getExtensionMap(armature);
@@ -290,12 +292,13 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
for (; child; child = child->next) {
BoneExtended *be = extended_bones[child->name];
if (be != NULL) {
- if (be->get_chain_length() <= clip) {
- if (be->get_chain_length() > maxlen) {
+ int chain_len = be->get_chain_length();
+ if (chain_len <= clip) {
+ if (chain_len > maxlen) {
dominant_child = be;
- maxlen = be->get_chain_length();
+ maxlen = chain_len;
}
- else if (be->get_chain_length() == maxlen) {
+ else if (chain_len == maxlen) {
dominant_child = NULL;
}
}
@@ -309,7 +312,6 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
EditBone *pebone = bc_get_edit_bone(armature, parentbone->name);
EditBone *cebone = bc_get_edit_bone(armature, dominant_child->get_name());
if (pebone && !(cebone->flag & BONE_CONNECTED)) {
-
float vec[3];
sub_v3_v3v3(vec, cebone->head, pebone->head);
@@ -322,14 +324,16 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
if (len_squared_v3(vec) > MINIMUM_BONE_LENGTH)
{
- pebone->tail[0] = cebone->head[0];
- pebone->tail[1] = cebone->head[1];
- pebone->tail[2] = cebone->head[2];
-
+ copy_v3_v3(pebone->tail, cebone->head);
+ pbe->set_tail(pebone->tail); /* to make fix_leafbone happy ...*/
if (pbe && pbe->get_chain_length() >= this->import_settings->min_chain_length) {
+
+ BoneExtended *cbe = extended_bones[cebone->name];
+ cbe->set_use_connect(true);
+
cebone->flag |= BONE_CONNECTED;
- printf("Connecting chain: parent %s --> %s (child)\n", pebone->name, cebone->name);
pbe->set_leaf_bone(false);
+ printf("Connect Bone chain: parent (%s --> %s) child)\n", pebone->name, cebone->name);
}
}
}
diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp
index a868adc1e66..1c2642e8313 100644
--- a/source/blender/collada/ControllerExporter.cpp
+++ b/source/blender/collada/ControllerExporter.cpp
@@ -463,81 +463,6 @@ std::string ControllerExporter::add_joints_source(Object *ob_arm, ListBase *defb
return source_id;
}
-static float get_property(Bone *bone, const char *key, float def)
-{
- float result = def;
- if (bone->prop) {
- IDProperty *property = IDP_GetPropertyFromGroup(bone->prop, key);
- if (property) {
- switch (property->type) {
- case IDP_INT:
- result = (float)(IDP_Int(property));
- break;
- case IDP_FLOAT:
- result = (float)(IDP_Float(property));
- break;
- case IDP_DOUBLE:
- result = (float)(IDP_Double(property));
- break;
- default:
- result = def;
- }
- }
- }
- return result;
-}
-
-/**
- * This function creates an arbitrary rest pose matrix from
- * data provided as custom properties. This is a workaround
- * for support of maya's restpose matrix which can be arbitrary
- * in opposition to Blender where the Rest pose Matrix is always
- * the Identity matrix.
- *
- * The custom properties are:
- *
- * restpose_scale_x
- * restpose_scale_y
- * restpose_scale_z
- *
- * restpose_rot_x
- * restpose_rot_y
- * restpose_rot_z
- *
- * restpose_loc_x
- * restpose_loc_y
- * restpose_loc_z
- *
- * The matrix is only setup if the scale AND the rot properties are defined.
- * The presence of the loc properties is optional.
- *
- * This feature has been implemented to support Second Life "Fitted Mesh"
- * TODO: Check if an arbitrary rest pose matrix makes sense within Blender.
- * Eventually leverage the custom property data into an "official"
- * Edit_bone Property
- */
-static void create_restpose_mat(Bone *bone, float mat[4][4])
-{
- float loc[3] = {
- get_property(bone, "restpose_loc_x", 0.0),
- get_property(bone, "restpose_loc_y", 0.0),
- get_property(bone, "restpose_loc_z", 0.0)
- };
-
- float rot[3] = {
- DEG2RADF(get_property(bone, "restpose_rot_x", 0.0)),
- DEG2RADF(get_property(bone, "restpose_rot_y", 0.0)),
- DEG2RADF(get_property(bone, "restpose_rot_z", 0.0))
- };
-
- float scale[3] = {
- get_property(bone, "restpose_scale_x", 1.0),
- get_property(bone, "restpose_scale_y", 1.0),
- get_property(bone, "restpose_scale_z", 1.0)
- };
-
- loc_eulO_size_to_mat4(mat, loc, rot, scale, 6);
-}
std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id)
{
@@ -580,30 +505,36 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas
float world[4][4];
float inv_bind_mat[4][4];
+ float bind_mat[4][4]; /* derived from bone->arm_mat */
+
+ bool has_bindmat = bc_get_property_matrix(pchan->bone, "bind_mat", bind_mat);
- // SL/OPEN_SIM COMPATIBILITY
- if (export_settings->open_sim) {
- // Only translations, no rotation vs armature
- float temp[4][4];
- unit_m4(temp);
- copy_v3_v3(temp[3], pchan->bone->arm_mat[3]);
- mul_m4_m4m4(world, ob_arm->obmat, temp);
-
- // Add Maya restpose matrix (if defined as properties)
- float restpose_mat[4][4];
- create_restpose_mat(pchan->bone, restpose_mat);
- mul_m4_m4m4(world, world, restpose_mat);
+ if (!has_bindmat) {
- }
- else {
- // make world-space matrix, arm_mat is armature-space
- mul_m4_m4m4(world, ob_arm->obmat, pchan->bone->arm_mat);
+ /* Have no bind matrix stored, try old style <= Blender 2.78 */
+
+ bc_create_restpose_mat(this->export_settings, pchan->bone, bind_mat, pchan->bone->arm_mat, true);
+
+ // SL/OPEN_SIM COMPATIBILITY
+ if (export_settings->open_sim) {
+
+ float loc[3];
+ float rot[3] = { 0, 0, 0 };
+ float scale[3];
+ bc_decompose(bind_mat, loc, NULL, NULL, scale);
+
+ // Only translations, no rotation vs armature
+ loc_eulO_size_to_mat4(bind_mat, loc, rot, scale, 6);
+ }
}
+ // make world-space matrix (bind_mat is armature-space)
+ mul_m4_m4m4(world, ob_arm->obmat, bind_mat);
invert_m4_m4(mat, world);
converter.mat4_to_dae(inv_bind_mat, mat);
-
+ if (this->export_settings->limit_precision)
+ bc_sanitize_mat(inv_bind_mat, 6);
source.appendValues(inv_bind_mat);
}
}
diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h
index 9451cac9dae..de91f68a492 100644
--- a/source/blender/collada/ExportSettings.h
+++ b/source/blender/collada/ExportSettings.h
@@ -51,7 +51,10 @@ public:
bool use_blender_profile;
bool sort_by_name;
BC_export_transformation_type export_transformation_type;
+
bool open_sim;
+ bool limit_precision;
+ bool keep_bind_info;
char *filepath;
LinkNode *export_set;
diff --git a/source/blender/collada/ImportSettings.h b/source/blender/collada/ImportSettings.h
index 2c52d73e756..4a2d4e8046a 100644
--- a/source/blender/collada/ImportSettings.h
+++ b/source/blender/collada/ImportSettings.h
@@ -37,6 +37,7 @@ public:
bool fix_orientation;
int min_chain_length;
char *filepath;
+ bool keep_bind_info;
};
#endif
diff --git a/source/blender/collada/TransformReader.cpp b/source/blender/collada/TransformReader.cpp
index f8f31304d28..7f742be7e30 100644
--- a/source/blender/collada/TransformReader.cpp
+++ b/source/blender/collada/TransformReader.cpp
@@ -34,7 +34,21 @@ TransformReader::TransformReader(UnitConverter *conv) : unit_converter(conv)
/* pass */
}
-void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob)
+void TransformReader::get_node_mat(
+ float mat[4][4],
+ COLLADAFW::Node *node,
+ std::map<COLLADAFW::UniqueId, Animation> *animation_map,
+ Object *ob)
+{
+ get_node_mat(mat, node, animation_map, ob, NULL);
+}
+
+void TransformReader::get_node_mat(
+ float mat[4][4],
+ COLLADAFW::Node *node,
+ std::map<COLLADAFW::UniqueId, Animation> *animation_map,
+ Object *ob,
+ float parent_mat[4][4])
{
float cur[4][4];
float copy[4][4];
@@ -52,6 +66,9 @@ void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::
// then this is considered as redundant information.
// So if we find a Matrix we use that and return.
dae_matrix_to_mat4(tm, mat);
+ if (parent_mat) {
+ mul_m4_m4m4(mat, parent_mat, mat);
+ }
return;
case COLLADAFW::Transformation::TRANSLATE:
dae_translate_to_mat4(tm, cur);
@@ -80,6 +97,10 @@ void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::
(*animation_map)[anim_list_id] = anim;
}
}
+
+ if (parent_mat) {
+ mul_m4_m4m4(mat, parent_mat, mat);
+ }
}
void TransformReader::dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4])
diff --git a/source/blender/collada/TransformReader.h b/source/blender/collada/TransformReader.h
index ab974b9ba85..08bb17ccac1 100644
--- a/source/blender/collada/TransformReader.h
+++ b/source/blender/collada/TransformReader.h
@@ -43,7 +43,7 @@
//struct Object;
-class TransformReader : public TransformBase
+class TransformReader
{
protected:
@@ -59,7 +59,8 @@ public:
TransformReader(UnitConverter *conv);
void get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob);
-
+ void get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob, float parent_mat[4][4]);
+
void dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]);
void dae_translate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]);
void dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]);
diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp
index 908111ebae6..b7eeff3b074 100644
--- a/source/blender/collada/TransformWriter.cpp
+++ b/source/blender/collada/TransformWriter.cpp
@@ -27,11 +27,10 @@
#include "BKE_object.h"
+#include "BLI_math.h"
#include "TransformWriter.h"
-#include "BLI_math.h"
-
void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4], float parent_mat[4][4])
{
float loc[3], rot[3], scale[3];
@@ -51,7 +50,7 @@ void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4],
converter->mat4_to_dae_double(dmat, local);
delete converter;
- TransformBase::decompose(local, loc, rot, NULL, scale);
+ bc_decompose(local, loc, rot, NULL, scale);
if (node.getType() == COLLADASW::Node::JOINT) {
// XXX Why are joints handled differently ?
@@ -116,7 +115,7 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B
case BC_TRANSFORMATION_TYPE_TRANSROTLOC:
{
float loc[3], rot[3], scale[3];
- TransformBase::decompose(f_obmat, loc, rot, NULL, scale);
+ bc_decompose(f_obmat, loc, rot, NULL, scale);
add_transform(node, loc, rot, scale);
break;
}
diff --git a/source/blender/collada/TransformWriter.h b/source/blender/collada/TransformWriter.h
index 7f69a4b9c95..5bb13d4aac9 100644
--- a/source/blender/collada/TransformWriter.h
+++ b/source/blender/collada/TransformWriter.h
@@ -33,9 +33,10 @@
#include "DNA_object_types.h"
#include "collada_internal.h"
+#include "collada_utils.h"
#include "collada.h"
-class TransformWriter : protected TransformBase
+class TransformWriter
{
protected:
void add_node_transform(COLLADASW::Node& node, float mat[4][4], float parent_mat[4][4]);
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index fe8b1d2320a..bfe3180909b 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -48,7 +48,8 @@ int collada_import(bContext *C,
int find_chains,
int auto_connect,
int fix_orientation,
- int min_chain_length)
+ int min_chain_length,
+ int keep_bind_info)
{
ImportSettings import_settings;
@@ -58,6 +59,7 @@ int collada_import(bContext *C,
import_settings.find_chains = find_chains != 0;
import_settings.fix_orientation = fix_orientation != 0;
import_settings.min_chain_length = min_chain_length;
+ import_settings.keep_bind_info = keep_bind_info !=0;
DocumentImporter imp(C, &import_settings);
if (imp.import()) return 1;
@@ -87,7 +89,9 @@ int collada_export(Scene *sce,
int use_blender_profile,
int sort_by_name,
BC_export_transformation_type export_transformation_type,
- int open_sim)
+ int open_sim,
+ int limit_precision,
+ int keep_bind_info)
{
ExportSettings export_settings;
@@ -112,7 +116,8 @@ int collada_export(Scene *sce,
export_settings.sort_by_name = sort_by_name != 0;
export_settings.export_transformation_type = export_transformation_type;
export_settings.open_sim = open_sim != 0;
-
+ export_settings.limit_precision = limit_precision != 0;
+ export_settings.keep_bind_info = keep_bind_info !=0;
int includeFilter = OB_REL_NONE;
if (export_settings.include_armatures) includeFilter |= OB_REL_MOD_ARMATURE;
diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h
index a4416608584..8035af59c8b 100644
--- a/source/blender/collada/collada.h
+++ b/source/blender/collada/collada.h
@@ -58,7 +58,9 @@ int collada_import(struct bContext *C,
int find_chains,
int auto_connect,
int fix_orientation,
- int min_chain_length);
+ int min_chain_length,
+
+ int keep_bind_info);
int collada_export(struct Scene *sce,
const char *filepath,
@@ -81,9 +83,10 @@ int collada_export(struct Scene *sce,
int use_blender_profile,
int sort_by_name,
BC_export_transformation_type export_transformation_type,
- int open_sim);
-
+ int open_sim,
+ int limit_precision,
+ int keep_bind_info);
#ifdef __cplusplus
}
diff --git a/source/blender/collada/collada_internal.cpp b/source/blender/collada/collada_internal.cpp
index 70b44ebc222..6ebde6bd773 100644
--- a/source/blender/collada/collada_internal.cpp
+++ b/source/blender/collada/collada_internal.cpp
@@ -162,18 +162,6 @@ void UnitConverter::calculate_scale(Scene &sce)
size_to_mat4(scale_mat4, rescale);
}
-void TransformBase::decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size)
-{
- mat4_to_size(size, mat);
- if (eul) {
- mat4_to_eul(eul, mat);
- }
- if (quat) {
- mat4_to_quat(quat, mat);
- }
- copy_v3_v3(loc, mat[3]);
-}
-
/**
* Translation map.
* Used to translate every COLLADA id to a valid id, no matter what "wrong" letters may be
diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h
index 482dbf9ab31..1c7aa160f57 100644
--- a/source/blender/collada/collada_internal.h
+++ b/source/blender/collada/collada_internal.h
@@ -85,12 +85,6 @@ public:
};
-class TransformBase
-{
-public:
- void decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size);
-};
-
extern void clear_global_id_map();
/** Look at documentation of translate_map */
extern std::string translate_id(const std::string &id);
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index 2efa8b21d81..ac4395e1430 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -32,8 +32,6 @@
#include "COLLADAFWMeshPrimitive.h"
#include "COLLADAFWMeshVertexData.h"
-#include "collada_utils.h"
-
extern "C" {
#include "DNA_modifier_types.h"
#include "DNA_customdata_types.h"
@@ -63,6 +61,9 @@ extern "C" {
#include "bmesh_tools.h"
}
+#include "collada_utils.h"
+#include "ExportSettings.h"
+
float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index)
{
if (index >= array.getValuesCount())
@@ -352,6 +353,28 @@ void bc_match_scale(std::vector<Object *> *objects_done,
}
}
+/*
+ Convenience function to get only the needed components of a matrix
+*/
+void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size)
+{
+ if (size) {
+ mat4_to_size(size, mat);
+ }
+
+ if (eul) {
+ mat4_to_eul(eul, mat);
+ }
+
+ if (quat) {
+ mat4_to_quat(quat, mat);
+ }
+
+ if (loc) {
+ copy_v3_v3(loc, mat[3]);
+ }
+}
+
void bc_triangulate_mesh(Mesh *me)
{
bool use_beauty = false;
@@ -612,3 +635,200 @@ int BoneExtended::get_use_connect()
{
return this->use_connect;
}
+
+/**
+* Stores a 4*4 matrix as a custom bone property array of size 16
+*/
+void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4])
+{
+ IDProperty *idgroup = (IDProperty *)ebone->prop;
+ if (idgroup == NULL)
+ {
+ IDPropertyTemplate val = { 0 };
+ idgroup = IDP_New(IDP_GROUP, &val, "RNA_EditBone ID properties");
+ ebone->prop = idgroup;
+ }
+
+ IDPropertyTemplate val = { 0 };
+ val.array.len = 16;
+ val.array.type = IDP_FLOAT;
+
+ IDProperty *data = IDP_New(IDP_ARRAY, &val, key);
+ float *array = (float *)IDP_Array(data);
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ array[4 * i + j] = mat[i][j];
+
+ IDP_AddToGroup(idgroup, data);
+}
+
+#if 0
+/**
+* Stores a Float value as a custom bone property
+*
+* Note: This function is currently not needed. Keep for future usage
+*/
+static void bc_set_IDProperty(EditBone *ebone, const char *key, float value)
+{
+ if (ebone->prop == NULL)
+ {
+ IDPropertyTemplate val = { 0 };
+ ebone->prop = IDP_New(IDP_GROUP, &val, "RNA_EditBone ID properties");
+ }
+
+ IDProperty *pgroup = (IDProperty *)ebone->prop;
+ IDPropertyTemplate val = { 0 };
+ IDProperty *prop = IDP_New(IDP_FLOAT, &val, key);
+ IDP_Float(prop) = value;
+ IDP_AddToGroup(pgroup, prop);
+
+}
+#endif
+
+/*
+* Get a custom property when it exists.
+* This function is also used to check if a property exists.
+*/
+IDProperty *bc_get_IDProperty(Bone *bone, std::string key)
+{
+ return (bone->prop == NULL) ? NULL : IDP_GetPropertyFromGroup(bone->prop, key.c_str());
+}
+
+/**
+* Read a custom bone property and convert to float
+* Return def if the property does not exist.
+*/
+float bc_get_property(Bone *bone, std::string key, float def)
+{
+ float result = def;
+ IDProperty *property = bc_get_IDProperty(bone, key);
+ if (property) {
+ switch (property->type) {
+ case IDP_INT:
+ result = (float)(IDP_Int(property));
+ break;
+ case IDP_FLOAT:
+ result = (float)(IDP_Float(property));
+ break;
+ case IDP_DOUBLE:
+ result = (float)(IDP_Double(property));
+ break;
+ default:
+ result = def;
+ }
+ }
+ return result;
+}
+
+/**
+* Read a custom bone property and convert to matrix
+* Return true if conversion was succesfull
+*
+* Return false if:
+* - the property does not exist
+* - is not an array of size 16
+*/
+bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4])
+{
+ IDProperty *property = bc_get_IDProperty(bone, key);
+ if (property && property->type == IDP_ARRAY && property->len == 16) {
+ float *array = (float *)IDP_Array(property);
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ mat[i][j] = array[4 * i + j];
+ return true;
+ }
+ return false;
+}
+
+/**
+* get a vector that is stored in 3 custom properties (used in Blender <= 2.78)
+*/
+void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3])
+{
+ val[0] = bc_get_property(bone, key + "_x", def[0]);
+ val[1] = bc_get_property(bone, key + "_y", def[1]);
+ val[2] = bc_get_property(bone, key + "_z", def[2]);
+}
+
+/**
+* Check if vector exist stored in 3 custom properties (used in Blender <= 2.78)
+*/
+static bool has_custom_props(Bone *bone, bool enabled, std::string key)
+{
+ if (!enabled)
+ return false;
+
+ return (bc_get_IDProperty(bone, key + "_x")
+ || bc_get_IDProperty(bone, key + "_y")
+ || bc_get_IDProperty(bone, key + "_z"));
+
+}
+
+/**
+* Check if custom information about bind matrix exists and modify the from_mat
+* accordingly.
+*
+* Note: This is old style for Blender <= 2.78 only kept for compatibility
+*/
+void bc_create_restpose_mat(const ExportSettings *export_settings, Bone *bone, float to_mat[4][4], float from_mat[4][4], bool use_local_space)
+{
+ float loc[3];
+ float rot[3];
+ float scale[3];
+ static const float V0[3] = { 0, 0, 0 };
+
+ if (!has_custom_props(bone, export_settings->keep_bind_info, "restpose_loc") &&
+ !has_custom_props(bone, export_settings->keep_bind_info, "restpose_rot") &&
+ !has_custom_props(bone, export_settings->keep_bind_info, "restpose_scale"))
+ {
+ /* No need */
+ copy_m4_m4(to_mat, from_mat);
+ return;
+ }
+
+ bc_decompose(from_mat, loc, rot, NULL, scale);
+ loc_eulO_size_to_mat4(to_mat, loc, rot, scale, 6);
+
+ if (export_settings->keep_bind_info) {
+ bc_get_property_vector(bone, "restpose_loc", loc, loc);
+
+ if (use_local_space && bone->parent) {
+ Bone *b = bone;
+ while (b->parent) {
+ b = b->parent;
+ float ploc[3];
+ bc_get_property_vector(b, "restpose_loc", ploc, V0);
+ loc[0] += ploc[0];
+ loc[1] += ploc[1];
+ loc[2] += ploc[2];
+ }
+ }
+ }
+
+ if (export_settings->keep_bind_info) {
+ if (bc_get_IDProperty(bone, "restpose_rot_x"))
+ rot[0] = DEG2RADF(bc_get_property(bone, "restpose_rot_x", 0));
+ if (bc_get_IDProperty(bone, "restpose_rot_y"))
+ rot[1] = DEG2RADF(bc_get_property(bone, "restpose_rot_y", 0));
+ if (bc_get_IDProperty(bone, "restpose_rot_z"))
+ rot[2] = DEG2RADF(bc_get_property(bone, "restpose_rot_z", 0));
+ }
+
+ if (export_settings->keep_bind_info) {
+ bc_get_property_vector(bone, "restpose_scale", scale, scale);
+ }
+
+ loc_eulO_size_to_mat4(to_mat, loc, rot, scale, 6);
+
+}
+
+/*
+ Make 4*4 matrices better readable
+*/
+void bc_sanitize_mat(float mat[4][4], int precision)
+{
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ mat[i][j] = double_round(mat[i][j], precision);
+} \ No newline at end of file
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
index 7fdbef3b6cb..38c0bd5096a 100644
--- a/source/blender/collada/collada_utils.h
+++ b/source/blender/collada/collada_utils.h
@@ -53,8 +53,10 @@ extern "C" {
#include "BKE_object.h"
#include "BKE_DerivedMesh.h"
#include "BKE_scene.h"
+#include "BKE_idprop.h"
}
+#include "ImportSettings.h"
#include "ExportSettings.h"
#include "collada_internal.h"
@@ -88,11 +90,24 @@ extern std::string bc_url_encode(std::string data);
extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene);
extern void bc_match_scale(std::vector<Object *> *objects_done, UnitConverter &unit_converter, bool scale_to_scene);
+extern void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size);
+
extern void bc_triangulate_mesh(Mesh *me);
extern bool bc_is_leaf_bone(Bone *bone);
extern EditBone *bc_get_edit_bone(bArmature * armature, char *name);
extern int bc_set_layer(int bitfield, int layer, bool enable);
extern int bc_set_layer(int bitfield, int layer);
+extern void bc_sanitize_mat(float mat[4][4], int precision);
+
+extern IDProperty *bc_get_IDProperty(Bone *bone, std::string key);
+extern void bc_set_IDProperty(EditBone *ebone, const char *key, float value);
+extern void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4]);
+
+extern float bc_get_property(Bone *bone, std::string key, float def);
+extern void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3]);
+extern bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4]);
+
+extern void bc_create_restpose_mat(const ExportSettings *export_settings, Bone *bone, float to_mat[4][4], float world[4][4], bool use_local_space);
class BCPolygonNormalsIndices
{
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index cb2f057a090..7f62eb122db 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -52,14 +52,6 @@
namespace DEG {
-string deg_fcurve_id_name(const FCurve *fcu)
-{
- char index_buf[32];
- // TODO(sergey): Use int-to-string utility or so.
- BLI_snprintf(index_buf, sizeof(index_buf), "[%d]", fcu->array_index);
- return string(fcu->rna_path) + index_buf;
-}
-
static bool check_object_needs_evaluation(Object *object)
{
if (object->recalc & OB_RECALC_ALL) {
@@ -77,28 +69,8 @@ static bool check_object_needs_evaluation(Object *object)
return false;
}
-void deg_graph_build_finalize(Depsgraph *graph)
+void deg_graph_build_flush_layers(Depsgraph *graph)
{
- /* STEP 1: Make sure new invisible dependencies are ready for use.
- *
- * TODO(sergey): This might do a bit of extra tagging, but it's kinda nice
- * to do it ahead of a time and don't spend time on flushing updates on
- * every frame change.
- */
- GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
- {
- if (id_node->layers == 0) {
- ID *id = id_node->id;
- if (GS(id->name) == ID_OB) {
- Object *object = (Object *)id;
- if (check_object_needs_evaluation(object)) {
- id_node->tag_update(graph);
- }
- }
- }
- }
- GHASH_FOREACH_END();
- /* STEP 2: Flush visibility layers from children to parent. */
std::stack<OperationDepsNode *> stack;
foreach (OperationDepsNode *node, graph->operations) {
IDDepsNode *id_node = node->owner->owner;
@@ -143,6 +115,31 @@ void deg_graph_build_finalize(Depsgraph *graph)
}
}
}
+}
+
+void deg_graph_build_finalize(Depsgraph *graph)
+{
+ /* STEP 1: Make sure new invisible dependencies are ready for use.
+ *
+ * TODO(sergey): This might do a bit of extra tagging, but it's kinda nice
+ * to do it ahead of a time and don't spend time on flushing updates on
+ * every frame change.
+ */
+ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
+ {
+ if (id_node->layers == 0) {
+ ID *id = id_node->id;
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ if (check_object_needs_evaluation(object)) {
+ id_node->tag_update(graph);
+ }
+ }
+ }
+ }
+ GHASH_FOREACH_END();
+ /* STEP 2: Flush visibility layers from children to parent. */
+ deg_graph_build_flush_layers(graph);
/* STEP 3: Re-tag IDs for update if it was tagged before the relations
* update tag.
*/
@@ -154,7 +151,7 @@ void deg_graph_build_finalize(Depsgraph *graph)
}
GHASH_FOREACH_END();
- if ((id_node->layers & graph->layers) != 0) {
+ if ((id_node->layers & graph->layers) != 0 || graph->layers == 0) {
ID *id = id_node->id;
if ((id->tag & LIB_TAG_ID_RECALC_ALL) &&
(id->tag & LIB_TAG_DOIT))
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h
index bdc030e3810..b8ea8c8e599 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder.h
@@ -38,9 +38,7 @@ namespace DEG {
struct Depsgraph;
-/* Get unique identifier for FCurves and Drivers */
-string deg_fcurve_id_name(const FCurve *fcu);
-
void deg_graph_build_finalize(struct Depsgraph *graph);
+void deg_graph_build_flush_layers(struct Depsgraph *graph);
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index e8ed03666a6..cfc9005a1e3 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -56,8 +56,8 @@ extern "C" {
#include "DEG_depsgraph.h"
} /* extern "C" */
+#include "intern/builder/deg_builder.h"
#include "intern/eval/deg_eval_flush.h"
-
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
@@ -346,6 +346,27 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
GHASH_FOREACH_END();
}
scene->lay_updated |= graph->layers;
+ /* Special trick to get local view to work. */
+ LINKLIST_FOREACH (Base *, base, &scene->base) {
+ Object *object = base->object;
+ DEG::IDDepsNode *id_node = graph->find_id_node(&object->id);
+ id_node->layers = 0;
+ }
+ LINKLIST_FOREACH (Base *, base, &scene->base) {
+ Object *object = base->object;
+ DEG::IDDepsNode *id_node = graph->find_id_node(&object->id);
+ id_node->layers |= base->lay;
+ }
+ DEG::deg_graph_build_flush_layers(graph);
+ LINKLIST_FOREACH (Base *, base, &scene->base) {
+ Object *object = base->object;
+ DEG::IDDepsNode *id_node = graph->find_id_node(&object->id);
+ GHASH_FOREACH_BEGIN(DEG::ComponentDepsNode *, comp, id_node->components)
+ {
+ id_node->layers |= comp->layers;
+ }
+ GHASH_FOREACH_END();
+ }
}
void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 47f42ab5321..648fe930030 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -6047,6 +6047,9 @@ int join_curve_exec(bContext *C, wmOperator *op)
cu = ob->data;
BLI_movelisttolist(&cu->nurb, &tempbase);
+ /* Account for mixed 2D/3D curves when joining */
+ BKE_curve_curve_dimension_update(cu);
+
DAG_relations_tag_update(bmain); // because we removed object(s), call before editmode!
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index a542bf8fa11..f091609da49 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -701,24 +701,25 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
*/
{
bGPDspoint *pt1, *pt2;
- float pm[2];
+ float s0[2], s1[2]; /* segment 'center' points */
+ float pm[2]; /* normal from previous segment. */
int i;
float fpt[3];
glShadeModel(GL_FLAT);
glBegin(GL_QUADS);
-
+
+ /* get x and y coordinates from first point */
+ mul_v3_m4v3(fpt, diff_mat, &points->x);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
+
for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
- float s0[2], s1[2]; /* segment 'center' points */
float t0[2], t1[2]; /* tessellated coordinates */
float m1[2], m2[2]; /* gradient and normal */
float mt[2], sc[2]; /* gradient for thickness, point for end-cap */
float pthick; /* thickness at segment point */
- /* get x and y coordinates from points */
- mul_v3_m4v3(fpt, diff_mat, &pt1->x);
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
-
+ /* get x and y coordinates from point2 (point1 has already been computed in previous iteration). */
mul_v3_m4v3(fpt, diff_mat, &pt2->x);
gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s1);
@@ -846,6 +847,8 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
glVertex2fv(t0);
}
+ /* store computed point2 coordinates as point1 ones of next segment. */
+ copy_v2_v2(s0, s1);
/* store stroke's 'natural' normal for next stroke to use */
copy_v2_v2(pm, m2);
}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index fa9acc36a2b..601a86b97cb 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -2126,10 +2126,10 @@ static int gp_count_subdivision_cuts(bGPDstroke *gps)
int totnewpoints = 0;
for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
- if (i + 1 < gps->totpoints){
+ if (i + 1 < gps->totpoints) {
if (gps->points[i + 1].flag & GP_SPOINT_SELECT) {
++totnewpoints;
- };
+ }
}
}
}
@@ -2184,7 +2184,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
/* if next point is selected add a half way point */
if (pt->flag & GP_SPOINT_SELECT) {
- if (i + 1 < oldtotpoints){
+ if (i + 1 < oldtotpoints) {
if (temp_points[i + 1].flag & GP_SPOINT_SELECT) {
pt_final = &gps->points[i2];
/* Interpolate all values */
@@ -2196,7 +2196,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
pt_final->time = interpf(pt->time, next->time, 0.5f);
pt_final->flag |= GP_SPOINT_SELECT;
++i2;
- };
+ }
}
}
}
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 297058168a0..d2360fea672 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -86,13 +86,14 @@
/* Core/Shared Utilities */
/* Poll callback for interpolation operators */
-static int gpencil_interpolate_poll(bContext *C)
+static int gpencil_view3d_poll(bContext *C)
{
bGPdata *gpd = CTX_data_gpencil_data(C);
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
/* only 3D view */
- if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) {
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype != SPACE_VIEW3D) {
return 0;
}
@@ -673,7 +674,7 @@ void GPENCIL_OT_interpolate(wmOperatorType *ot)
ot->invoke = gpencil_interpolate_invoke;
ot->modal = gpencil_interpolate_modal;
ot->cancel = gpencil_interpolate_cancel;
- ot->poll = gpencil_interpolate_poll;
+ ot->poll = gpencil_view3d_poll;
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
@@ -1017,7 +1018,7 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
/* api callbacks */
ot->exec = gpencil_interpolate_seq_exec;
- ot->poll = gpencil_interpolate_poll;
+ ot->poll = gpencil_view3d_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1025,24 +1026,14 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
/* ******************** Remove Breakdowns ************************ */
-/* Same as gpencil_interpolate_poll(),
- * except we ALSO need to have an active frame that is a breakdown
- */
static int gpencil_interpolate_reverse_poll(bContext *C)
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
-
- /* only 3D view */
- if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) {
- return 0;
- }
-
- /* need data to interpolate */
- if (ELEM(NULL, gpd, gpl)) {
+ if (!gpencil_view3d_poll(C)) {
return 0;
}
-
+
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+
/* need to be on a breakdown frame */
if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN)) {
CTX_wm_operator_poll_msg_set(C, "Expected current frame to be a breakdown");
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 9fbce7dd203..4945406c57b 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -421,7 +421,7 @@ typedef void (*uiBlockCancelFunc)(struct bContext *C, void *arg1);
void UI_popup_block_invoke(struct bContext *C, uiBlockCreateFunc func, void *arg);
void UI_popup_block_invoke_ex(struct bContext *C, uiBlockCreateFunc func, void *arg, const char *opname, int opcontext);
-void UI_popup_block_ex(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg);
+void UI_popup_block_ex(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg, struct wmOperator *op);
/* void uiPupBlockOperator(struct bContext *C, uiBlockCreateFunc func, struct wmOperator *op, int opcontext); */ /* UNUSED */
void UI_popup_block_close(struct bContext *C, struct wmWindow *win, uiBlock *block);
@@ -695,7 +695,7 @@ void UI_but_func_search_set(
int UI_searchbox_size_y(void);
int UI_searchbox_size_x(void);
/* check if a string is in an existing search box */
-int UI_search_items_find_index(uiSearchItems *items, const char *name);
+int UI_search_items_find_index(uiSearchItems *items, const char *name, const size_t offset);
void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg);
void UI_block_func_butmenu_set(uiBlock *block, uiMenuHandleFunc func, void *arg);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 57f3d228a17..d4b1a7e603a 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -1337,7 +1337,7 @@ static void ui_but_to_pixelrect(rcti *rect, const ARegion *ar, uiBlock *block, u
rctf rectf;
ui_block_to_window_rctf(ar, block, &rectf, (but) ? &but->rect : &block->rect);
- BLI_rcti_rctf_copy_floor(rect, &rectf);
+ BLI_rcti_rctf_copy(rect, &rectf);
BLI_rcti_translate(rect, -ar->winrct.xmin, -ar->winrct.ymin);
}
@@ -3913,7 +3913,7 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block, int type, wmOperatorType *ot, int o
uiBut *uiDefIconTextButO(uiBlock *block, int type, const char *opname, int opcontext, int icon, const char *str, int x, int y, short width, short height, const char *tip)
{
wmOperatorType *ot = WM_operatortype_find(opname, 0);
- if (str[0] == '\0')
+ if (str && str[0] == '\0')
return uiDefIconButO_ptr(block, type, ot, opcontext, icon, x, y, width, height, tip);
return uiDefIconTextButO_ptr(block, type, ot, opcontext, icon, str, x, y, width, height, tip);
}
@@ -4372,7 +4372,7 @@ void UI_but_func_search_set(
if (0 == (but->block->flag & UI_BLOCK_LOOP)) {
/* skip empty buttons, not all buttons need input, we only show invalid */
if (but->drawstr[0])
- ui_but_search_refresh(but);
+ ui_but_search_refresh(but, false);
}
}
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 5da294302e9..a04360b3395 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -39,6 +39,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_nla.h"
@@ -210,6 +211,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
/* updates */
driver->flag |= DRIVER_FLAG_RECOMPILE;
+ DAG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL);
ok = true;
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 6e3c3c3674a..2974c2e9304 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -87,6 +87,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "wm_event_system.h"
#ifdef WITH_INPUT_IME
# include "wm_window.h"
@@ -380,6 +381,7 @@ typedef struct uiAfterFunc {
void *butm_func_arg;
int a2;
+ wmOperator *popup_op;
wmOperatorType *optype;
int opcontext;
PointerRNA *opptr;
@@ -635,13 +637,24 @@ PointerRNA *ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext,
return ptr;
}
+static void popup_check(bContext *C, wmOperator *op)
+{
+ if (op && op->type->check && op->type->check(C, op)) {
+ /* check for popup and re-layout buttons */
+ ARegion *ar_menu = CTX_wm_menu(C);
+ if (ar_menu)
+ ED_region_tag_refresh_ui(ar_menu);
+ }
+}
+
/**
* Check if a #uiAfterFunc is needed for this button.
*/
static bool ui_afterfunc_check(const uiBlock *block, const uiBut *but)
{
return (but->func || but->funcN || but->rename_func || but->optype || but->rnaprop || block->handle_func ||
- (but->type == UI_BTYPE_BUT_MENU && block->butm_func));
+ (but->type == UI_BTYPE_BUT_MENU && block->butm_func) ||
+ (block->handle && block->handle->popup_op));
}
static void ui_apply_but_func(bContext *C, uiBut *but)
@@ -682,6 +695,9 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
after->butm_func_arg = block->butm_func_arg;
after->a2 = but->a2;
}
+
+ if (block->handle)
+ after->popup_op = block->handle->popup_op;
after->optype = but->optype;
after->opcontext = but->opcontext;
@@ -766,6 +782,9 @@ static void ui_apply_but_funcs_after(bContext *C)
if (after.context)
CTX_store_set(C, after.context);
+ if (after.popup_op)
+ popup_check(C, after.popup_op);
+
if (after.opptr) {
/* free in advance to avoid leak on exit */
opptr = *after.opptr;
@@ -6665,7 +6684,7 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = (uiBut *)arg1;
- UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but);
+ UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but, NULL);
}
/**
@@ -7005,20 +7024,17 @@ static bool ui_but_menu(bContext *C, uiBut *but)
uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"),
ICON_URL, "WM_OT_doc_view_manual_ui_context");
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_view");
+ ptr_props = uiItemFullO(layout, "WM_OT_doc_view",
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
+ ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr_props, "doc_id", buf);
- uiItemFullO(layout, "WM_OT_doc_view",
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
- ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
/* XXX inactive option, not for public! */
#if 0
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_edit");
+ ptr_props = uiItemFullO(layout, "WM_OT_doc_edit",
+ "Submit Description", ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr_props, "doc_id", buf);
RNA_string_set(&ptr_props, "doc_new", RNA_property_description(but->rnaprop));
-
- uiItemFullO(layout, "WM_OT_doc_edit",
- "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
#endif
}
}
@@ -10182,6 +10198,25 @@ void UI_popup_handlers_add(bContext *C, ListBase *handlers, uiPopupBlockHandle *
void UI_popup_handlers_remove(ListBase *handlers, uiPopupBlockHandle *popup)
{
+ wmEventHandler *handler;
+
+ for (handler = handlers->first; handler; handler = handler->next) {
+ if (handler->ui_handle == ui_popup_handler &&
+ handler->ui_remove == ui_popup_handler_remove &&
+ handler->ui_userdata == popup)
+ {
+ /* tag refresh parent popup */
+ if (handler->next &&
+ handler->next->ui_handle == ui_popup_handler &&
+ handler->next->ui_remove == ui_popup_handler_remove)
+ {
+ uiPopupBlockHandle *parent_popup = handler->next->ui_userdata;
+ ED_region_tag_refresh_ui(parent_popup->region);
+ }
+ break;
+ }
+ }
+
WM_event_remove_ui_handler(handlers, ui_popup_handler, ui_popup_handler_remove, popup, false);
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index d8f9fdcbaae..6706298c3c0 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -556,6 +556,7 @@ struct uiPopupBlockHandle {
struct uiKeyNavLock keynav_state;
/* for operator popups */
+ struct wmOperator *popup_op;
struct wmOperatorType *optype;
ScrArea *ctx_area;
ARegion *ctx_region;
@@ -604,7 +605,7 @@ int ui_searchbox_autocomplete(struct bContext *C, struct ARegion *ar, uiBut *but
void ui_searchbox_event(struct bContext *C, struct ARegion *ar, uiBut *but, const struct wmEvent *event);
bool ui_searchbox_apply(uiBut *but, struct ARegion *ar);
void ui_searchbox_free(struct bContext *C, struct ARegion *ar);
-void ui_but_search_refresh(uiBut *but);
+void ui_but_search_refresh(uiBut *but, const bool is_template_ID);
uiBlock *ui_popup_block_refresh(
struct bContext *C, uiPopupBlockHandle *handle,
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index c62fb4cadd6..30a2094fee7 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1274,7 +1274,8 @@ static void ui_item_rna_size(
if (!w) {
if (type == PROP_ENUM && icon_only) {
w = ui_text_icon_width(layout, "", ICON_BLANK1, 0);
- w += 0.6f * UI_UNIT_X;
+ if (index != RNA_ENUM_VALUE)
+ w += 0.6f * UI_UNIT_X;
}
else {
w = ui_text_icon_width(layout, name, icon, 0);
@@ -2171,7 +2172,17 @@ static void ui_litem_layout_row(uiLayout *litem)
x += neww;
- if ((neww < minw || itemw == minw || item->flag & UI_ITEM_MIN) && w != 0) {
+ bool min_flag = item->flag & UI_ITEM_MIN;
+ /* ignore min flag for rows with right or center alignment */
+ if (item->type != ITEM_BUTTON &&
+ ELEM(((uiLayout *)item)->alignment, UI_LAYOUT_ALIGN_RIGHT, UI_LAYOUT_ALIGN_CENTER) &&
+ litem->alignment == UI_LAYOUT_ALIGN_EXPAND &&
+ ((uiItem *)litem)->flag & UI_ITEM_MIN)
+ {
+ min_flag = false;
+ }
+
+ if ((neww < minw || min_flag) && w != 0) {
/* fixed size */
item->flag |= UI_ITEM_FIXED;
if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
@@ -2253,10 +2264,11 @@ static void ui_litem_layout_row(uiLayout *litem)
}
/* single-column layout */
-static void ui_litem_estimate_column(uiLayout *litem)
+static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
{
uiItem *item;
int itemw, itemh;
+ bool min_size_flag = true;
litem->w = 0;
litem->h = 0;
@@ -2264,15 +2276,21 @@ static void ui_litem_estimate_column(uiLayout *litem)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
+
litem->w = MAX2(litem->w, itemw);
litem->h += itemh;
- if (item->next)
+ if (item->next && (!is_box || item != litem->items.first))
litem->h += litem->space;
}
+
+ if (min_size_flag) {
+ litem->item.flag |= UI_ITEM_MIN;
+ }
}
-static void ui_litem_layout_column(uiLayout *litem)
+static void ui_litem_layout_column(uiLayout *litem, bool is_box)
{
uiItem *item;
int itemh, x, y;
@@ -2286,7 +2304,7 @@ static void ui_litem_layout_column(uiLayout *litem)
y -= itemh;
ui_item_position(item, x, y, litem->w, itemh);
- if (item->next)
+ if (item->next && (!is_box || item != litem->items.first))
y -= litem->space;
}
@@ -2428,7 +2446,7 @@ static void ui_litem_layout_root(uiLayout *litem)
else if (litem->root->type == UI_LAYOUT_PIEMENU)
ui_litem_layout_root_radial(litem);
else
- ui_litem_layout_column(litem);
+ ui_litem_layout_column(litem, false);
}
/* box layout */
@@ -2436,9 +2454,10 @@ static void ui_litem_estimate_box(uiLayout *litem)
{
uiStyle *style = litem->root->style;
- ui_litem_estimate_column(litem);
+ ui_litem_estimate_column(litem, true);
+ litem->item.flag &= ~UI_ITEM_MIN;
litem->w += 2 * style->boxspace;
- litem->h += style->boxspace;
+ litem->h += 2 * style->boxspace;
}
static void ui_litem_layout_box(uiLayout *litem)
@@ -2452,17 +2471,18 @@ static void ui_litem_layout_box(uiLayout *litem)
h = litem->h;
litem->x += style->boxspace;
+ litem->y -= style->boxspace;
if (w != 0) litem->w -= 2 * style->boxspace;
if (h != 0) litem->h -= 2 * style->boxspace;
- ui_litem_layout_column(litem);
+ ui_litem_layout_column(litem, true);
litem->x -= style->boxspace;
litem->y -= style->boxspace;
if (w != 0) litem->w += 2 * style->boxspace;
- if (h != 0) litem->h += style->boxspace;
+ if (h != 0) litem->h += 2 * style->boxspace;
/* roundbox around the sublayout */
but = box->roundbox;
@@ -3115,7 +3135,7 @@ static void ui_item_estimate(uiItem *item)
switch (litem->item.type) {
case ITEM_LAYOUT_COLUMN:
- ui_litem_estimate_column(litem);
+ ui_litem_estimate_column(litem, false);
break;
case ITEM_LAYOUT_COLUMN_FLOW:
ui_litem_estimate_column_flow(litem);
@@ -3170,7 +3190,9 @@ static void ui_item_align(uiLayout *litem, short nr)
}
else if (item->type == ITEM_LAYOUT_BOX) {
box = (uiLayoutItemBx *)item;
- box->roundbox->alignnr = nr;
+ if (!box->roundbox->alignnr) {
+ box->roundbox->alignnr = nr;
+ }
}
else if (((uiLayout *)item)->align) {
ui_item_align((uiLayout *)item, nr);
@@ -3212,7 +3234,7 @@ static void ui_item_layout(uiItem *item)
switch (litem->item.type) {
case ITEM_LAYOUT_COLUMN:
- ui_litem_layout_column(litem);
+ ui_litem_layout_column(litem, false);
break;
case ITEM_LAYOUT_COLUMN_FLOW:
ui_litem_layout_column_flow(litem);
@@ -3556,14 +3578,13 @@ void uiLayoutOperatorButs(
row = uiLayoutRow(layout, true);
uiItemM(row, (bContext *)C, "WM_MT_operator_presets", NULL, ICON_NONE);
- WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add");
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false);
+ op_ptr = uiItemFullO_ptr(row, ot, "", ICON_ZOOMIN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&op_ptr, "operator", op->type->idname);
- uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMIN, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
- WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add");
+ op_ptr = uiItemFullO_ptr(row, ot, "", ICON_ZOOMOUT, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&op_ptr, "operator", op->type->idname);
RNA_boolean_set(&op_ptr, "remove_active", true);
- uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMOUT, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
}
if (op->type->ui) {
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 466978272bc..0d9d8c4f887 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -811,11 +811,11 @@ int UI_searchbox_size_x(void)
return 12 * UI_UNIT_X;
}
-int UI_search_items_find_index(uiSearchItems *items, const char *name)
+int UI_search_items_find_index(uiSearchItems *items, const char *name, const size_t offset)
{
int i;
for (i = 0; i < items->totitem; i++) {
- if (STREQ(name, items->names[i])) {
+ if (STREQ(name, items->names[i] + offset)) {
return i;
}
}
@@ -894,7 +894,7 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr
int ui_searchbox_find_index(ARegion *ar, const char *name)
{
uiSearchboxData *data = ar->regiondata;
- return UI_search_items_find_index(&data->items, name);
+ return UI_search_items_find_index(&data->items, name, 0);
}
/* x and y in screencoords */
@@ -1420,14 +1420,14 @@ void ui_searchbox_free(bContext *C, ARegion *ar)
/* sets red alert if button holds a string it can't find */
/* XXX weak: search_func adds all partial matches... */
-void ui_but_search_refresh(uiBut *but)
+void ui_but_search_refresh(uiBut *but, const bool is_template_ID)
{
uiSearchItems *items;
int x1;
- /* possibly very large lists (such as ID datablocks) only
- * only validate string RNA buts (not pointers) */
- if (but->rnaprop && RNA_property_type(but->rnaprop) != PROP_STRING) {
+ /* possibly very large lists (such as ID datablocks),
+ * only validate string and pointer RNA buts */
+ if (but->rnaprop && !ELEM(RNA_property_type(but->rnaprop), PROP_STRING, PROP_POINTER)) {
return;
}
@@ -1447,7 +1447,8 @@ void ui_but_search_refresh(uiBut *but)
UI_but_flag_enable(but, UI_BUT_REDALERT);
}
else if (items->more == 0) {
- if (UI_search_items_find_index(items, but->drawstr) == -1) {
+ const size_t offset = is_template_ID ? 3 : 0;
+ if (UI_search_items_find_index(items, but->drawstr, offset) == -1) {
UI_but_flag_enable(but, UI_BUT_REDALERT);
}
}
@@ -1692,6 +1693,28 @@ static void ui_block_region_draw(const bContext *C, ARegion *ar)
UI_block_draw(C, block);
}
+/**
+ * Use to refresh centered popups on screen resizing (for splash).
+ */
+static void ui_block_region_popup_window_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+{
+ switch (wmn->category) {
+ case NC_WINDOW:
+ {
+ switch (wmn->action) {
+ case NA_EDITED:
+ {
+ /* window resize */
+ ED_region_tag_refresh_ui(ar);
+ break;
+ }
+ }
+ break;
+ }
+ }
+}
+
static void ui_popup_block_clip(wmWindow *window, uiBlock *block)
{
uiBut *bt;
@@ -2003,6 +2026,11 @@ uiPopupBlockHandle *ui_popup_block_create(
block = ui_popup_block_refresh(C, handle, butregion, but);
handle = block->handle;
+ /* keep centered on window resizing */
+ if ((block->bounds_type == UI_BLOCK_BOUNDS_POPUP_CENTER) && handle->can_refresh) {
+ type.listener = ui_block_region_popup_window_listener;
+ }
+
return handle;
}
@@ -3285,7 +3313,7 @@ void UI_popup_block_invoke(bContext *C, uiBlockCreateFunc func, void *arg)
UI_popup_block_invoke_ex(C, func, arg, NULL, WM_OP_INVOKE_DEFAULT);
}
-void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg)
+void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg, wmOperator *op)
{
wmWindow *window = CTX_wm_window(C);
uiPopupBlockHandle *handle;
@@ -3294,6 +3322,7 @@ void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc po
handle->popup = true;
handle->retvalue = 1;
+ handle->popup_op = op;
handle->popup_arg = arg;
handle->popup_func = popup_func;
handle->cancel_func = cancel_func;
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 131584dd405..a3541e641ed 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -451,6 +451,11 @@ static void template_ID(
but = uiDefButR(block, UI_BTYPE_TEXT, 0, name, 0, 0, UI_UNIT_X * 6, UI_UNIT_Y,
&idptr, "name", -1, 0, 0, -1, -1, RNA_struct_ui_description(type));
UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
+
+ but->search_func = id_search_cb;
+ but->search_arg = template;
+ ui_but_search_refresh(but, true);
+
if (user_alert) UI_but_flag_enable(but, UI_BUT_REDALERT);
if (id->lib) {
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index df6f098ee81..636b7e4e9ce 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -127,12 +127,10 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
break;
case PROP_POINTER:
{
- PointerRNA pptr;
-
- pptr = RNA_property_pointer_get(ptr, prop);
- if (!pptr.type)
- pptr.type = RNA_property_pointer_type(ptr, prop);
- icon = RNA_struct_ui_icon(pptr.type);
+ if (icon == 0) {
+ PointerRNA pptr = RNA_property_pointer_get(ptr, prop);
+ icon = RNA_struct_ui_icon(pptr.type ? pptr.type : RNA_property_pointer_type(ptr, prop));
+ }
if (icon == ICON_DOT)
icon = 0;
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 5ec0c49a8cd..f7f2b422724 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -874,24 +874,18 @@ static void widget_draw_icon(
float ofs = 1.0f / aspect;
if (but->drawflag & UI_BUT_ICON_LEFT) {
- if (but->block->flag & UI_BLOCK_LOOP) {
- if (but->type == UI_BTYPE_SEARCH_MENU)
- xs = rect->xmin + 4.0f * ofs;
- else
- xs = rect->xmin + ofs;
- }
- else {
- if (but->dt == UI_EMBOSS_NONE || but->type == UI_BTYPE_LABEL)
- xs = rect->xmin + 2.0f * ofs;
- else
- xs = rect->xmin + 4.0f * ofs;
- }
- ys = (rect->ymin + rect->ymax - height) / 2.0f;
+ /* special case - icon_only pie buttons */
+ if (ui_block_is_pie_menu(but->block) && but->type != UI_BTYPE_MENU && but->str && but->str[0] == '\0')
+ xs = rect->xmin + 2.0f * ofs;
+ else if (but->dt == UI_EMBOSS_NONE || but->type == UI_BTYPE_LABEL)
+ xs = rect->xmin + 2.0f * ofs;
+ else
+ xs = rect->xmin + 4.0f * ofs;
}
else {
xs = (rect->xmin + rect->xmax - height) / 2.0f;
- ys = (rect->ymin + rect->ymax - height) / 2.0f;
}
+ ys = (rect->ymin + rect->ymax - height) / 2.0f;
/* force positions to integers, for zoom levels near 1. draws icons crisp. */
if (aspect > 0.95f && aspect < 1.05f) {
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index 0e185cd93a7..139c9817437 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -97,7 +97,10 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int use_blender_profile;
int sort_by_name;
int export_transformation_type;
+
int open_sim;
+ int limit_precision;
+ int keep_bind_info;
int export_count;
@@ -148,6 +151,9 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
export_transformation_type = RNA_enum_get(op->ptr, "export_transformation_type_selection");
open_sim = RNA_boolean_get(op->ptr, "open_sim");
+ limit_precision = RNA_boolean_get(op->ptr, "limit_precision");
+ keep_bind_info = RNA_boolean_get(op->ptr, "keep_bind_info");
+
/* get editmode results */
ED_object_editmode_load(CTX_data_edit_object(C));
@@ -172,7 +178,11 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
use_blender_profile,
sort_by_name,
export_transformation_type,
- open_sim);
+
+ open_sim,
+ limit_precision,
+ keep_bind_info
+ );
if (export_count == 0) {
BKE_report(op->reports, RPT_WARNING, "No objects selected -- Created empty export file");
@@ -270,6 +280,12 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "sort_by_name", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "keep_bind_info", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "limit_precision", 0, NULL, ICON_NONE);
+
}
static void wm_collada_export_draw(bContext *UNUSED(C), wmOperator *op)
@@ -386,6 +402,13 @@ void WM_OT_collada_export(wmOperatorType *ot)
RNA_def_boolean(func, "open_sim", 0, "Export to SL/OpenSim",
"Compatibility mode for SL, OpenSim and other compatible online worlds");
+
+ RNA_def_boolean(func, "limit_precision", 0,
+ "Limit Precision", "Reduce the precision of the exported data to 6 digits");
+
+ RNA_def_boolean(func, "keep_bind_info", 0,
+ "Keep Bind Info", "Store Bindpose information in custom bone properties for later use during Collada export");
+
}
@@ -397,7 +420,9 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
int find_chains;
int auto_connect;
int fix_orientation;
- int min_chain_length;
+ int min_chain_length;
+
+ int keep_bind_info;
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
@@ -409,6 +434,9 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
find_chains = RNA_boolean_get(op->ptr, "find_chains");
auto_connect = RNA_boolean_get(op->ptr, "auto_connect");
fix_orientation = RNA_boolean_get(op->ptr, "fix_orientation");
+
+ keep_bind_info = RNA_boolean_get(op->ptr, "keep_bind_info");
+
min_chain_length = RNA_int_get(op->ptr, "min_chain_length");
RNA_string_get(op->ptr, "filepath", filename);
@@ -418,7 +446,8 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
find_chains,
auto_connect,
fix_orientation,
- min_chain_length))
+ min_chain_length,
+ keep_bind_info) )
{
return OPERATOR_FINISHED;
}
@@ -455,6 +484,13 @@ static void uiCollada_importSettings(uiLayout *layout, PointerRNA *imfptr)
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "min_chain_length", 0, NULL, ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "keep_bind_info", 0, NULL, ICON_NONE);
+
}
static void wm_collada_import_draw(bContext *UNUSED(C), wmOperator *op)
@@ -510,5 +546,9 @@ void WM_OT_collada_import(wmOperatorType *ot)
0,
INT_MAX);
+ RNA_def_boolean(ot->srna,
+ "keep_bind_info", 0, "Keep Bind Info",
+ "Store Bindpose information in custom bone properties for later use during Collada export");
+
}
#endif
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 743efb246ab..7faa1dd99e1 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -57,6 +57,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_material.h"
+#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_editmesh.h"
#include "BKE_multires.h"
@@ -596,6 +597,9 @@ int join_mesh_exec(bContext *C, wmOperator *op)
BKE_key_sort(key);
}
+ /* Due to dependnecy cycle some other object might access old derived data. */
+ BKE_object_free_derived_caches(ob);
+
DAG_relations_tag_update(bmain); /* removed objects, need to rebuild dag */
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index d601f5c3b14..1aa1407797b 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -793,7 +793,7 @@ void OBJECT_OT_modifier_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Add Modifier";
- ot->description = "Add a modifier to the active object";
+ ot->description = "Add a procedural operation/effect to the active object";
ot->idname = "OBJECT_OT_modifier_add";
/* api callbacks */
@@ -1484,7 +1484,6 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(ob);
BMesh *bm = em->bm;
- const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
BMVert *bm_vert;
BMIter bm_iter;
GSet *visited;
@@ -1493,6 +1492,8 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op))
BKE_mesh_ensure_skin_customdata(ob->data);
+ const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
+
BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT) &&
BLI_gset_add(visited, bm_vert))
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index b5fbe4ba586..861e249b0ee 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -72,6 +72,7 @@
#include "BKE_global.h"
#include "BKE_group.h"
#include "BKE_fcurve.h"
+#include "BKE_idprop.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
@@ -2101,6 +2102,34 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo
single_tex_users_expand(bmain);
}
+ /* Relink datablock pointer properties */
+ {
+ IDP_RelinkProperty(scene->id.properties);
+
+ for (Base *base = scene->base.first; base; base = base->next) {
+ Object *ob = base->object;
+ if (!ID_IS_LINKED_DATABLOCK(ob)) {
+ IDP_RelinkProperty(ob->id.properties);
+ }
+ }
+
+ if (scene->nodetree) {
+ IDP_RelinkProperty(scene->nodetree->id.properties);
+ for (bNode *node = scene->nodetree->nodes.first; node; node = node->next) {
+ IDP_RelinkProperty(node->prop);
+ }
+ }
+
+ if (scene->gpd) {
+ IDP_RelinkProperty(scene->gpd->id.properties);
+ }
+
+ IDP_RelinkProperty(scene->world->id.properties);
+
+ if (scene->clip) {
+ IDP_RelinkProperty(scene->clip->id.properties);
+ }
+ }
BKE_main_id_clear_newpoins(bmain);
DAG_relations_tag_update(bmain);
}
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 837573ad175..0878636d0fa 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -611,7 +611,7 @@ void WORLD_OT_new(wmOperatorType *ot)
/* identifiers */
ot->name = "New World";
ot->idname = "WORLD_OT_new";
- ot->description = "Add a new world";
+ ot->description = "Create a new world Data-Block";
/* api callbacks */
ot->exec = new_world_exec;
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 93bac3f6660..216cbe9d7f4 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -566,7 +566,7 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
float rast_x = x + off_x * xzoom;
float rast_y = y + off_y * yzoom;
- GLfloat scissor[4];
+ GLfloat viewport[4];
int draw_w, draw_h;
/* Determine the smallest number of pixels we need to draw
@@ -581,9 +581,9 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
* fails if we zoom in on one really huge pixel so that it
* covers the entire screen).
*/
- glGetFloatv(GL_SCISSOR_BOX, scissor);
- draw_w = min_ii(img_w - off_x, ceil((scissor[2] - rast_x) / xzoom));
- draw_h = min_ii(img_h - off_y, ceil((scissor[3] - rast_y) / yzoom));
+ glGetFloatv(GL_VIEWPORT, viewport);
+ draw_w = min_ii(img_w - off_x, ceil((viewport[2] - rast_x) / xzoom));
+ draw_h = min_ii(img_h - off_y, ceil((viewport[3] - rast_y) / yzoom));
if (draw_w > 0 && draw_h > 0) {
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index d88c36a8e24..c2e094fc161 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -2808,7 +2808,7 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent
bScreen *sc = CTX_wm_screen(C);
uiPopupMenu *pup;
uiLayout *layout;
- PointerRNA ptr1, ptr2;
+ PointerRNA ptr;
ScrEdge *actedge;
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
@@ -2820,22 +2820,17 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent
pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
layout = UI_popup_menu_layout(pup);
- WM_operator_properties_create(&ptr1, "SCREEN_OT_area_join");
-
- /* mouse cursor on edge, '4' can fail on wide edges... */
- RNA_int_set(&ptr1, "min_x", event->x + 4);
- RNA_int_set(&ptr1, "min_y", event->y + 4);
- RNA_int_set(&ptr1, "max_x", event->x - 4);
- RNA_int_set(&ptr1, "max_y", event->y - 4);
-
- WM_operator_properties_create(&ptr2, "SCREEN_OT_area_split");
-
+ ptr = uiItemFullO(layout, "SCREEN_OT_area_split", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
/* store initial mouse cursor position */
- RNA_int_set(&ptr2, "mouse_x", event->x);
- RNA_int_set(&ptr2, "mouse_y", event->y);
-
- uiItemFullO(layout, "SCREEN_OT_area_split", NULL, ICON_NONE, ptr2.data, WM_OP_INVOKE_DEFAULT, 0);
- uiItemFullO(layout, "SCREEN_OT_area_join", NULL, ICON_NONE, ptr1.data, WM_OP_INVOKE_DEFAULT, 0);
+ RNA_int_set(&ptr, "mouse_x", event->x);
+ RNA_int_set(&ptr, "mouse_y", event->y);
+
+ ptr = uiItemFullO(layout, "SCREEN_OT_area_join", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ /* mouse cursor on edge, '4' can fail on wide edges... */
+ RNA_int_set(&ptr, "min_x", event->x + 4);
+ RNA_int_set(&ptr, "min_y", event->y + 4);
+ RNA_int_set(&ptr, "max_x", event->x - 4);
+ RNA_int_set(&ptr, "max_y", event->y - 4);
UI_popup_menu_end(C, pup);
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index c2c52f58181..e273d3a40f0 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -670,7 +670,7 @@ static void SOUND_OT_mixdown(wmOperatorType *ot)
/* identifiers */
ot->name = "Mixdown";
- ot->description = "Mixes the scene's audio to a sound file";
+ ot->description = "Mix the scene's audio to a sound file";
ot->idname = "SOUND_OT_mixdown";
/* api callbacks */
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index b7871225306..646541c7bd9 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -72,7 +72,7 @@ void clip_graph_tracking_values_iterate_track(
BKE_movieclip_get_size(clip, &sc->user, &width, &height);
for (coord = 0; coord < 2; coord++) {
- int i, prevfra = 0;
+ int i, prevfra = track->markers[0].framenr;
bool open = false;
float prevval = 0.0f;
@@ -179,6 +179,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
bool has_bundle = false;
char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2];
+ const bool used_for_stabilization = (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT));
if (track == act_track)
tracking->act_track = NULL;
@@ -200,7 +201,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
- if (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)) {
+ if (used_for_stabilization) {
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index d7aa1040e0f..71d49e0dc2e 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -169,12 +169,15 @@ void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path)
static void fsmenu_entry_generate_name(struct FSMenuEntry *fsentry, char *name, size_t name_size)
{
- char temp[FILE_MAX];
+ int offset = 0;
+ int len = name_size;
- BLI_strncpy(temp, fsentry->path, FILE_MAX);
- BLI_add_slash(temp);
- BLI_getlastdir(temp, name, name_size);
- BLI_del_slash(name);
+ if (BLI_path_name_at_index(fsentry->path, -1, &offset, &len)) {
+ /* use as size */
+ len += 1;
+ }
+
+ BLI_strncpy(name, &fsentry->path[offset], MIN2(len, name_size));
if (!name[0]) {
name[0] = '/';
name[1] = '\0';
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index d31a475e45e..e4f5802a395 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -1320,9 +1320,6 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point
PropertyRNA *prop;
const char *layer_name;
char scene_name[MAX_ID_NAME - 2];
- wmOperatorType *ot = WM_operatortype_find("RENDER_OT_render", 1);
-
- BLI_assert(ot != 0);
uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL);
@@ -1339,11 +1336,9 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point
scn_ptr = RNA_pointer_get(ptr, "scene");
RNA_string_get(&scn_ptr, "name", scene_name);
- WM_operator_properties_create_ptr(&op_ptr, ot);
+ op_ptr = uiItemFullO(row, "RENDER_OT_render", "", ICON_RENDER_STILL, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&op_ptr, "layer", layer_name);
RNA_string_set(&op_ptr, "scene", scene_name);
- uiItemFullO_ptr(row, ot, "", ICON_RENDER_STILL, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
-
}
@@ -1792,6 +1787,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
Scene *scene = CTX_data_scene(C);
PointerRNA imfptr = RNA_pointer_get(ptr, "format");
PointerRNA active_input_ptr, op_ptr;
+ wmOperatorType *ot;
uiLayout *row, *col;
int active_index;
const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
@@ -1830,11 +1826,10 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
active_input_ptr.id.data = ptr->id.data;
col = uiLayoutColumn(row, true);
- op_ptr = uiItemFullO(col, "NODE_OT_output_file_move_active_socket", "",
- ICON_TRIA_UP, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false);
+ op_ptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&op_ptr, "direction", 1);
- op_ptr = uiItemFullO(col, "NODE_OT_output_file_move_active_socket", "",
- ICON_TRIA_DOWN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ op_ptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&op_ptr, "direction", 2);
if (active_input_ptr.data) {
@@ -2166,14 +2161,7 @@ static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), Poi
static void node_composit_buts_switch_view_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *UNUSED(ptr))
{
- PointerRNA op_ptr;
- wmOperatorType *ot = WM_operatortype_find("NODE_OT_switch_view_update", 1);
-
- BLI_assert(ot != 0);
-
- WM_operator_properties_create_ptr(&op_ptr, ot);
-
- uiItemFullO_ptr(layout, ot, "Update Views", ICON_FILE_REFRESH, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
+ uiItemFullO(layout, "NODE_OT_switch_view_update", "Update Views", ICON_FILE_REFRESH, NULL, WM_OP_INVOKE_DEFAULT, 0);
}
static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index d49df2afbd4..bcd0f6623e1 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -44,6 +44,8 @@
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_texture.h"
#include "ED_node.h" /* own include */
#include "ED_screen.h"
@@ -312,7 +314,10 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
switch (snode->nodetree->type) {
case NTREE_SHADER:
- type = SH_NODE_TEX_IMAGE;
+ if (BKE_scene_use_new_shading_nodes(CTX_data_scene(C)))
+ type = SH_NODE_TEX_IMAGE;
+ else
+ type = SH_NODE_TEXTURE;
break;
case NTREE_TEXTURE:
type = TEX_NODE_IMAGE;
@@ -333,7 +338,14 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- node->id = (ID *)ima;
+ if (type == SH_NODE_TEXTURE) {
+ Tex *tex = BKE_texture_add(CTX_data_main(C), DATA_(ima->id.name));
+ tex->ima = ima;
+ node->id = (ID *)tex;
+ WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, node->id);
+ }
+ else
+ node->id = (ID *)ima;
/* When adding new image file via drag-drop we need to load imbuf in order
* to get proper image source.
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
index f0567924edd..925298451ce 100644
--- a/source/blender/editors/space_node/node_buttons.c
+++ b/source/blender/editors/space_node/node_buttons.c
@@ -133,6 +133,7 @@ static void node_tree_interface_panel(const bContext *C, Panel *pa)
int in_out;
uiLayout *layout = pa->layout, *row, *split, *col;
PointerRNA ptr, sockptr, opptr;
+ wmOperatorType *ot;
if (!ntree)
return;
@@ -146,23 +147,25 @@ static void node_tree_interface_panel(const bContext *C, Panel *pa)
split = uiLayoutRow(row, true);
col = uiLayoutColumn(split, true);
+ ot = WM_operatortype_find("NODE_OT_tree_socket_add", false);
uiItemL(col, IFACE_("Inputs:"), ICON_NONE);
uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "inputs", &ptr, "inputs", &ptr, "active_input",
NULL, 0, 0, 0, 0);
- opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ opptr = uiItemFullO_ptr(col, ot, "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "in_out", SOCK_IN);
col = uiLayoutColumn(split, true);
uiItemL(col, IFACE_("Outputs:"), ICON_NONE);
uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "outputs", &ptr, "outputs", &ptr, "active_output",
NULL, 0, 0, 0, 0);
- opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ opptr = uiItemFullO_ptr(col, ot, "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "in_out", SOCK_OUT);
+ ot = WM_operatortype_find("NODE_OT_tree_socket_move", false);
col = uiLayoutColumn(row, true);
- opptr = uiItemFullO(col, "NODE_OT_tree_socket_move", "", ICON_TRIA_UP, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ opptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "direction", 1);
- opptr = uiItemFullO(col, "NODE_OT_tree_socket_move", "", ICON_TRIA_DOWN, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ opptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "direction", 2);
if (sock) {
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 42d9e4356ee..121fe812016 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -1052,8 +1052,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT;
x += 2.0f * aspect;
y += 2.0f * aspect;
- arg.x = x = x;
- arg.y = y = y;
+ arg.x = x;
+ arg.y = y;
if (tselem->type) {
switch (tselem->type) {
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 8c3b9a55089..335eb95da0e 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -519,7 +519,8 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
ot->flag = 0;
- RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
+ prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace");
RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf);
@@ -2071,74 +2072,62 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false);
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE);
uiLayout *layout = UI_popup_menu_layout(pup);
-
PointerRNA ptr;
- WM_operator_properties_create_ptr(&ptr, ot);
+ /* Cannot use uiItemEnumO()... have multiple properties to set. */
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_OBJECT);
- /* Cannot use uiItemEnumO()... have multiple properties to set. */
- uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
+
/* par becomes parent, make the associated menus */
if (par->type == OB_ARMATURE) {
- WM_operator_properties_create_ptr(&ptr, ot);
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_ARMATURE);
- uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_(" With Empty Groups"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME);
- uiItemFullO_ptr(layout, ot, IFACE_(" With Empty Groups"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_(" With Envelope Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE);
- uiItemFullO_ptr(layout, ot, IFACE_(" With Envelope Weights"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_(" With Automatic Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO);
- uiItemFullO_ptr(layout, ot, IFACE_(" With Automatic Weights"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Bone"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_BONE);
- uiItemFullO_ptr(layout, ot, IFACE_("Bone"),
- 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
}
else if (par->type == OB_CURVE) {
- WM_operator_properties_create_ptr(&ptr, ot);
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_CURVE);
- uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_FOLLOW);
- uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_PATH_CONST);
- uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
}
else if (par->type == OB_LATTICE) {
- WM_operator_properties_create_ptr(&ptr, ot);
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_LATTICE);
- uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
}
UI_popup_menu_end(C, pup);
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index ede6b7ce469..46f212e3679 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -38,6 +38,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "DNA_scene_types.h"
#include "DNA_mask_types.h"
@@ -445,6 +447,7 @@ void SEQUENCER_OT_movieclip_strip_add(struct wmOperatorType *ot)
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
prop = RNA_def_enum(ot->srna, "clip", DummyRNA_NULL_items, 0, "Clip", "");
RNA_def_enum_funcs(prop, RNA_movieclip_itemf);
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_MOVIECLIP);
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
ot->prop = prop;
}
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index be2e4ab05e0..335d0649729 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -1824,16 +1824,16 @@ static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], con
glBegin(mode);
glVertex3fv(near_plane[2]);
- glVertex3fv(near_plane[1]);
- glVertex3fv(far_plane[1]);
glVertex3fv(far_plane[2]);
+ glVertex3fv(far_plane[3]);
+ glVertex3fv(near_plane[3]);
glEnd();
glBegin(mode);
- glVertex3fv(far_plane[0]);
- glVertex3fv(near_plane[0]);
- glVertex3fv(near_plane[3]);
glVertex3fv(far_plane[3]);
+ glVertex3fv(near_plane[3]);
+ glVertex3fv(near_plane[0]);
+ glVertex3fv(far_plane[0]);
glEnd();
}
@@ -4212,7 +4212,6 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
if (is_obact && BKE_paint_select_vert_test(ob)) {
const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) != 0;
- glColor3f(0.0f, 0.0f, 0.0f);
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
if (!use_depth) glDisable(GL_DEPTH_TEST);
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 351c7ccec15..34e01405e7e 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -814,10 +814,6 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
if (dv && dv->totweight) {
ToolSettings *ts = scene->toolsettings;
- wmOperatorType *ot_weight_set_active = WM_operatortype_find("OBJECT_OT_vertex_weight_set_active", true);
- wmOperatorType *ot_weight_paste = WM_operatortype_find("OBJECT_OT_vertex_weight_paste", true);
- wmOperatorType *ot_weight_delete = WM_operatortype_find("OBJECT_OT_vertex_weight_delete", true);
-
wmOperatorType *ot;
PointerRNA op_ptr, tools_ptr;
PointerRNA *but_ptr;
@@ -856,7 +852,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
/* The Weight Group Name */
- ot = ot_weight_set_active;
+ ot = WM_operatortype_find("OBJECT_OT_vertex_weight_set_active", true);
but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, WM_OP_EXEC_DEFAULT, dg->name,
xco, yco, (x = UI_UNIT_X * 5), UI_UNIT_Y, "");
but_ptr = UI_but_operator_ptr_get(but);
@@ -882,23 +878,16 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
xco += x;
/* The weight group paste function */
-
- ot = ot_weight_paste;
- WM_operator_properties_create_ptr(&op_ptr, ot);
- RNA_int_set(&op_ptr, "weight_group", i);
icon = (locked) ? ICON_BLANK1 : ICON_PASTEDOWN;
- uiItemFullO_ptr(row, ot, "", icon, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
+ op_ptr = uiItemFullO(row, "OBJECT_OT_vertex_weight_paste", "", icon, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ RNA_int_set(&op_ptr, "weight_group", i);
/* The weight entry delete function */
-
- ot = ot_weight_delete;
- WM_operator_properties_create_ptr(&op_ptr, ot);
- RNA_int_set(&op_ptr, "weight_group", i);
icon = (locked) ? ICON_LOCKED : ICON_X;
- uiItemFullO_ptr(row, ot, "", icon, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
+ op_ptr = uiItemFullO(row, "OBJECT_OT_vertex_weight_delete", "", icon, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ RNA_int_set(&op_ptr, "weight_group", i);
yco -= UI_UNIT_Y;
-
}
}
}
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 8230a0de6b9..fe8274064e5 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -1405,6 +1405,8 @@ static bool view3d_localview_init(
}
}
+ DAG_on_visible_update(bmain, false);
+
return ok;
}
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 0a984d90ae3..f23c913da1e 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -143,21 +143,17 @@ static void protectflag_to_drawflags(short protectflag, short *drawflags)
}
/* for pose mode */
-static void stats_pose(Scene *scene, RegionView3D *rv3d, bPoseChannel *pchan)
+static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan)
{
- Bone *bone = pchan->bone;
-
- if (bone) {
- calc_tw_center(scene, pchan->pose_head);
- protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
- }
+ protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
}
/* for editmode*/
-static void stats_editbone(RegionView3D *rv3d, EditBone *ebo)
+static void protectflag_to_drawflags_ebone(RegionView3D *rv3d, const EditBone *ebo)
{
- if (ebo->flag & BONE_EDITMODE_LOCKED)
+ if (ebo->flag & BONE_EDITMODE_LOCKED) {
protectflag_to_drawflags(OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE, &rv3d->twdrawflag);
+ }
}
/* could move into BLI_math however this is only useful for display/editing purposes */
@@ -192,73 +188,71 @@ static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], con
}
-static int test_rotmode_euler(short rotmode)
+static bool test_rotmode_euler(short rotmode)
{
return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1;
}
bool gimbal_axis(Object *ob, float gmat[3][3])
{
- if (ob) {
- if (ob->mode & OB_MODE_POSE) {
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
-
- if (pchan) {
- float mat[3][3], tmat[3][3], obmat[3][3];
- if (test_rotmode_euler(pchan->rotmode)) {
- eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
- }
- else { /* quat */
- return 0;
- }
-
-
- /* apply bone transformation */
- mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
+ if (ob->mode & OB_MODE_POSE) {
+ bPoseChannel *pchan = BKE_pose_channel_active(ob);
- if (pchan->parent) {
- float parent_mat[3][3];
-
- copy_m3_m4(parent_mat, pchan->parent->pose_mat);
- mul_m3_m3m3(mat, parent_mat, tmat);
-
- /* needed if object transformation isn't identity */
- copy_m3_m4(obmat, ob->obmat);
- mul_m3_m3m3(gmat, obmat, mat);
- }
- else {
- /* needed if object transformation isn't identity */
- copy_m3_m4(obmat, ob->obmat);
- mul_m3_m3m3(gmat, obmat, tmat);
- }
-
- normalize_m3(gmat);
- return 1;
- }
- }
- else {
- if (test_rotmode_euler(ob->rotmode)) {
- eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
+ if (pchan) {
+ float mat[3][3], tmat[3][3], obmat[3][3];
+ if (test_rotmode_euler(pchan->rotmode)) {
+ eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
}
- else if (ob->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
}
else { /* quat */
return 0;
}
- if (ob->parent) {
+
+ /* apply bone transformation */
+ mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
+
+ if (pchan->parent) {
float parent_mat[3][3];
- copy_m3_m4(parent_mat, ob->parent->obmat);
- normalize_m3(parent_mat);
- mul_m3_m3m3(gmat, parent_mat, gmat);
+
+ copy_m3_m4(parent_mat, pchan->parent->pose_mat);
+ mul_m3_m3m3(mat, parent_mat, tmat);
+
+ /* needed if object transformation isn't identity */
+ copy_m3_m4(obmat, ob->obmat);
+ mul_m3_m3m3(gmat, obmat, mat);
+ }
+ else {
+ /* needed if object transformation isn't identity */
+ copy_m3_m4(obmat, ob->obmat);
+ mul_m3_m3m3(gmat, obmat, tmat);
}
+
+ normalize_m3(gmat);
return 1;
}
}
+ else {
+ if (test_rotmode_euler(ob->rotmode)) {
+ eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
+ }
+ else if (ob->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
+ }
+ else { /* quat */
+ return 0;
+ }
+
+ if (ob->parent) {
+ float parent_mat[3][3];
+ copy_m3_m4(parent_mat, ob->parent->obmat);
+ normalize_m3(parent_mat);
+ mul_m3_m3m3(gmat, parent_mat, gmat);
+ }
+ return 1;
+ }
return 0;
}
@@ -385,7 +379,7 @@ static int calc_manipulator_stats(const bContext *C)
calc_tw_center(scene, ebo->head);
totsel++;
}
- stats_editbone(rv3d, ebo);
+ protectflag_to_drawflags_ebone(rv3d, ebo);
}
else {
for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
@@ -405,7 +399,7 @@ static int calc_manipulator_stats(const bContext *C)
totsel++;
}
if (ebo->flag & BONE_SELECTED) {
- stats_editbone(rv3d, ebo);
+ protectflag_to_drawflags_ebone(rv3d, ebo);
}
}
}
@@ -530,7 +524,8 @@ static int calc_manipulator_stats(const bContext *C)
/* doesn't check selection or visibility intentionally */
Bone *bone = pchan->bone;
if (bone) {
- stats_pose(scene, rv3d, pchan);
+ calc_tw_center(scene, pchan->pose_head);
+ protectflag_to_drawflags_pchan(rv3d, pchan);
totsel = 1;
ok = true;
}
@@ -543,7 +538,8 @@ static int calc_manipulator_stats(const bContext *C)
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
Bone *bone = pchan->bone;
if (bone && (bone->flag & BONE_TRANSFORM)) {
- stats_pose(scene, rv3d, pchan);
+ calc_tw_center(scene, pchan->pose_head);
+ protectflag_to_drawflags_pchan(rv3d, pchan);
}
}
ok = true;
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 058af768885..674d2c376bb 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -451,7 +451,7 @@ void initTransformOrientation(bContext *C, TransInfo *t)
case V3D_MANIP_GIMBAL:
unit_m3(t->spacemtx);
- if (gimbal_axis(ob, t->spacemtx)) {
+ if (ob && gimbal_axis(ob, t->spacemtx)) {
BLI_strncpy(t->spacename, IFACE_("gimbal"), sizeof(t->spacename));
break;
}
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 3c9becc60dc..b33528b4149 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -1122,15 +1122,14 @@ static bool snapDerivedMesh(
float dist_px_sq = dist_squared_to_projected_aabb_simple(
lpmat, snapdata->win_half, ray_min_dist, snapdata->mval,
ray_org_local, ray_normal_local, bb->vec[0], bb->vec[6]);
- if (dist_px_sq > SQUARE(*dist_px))
- {
+ if (dist_px_sq > SQUARE(*dist_px)) {
return retval;
}
}
else {
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
if (!isect_ray_aabb_v3_simple(
- ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], NULL, NULL))
+ ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], NULL, NULL))
{
return retval;
}
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 0d92d22a173..6db23686832 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -98,6 +98,7 @@ typedef enum GPUBuiltin {
GPU_PARTICLE_ANG_VELOCITY = (1 << 12),
GPU_LOC_TO_VIEW_MATRIX = (1 << 13),
GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14),
+ GPU_OBJECT_INFO = (1 << 15)
} GPUBuiltin;
typedef enum GPUOpenGLBuiltin {
@@ -213,6 +214,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link);
void GPU_material_enable_alpha(GPUMaterial *material);
+GPUBuiltin GPU_get_material_builtins(GPUMaterial *material);
GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]);
/* High level functions to create and use GPU materials */
@@ -230,7 +232,7 @@ void GPU_material_bind(
float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock);
void GPU_material_bind_uniforms(
GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4],
- float autobumpscale, GPUParticleInfo *pi);
+ float autobumpscale, GPUParticleInfo *pi, float object_info[3]);
void GPU_material_unbind(GPUMaterial *material);
bool GPU_material_bound(GPUMaterial *material);
struct Scene *GPU_material_scene(GPUMaterial *material);
@@ -345,6 +347,7 @@ struct GPUParticleInfo
float location[3];
float velocity[3];
float angular_velocity[3];
+ int random_id;
};
#ifdef WITH_OPENSUBDIV
diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c
index a2b89239344..8505bd847a0 100644
--- a/source/blender/gpu/intern/gpu_basic_shader.c
+++ b/source/blender/gpu/intern/gpu_basic_shader.c
@@ -407,7 +407,7 @@ static GPUShader *gpu_basic_shader(int options)
return shader;
}
-static void GPU_basic_shader_uniform_autoset(GPUShader *shader, int options)
+static void gpu_basic_shader_uniform_autoset(GPUShader *shader, int options)
{
if (options & GPU_SHADER_LINE) {
glGetIntegerv(GL_VIEWPORT, &GPU_MATERIAL_STATE.viewport[0]);
@@ -443,7 +443,7 @@ void GPU_basic_shader_bind(int options)
if (shader) {
GPU_shader_bind(shader);
- GPU_basic_shader_uniform_autoset(shader, options);
+ gpu_basic_shader_uniform_autoset(shader, options);
}
}
else {
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 370841327aa..3325240a2d1 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -743,7 +743,7 @@ void GPU_triangle_setup(struct DerivedMesh *dm)
GLStates |= GPU_BUFFER_ELEMENT_STATE;
}
-static int GPU_typesize(int type)
+static int gpu_typesize(int type)
{
switch (type) {
case GL_FLOAT:
@@ -766,7 +766,7 @@ int GPU_attrib_element_size(GPUAttrib data[], int numdata)
int i, elementsize = 0;
for (i = 0; i < numdata; i++) {
- int typesize = GPU_typesize(data[i].type);
+ int typesize = gpu_typesize(data[i].type);
if (typesize != 0)
elementsize += typesize * data[i].size;
}
@@ -803,7 +803,7 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda
glVertexAttribPointer(data[i].index, data[i].size, data[i].type,
GL_TRUE, elementsize, BUFFER_OFFSET(offset));
- offset += data[i].size * GPU_typesize(data[i].type);
+ offset += data[i].size * gpu_typesize(data[i].type);
attribData[i].index = data[i].index;
attribData[i].size = data[i].size;
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 211394e7932..b5512aa108d 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -360,7 +360,7 @@ static void codegen_print_datatype(DynStr *ds, const GPUType type, float *data)
BLI_dynstr_appendf(ds, "%s(", GPU_DATATYPE_STR[type]);
for (i = 0; i < type; i++) {
- BLI_dynstr_appendf(ds, "%f", data[i]);
+ BLI_dynstr_appendf(ds, "%.12f", data[i]);
if (i == type - 1)
BLI_dynstr_append(ds, ")");
else
@@ -410,6 +410,8 @@ const char *GPU_builtin_name(GPUBuiltin builtin)
return "unfparticlevel";
else if (builtin == GPU_PARTICLE_ANG_VELOCITY)
return "unfparticleangvel";
+ else if (builtin == GPU_OBJECT_INFO)
+ return "unfobjectinfo";
else
return "";
}
diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c
index 964c2b5051e..2f2a16f9e1d 100644
--- a/source/blender/gpu/intern/gpu_compositing.c
+++ b/source/blender/gpu/intern/gpu_compositing.c
@@ -798,7 +798,9 @@ bool GPU_fx_do_composite_pass(
ssao_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_SSAO, is_persp);
if (ssao_shader) {
const GPUSSAOSettings *fx_ssao = fx->settings.ssao;
- float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, fx_ssao->attenuation, 0.0f};
+ /* adjust attenuation to be scale invariant */
+ float attenuation = fx_ssao->attenuation / (fx_ssao->distance_max * fx_ssao->distance_max);
+ float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, attenuation, 0.0f};
float sample_params[3];
sample_params[0] = fx->ssao_sample_count_cache;
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 7936811ab4d..79934190cbc 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -45,6 +45,7 @@
#include "BLI_math.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLI_hash.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
@@ -1203,7 +1204,7 @@ void GPU_paint_set_mipmap(bool mipmap)
/* check if image has been downscaled and do scaled partial update */
-static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h)
+static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h)
{
if ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) ||
is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y))
@@ -1296,7 +1297,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
bool is_data = (ima->tpageflag & IMA_GLBIND_IS_DATA) != 0;
IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data);
- if (GPU_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) {
+ if (gpu_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) {
MEM_freeN(buffer);
BKE_image_release_ibuf(ima, ibuf, NULL);
return;
@@ -1320,7 +1321,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
return;
}
- if (GPU_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) {
+ if (gpu_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) {
BKE_image_release_ibuf(ima, ibuf, NULL);
return;
}
@@ -1870,7 +1871,7 @@ void GPU_begin_object_materials(
GPU_object_material_unbind();
}
-static int GPU_get_particle_info(GPUParticleInfo *pi)
+static int gpu_get_particle_info(GPUParticleInfo *pi)
{
DupliObject *dob = GMS.dob;
if (dob->particle_system) {
@@ -1899,6 +1900,21 @@ static int GPU_get_particle_info(GPUParticleInfo *pi)
return 0;
}
+static void GPU_get_object_info(float oi[3], Material *mat)
+{
+ Object *ob = GMS.gob;
+ oi[0] = ob->index;
+ oi[1] = mat->index;
+ unsigned int random;
+ if (GMS.dob) {
+ random = GMS.dob->random_id;
+ }
+ else {
+ random = BLI_hash_int_2d(BLI_hash_string(GMS.gob->id.name + 2), 0);
+ }
+ oi[2] = random * (1.0f/(float)0xFFFFFFFF);
+}
+
int GPU_object_material_bind(int nr, void *attribs)
{
GPUVertexAttribs *gattribs = attribs;
@@ -1958,21 +1974,27 @@ int GPU_object_material_bind(int nr, void *attribs)
/* bind glsl material and get attributes */
Material *mat = GMS.gmatbuf[nr];
GPUParticleInfo partile_info;
+ float object_info[3] = {0};
float auto_bump_scale;
GPUMaterial *gpumat = GPU_material_from_blender(GMS.gscene, mat, GMS.is_opensubdiv);
GPU_material_vertex_attributes(gpumat, gattribs);
- if (GMS.dob)
- GPU_get_particle_info(&partile_info);
+ if (GMS.dob) {
+ gpu_get_particle_info(&partile_info);
+ }
+
+ if (GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) {
+ GPU_get_object_info(object_info, mat);
+ }
GPU_material_bind(
gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT),
GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock);
auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f;
- GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info);
+ GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info, object_info);
GMS.gboundmat = mat;
/* for glsl use alpha blend mode, unless it's set to solid and
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
index f62ef677434..e7a8beae5cc 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -52,7 +52,7 @@ struct GPUFrameBuffer {
GPUTexture *depthtex;
};
-static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
+static void gpu_print_framebuffer_error(GLenum status, char err_out[256])
{
const char *err = "unknown";
@@ -164,7 +164,7 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot
if (error == GL_INVALID_OPERATION) {
GPU_framebuffer_restore();
- GPU_print_framebuffer_error(error, err_out);
+ gpu_print_framebuffer_error(error, err_out);
return 0;
}
@@ -331,7 +331,7 @@ bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
GPU_framebuffer_restore();
- GPU_print_framebuffer_error(status, err_out);
+ gpu_print_framebuffer_error(status, err_out);
return false;
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 4e2043471b6..1f3ae7f708a 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -122,6 +122,8 @@ struct GPUMaterial {
int partvel;
int partangvel;
+ int objectinfoloc;
+
ListBase lamps;
bool bound;
@@ -225,7 +227,7 @@ static void gpu_material_set_attrib_id(GPUMaterial *material)
attribs->totlayer = b;
}
-static int GPU_material_construct_end(GPUMaterial *material, const char *passname)
+static int gpu_material_construct_end(GPUMaterial *material, const char *passname)
{
if (material->outlink) {
GPUNodeLink *outlink = material->outlink;
@@ -268,6 +270,8 @@ static int GPU_material_construct_end(GPUMaterial *material, const char *passnam
material->partvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_VELOCITY));
if (material->builtins & GPU_PARTICLE_ANG_VELOCITY)
material->partangvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_ANG_VELOCITY));
+ if (material->builtins & GPU_OBJECT_INFO)
+ material->objectinfoloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_INFO));
return 1;
}
else {
@@ -398,9 +402,14 @@ void GPU_material_bind(
}
}
+GPUBuiltin GPU_get_material_builtins(GPUMaterial *material)
+{
+ return material->builtins;
+}
+
void GPU_material_bind_uniforms(
GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4],
- float autobumpscale, GPUParticleInfo *pi)
+ float autobumpscale, GPUParticleInfo *pi, float object_info[3])
{
if (material->pass) {
GPUShader *shader = GPU_pass_shader(material->pass);
@@ -449,6 +458,9 @@ void GPU_material_bind_uniforms(
if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) {
GPU_shader_uniform_vector(shader, material->partangvel, 3, 1, pi->angular_velocity);
}
+ if (material->builtins & GPU_OBJECT_INFO) {
+ GPU_shader_uniform_vector(shader, material->objectinfoloc, 3, 1, object_info);
+ }
}
}
@@ -1891,7 +1903,7 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, bool use_opensubdiv
GPU_material_output_link(mat, outlink);
- GPU_material_construct_end(mat, "matcap_pass");
+ gpu_material_construct_end(mat, "matcap_pass");
/* note that even if building the shader fails in some way, we still keep
* it to avoid trying to compile again and again, and simple do not use
@@ -2044,7 +2056,7 @@ static void do_world_tex(GPUShadeInput *shi, struct World *wo, GPUNodeLink **hor
}
}
-static void GPU_material_old_world(struct GPUMaterial *mat, struct World *wo)
+static void gpu_material_old_world(struct GPUMaterial *mat, struct World *wo)
{
GPUShadeInput shi;
GPUShadeResult shr;
@@ -2112,17 +2124,18 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo)
mat->type = GPU_MATERIAL_TYPE_WORLD;
/* create nodes */
- if (BKE_scene_use_new_shading_nodes(scene) && wo->nodetree && wo->use_nodes)
+ if (BKE_scene_use_new_shading_nodes(scene) && wo->nodetree && wo->use_nodes) {
ntreeGPUMaterialNodes(wo->nodetree, mat, NODE_NEW_SHADING);
+ }
else {
- GPU_material_old_world(mat, wo);
+ gpu_material_old_world(mat, wo);
}
if (GPU_material_do_color_management(mat))
if (mat->outlink)
GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink);
- GPU_material_construct_end(mat, wo->id.name);
+ gpu_material_construct_end(mat, wo->id.name);
/* note that even if building the shader fails in some way, we still keep
* it to avoid trying to compile again and again, and simple do not use
@@ -2188,7 +2201,7 @@ GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_open
if (mat->outlink)
GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink);
- GPU_material_construct_end(mat, ma->id.name);
+ gpu_material_construct_end(mat, ma->id.name);
/* note that even if building the shader fails in some way, we still keep
* it to avoid trying to compile again and again, and simple do not use
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 14f2764b009..b579f87698c 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -39,6 +39,7 @@
#include "GPU_glew.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
+#include "GPU_material.h"
/* TODO(sergey): Find better default values for this constants. */
#define MAX_DEFINE_LENGTH 1024
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 54f0003c086..1c97c2ce811 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -79,7 +79,7 @@ static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixel
return pixels;
}
-static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
+static void gpu_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
{
void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels");
@@ -193,7 +193,7 @@ static GPUTexture *GPU_texture_create_nD(
pixels ? pixels : fpixels);
if (tex->w > w) {
- GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1);
+ gpu_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1);
}
}
}
@@ -210,10 +210,12 @@ static GPUTexture *GPU_texture_create_nD(
glTexSubImage2D(tex->target, 0, 0, 0, w, h,
format, type, pixels ? pixels : fpixels);
- if (tex->w > w)
- GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, tex->h);
- if (tex->h > h)
- GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h - h);
+ if (tex->w > w) {
+ gpu_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, tex->h);
+ }
+ if (tex->h > h) {
+ gpu_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h - h);
+ }
}
}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
index 50c8e255162..f19ff4ec65a 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
@@ -75,7 +75,7 @@ float calculate_ssao_factor(float depth)
float f = dot(dir, normal);
/* use minor bias here to avoid self shadowing */
- if (f > 0.05 * len + 0.0001)
+ if (f > 0.05 * len)
factor += f * 1.0 / (len * (1.0 + len * len * ssao_params.z));
}
}
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 0f3ffa8244b..c354b274f00 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -3563,12 +3563,12 @@ void node_light_falloff(float strength, float tsmooth, out float quadratic, out
constant = strength;
}
-void node_object_info(out vec3 location, out float object_index, out float material_index, out float random)
+void node_object_info(mat4 obmat, vec3 info, out vec3 location, out float object_index, out float material_index, out float random)
{
- location = vec3(0.0);
- object_index = 0.0;
- material_index = 0.0;
- random = 0.0;
+ location = obmat[3].xyz;
+ object_index = info.x;
+ material_index = info.y;
+ random = info.z;
}
void node_normal_map(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 48cba3e0800..0881a24422d 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -1406,7 +1406,7 @@ static void *do_display_buffer_apply_thread(void *handle_v)
bool is_data = handle->is_data;
if (cm_processor == NULL) {
- if (display_buffer_byte) {
+ if (display_buffer_byte && display_buffer_byte != handle->byte_buffer) {
IMB_buffer_byte_from_byte(display_buffer_byte, handle->byte_buffer, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
false, width, height, width, width);
}
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 2c6f3d2fc66..da0f505c4f3 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -82,8 +82,6 @@ enum {
IDP_FLOAT = 2,
IDP_ARRAY = 5,
IDP_GROUP = 6,
- /* the ID link property type hasn't been implemented yet, this will require
- * some cleanup of blenkernel, most likely. */
IDP_ID = 7,
IDP_DOUBLE = 8,
IDP_IDPARRAY = 9,
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 621807d111c..3676066a399 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -164,8 +164,8 @@ typedef struct MLoop {
* MEdge *ed = &medge[mloop[lt->tri[j]].e];
* unsigned int tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v};
*
- * if (ELEM(ed->v1, tri_edge[0], tri_edge[1]) &&
- * ELEM(ed->v2, tri_edge[0], tri_edge[1]))
+ * if (((ed->v1 == tri_edge[0]) && (ed->v1 == tri_edge[1])) ||
+ * ((ed->v1 == tri_edge[1]) && (ed->v1 == tri_edge[0])))
* {
* printf("real edge found %u %u\n", tri_edge[0], tri_edge[1]);
* }
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 32b43c7ea55..823a7f0812f 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -277,6 +277,7 @@ typedef struct MirrorModifierData {
short axis DNA_DEPRECATED; /* deprecated, use flag instead */
short flag;
float tolerance;
+ float uv_offset[2];
struct Object *mirror_ob;
} MirrorModifierData;
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index d24c7faa9f5..6d79e6d49f8 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -335,6 +335,8 @@ typedef struct DupliObject {
/* particle this dupli was generated from */
struct ParticleSystem *particle_system;
+ unsigned int random_id;
+ unsigned int pad;
} DupliObject;
/* **************** OBJECT ********************* */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index fc970c40c12..61b580c0904 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -468,13 +468,18 @@ typedef struct UserDef {
int audioformat;
int audiochannels;
- int scrollback; /* console scrollback limit */
- int dpi; /* range 48-128? */
- char node_margin; /* node insert offset (aka auto-offset) margin, but might be useful for later stuff as well */
+ int scrollback; /* console scrollback limit */
+ int dpi; /* range 48-128? */
+ float ui_scale; /* interface scale */
+ int pad1;
+ char node_margin; /* node insert offset (aka auto-offset) margin, but might be useful for later stuff as well */
char pad2;
short transopts;
short menuthreshold1, menuthreshold2;
-
+
+ /* startup template */
+ char app_template[64];
+
struct ListBase themes;
struct ListBase uifonts;
struct ListBase uistyles;
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index f9aaec69ce7..a1af3f98274 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -767,6 +767,8 @@ void RNA_struct_blender_type_set(StructRNA *srna, void *blender_type);
struct IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create);
bool RNA_struct_idprops_check(StructRNA *srna);
bool RNA_struct_idprops_register_check(const StructRNA *type);
+bool RNA_struct_idprops_datablock_allowed(const StructRNA *type);
+bool RNA_struct_idprops_contains_datablock(const StructRNA *type);
bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier);
PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier);
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index 2a680b6eaeb..6e62313b00a 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -167,6 +167,7 @@ void RNA_def_property_editable_func(PropertyRNA *prop, const char *editable);
void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editable);
void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func);
+void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func);
void RNA_def_property_dynamic_array_funcs(PropertyRNA *prop, const char *getlength);
void RNA_def_property_boolean_funcs(PropertyRNA *prop, const char *get, const char *set);
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index dee8df7d933..cd04f9e8a6d 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -434,6 +434,8 @@ typedef enum StructFlag {
STRUCT_GENERATED = (1 << 4),
STRUCT_FREE_POINTERS = (1 << 5),
STRUCT_NO_IDPROPERTIES = (1 << 6), /* Menus and Panels don't need properties */
+ STRUCT_NO_DATABLOCK_IDPROPERTIES = (1 << 7), /* e.g. for Operator */
+ STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES = (1 << 8), /* for PropertyGroup which contains pointers to datablocks */
} StructFlag;
typedef int (*StructValidateFunc)(struct PointerRNA *ptr, void *data, int *have_function);
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 4552c773097..9d68c05dda0 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -507,7 +507,7 @@ static void rna_float_print(FILE *f, float num)
{
if (num == -FLT_MAX) fprintf(f, "-FLT_MAX");
else if (num == FLT_MAX) fprintf(f, "FLT_MAX");
- else if ((int64_t)num == num) fprintf(f, "%.1ff", num);
+ else if ((ABS(num) < INT64_MAX) && ((int64_t)num == num)) fprintf(f, "%.1ff", num);
else fprintf(f, "%.10ff", num);
}
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 671902c5cc7..6ed2c55138c 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -802,7 +802,11 @@ static void rna_def_ID_properties(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
#endif
- /* IDP_ID -- not implemented yet in id properties */
+ /* IDP_ID */
+ prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY | PROP_NEVER_UNLINK);
+ RNA_def_property_struct_type(prop, "ID");
+
/* ID property groups > level 0, since level 0 group is merged
* with native RNA properties. the builtin_properties will take
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index bb839fd77f8..c3d2d92fc5e 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -50,6 +50,7 @@
#include "BKE_idcode.h"
#include "BKE_idprop.h"
#include "BKE_fcurve.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -380,6 +381,7 @@ static bool rna_idproperty_verify_valid(PointerRNA *ptr, PropertyRNA *prop, IDPr
return false;
break;
case IDP_GROUP:
+ case IDP_ID:
if (prop->type != PROP_POINTER)
return false;
break;
@@ -395,7 +397,8 @@ static PropertyRNA *typemap[IDP_NUMTYPES] = {
(PropertyRNA *)&rna_PropertyGroupItem_int,
(PropertyRNA *)&rna_PropertyGroupItem_float,
NULL, NULL, NULL,
- (PropertyRNA *)&rna_PropertyGroupItem_group, NULL,
+ (PropertyRNA *)&rna_PropertyGroupItem_group,
+ (PropertyRNA *)&rna_PropertyGroupItem_id,
(PropertyRNA *)&rna_PropertyGroupItem_double,
(PropertyRNA *)&rna_PropertyGroupItem_idp_array
};
@@ -587,6 +590,21 @@ bool RNA_struct_idprops_register_check(const StructRNA *type)
return (type->flag & STRUCT_NO_IDPROPERTIES) == 0;
}
+bool RNA_struct_idprops_datablock_allowed(const StructRNA *type)
+{
+ return (type->flag & (STRUCT_NO_DATABLOCK_IDPROPERTIES | STRUCT_NO_IDPROPERTIES)) == 0;
+}
+
+/**
+ * Whether given type implies datablock usage by IDProperties.
+ * This is used to prevent classes allowed to have IDProperties, but not datablock ones, to indirectly use some
+ * (e.g. by assigning an IDP_GROUP containing some IDP_ID pointers...).
+ */
+bool RNA_struct_idprops_contains_datablock(const StructRNA *type)
+{
+ return (type->flag & (STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES | STRUCT_ID)) != 0;
+}
+
/* remove an id-property */
bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier)
{
@@ -628,8 +646,11 @@ PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
/* id prop lookup, not so common */
PropertyRNA *r_prop = NULL;
PointerRNA r_ptr; /* only support single level props */
- if (RNA_path_resolve(ptr, identifier, &r_ptr, &r_prop) && (r_ptr.type == ptr->type) && (r_ptr.data == ptr->data))
+ if (RNA_path_resolve_property(ptr, identifier, &r_ptr, &r_prop) &&
+ (r_ptr.type == ptr->type) && (r_ptr.data == ptr->data))
+ {
return r_prop;
+ }
}
else {
/* most common case */
@@ -1201,13 +1222,20 @@ int RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *va
if (prop->type == PROP_POINTER) {
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
- if (pprop->poll)
- return pprop->poll(ptr, *value);
+
+ if (pprop->poll) {
+ if (rna_idproperty_check(&prop, ptr)) {
+ return ((PropPointerPollFuncPy) pprop->poll)(ptr, *value, prop);
+ }
+ else {
+ return pprop->poll(ptr, *value);
+ }
+ }
return 1;
}
- printf("%s %s: is not a pointer property.\n", __func__, prop->identifier);
+ printf("%s: %s is not a pointer property.\n", __func__, prop->identifier);
return 0;
}
@@ -2967,6 +2995,10 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
if ((idprop = rna_idproperty_check(&prop, ptr))) {
pprop = (PointerPropertyRNA *)prop;
+ if (RNA_struct_is_ID(pprop->type)) {
+ return rna_pointer_inherit_refine(ptr, pprop->type, IDP_Id(idprop));
+ }
+
/* for groups, data is idprop itself */
if (pprop->typef)
return rna_pointer_inherit_refine(ptr, pprop->typef(ptr), idprop);
@@ -2989,22 +3021,32 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value)
{
- /*IDProperty *idprop;*/
-
+ PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
BLI_assert(RNA_property_type(prop) == PROP_POINTER);
- if ((/*idprop = */ rna_idproperty_check(&prop, ptr))) {
- /* not supported */
- /* rna_idproperty_touch(idprop); */
+ /* Check types */
+ if (ptr_value.type != NULL && !RNA_struct_is_a(ptr_value.type, pprop->type)) {
+ printf("%s: expected %s type, not %s.\n", __func__, pprop->type->identifier, ptr_value.type->identifier);
+ return;
}
- else {
- PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
- if (pprop->set &&
- !((prop->flag & PROP_NEVER_NULL) && ptr_value.data == NULL) &&
- !((prop->flag & PROP_ID_SELF_CHECK) && ptr->id.data == ptr_value.id.data))
- {
- pprop->set(ptr, ptr_value);
+ /* RNA */
+ if (pprop->set &&
+ !((prop->flag & PROP_NEVER_NULL) && ptr_value.data == NULL) &&
+ !((prop->flag & PROP_ID_SELF_CHECK) && ptr->id.data == ptr_value.id.data))
+ {
+ pprop->set(ptr, ptr_value);
+ }
+ /* IDProperty */
+ else if (prop->flag & PROP_EDITABLE) {
+ IDPropertyTemplate val = {0};
+ IDProperty *group;
+
+ val.id = ptr_value.data;
+
+ group = RNA_struct_idprops(ptr, true);
+ if (group) {
+ IDP_ReplaceInGroup(group, IDP_New(IDP_ID, &val, prop->identifier));
}
}
}
@@ -5547,6 +5589,9 @@ static char *rna_pointer_as_string__bldata(PointerRNA *ptr)
return BLI_strdup("None");
}
else if (RNA_struct_is_ID(ptr->type)) {
+ if (ptr->id.data == NULL) {
+ return BLI_strdup("None");
+ }
return RNA_path_full_ID_py(ptr->id.data);
}
else {
@@ -5556,7 +5601,10 @@ static char *rna_pointer_as_string__bldata(PointerRNA *ptr)
char *RNA_pointer_as_string(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *prop_ptr, PointerRNA *ptr_prop)
{
- if (RNA_property_flag(prop_ptr) & PROP_IDPROPERTY) {
+ if (ptr_prop->data == NULL) {
+ return BLI_strdup("None");
+ }
+ else if (RNA_property_flag(prop_ptr) & PROP_IDPROPERTY) {
return RNA_pointer_as_string_id(C, ptr_prop);
}
else {
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 0c4c7ddac81..d398ce95a52 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -34,6 +34,8 @@
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "BKE_action.h"
#include "RNA_access.h"
@@ -731,6 +733,7 @@ static void rna_def_action(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "ID Root Type",
"Type of ID block that action can be used on - "
"DO NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
/* API calls */
RNA_api_action(srna);
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index 9adbf5f6b2e..f271bccd326 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -32,6 +32,8 @@
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
@@ -742,6 +744,7 @@ static void rna_def_keyingset_path(BlenderRNA *brna)
RNA_def_property_enum_default(prop, ID_OB);
RNA_def_property_enum_funcs(prop, NULL, "rna_ksPath_id_type_set", NULL);
RNA_def_property_ui_text(prop, "ID Type", "Type of ID-block that can be used");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
RNA_def_property_update(prop, NC_SCENE | ND_KEYINGSET | NA_EDITED, NULL); /* XXX: maybe a bit too noisy */
/* Group */
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 1d232d2df39..49983b0bc2b 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -2168,6 +2168,16 @@ void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func)
prop->update = (void *)func;
}
+void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func)
+{
+ if (prop->type == PROP_POINTER) {
+ ((PointerPropertyRNA *)prop)->poll = func;
+ }
+ else {
+ fprintf(stderr, "%s: %s is not a Pointer Property.\n", __func__, prop->identifier);
+ }
+}
+
void RNA_def_property_dynamic_array_funcs(PropertyRNA *prop, const char *getlength)
{
if (!DefRNA.preprocess) {
@@ -2982,6 +2992,9 @@ PropertyRNA *RNA_def_pointer_runtime(StructOrFunctionRNA *cont_, const char *ide
prop = RNA_def_property(cont, identifier, PROP_POINTER, PROP_NONE);
RNA_def_property_struct_runtime(prop, type);
+ if ((type->flag & STRUCT_ID) != 0) {
+ prop->flag |= PROP_EDITABLE;
+ }
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 4acdee490b8..bccc47aa95d 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -35,6 +35,8 @@
#include "BLI_math.h"
+#include "BLT_translation.h"
+
#include "BKE_action.h"
#include "RNA_access.h"
@@ -1448,6 +1450,7 @@ static void rna_def_drivertarget(BlenderRNA *brna)
RNA_def_property_enum_funcs(prop, NULL, "rna_DriverTarget_id_type_set", NULL);
RNA_def_property_editable_func(prop, "rna_DriverTarget_id_type_editable");
RNA_def_property_ui_text(prop, "ID Type", "Type of ID-block that can be used");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data");
/* Target Properties - Property to Drive */
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 76455adbc78..dfd5af788f6 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -344,6 +344,7 @@ extern IntPropertyRNA rna_PropertyGroupItem_int_array;
extern FloatPropertyRNA rna_PropertyGroupItem_float;
extern FloatPropertyRNA rna_PropertyGroupItem_float_array;
extern PointerPropertyRNA rna_PropertyGroupItem_group;
+extern PointerPropertyRNA rna_PropertyGroupItem_id;
extern CollectionPropertyRNA rna_PropertyGroupItem_collection;
extern CollectionPropertyRNA rna_PropertyGroupItem_idp_array;
extern FloatPropertyRNA rna_PropertyGroupItem_double;
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index fce81e6967e..df591659fdb 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -94,6 +94,7 @@ typedef PointerRNA (*PropPointerGetFunc)(struct PointerRNA *ptr);
typedef StructRNA *(*PropPointerTypeFunc)(struct PointerRNA *ptr);
typedef void (*PropPointerSetFunc)(struct PointerRNA *ptr, const PointerRNA value);
typedef int (*PropPointerPollFunc)(struct PointerRNA *ptr, const PointerRNA value);
+typedef int (*PropPointerPollFuncPy)(struct PointerRNA *ptr, const PointerRNA value, const PropertyRNA *prop);
typedef void (*PropCollectionBeginFunc)(struct CollectionPropertyIterator *iter, struct PointerRNA *ptr);
typedef void (*PropCollectionNextFunc)(struct CollectionPropertyIterator *iter);
typedef void (*PropCollectionEndFunc)(struct CollectionPropertyIterator *iter);
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 36cf909b299..1a8dd05a7b5 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1526,6 +1526,20 @@ static void rna_def_modifier_mirror(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mirror V", "Mirror the V texture coordinate around the 0.5 point");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "mirror_offset_u", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "uv_offset[0]");
+ RNA_def_property_range(prop, -1, 1);
+ RNA_def_property_ui_range(prop, -1, 1, 2, 4);
+ RNA_def_property_ui_text(prop, "U Offset", "Amount to offset mirrored UVs from the 0.5 point on the U axis");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "mirror_offset_v", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "uv_offset[1]");
+ RNA_def_property_range(prop, -1, 1);
+ RNA_def_property_ui_range(prop, -1, 1, 2, 4);
+ RNA_def_property_ui_text(prop, "V Offset", "Amount to offset mirrored UVs from the 0.5 point on the V axis");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "tolerance");
RNA_def_property_range(prop, 0, FLT_MAX);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 784004182dd..8d42d746e1c 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -3327,6 +3327,7 @@ static void def_frame(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
RNA_def_struct_sdna_from(srna, "NodeFrame", "storage");
+ RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_ID_NODETREE);
prop = RNA_def_property(srna, "shrink", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_FRAME_SHRINK);
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index b3c166a6810..ec6a03e713d 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -2897,6 +2897,10 @@ static void rna_def_dupli_object(BlenderRNA *brna)
RNA_def_property_enum_items(prop, dupli_items);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Dupli Type", "Duplicator type that generated this dupli object");
+
+ prop = RNA_def_property(srna, "random_id", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Dupli random id", "Random id for this dupli object");
}
static void rna_def_object_base(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index c680abe71a4..55852139065 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -321,13 +321,30 @@ static void rna_Object_ray_cast(
float origin[3], float direction[3], float distance,
int *r_success, float r_location[3], float r_normal[3], int *r_index)
{
- BVHTreeFromMesh treeData = {NULL};
-
if (ob->derivedFinal == NULL) {
BKE_reportf(reports, RPT_ERROR, "Object '%s' has no mesh data to be used for ray casting", ob->id.name + 2);
return;
}
+ *r_success = false;
+
+ /* Test BoundBox first (efficiency) */
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ if (bb) {
+ float distmin, distmax;
+ if (isect_ray_aabb_v3_simple(origin, direction, bb->vec[0], bb->vec[6], &distmin, &distmax)) {
+ float dist = distmin >= 0 ? distmin : distmax;
+ if (dist > distance) {
+ goto finally;
+ }
+ }
+ else {
+ goto finally;
+ }
+ }
+
+ BVHTreeFromMesh treeData = {NULL};
+
/* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
bvhtree_from_mesh_looptri(&treeData, ob->derivedFinal, 0.0f, 4, 6);
@@ -350,20 +367,18 @@ static void rna_Object_ray_cast(
copy_v3_v3(r_location, hit.co);
copy_v3_v3(r_normal, hit.no);
*r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]);
-
- goto finally;
}
}
- }
-
- *r_success = false;
- zero_v3(r_location);
- zero_v3(r_normal);
- *r_index = -1;
+ free_bvhtree_from_mesh(&treeData);
+ }
+ if (*r_success == false) {
finally:
- free_bvhtree_from_mesh(&treeData);
+ zero_v3(r_location);
+ zero_v3(r_normal);
+ *r_index = -1;
+ }
}
static void rna_Object_closest_point_on_mesh(
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index d4d8e23fdf5..9b202120b82 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -284,32 +284,36 @@ static void rna_Scene_collada_export(
int use_blender_profile,
int sort_by_name,
int export_transformation_type,
- int open_sim)
+ int open_sim,
+ int limit_precision,
+ int keep_bind_info)
{
- collada_export(scene,
- filepath,
-
- apply_modifiers,
- export_mesh_type,
-
- selected,
- include_children,
- include_armatures,
- include_shapekeys,
- deform_bones_only,
-
- active_uv_only,
- include_uv_textures,
- include_material_textures,
- use_texture_copies,
-
- triangulate,
- use_object_instantiation,
- use_blender_profile,
- sort_by_name,
-
- export_transformation_type,
- open_sim);
+ collada_export(scene,
+ filepath,
+
+ apply_modifiers,
+ export_mesh_type,
+
+ selected,
+ include_children,
+ include_armatures,
+ include_shapekeys,
+ deform_bones_only,
+
+ active_uv_only,
+ include_uv_textures,
+ include_material_textures,
+ use_texture_copies,
+
+ triangulate,
+ use_object_instantiation,
+ use_blender_profile,
+ sort_by_name,
+
+ export_transformation_type,
+ open_sim,
+ limit_precision,
+ keep_bind_info);
}
#endif
@@ -374,59 +378,60 @@ void RNA_api_scene(StructRNA *srna)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_subtype(parm, PROP_FILEPATH); /* allow non utf8 */
- RNA_def_boolean(func,
- "apply_modifiers", 0, "Apply Modifiers",
- "Apply modifiers to exported mesh (non destructive))");
+ RNA_def_boolean(func, "apply_modifiers", false,
+ "Apply Modifiers", "Apply modifiers to exported mesh (non destructive))");
RNA_def_int(func, "export_mesh_type", 0, INT_MIN, INT_MAX,
- "Resolution", "Modifier resolution for export", INT_MIN, INT_MAX);
+ "Resolution", "Modifier resolution for export", INT_MIN, INT_MAX);
- RNA_def_boolean(func, "selected", 0, "Selection Only",
- "Export only selected elements");
+ RNA_def_boolean(func, "selected", false, "Selection Only", "Export only selected elements");
- RNA_def_boolean(func, "include_children", 0, "Include Children",
- "Export all children of selected objects (even if not selected)");
+ RNA_def_boolean(func, "include_children", false,
+ "Include Children", "Export all children of selected objects (even if not selected)");
- RNA_def_boolean(func, "include_armatures", 0, "Include Armatures",
- "Export related armatures (even if not selected)");
+ RNA_def_boolean(func, "include_armatures", false,
+ "Include Armatures", "Export related armatures (even if not selected)");
- RNA_def_boolean(func, "include_shapekeys", 1, "Include Shape Keys",
- "Export all Shape Keys from Mesh Objects");
+ RNA_def_boolean(func, "include_shapekeys", true, "Include Shape Keys", "Export all Shape Keys from Mesh Objects");
- RNA_def_boolean(func, "deform_bones_only", 0, "Deform Bones only",
- "Only export deforming bones with armatures");
+ RNA_def_boolean(func, "deform_bones_only", false,
+ "Deform Bones only", "Only export deforming bones with armatures");
+ RNA_def_boolean(func, "active_uv_only", false, "Only Selected UV Map", "Export only the selected UV Map");
- RNA_def_boolean(func, "active_uv_only", 0, "Only Selected UV Map",
- "Export only the selected UV Map");
+ RNA_def_boolean(func, "include_uv_textures", false,
+ "Include UV Textures", "Export textures assigned to the object UV Maps");
- RNA_def_boolean(func, "include_uv_textures", 0, "Include UV Textures",
- "Export textures assigned to the object UV Maps");
+ RNA_def_boolean(func, "include_material_textures", false,
+ "Include Material Textures", "Export textures assigned to the object Materials");
- RNA_def_boolean(func, "include_material_textures", 0, "Include Material Textures",
- "Export textures assigned to the object Materials");
+ RNA_def_boolean(func, "use_texture_copies", true,
+ "Copy", "Copy textures to same folder where the .dae file is exported");
- RNA_def_boolean(func, "use_texture_copies", 1, "Copy",
- "Copy textures to same folder where the .dae file is exported");
+ RNA_def_boolean(func, "triangulate", true, "Triangulate", "Export Polygons (Quads & NGons) as Triangles");
+ RNA_def_boolean(func, "use_object_instantiation", true,
+ "Use Object Instances", "Instantiate multiple Objects from same Data");
- RNA_def_boolean(func, "triangulate", 1, "Triangulate",
- "Export Polygons (Quads & NGons) as Triangles");
+ RNA_def_boolean(func, "use_blender_profile", true, "Use Blender Profile",
+ "Export additional Blender specific information (for material, shaders, bones, etc.)");
- RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instances",
- "Instantiate multiple Objects from same Data");
+ RNA_def_boolean(func, "sort_by_name", false, "Sort by Object name", "Sort exported data by Object name");
- RNA_def_boolean(func, "use_blender_profile", 1, "Use Blender Profile",
- "Export additional Blender specific information (for material, shaders, bones, etc.)");
+ RNA_def_int(func, "export_transformation_type", 0, INT_MIN, INT_MAX,
+ "Transform", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX);
- RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name",
- "Sort exported data by Object name");
+ RNA_def_boolean(func, "open_sim", false,
+ "Export to SL/OpenSim", "Compatibility mode for SL, OpenSim and other compatible online worlds");
- RNA_def_int(func, "export_transformation_type", 0, INT_MIN, INT_MAX,
- "Transform", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX);
+ RNA_def_boolean(func, "limit_precision", false,
+ "Limit Precision",
+ "Reduce the precision of the exported data to 6 digits");
+
+ RNA_def_boolean(func, "keep_bind_info", false,
+ "Keep Bind Info",
+ "Store bind pose information in custom bone properties for later use during Collada export");
- RNA_def_boolean(func, "open_sim", 0, "Export to SL/OpenSim",
- "Compatibility mode for SL, OpenSim and other compatible online worlds");
#endif
#ifdef WITH_ALEMBIC
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index 7a3c862f04c..54b82fc89d6 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -1039,6 +1039,7 @@ static void rna_def_uilist(BlenderRNA *brna)
RNA_def_struct_refine_func(srna, "rna_UIList_refine");
RNA_def_struct_register_funcs(srna, "rna_UIList_register", "rna_UIList_unregister", NULL);
RNA_def_struct_idprops_func(srna, "rna_UIList_idprops");
+ RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES);
/* Registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 6927abcb4f8..629a42e92bd 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -138,23 +138,11 @@ static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe
}
/* also used by buffer swap switching */
-static void rna_userdef_dpi_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_userdef_dpi_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
/* font's are stored at each DPI level, without this we can easy load 100's of fonts */
BLF_cache_clear();
- BKE_blender_userdef_refresh();
- WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */
- WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
-}
-
-static void rna_userdef_virtual_pixel_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
-{
- /* font's are stored at each DPI level, without this we can easy load 100's of fonts */
- BLF_cache_clear();
-
- BKE_blender_userdef_refresh();
-
/* force setting drawable again */
wmWindowManager *wm = bmain->wm.first;
if (wm) {
@@ -3180,6 +3168,7 @@ static void rna_def_userdef_addon_pref(BlenderRNA *brna)
RNA_def_struct_refine_func(srna, "rna_AddonPref_refine");
RNA_def_struct_register_funcs(srna, "rna_AddonPref_register", "rna_AddonPref_unregister", NULL);
RNA_def_struct_idprops_func(srna, "rna_AddonPref_idprops");
+ RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES); /* Mandatory! */
/* registration */
RNA_define_verify_sdna(0);
@@ -3337,6 +3326,12 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "View & Controls", "Preferences related to viewing data");
/* View */
+ prop = RNA_def_property(srna, "ui_scale", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_ui_text(prop, "UI Scale", "Changes the size of the fonts and buttons in the interface");
+ RNA_def_property_range(prop, 0.25f, 4.0f);
+ RNA_def_property_ui_range(prop, 0.5f, 2.0f, 1, 1);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
/* display */
prop = RNA_def_property(srna, "show_tooltips", PROP_BOOLEAN, PROP_NONE);
@@ -3928,12 +3923,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static EnumPropertyItem virtual_pixel_mode_items[] = {
- {VIRTUAL_PIXEL_NATIVE, "NATIVE", 0, "Native", "Use native pixel size of the display"},
- {VIRTUAL_PIXEL_DOUBLE, "DOUBLE", 0, "Double", "Use double the native pixel size of the display"},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "UserPreferencesSystem", NULL);
RNA_def_struct_sdna(srna, "UserDef");
RNA_def_struct_nested(brna, srna, "UserPreferences");
@@ -3948,16 +3937,8 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update");
prop = RNA_def_property(srna, "dpi", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "dpi");
- RNA_def_property_range(prop, 48, 144);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "DPI", "Font size and resolution for display");
- RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
-
- prop = RNA_def_property(srna, "virtual_pixel_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "virtual_pixel");
- RNA_def_property_enum_items(prop, virtual_pixel_mode_items);
- RNA_def_property_ui_text(prop, "Virtual Pixel Mode", "Modify the pixel size for hi-res devices");
- RNA_def_property_update(prop, 0, "rna_userdef_virtual_pixel_update");
prop = RNA_def_property(srna, "pixel_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -4690,6 +4671,11 @@ void RNA_def_userdef(BlenderRNA *brna)
"Active section of the user preferences shown in the user interface");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ /* don't expose this directly via the UI, modify via an operator */
+ prop = RNA_def_property(srna, "app_template", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "app_template");
+ RNA_def_property_ui_text(prop, "Application Template", "");
+
prop = RNA_def_property(srna, "themes", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "themes", NULL);
RNA_def_property_struct_type(prop, "Theme");
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 35c9c9bcc89..b458b2e69d5 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -1556,6 +1556,7 @@ static void rna_def_operator(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Operator Properties", "Input properties of an Operator");
RNA_def_struct_refine_func(srna, "rna_OperatorProperties_refine");
RNA_def_struct_idprops_func(srna, "rna_OperatorProperties_idprops");
+ RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES);
}
static void rna_def_macro_operator(BlenderRNA *brna)
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index d956763fc1f..f0edcc31a10 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -112,7 +112,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (!mcmd->reader) {
mcmd->reader = CacheReader_open_alembic_object(cache_file->handle,
- mcmd->reader,
+ NULL,
ob,
mcmd->object_path);
if (!mcmd->reader) {
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index dd127cc255c..9705edc580c 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -274,8 +274,8 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
int j = maxLoops;
dmloopuv += j; /* second set of loops only */
for (; j-- > 0; dmloopuv++) {
- if (do_mirr_u) dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0];
- if (do_mirr_v) dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1];
+ if (do_mirr_u) dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0];
+ if (do_mirr_v) dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1];
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index 776cf02754e..da9b926d1f4 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -1120,6 +1120,11 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un
tdm = smd->target->derivedFinal;
}
+ if (!tdm) {
+ modifier_setError(md, "No valid target mesh");
+ return;
+ }
+
tnumverts = tdm->getNumVerts(tdm);
tnumpoly = tdm->getNumPolys(tdm);
@@ -1139,12 +1144,10 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un
/* Poly count checks */
if (smd->numverts != numverts) {
modifier_setError(md, "Verts changed from %u to %u", smd->numverts, numverts);
- tdm->release(tdm);
return;
}
else if (smd->numpoly != tnumpoly) {
modifier_setError(md, "Target polygons changed from %u to %u", smd->numpoly, tnumpoly);
- tdm->release(tdm);
return;
}
@@ -1170,8 +1173,6 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un
MEM_freeN(data.targetCos);
}
-
- tdm->release(tdm);
}
static void deformVerts(ModifierData *md, Object *ob,
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
index 48d1688c386..e0bf34f42e4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -63,7 +63,7 @@ static void node_shader_exec_normal_map(void *data, int UNUSED(thread), bNode *n
CLAMP_MIN(strength, 0.0f);
- float *N = shi->vno;
+ float *N = shi->nmapnorm;
int uv_index = 0;
switch (nm->space) {
case SHD_NORMAL_MAP_TANGENT:
diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.c b/source/blender/nodes/shader/nodes/node_shader_object_info.c
index d1905246fd4..165d565a5b4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_object_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_object_info.c
@@ -39,7 +39,16 @@ static bNodeSocketTemplate sh_node_object_info_out[] = {
static int node_shader_gpu_object_info(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_object_info", in, out);
+ return GPU_stack_link(mat, "node_object_info", in, out, GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_OBJECT_INFO));
+}
+
+static void node_shader_exec_object_info(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out)
+{
+ ShaderCallData *scd = (ShaderCallData *)data;
+ copy_v4_v4(out[0]->vec, RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB)[3]);
+ out[1]->vec[0] = RE_object_instance_get_object_pass_index(scd->shi->obi);
+ out[2]->vec[0] = scd->shi->mat->index;
+ out[3]->vec[0] = RE_object_instance_get_random_id(scd->shi->obi) * (1.0f/(float)0xFFFFFFFF);;
}
/* node type definition */
@@ -53,6 +62,7 @@ void register_node_type_sh_object_info(void)
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_object_info);
+ node_type_exec(&ntype, NULL, NULL, node_shader_exec_object_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 359395b63c4..b694b6e994d 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -333,19 +333,14 @@ static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothMo
return 1;
}
-BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, float time)
+BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s)
{
Cloth *cloth = clmd->clothObject;
ClothSimSettings *parms = clmd->sim_parms;
Implicit_Data *data = cloth->implicit;
- ClothVertex *verts = cloth->verts;
bool no_compress = parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
- zero_v3(s->f);
- zero_m3(s->dfdx);
- zero_m3(s->dfdv);
-
s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
// calculate force of structural + shear springs
@@ -361,31 +356,13 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
if (s->type & CLOTH_SPRING_TYPE_SEWING) {
// TODO: verify, half verified (couldn't see error)
// sewing springs usually have a large distance at first so clamp the force so we don't get tunnelling through colission objects
- BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, parms->max_sewing, s->f, s->dfdx, s->dfdv);
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, parms->max_sewing);
}
else {
- BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, 0.0f, s->f, s->dfdx, s->dfdv);
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, 0.0f);
}
#endif
}
- else if (s->type & CLOTH_SPRING_TYPE_GOAL) {
-#ifdef CLOTH_FORCE_SPRING_GOAL
- float goal_x[3], goal_v[3];
- float k, scaling;
-
- s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
- // current_position = xold + t * (newposition - xold)
- /* divide by time_scale to prevent goal vertices' delta locations from being multiplied */
- interp_v3_v3v3(goal_x, verts[s->ij].xold, verts[s->ij].xconst, time / parms->time_scale);
- sub_v3_v3v3(goal_v, verts[s->ij].xconst, verts[s->ij].xold); // distance covered over dt==1
-
- scaling = parms->goalspring + s->stiffness * fabsf(parms->max_struct - parms->goalspring);
- k = verts[s->ij].goal * scaling / (parms->avg_spring_len + FLT_EPSILON);
-
- BPH_mass_spring_force_spring_goal(data, s->ij, goal_x, goal_v, k, parms->goalfrict * 0.01f, s->f, s->dfdx, s->dfdv);
-#endif
- }
else if (s->type & CLOTH_SPRING_TYPE_BENDING) { /* calculate force of bending springs */
#ifdef CLOTH_FORCE_SPRING_BEND
float kb, cb, scaling;
@@ -398,7 +375,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
// Fix for [#45084] for cloth stiffness must have cb proportional to kb
cb = kb * parms->bending_damping;
- BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb, s->f, s->dfdx, s->dfdv);
+ BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb);
#endif
}
else if (s->type & CLOTH_SPRING_TYPE_BENDING_ANG) {
@@ -474,9 +451,24 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
/* scale gravity force */
mul_v3_v3fl(gravity, clmd->scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity);
}
+
vert = cloth->verts;
for (i = 0; i < cloth->mvert_num; i++, vert++) {
BPH_mass_spring_force_gravity(data, i, vert->mass, gravity);
+
+ /* Vertex goal springs */
+ if ((!(vert->flags & CLOTH_VERT_FLAG_PINNED)) && (vert->goal > FLT_EPSILON)) {
+ float goal_x[3], goal_v[3];
+ float k;
+
+ /* divide by time_scale to prevent goal vertices' delta locations from being multiplied */
+ interp_v3_v3v3(goal_x, vert->xold, vert->xconst, time / clmd->sim_parms->time_scale);
+ sub_v3_v3v3(goal_v, vert->xconst, vert->xold); /* distance covered over dt==1 */
+
+ k = vert->goal * clmd->sim_parms->goalspring / (clmd->sim_parms->avg_spring_len + FLT_EPSILON);
+
+ BPH_mass_spring_force_spring_goal(data, i, goal_x, goal_v, k, clmd->sim_parms->goalfrict * 0.01f);
+ }
}
#endif
@@ -544,8 +536,9 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
for (LinkNode *link = cloth->springs; link; link = link->next) {
ClothSpring *spring = (ClothSpring *)link->link;
// only handle active springs
- if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE))
- cloth_calc_spring_force(clmd, spring, time);
+ if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE)) {
+ cloth_calc_spring_force(clmd, spring);
+ }
}
}
diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h
index d1a75ca5297..2f62ab98e12 100644
--- a/source/blender/physics/intern/implicit.h
+++ b/source/blender/physics/intern/implicit.h
@@ -114,19 +114,15 @@ void BPH_mass_spring_force_edge_wind(struct Implicit_Data *data, int v1, int v2,
void BPH_mass_spring_force_vertex_wind(struct Implicit_Data *data, int v, float radius, const float (*winvec)[3]);
/* Linear spring force between two points */
bool BPH_mass_spring_force_spring_linear(struct Implicit_Data *data, int i, int j, float restlen,
- float stiffness, float damping, bool no_compress, float clamp_force,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
+ float stiffness, float damping, bool no_compress, float clamp_force);
/* Bending force, forming a triangle at the base of two structural springs */
-bool BPH_mass_spring_force_spring_bending(struct Implicit_Data *data, int i, int j, float restlen,
- float kb, float cb,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
+bool BPH_mass_spring_force_spring_bending(struct Implicit_Data *data, int i, int j, float restlen, float kb, float cb);
/* Angular bending force based on local target vectors */
bool BPH_mass_spring_force_spring_bending_angular(struct Implicit_Data *data, int i, int j, int k,
const float target[3], float stiffness, float damping);
/* Global goal spring */
bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3],
- float stiffness, float damping,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
+ float stiffness, float damping);
/* ======== Hair Volumetric Forces ======== */
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index 2ad8ee0547f..16cd335dc0c 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -1579,8 +1579,7 @@ BLI_INLINE void apply_spring(Implicit_Data *data, int i, int j, const float f[3]
}
bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, float restlen,
- float stiffness, float damping, bool no_compress, float clamp_force,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+ float stiffness, float damping, bool no_compress, float clamp_force)
{
float extent[3], length, dir[3], vel[3];
@@ -1608,25 +1607,15 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa
apply_spring(data, i, j, f, dfdx, dfdv);
- if (r_f) copy_v3_v3(r_f, f);
- if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
- if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
-
return true;
}
else {
- if (r_f) zero_v3(r_f);
- if (r_dfdx) zero_m3(r_dfdx);
- if (r_dfdv) zero_m3(r_dfdv);
-
return false;
}
}
/* See "Stable but Responsive Cloth" (Choi, Ko 2005) */
-bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, float restlen,
- float kb, float cb,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, float restlen, float kb, float cb)
{
float extent[3], length, dir[3], vel[3];
@@ -1646,17 +1635,9 @@ bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, flo
apply_spring(data, i, j, f, dfdx, dfdv);
- if (r_f) copy_v3_v3(r_f, f);
- if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
- if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
-
return true;
}
else {
- if (r_f) zero_v3(r_f);
- if (r_dfdx) zero_m3(r_dfdx);
- if (r_dfdv) zero_m3(r_dfdv);
-
return false;
}
}
@@ -1945,8 +1926,7 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in
}
bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3],
- float stiffness, float damping,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+ float stiffness, float damping)
{
float root_goal_x[3], root_goal_v[3], extent[3], length, dir[3], vel[3];
float f[3], dfdx[3][3], dfdv[3][3];
@@ -1973,17 +1953,9 @@ bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float g
add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfdx);
add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, dfdv);
- if (r_f) copy_v3_v3(r_f, f);
- if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
- if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
-
return true;
}
else {
- if (r_f) zero_v3(r_f);
- if (r_dfdx) zero_m3(r_dfdx);
- if (r_dfdv) zero_m3(r_dfdv);
-
return false;
}
}
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 2e15b7b1413..5d6a7c578a2 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -43,6 +43,9 @@
#include "python_utildefines.h"
+extern bool pyrna_id_FromPyObject(PyObject *obj, ID **id);
+extern PyObject *pyrna_id_CreatePyObject(ID *id);
+extern bool pyrna_id_CheckPyObject(PyObject *obj);
/*********************** ID Property Main Wrapper Stuff ***************/
@@ -88,6 +91,11 @@ static PyObject *idprop_py_from_idp_group(ID *id, IDProperty *prop, IDProperty *
return (PyObject *)group;
}
+static PyObject *idprop_py_from_idp_id(IDProperty *prop)
+{
+ return pyrna_id_CreatePyObject(prop->data.pointer);
+}
+
static PyObject *idprop_py_from_idp_array(ID *id, IDProperty *prop)
{
BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &BPy_IDArray_Type);
@@ -148,6 +156,7 @@ PyObject *BPy_IDGroup_WrapData(ID *id, IDProperty *prop, IDProperty *parent)
case IDP_GROUP: return idprop_py_from_idp_group(id, prop, parent);
case IDP_ARRAY: return idprop_py_from_idp_array(id, prop);
case IDP_IDPARRAY: return idprop_py_from_idp_idparray(id, prop); /* this could be better a internal type */
+ case IDP_ID: return idprop_py_from_idp_id(prop);
default: Py_RETURN_NONE;
}
}
@@ -335,19 +344,9 @@ static char idp_sequence_type(PyObject *seq_fast)
return type;
}
-/**
- * \note group can be a pointer array or a group.
- * assume we already checked key is a string.
- *
- * \return success.
- */
-bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
+static const char *idp_try_read_name(PyObject *name_obj)
{
- IDProperty *prop = NULL;
- IDPropertyTemplate val = {0};
-
- const char *name;
-
+ const char *name = NULL;
if (name_obj) {
Py_ssize_t name_size;
name = _PyUnicode_AsStringAndSize(name_obj, &name_size);
@@ -356,168 +355,307 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group,
PyErr_Format(PyExc_KeyError,
"invalid id-property key, expected a string, not a %.200s",
Py_TYPE(name_obj)->tp_name);
- return false;
+ return NULL;
}
if (name_size > MAX_IDPROP_NAME) {
PyErr_SetString(PyExc_KeyError, "the length of IDProperty names is limited to 63 characters");
- return false;
+ return NULL;
}
}
else {
name = "";
}
+ return name;
+}
- if (PyFloat_Check(ob)) {
- val.d = PyFloat_AsDouble(ob);
- prop = IDP_New(IDP_DOUBLE, &val, name);
- }
- else if (PyLong_Check(ob)) {
- val.i = _PyLong_AsInt(ob);
- if (val.i == -1 && PyErr_Occurred()) {
- return false;
- }
- prop = IDP_New(IDP_INT, &val, name);
+/* -------------------------------------------------------------------------- */
+
+/**
+ * The 'idp_from_Py*' functions expect that the input type has been checked before
+ * and return NULL if the IDProperty can't be created.
+ */
+
+static IDProperty *idp_from_PyFloat(const char *name, PyObject *ob)
+{
+ IDPropertyTemplate val = {0};
+ val.d = PyFloat_AsDouble(ob);
+ return IDP_New(IDP_DOUBLE, &val, name);
+}
+
+static IDProperty *idp_from_PyLong(const char *name, PyObject *ob)
+{
+ IDPropertyTemplate val = {0};
+ val.i = _PyLong_AsInt(ob);
+ if (val.i == -1 && PyErr_Occurred()) {
+ return NULL;
}
- else if (PyUnicode_Check(ob)) {
+ return IDP_New(IDP_INT, &val, name);
+}
+
+static IDProperty *idp_from_PyUnicode(const char *name, PyObject *ob)
+{
+ IDProperty *prop;
+ IDPropertyTemplate val = {0};
#ifdef USE_STRING_COERCE
- Py_ssize_t value_size;
- PyObject *value_coerce = NULL;
- val.string.str = PyC_UnicodeAsByteAndSize(ob, &value_size, &value_coerce);
- val.string.len = (int)value_size + 1;
- val.string.subtype = IDP_STRING_SUB_UTF8;
- prop = IDP_New(IDP_STRING, &val, name);
- Py_XDECREF(value_coerce);
+ Py_ssize_t value_size;
+ PyObject *value_coerce = NULL;
+ val.string.str = PyC_UnicodeAsByteAndSize(ob, &value_size, &value_coerce);
+ val.string.len = (int)value_size + 1;
+ val.string.subtype = IDP_STRING_SUB_UTF8;
+ prop = IDP_New(IDP_STRING, &val, name);
+ Py_XDECREF(value_coerce);
#else
- val.str = _PyUnicode_AsString(ob);
- prop = IDP_New(IDP_STRING, val, name);
+ val.str = _PyUnicode_AsString(ob);
+ prop = IDP_New(IDP_STRING, val, name);
#endif
- }
- else if (PyBytes_Check(ob)) {
- val.string.str = PyBytes_AS_STRING(ob);
- val.string.len = PyBytes_GET_SIZE(ob);
- val.string.subtype = IDP_STRING_SUB_BYTE;
+ return prop;
+}
+
+static IDProperty *idp_from_PyBytes(const char *name, PyObject *ob)
+{
+ IDPropertyTemplate val = {0};
+ val.string.str = PyBytes_AS_STRING(ob);
+ val.string.len = PyBytes_GET_SIZE(ob);
+ val.string.subtype = IDP_STRING_SUB_BYTE;
+ return IDP_New(IDP_STRING, &val, name);
+}
- prop = IDP_New(IDP_STRING, &val, name);
- //prop = IDP_NewString(PyBytes_AS_STRING(ob), name, PyBytes_GET_SIZE(ob));
- //prop->subtype = IDP_STRING_SUB_BYTE;
+static int idp_array_type_from_format_char(char format)
+{
+ if (format == 'i') return IDP_INT;
+ if (format == 'f') return IDP_FLOAT;
+ if (format == 'd') return IDP_DOUBLE;
+ return -1;
+}
+
+static const char *idp_format_from_array_type(int type)
+{
+ if (type == IDP_INT) return "i";
+ if (type == IDP_FLOAT) return "f";
+ if (type == IDP_DOUBLE) return "d";
+ return NULL;
+}
+
+static IDProperty *idp_from_PySequence_Buffer(const char *name, Py_buffer *buffer)
+{
+ IDProperty *prop;
+ IDPropertyTemplate val = {0};
+
+ int format = idp_array_type_from_format_char(*buffer->format);
+ if (format == -1) {
+ /* should never happen as the type has been checked before */
+ return NULL;
}
- else if (PySequence_Check(ob)) {
- PyObject *ob_seq_fast;
- PyObject **ob_seq_fast_items;
- PyObject *item;
- int i;
+ else {
+ val.array.type = format;
+ val.array.len = buffer->len / buffer->itemsize;
+ }
+ prop = IDP_New(IDP_ARRAY, &val, name);
+ memcpy(IDP_Array(prop), buffer->buf, buffer->len);
+ return prop;
+}
- if (!(ob_seq_fast = PySequence_Fast(ob, "py -> idprop"))) {
- return false;
- }
+static IDProperty *idp_from_PySequence_Fast(const char *name, PyObject *ob)
+{
+ IDProperty *prop;
+ IDPropertyTemplate val = {0};
- ob_seq_fast_items = PySequence_Fast_ITEMS(ob_seq_fast);
+ PyObject **ob_seq_fast_items;
+ PyObject *item;
+ int i;
- if ((val.array.type = idp_sequence_type(ob_seq_fast)) == (char)-1) {
- Py_DECREF(ob_seq_fast);
- PyErr_SetString(PyExc_TypeError, "only floats, ints and dicts are allowed in ID property arrays");
- return false;
- }
+ ob_seq_fast_items = PySequence_Fast_ITEMS(ob);
- /* validate sequence and derive type.
- * we assume IDP_INT unless we hit a float
- * number; then we assume it's */
+ if ((val.array.type = idp_sequence_type(ob)) == (char)-1) {
+ PyErr_SetString(PyExc_TypeError, "only floats, ints and dicts are allowed in ID property arrays");
+ return NULL;
+ }
- val.array.len = PySequence_Fast_GET_SIZE(ob_seq_fast);
+ /* validate sequence and derive type.
+ * we assume IDP_INT unless we hit a float
+ * number; then we assume it's */
- switch (val.array.type) {
- case IDP_DOUBLE:
- {
- double *prop_data;
-
- prop = IDP_New(IDP_ARRAY, &val, name);
- prop_data = IDP_Array(prop);
- for (i = 0; i < val.array.len; i++) {
- item = ob_seq_fast_items[i];
- if (((prop_data[i] = PyFloat_AsDouble(item)) == -1.0) && PyErr_Occurred()) {
- Py_DECREF(ob_seq_fast);
- return false;
- }
+ val.array.len = PySequence_Fast_GET_SIZE(ob);
+
+ switch (val.array.type) {
+ case IDP_DOUBLE:
+ {
+ double *prop_data;
+ prop = IDP_New(IDP_ARRAY, &val, name);
+ prop_data = IDP_Array(prop);
+ for (i = 0; i < val.array.len; i++) {
+ item = ob_seq_fast_items[i];
+ if (((prop_data[i] = PyFloat_AsDouble(item)) == -1.0) && PyErr_Occurred()) {
+ return NULL;
}
- break;
}
- case IDP_INT:
- {
- int *prop_data;
- prop = IDP_New(IDP_ARRAY, &val, name);
- prop_data = IDP_Array(prop);
- for (i = 0; i < val.array.len; i++) {
- item = ob_seq_fast_items[i];
- if (((prop_data[i] = _PyLong_AsInt(item)) == -1) && PyErr_Occurred()) {
- Py_DECREF(ob_seq_fast);
- return false;
- }
+ break;
+ }
+ case IDP_INT:
+ {
+ int *prop_data;
+ prop = IDP_New(IDP_ARRAY, &val, name);
+ prop_data = IDP_Array(prop);
+ for (i = 0; i < val.array.len; i++) {
+ item = ob_seq_fast_items[i];
+ if (((prop_data[i] = _PyLong_AsInt(item)) == -1) && PyErr_Occurred()) {
+ return NULL;
}
- break;
}
- case IDP_IDPARRAY:
- {
- prop = IDP_NewIDPArray(name);
- for (i = 0; i < val.array.len; i++) {
- item = ob_seq_fast_items[i];
-
- if (BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item) == false) {
- Py_DECREF(ob_seq_fast);
- return false;
- }
+ break;
+ }
+ case IDP_IDPARRAY:
+ {
+ prop = IDP_NewIDPArray(name);
+ for (i = 0; i < val.array.len; i++) {
+ item = ob_seq_fast_items[i];
+ if (BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item) == false) {
+ return NULL;
}
- break;
}
- default:
- /* should never happen */
- Py_DECREF(ob_seq_fast);
- PyErr_SetString(PyExc_RuntimeError, "internal error with idp array.type");
- return false;
+ break;
}
+ default:
+ /* should never happen */
+ PyErr_SetString(PyExc_RuntimeError, "internal error with idp array.type");
+ return NULL;
+ }
+ return prop;
+}
- Py_DECREF(ob_seq_fast);
+
+static IDProperty *idp_from_PySequence(const char *name, PyObject *ob)
+{
+ Py_buffer buffer;
+ bool use_buffer = false;
+
+ if (PyObject_CheckBuffer(ob)) {
+ PyObject_GetBuffer(ob, &buffer, PyBUF_SIMPLE | PyBUF_FORMAT);
+ char format = *buffer.format;
+ if (ELEM(format, 'i', 'f', 'd')) {
+ use_buffer = true;
+ }
+ else {
+ PyBuffer_Release(&buffer);
+ }
}
- else if (PyMapping_Check(ob)) {
- PyObject *keys, *vals, *key, *pval;
- int i, len;
- /*yay! we get into recursive stuff now!*/
- keys = PyMapping_Keys(ob);
- vals = PyMapping_Values(ob);
-
- /* we allocate the group first; if we hit any invalid data,
- * we can delete it easily enough.*/
- prop = IDP_New(IDP_GROUP, &val, name);
- len = PyMapping_Length(ob);
- for (i = 0; i < len; i++) {
- key = PySequence_GetItem(keys, i);
- pval = PySequence_GetItem(vals, i);
- if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval) == false) {
- IDP_FreeProperty(prop);
- MEM_freeN(prop);
- Py_XDECREF(keys);
- Py_XDECREF(vals);
- Py_XDECREF(key);
- Py_XDECREF(pval);
- /* error is already set */
- return false;
- }
+
+ if (use_buffer) {
+ IDProperty *prop = idp_from_PySequence_Buffer(name, &buffer);
+ PyBuffer_Release(&buffer);
+ return prop;
+ }
+ else {
+ PyObject *ob_seq_fast = PySequence_Fast(ob, "py -> idprop");
+ if (ob_seq_fast != NULL) {
+ IDProperty *prop = idp_from_PySequence_Fast(name, ob_seq_fast);
+ Py_DECREF(ob_seq_fast);
+ return prop;
+ }
+ else {
+ return NULL;
+ }
+ }
+}
+
+static IDProperty *idp_from_PyMapping(const char *name, PyObject *ob)
+{
+ IDProperty *prop;
+ IDPropertyTemplate val = {0};
+
+ PyObject *keys, *vals, *key, *pval;
+ int i, len;
+ /* yay! we get into recursive stuff now! */
+ keys = PyMapping_Keys(ob);
+ vals = PyMapping_Values(ob);
+
+ /* we allocate the group first; if we hit any invalid data,
+ * we can delete it easily enough.*/
+ prop = IDP_New(IDP_GROUP, &val, name);
+ len = PyMapping_Length(ob);
+ for (i = 0; i < len; i++) {
+ key = PySequence_GetItem(keys, i);
+ pval = PySequence_GetItem(vals, i);
+ if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval) == false) {
+ IDP_FreeProperty(prop);
+ MEM_freeN(prop);
+ Py_XDECREF(keys);
+ Py_XDECREF(vals);
Py_XDECREF(key);
Py_XDECREF(pval);
+ /* error is already set */
+ return NULL;
}
- Py_XDECREF(keys);
- Py_XDECREF(vals);
+ Py_XDECREF(key);
+ Py_XDECREF(pval);
+ }
+ Py_XDECREF(keys);
+ Py_XDECREF(vals);
+ return prop;
+}
+
+static IDProperty *idp_from_DatablockPointer(const char *name, PyObject *ob, IDPropertyTemplate *val)
+{
+ pyrna_id_FromPyObject(ob, &val->id);
+ return IDP_New(IDP_ID, val, name);
+}
+
+static IDProperty *idp_from_PyObject(PyObject *name_obj, PyObject *ob)
+{
+ IDPropertyTemplate val = {0};
+ const char *name = idp_try_read_name(name_obj);
+ if (name == NULL) {
+ return NULL;
+ }
+
+ if (PyFloat_Check(ob)) {
+ return idp_from_PyFloat(name, ob);
+ }
+ else if (PyLong_Check(ob)) {
+ return idp_from_PyLong(name, ob);
+ }
+ else if (PyUnicode_Check(ob)) {
+ return idp_from_PyUnicode(name, ob);
+ }
+ else if (PyBytes_Check(ob)) {
+ return idp_from_PyBytes(name, ob);
+ }
+ else if (PySequence_Check(ob)) {
+ return idp_from_PySequence(name, ob);
+ }
+ else if (ob == Py_None || pyrna_id_CheckPyObject(ob)) {
+ return idp_from_DatablockPointer(name, ob, &val);
+ }
+ else if (PyMapping_Check(ob)) {
+ return idp_from_PyMapping(name, ob);
}
else {
PyErr_Format(PyExc_TypeError,
"invalid id-property type %.200s not supported",
Py_TYPE(ob)->tp_name);
+ return NULL;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * \note group can be a pointer array or a group.
+ * assume we already checked key is a string.
+ *
+ * \return success.
+ */
+bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
+{
+ IDProperty *prop = idp_from_PyObject(name_obj, ob);
+ if (prop == NULL) {
return false;
}
if (group->type == IDP_IDPARRAY) {
IDP_AppendArray(group, prop);
- // IDP_FreeProperty(item); /* IDP_AppendArray does a shallow copy (memcpy), only free memory */
+ /* IDP_AppendArray does a shallow copy (memcpy), only free memory */
MEM_freeN(prop);
}
else {
@@ -613,6 +751,8 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
return idprop_py_from_idp_float(prop);
case IDP_DOUBLE:
return idprop_py_from_idp_double(prop);
+ case IDP_ID:
+ return idprop_py_from_idp_id(prop);
case IDP_ARRAY:
{
PyObject *seq = PyList_New(prop->len);
@@ -1371,6 +1511,44 @@ static PyMappingMethods BPy_IDArray_AsMapping = {
(objobjargproc)BPy_IDArray_ass_subscript
};
+static int itemsize_by_idarray_type(int array_type)
+{
+ if (array_type == IDP_INT) return sizeof(int);
+ if (array_type == IDP_FLOAT) return sizeof(float);
+ if (array_type == IDP_DOUBLE) return sizeof(double);
+ return -1; /* should never happen */
+}
+
+static int BPy_IDArray_getbuffer(BPy_IDArray *self, Py_buffer *view, int flags)
+{
+ IDProperty *prop = self->prop;
+ int itemsize = itemsize_by_idarray_type(prop->subtype);
+ int length = itemsize * prop->len;
+
+ if (PyBuffer_FillInfo(view, (PyObject *)self, IDP_Array(prop), length, false, flags) == -1) {
+ return -1;
+ }
+
+ view->itemsize = itemsize;
+ view->format = (char *)idp_format_from_array_type(prop->subtype);
+
+ Py_ssize_t *shape = MEM_mallocN(sizeof(Py_ssize_t), __func__);
+ shape[0] = prop->len;
+ view->shape = shape;
+
+ return 0;
+}
+
+static void BPy_IDArray_releasebuffer(BPy_IDArray *UNUSED(self), Py_buffer *view)
+{
+ MEM_freeN(view->shape);
+}
+
+static PyBufferProcs BPy_IDArray_Buffer = {
+ (getbufferproc)BPy_IDArray_getbuffer,
+ (releasebufferproc)BPy_IDArray_releasebuffer,
+};
+
PyTypeObject BPy_IDArray_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
@@ -1403,7 +1581,7 @@ PyTypeObject BPy_IDArray_Type = {
NULL, /* setattrofunc tp_setattro; */
/* Functions to access object as input/output buffer */
- NULL, /* PyBufferProcs *tp_as_buffer; */
+ &BPy_IDArray_Buffer, /* PyBufferProcs *tp_as_buffer; */
/*** Flags to define presence of optional/expanded features ***/
Py_TPFLAGS_DEFAULT, /* long tp_flags; */
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index e61018865ab..2656e612b18 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -50,11 +50,13 @@
#include "../generic/py_capi_utils.h"
/* initial definition of callback slots we'll probably have more than 1 */
-#define BPY_DATA_CB_SLOT_SIZE 3
-
-#define BPY_DATA_CB_SLOT_UPDATE 0
-#define BPY_DATA_CB_SLOT_GET 1
-#define BPY_DATA_CB_SLOT_SET 2
+enum {
+ BPY_DATA_CB_SLOT_UPDATE = 0,
+ BPY_DATA_CB_SLOT_GET = 1,
+ BPY_DATA_CB_SLOT_SET = 2,
+ BPY_DATA_CB_SLOT_POLL = 3,
+ BPY_DATA_CB_SLOT_SIZE = 4,
+};
extern BPy_StructRNA *bpy_context_module;
@@ -71,6 +73,9 @@ static EnumPropertyItem property_flag_items[] = {
" :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'LIBRARY_EDITABLE', 'PROPORTIONAL'," \
"'TEXTEDIT_UPDATE'].\n" \
" :type options: set\n" \
+" :arg poll: function to be called to determine whether an item is valid for this property.\n" \
+" The function must take 2 values (self,object) and return Bool.\n" \
+" :type poll: function\n" \
static EnumPropertyItem property_flag_enum_items[] = {
{PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
@@ -230,7 +235,7 @@ static PyObject *bpy_prop_deferred_return(PyObject *func, PyObject *kw)
static void bpy_prop_update_cb(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop)
{
PyGILState_STATE gilstate;
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -279,7 +284,7 @@ static void bpy_prop_update_cb(struct bContext *C, struct PointerRNA *ptr, struc
static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -337,7 +342,7 @@ static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -389,9 +394,54 @@ static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *
}
}
+static int bpy_prop_poll_cb(struct PointerRNA *self, PointerRNA candidate, struct PropertyRNA *prop)
+{
+ PyObject *py_self;
+ PyObject *py_candidate;
+ PyObject *py_func;
+ PyObject **py_data = RNA_property_py_data_get(prop);
+ PyObject *args;
+ PyObject *ret;
+ bool result;
+ const int is_write_ok = pyrna_write_check();
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ BLI_assert(self != NULL);
+
+ py_self = pyrna_struct_as_instance(self);
+ py_candidate = pyrna_struct_as_instance(&candidate);
+ py_func = py_data[BPY_DATA_CB_SLOT_POLL];
+
+ if (!is_write_ok)
+ pyrna_write_set(true);
+
+ args = PyTuple_New(2);
+ PyTuple_SET_ITEM(args, 0, py_self);
+ PyTuple_SET_ITEM(args, 1, py_candidate);
+
+ ret = PyObject_CallObject(py_func, args);
+
+ Py_DECREF(args);
+
+ if (ret == NULL) {
+ printf_func_error(py_func);
+ result = false;
+ }
+ else {
+ result = PyObject_IsTrue(ret);
+ Py_DECREF(ret);
+ }
+
+ PyGILState_Release(gilstate);
+ if (!is_write_ok)
+ pyrna_write_set(false);
+
+ return result;
+}
+
static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -452,7 +502,7 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr, struct Propert
static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const int *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -513,7 +563,7 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct Propert
static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -571,7 +621,7 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -625,7 +675,7 @@ static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -686,7 +736,7 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA
static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const int *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -747,7 +797,7 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA
static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -805,7 +855,7 @@ static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, float value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -859,7 +909,7 @@ static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pr
static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, float *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -920,7 +970,7 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr, struct PropertyR
static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const float *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -981,7 +1031,7 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyR
static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, char *value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1040,7 +1090,7 @@ static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1102,7 +1152,7 @@ static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA
static void bpy_prop_string_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const char *value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1163,7 +1213,7 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr, struct PropertyRNA *p
static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1221,7 +1271,7 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
static void bpy_prop_enum_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1598,6 +1648,16 @@ static void bpy_prop_callback_assign_update(struct PropertyRNA *prop, PyObject *
}
}
+static void bpy_prop_callback_assign_pointer(struct PropertyRNA *prop, PyObject *poll_cb)
+{
+ if (poll_cb && poll_cb != Py_None) {
+ PyObject **py_data = bpy_prop_py_data_get(prop);
+
+ RNA_def_property_poll_runtime(prop, (void *) bpy_prop_poll_cb);
+ py_data[BPY_DATA_CB_SLOT_POLL] = poll_cb;
+ }
+}
+
static void bpy_prop_callback_assign_boolean(struct PropertyRNA *prop, PyObject *get_cb, PyObject *set_cb)
{
BooleanPropertyGetFunc rna_get_cb = NULL;
@@ -1904,7 +1964,7 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop, PyObject *ge
" :type set: function\n" \
#define BPY_PROPDEF_TYPE_DOC \
-" :arg type: A subclass of :class:`bpy.types.PropertyGroup`.\n" \
+" :arg type: A subclass of :class:`bpy.types.PropertyGroup` or :class:`bpy.types.ID`.\n" \
" :type type: class\n" \
#if 0
@@ -2772,7 +2832,7 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
Py_RETURN_NONE;
}
-static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix)
+StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix)
{
StructRNA *srna;
@@ -2782,25 +2842,18 @@ static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix
PyObject *msg = PyC_ExceptionBuffer();
const char *msg_char = _PyUnicode_AsString(msg);
PyErr_Format(PyExc_TypeError,
- "%.200s expected an RNA type derived from PropertyGroup, failed with: %s",
+ "%.200s expected an RNA type, failed with: %s",
error_prefix, msg_char);
Py_DECREF(msg);
}
else {
PyErr_Format(PyExc_TypeError,
- "%.200s expected an RNA type derived from PropertyGroup, failed with type '%s'",
+ "%.200s expected an RNA type, failed with type '%s'",
error_prefix, Py_TYPE(value)->tp_name);
}
return NULL;
}
- if (!RNA_struct_is_a(srna, &RNA_PropertyGroup)) {
- PyErr_Format(PyExc_TypeError,
- "%.200s expected an RNA type derived from PropertyGroup",
- error_prefix);
- return NULL;
- }
-
return srna;
}
@@ -2809,7 +2862,8 @@ PyDoc_STRVAR(BPy_PointerProperty_doc,
"name=\"\", "
"description=\"\", "
"options={'ANIMATABLE'}, "
- "update=None)\n"
+ "update=None,\n"
+ "poll=None)\n"
"\n"
" Returns a new pointer property definition.\n"
"\n"
@@ -2819,14 +2873,14 @@ BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC
BPY_PROPDEF_UPDATE_DOC
);
-static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
+PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
BPY_PROPDEF_HEAD(PointerProperty);
if (srna) {
- static const char *kwlist[] = {"attr", "type", "name", "description", "options", "update", NULL};
+ static const char *kwlist[] = {"attr", "type", "name", "description", "options", "poll", "update", NULL};
const char *id = NULL, *name = NULL, *description = "";
int id_len;
PropertyRNA *prop;
@@ -2834,33 +2888,47 @@ static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *k
PyObject *type = Py_None;
PyObject *pyopts = NULL;
int opts = 0;
- PyObject *update_cb = NULL;
+ PyObject *update_cb = NULL, *poll_cb = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#O|ssO!O:PointerProperty",
+ "s#O|ssO!OOO:PointerProperty",
(char **)kwlist, &id, &id_len,
&type, &name, &description,
&PySet_Type, &pyopts,
- &update_cb))
+ &poll_cb, &update_cb))
{
return NULL;
}
BPY_PROPDEF_CHECK(PointerProperty, property_flag_items);
- ptype = pointer_type_from_py(type, "PointerProperty(...):");
+ ptype = pointer_type_from_py(type, "PointerProperty(...)");
if (!ptype)
return NULL;
-
+ if (!RNA_struct_is_a(ptype, &RNA_PropertyGroup) && !RNA_struct_is_ID(ptype)) {
+ PyErr_Format(PyExc_TypeError,
+ "PointerProperty(...) expected an RNA type derived from %.200s or %.200s",
+ RNA_struct_ui_name(&RNA_ID), RNA_struct_ui_name(&RNA_PropertyGroup));
+ return NULL;
+ }
if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
return NULL;
}
-
+ if (bpy_prop_callback_check(poll_cb, "poll", 2) == -1) {
+ return NULL;
+ }
prop = RNA_def_pointer_runtime(srna, id, ptype, name ? name : id, description);
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+
+ if (RNA_struct_idprops_contains_datablock(ptype)) {
+ if (RNA_struct_is_a(srna, &RNA_PropertyGroup)) {
+ RNA_def_struct_flag(srna, STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES);
+ }
+ }
bpy_prop_callback_assign_update(prop, update_cb);
+ bpy_prop_callback_assign_pointer(prop, poll_cb);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
@@ -2879,7 +2947,7 @@ BPY_PROPDEF_NAME_DOC
BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC
);
-static PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
+PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -2910,10 +2978,23 @@ static PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject
if (!ptype)
return NULL;
+ if (!RNA_struct_is_a(ptype, &RNA_PropertyGroup)) {
+ PyErr_Format(PyExc_TypeError,
+ "CollectionProperty(...) expected an RNA type derived from %.200s",
+ RNA_struct_ui_name(&RNA_ID), RNA_struct_ui_name(&RNA_PropertyGroup));
+ return NULL;
+ }
+
prop = RNA_def_collection_runtime(srna, id, ptype, name ? name : id, description);
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+
+ if (RNA_struct_idprops_contains_datablock(ptype)) {
+ if (RNA_struct_is_a(srna, &RNA_PropertyGroup)) {
+ RNA_def_struct_flag(srna, STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES);
+ }
+ }
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h
index c9934ca0cf3..614c1b4b708 100644
--- a/source/blender/python/intern/bpy_props.h
+++ b/source/blender/python/intern/bpy_props.h
@@ -30,6 +30,10 @@
PyObject *BPY_rna_props(void);
+PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw);
+StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix);
+
#define PYRNA_STACK_ARRAY 32
#endif
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 2fd46ab94f0..00627030db3 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -1934,16 +1934,10 @@ static int pyrna_py_to_prop(
}
else {
/* data == NULL, assign to RNA */
- if (value == Py_None) {
- PointerRNA valueptr = {{NULL}};
- RNA_property_pointer_set(ptr, prop, valueptr);
- }
- else if (RNA_struct_is_a(param->ptr.type, ptr_type)) {
- RNA_property_pointer_set(ptr, prop, param->ptr);
- }
- else {
+ if (value == Py_None || RNA_struct_is_a(param->ptr.type, ptr_type))
+ RNA_property_pointer_set(ptr, prop, value == Py_None ? PointerRNA_NULL : param->ptr);
+ else
raise_error = true;
- }
}
if (raise_error) {
@@ -3277,6 +3271,16 @@ static int pyrna_struct_ass_subscript(BPy_StructRNA *self, PyObject *key, PyObje
return -1;
}
+ BPy_StructRNA *val = (BPy_StructRNA *)value;
+ if (val && self->ptr.type && val->ptr.type) {
+ if (!RNA_struct_idprops_datablock_allowed(self->ptr.type) &&
+ RNA_struct_idprops_contains_datablock(val->ptr.type))
+ {
+ PyErr_SetString(PyExc_TypeError, "bpy_struct[key] = val: datablock id properties not supported for this type");
+ return -1;
+ }
+ }
+
return BPy_Wrap_SetMapItem(group, key, value);
}
@@ -6745,7 +6749,7 @@ PyObject *pyrna_id_CreatePyObject(ID *id)
bool pyrna_id_FromPyObject(PyObject *obj, ID **id)
{
- if (BPy_StructRNA_Check(obj) && (RNA_struct_is_ID(((BPy_StructRNA *)obj)->ptr.type))) {
+ if (pyrna_id_CheckPyObject(obj)) {
*id = ((BPy_StructRNA *)obj)->ptr.id.data;
return true;
}
@@ -6755,6 +6759,11 @@ bool pyrna_id_FromPyObject(PyObject *obj, ID **id)
}
}
+bool pyrna_id_CheckPyObject(PyObject *obj)
+{
+ return BPy_StructRNA_Check(obj) && (RNA_struct_is_ID(((BPy_StructRNA *) obj)->ptr.type));
+}
+
void BPY_rna_init(void)
{
#ifdef USE_MATHUTILS /* register mathutils callbacks, ok to run more than once. */
@@ -7089,6 +7098,21 @@ static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item
args_fake = PyTuple_New(1);
PyTuple_SET_ITEM(args_fake, 0, py_srna_cobject);
+ PyObject *type = PyDict_GetItemString(py_kw, "type");
+ StructRNA *type_srna = srna_from_self(type, "");
+ if (type_srna) {
+ if (!RNA_struct_idprops_datablock_allowed(srna) &&
+ (*(PyCFunctionWithKeywords)PyCFunction_GET_FUNCTION(py_func) == BPy_PointerProperty ||
+ *(PyCFunctionWithKeywords)PyCFunction_GET_FUNCTION(py_func) == BPy_CollectionProperty) &&
+ RNA_struct_idprops_contains_datablock(type_srna))
+ {
+ PyErr_Format(PyExc_ValueError,
+ "bpy_struct \"%.200s\" doesn't support datablock properties \n",
+ RNA_struct_identifier(srna));
+ return -1;
+ }
+ }
+
py_ret = PyObject_Call(py_func, args_fake, py_kw);
if (py_ret) {
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index e38d4f095d6..605f79b1ad8 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -179,6 +179,7 @@ PyObject *pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop);
/* extern'd by other modules which don't deal closely with RNA */
PyObject *pyrna_id_CreatePyObject(struct ID *id);
bool pyrna_id_FromPyObject(PyObject *obj, struct ID **id);
+bool pyrna_id_CheckPyObject(PyObject *obj);
/* operators also need this to set args */
int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const bool all_args, const char *error_prefix);
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 4e980e4c0e6..bd44e77e7c6 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -1301,7 +1301,7 @@ PyDoc_STRVAR(Matrix_to_scale_doc,
" :return: Return the scale of a matrix.\n"
" :rtype: :class:`Vector`\n"
"\n"
-" .. note:: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.\n"
+" .. note:: This method does not return a negative scale on any axis because it is not possible to obtain this data from the matrix alone.\n"
);
static PyObject *Matrix_to_scale(MatrixObject *self)
{
@@ -1390,11 +1390,11 @@ PyDoc_STRVAR(Matrix_invert_doc,
"\n"
" Set the matrix to its inverse.\n"
"\n"
-" :arg fallback: Set the matrix to this value when the inverse can't be calculated\n"
+" :arg fallback: Set the matrix to this value when the inverse cannot be calculated\n"
" (instead of raising a :exc:`ValueError` exception).\n"
" :type fallback: :class:`Matrix`\n"
"\n"
-" .. seealso:: <https://en.wikipedia.org/wiki/Inverse_matrix>\n"
+" .. seealso:: `Inverse matrix <https://en.wikipedia.org/wiki/Inverse_matrix>` on Wikipedia.\n"
);
static PyObject *Matrix_invert(MatrixObject *self, PyObject *args)
{
@@ -1505,7 +1505,7 @@ PyDoc_STRVAR(Matrix_invert_safe_doc,
" If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, to get an invertible one.\n"
" If tweaked matrix is still degenerated, set to the identity matrix instead.\n"
"\n"
-" .. seealso:: <https://en.wikipedia.org/wiki/Inverse_matrix>\n"
+" .. seealso:: `Inverse Matrix <https://en.wikipedia.org/wiki/Inverse_matrix>` on Wikipedia.\n"
);
static PyObject *Matrix_invert_safe(MatrixObject *self)
{
@@ -1554,9 +1554,9 @@ PyDoc_STRVAR(Matrix_adjugate_doc,
"\n"
" Set the matrix to its adjugate.\n"
"\n"
-" .. note:: When the matrix cant be adjugated a :exc:`ValueError` exception is raised.\n"
+" .. note:: When the matrix cannot be adjugated a :exc:`ValueError` exception is raised.\n"
"\n"
-" .. seealso:: <https://en.wikipedia.org/wiki/Adjugate_matrix>\n"
+" .. seealso:: `Adjugate matrix <https://en.wikipedia.org/wiki/Adjugate_matrix>` on Wikipedia.\n"
);
static PyObject *Matrix_adjugate(MatrixObject *self)
{
@@ -1733,7 +1733,7 @@ PyDoc_STRVAR(Matrix_determinant_doc,
" :return: Return the determinant of a matrix.\n"
" :rtype: float\n"
"\n"
-" .. seealso:: <https://en.wikipedia.org/wiki/Determinant>\n"
+" .. seealso:: `Determinant <https://en.wikipedia.org/wiki/Determinant>` on Wikipedia.\n"
);
static PyObject *Matrix_determinant(MatrixObject *self)
{
@@ -1755,7 +1755,7 @@ PyDoc_STRVAR(Matrix_transpose_doc,
"\n"
" Set the matrix to its transpose.\n"
"\n"
-" .. seealso:: <https://en.wikipedia.org/wiki/Transpose>\n"
+" .. seealso:: `Transpose <https://en.wikipedia.org/wiki/Transpose>` on Wikipedia.\n"
);
static PyObject *Matrix_transpose(MatrixObject *self)
{
@@ -1887,10 +1887,10 @@ PyDoc_STRVAR(Matrix_identity_doc,
"\n"
" Set the matrix to the identity matrix.\n"
"\n"
-" .. note:: An object with zero location and rotation, a scale of one,\n"
+" .. note:: An object with a location and rotation of zero, and a scale of one\n"
" will have an identity matrix.\n"
"\n"
-" .. seealso:: <https://en.wikipedia.org/wiki/Identity_matrix>\n"
+" .. seealso:: `Identity matrix <https://en.wikipedia.org/wiki/Identity_matrix>` on Wikipedia.\n"
);
static PyObject *Matrix_identity(MatrixObject *self)
{
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index f535aa5aa71..eaa4cf2c69c 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -381,7 +381,7 @@ bool RE_allow_render_generic_object(struct Object *ob);
/* RE_updateRenderInstances flag */
enum {
RE_OBJECT_INSTANCES_UPDATE_VIEW = (1 << 0),
- RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1),
+ RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1)
};
void RE_updateRenderInstances(Render *re, int flag);
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
index ae389fdfd2e..b64c0c8fc52 100644
--- a/source/blender/render/extern/include/RE_shader_ext.h
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -178,6 +178,7 @@ typedef struct ShadeInput {
unsigned int lay;
int layflag, passflag, combinedflag;
+ short object_pass_index;
struct Group *light_override;
struct Material *mat_override;
@@ -241,6 +242,9 @@ enum {
const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4];
+float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi);
+float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi);
+
enum {
RE_VIEW_MATRIX,
RE_VIEWINV_MATRIX,
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index b3a5ccdae17..f0323340899 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -382,6 +382,8 @@ typedef struct ObjectInstanceRen {
float part_co[3];
float part_vel[3];
float part_avel[3];
+
+ unsigned int random_id;
} ObjectInstanceRen;
/* ------------------------------------------------------------------------- */
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index b4a14f5337d..42e4d4f27f6 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -1112,14 +1112,15 @@ static int multitex(Tex *tex,
const short which_output,
struct ImagePool *pool,
const bool skip_load_image,
- const bool texnode_preview)
+ const bool texnode_preview,
+ const bool use_nodes)
{
float tmpvec[3];
int retval = 0; /* return value, int:0, col:1, nor:2, everything:3 */
texres->talpha = false; /* is set when image texture returns alpha (considered premul) */
- if (tex->use_nodes && tex->nodetree) {
+ if (use_nodes && tex->use_nodes && tex->nodetree) {
retval = ntreeTexExecTree(tex->nodetree, texres, texvec, dxt, dyt, osatex, thread,
tex, which_output, R.r.cfra, texnode_preview, NULL, NULL);
}
@@ -1239,7 +1240,8 @@ static int multitex_nodes_intern(Tex *tex,
ImagePool *pool,
const bool scene_color_manage,
const bool skip_load_image,
- const bool texnode_preview)
+ const bool texnode_preview,
+ const bool use_nodes)
{
if (tex==NULL) {
memset(texres, 0, sizeof(TexResult));
@@ -1264,7 +1266,8 @@ static int multitex_nodes_intern(Tex *tex,
which_output,
pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ use_nodes);
if (mtex->mapto & (MAP_COL+MAP_COLSPEC+MAP_COLMIR)) {
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
@@ -1311,7 +1314,8 @@ static int multitex_nodes_intern(Tex *tex,
which_output,
pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ use_nodes);
{
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
@@ -1341,7 +1345,8 @@ static int multitex_nodes_intern(Tex *tex,
which_output,
pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ use_nodes);
}
}
@@ -1354,7 +1359,8 @@ int multitex_nodes(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int os
return multitex_nodes_intern(tex, texvec, dxt, dyt, osatex, texres,
thread, which_output, shi, mtex, pool, R.scene_color_manage,
(R.r.scemode & R_NO_IMAGE_LOAD) != 0,
- (R.r.scemode & R_TEXNODE_PREVIEW) != 0);
+ (R.r.scemode & R_TEXNODE_PREVIEW) != 0,
+ true);
}
/* this is called for surface shading */
@@ -1378,7 +1384,8 @@ static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt
mtex->which_output,
pool,
skip_load_image,
- (R.r.scemode & R_TEXNODE_PREVIEW) != 0);
+ (R.r.scemode & R_TEXNODE_PREVIEW) != 0,
+ true);
}
}
@@ -1408,7 +1415,8 @@ int multitex_ext(Tex *tex,
pool,
scene_color_manage,
skip_load_image,
- false);
+ false,
+ true);
}
/* extern-tex doesn't support nodes (ntreeBeginExec() can't be called when rendering is going on)\
@@ -1417,13 +1425,19 @@ int multitex_ext(Tex *tex,
*/
int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image)
{
- int use_nodes= tex->use_nodes, retval;
-
- tex->use_nodes = false;
- retval= multitex_nodes_intern(tex, texvec, NULL, NULL, 0, texres, 0, 0, NULL, NULL, pool, scene_color_manage, skip_load_image, false);
- tex->use_nodes= use_nodes;
-
- return retval;
+ return multitex_nodes_intern(tex,
+ texvec,
+ NULL, NULL,
+ 0,
+ texres,
+ 0,
+ 0,
+ NULL, NULL,
+ pool,
+ scene_color_manage,
+ skip_load_image,
+ false,
+ false);
}
@@ -2873,7 +2887,8 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
mtex->which_output,
re->pool,
skip_load_image,
- texnode_preview); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */
+ texnode_preview,
+ true); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */
/* texture output */
@@ -3051,7 +3066,8 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
mtex->which_output,
har->pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ true);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3274,7 +3290,8 @@ void do_sky_tex(
mtex->which_output,
R.pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ true);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3500,7 +3517,8 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r
mtex->which_output,
R.pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ true);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3614,7 +3632,8 @@ int externtex(MTex *mtex,
mtex->which_output,
pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ true);
if (rgb) {
texr.tin = IMB_colormanagement_get_luminance(&texr.tr);
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
index 76e6ca8d467..199322795f3 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -66,6 +66,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_hash.h"
#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
@@ -1458,6 +1459,14 @@ ObjectInstanceRen *RE_addRenderInstance(
}
}
+ /* Fill object info */
+ if (dob) {
+ obi->random_id = dob->random_id;
+ }
+ else {
+ obi->random_id = BLI_hash_int_2d(BLI_hash_string(obi->ob->id.name + 2), 0);
+ }
+
RE_updateRenderInstance(re, obi, RE_OBJECT_INSTANCES_UPDATE_OBMAT | RE_OBJECT_INSTANCES_UPDATE_VIEW);
if (mat) {
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index a8fb72fb7f8..8dea0930b9e 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -2141,6 +2141,16 @@ const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int m
return NULL;
}
+float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi)
+{
+ return obi->ob->index;
+}
+
+float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi)
+{
+ return obi->random_id;
+}
+
const float (*RE_render_current_get_matrix(int matrix_id))[4]
{
switch (matrix_id) {
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index b6245a8c0d1..925563a0777 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -128,10 +128,6 @@ if(WITH_PYTHON)
../python
)
add_definitions(-DWITH_PYTHON)
-
- if(WITH_PYTHON_SECURITY)
- add_definitions(-DWITH_PYTHON_SECURITY)
- endif()
endif()
if(WITH_GAMEENGINE)
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 4351cd22b18..d0522fdd7d4 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -489,7 +489,7 @@ void wm_close_and_free_all(bContext *C, ListBase *wmlist)
while ((wm = wmlist->first)) {
wm_close_and_free(C, wm);
BLI_remlink(wmlist, wm);
- BKE_libblock_free_data(bmain, &wm->id);
+ BKE_libblock_free_data(bmain, &wm->id, true);
MEM_freeN(wm);
}
}
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 60a361122c2..028355f9af3 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -316,7 +316,7 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
}
/* in case UserDef was read, we re-initialize all, and do versioning */
-static void wm_init_userdef(bContext *C, const bool from_memory)
+static void wm_init_userdef(bContext *C, const bool use_factory_settings)
{
Main *bmain = CTX_data_main(C);
@@ -336,7 +336,7 @@ static void wm_init_userdef(bContext *C, const bool from_memory)
}
/* avoid re-saving for every small change to our prefs, allow overrides */
- if (from_memory) {
+ if (use_factory_settings) {
BLO_update_defaults_userpref_blend();
}
@@ -470,6 +470,10 @@ static void wm_file_read_post(bContext *C, bool is_startup_file)
if (is_startup_file) {
/* possible python hasn't been initialized */
if (CTX_py_init_get(C)) {
+ /* Only run when we have a template path found. */
+ if (BKE_appdir_app_template_any()) {
+ BPY_execute_string(C, "__import__('bl_app_template_utils').reset()");
+ }
/* sync addons, these may have changed from the defaults */
BPY_execute_string(C, "__import__('addon_utils').reset_all()");
@@ -632,22 +636,31 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
* Called on startup, (context entirely filled with NULLs)
* or called for 'New File' both startup.blend and userpref.blend are checked.
*
- * \param from_memory: Ignore on-disk startup file, use bundled ``datatoc_startup_blend`` instead.
+ * \param use_factory_settings: Ignore on-disk startup file, use bundled ``datatoc_startup_blend`` instead.
* Used for "Restore Factory Settings".
* \param filepath_startup_override: Optional path pointing to an alternative blend file (may be NULL).
+ * \param app_template_override: Template to use instead of the template defined in user-preferences.
+ * When not-null, this is written into the user preferences.
*/
int wm_homefile_read(
bContext *C, ReportList *reports,
- bool from_memory, const char *filepath_startup_override)
+ bool use_factory_settings, bool use_empty_data,
+ const char *filepath_startup_override, const char *app_template_override)
{
ListBase wmbase;
+ bool success = false;
+
char filepath_startup[FILE_MAX];
char filepath_userdef[FILE_MAX];
- bool success = false;
+
+ /* When 'app_template' is set: '{BLENDER_USER_CONFIG}/{app_template}' */
+ char app_template_system[FILE_MAX];
+ /* When 'app_template' is set: '{BLENDER_SYSTEM_SCRIPTS}/startup/bl_app_templates_system/{app_template}' */
+ char app_template_config[FILE_MAX];
/* Indicates whether user preferences were really load from memory.
*
- * This is used for versioning code, and for this we can not rely on from_memory
+ * This is used for versioning code, and for this we can not rely on use_factory_settings
* passed via argument. This is because there might be configuration folder
* exists but it might not have userpref.blend and in this case we fallback to
* reading home file from memory.
@@ -658,7 +671,7 @@ int wm_homefile_read(
eBLOReadSkip skip_flags = 0;
/* options exclude eachother */
- BLI_assert((from_memory && filepath_startup_override) == 0);
+ BLI_assert((use_factory_settings && filepath_startup_override) == 0);
if ((G.f & G_SCRIPT_OVERRIDE_PREF) == 0) {
BKE_BIT_TEST_SET(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_SCRIPT_AUTOEXEC);
@@ -669,34 +682,32 @@ int wm_homefile_read(
UI_view2d_zoom_cache_reset();
G.relbase_valid = 0;
- if (!from_memory) {
- const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
- if (filepath_startup_override) {
- BLI_strncpy(filepath_startup, filepath_startup_override, FILE_MAX);
- if (cfgdir) {
- BLI_make_file_string(G.main->name, filepath_userdef, cfgdir, BLENDER_USERPREF_FILE);
- }
- else {
- filepath_userdef[0] = '\0';
- }
- }
- else if (cfgdir) {
- BLI_make_file_string(G.main->name, filepath_startup, cfgdir, BLENDER_STARTUP_FILE);
- BLI_make_file_string(G.main->name, filepath_userdef, cfgdir, BLENDER_USERPREF_FILE);
+ /* put aside screens to match with persistent windows later */
+ wm_window_match_init(C, &wmbase);
+
+ filepath_startup[0] = '\0';
+ filepath_userdef[0] = '\0';
+ app_template_system[0] = '\0';
+ app_template_config[0] = '\0';
+
+ const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
+ if (!use_factory_settings) {
+ if (cfgdir) {
+ BLI_path_join(filepath_startup, sizeof(filepath_startup), cfgdir, BLENDER_STARTUP_FILE, NULL);
+ BLI_path_join(filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL);
}
else {
- filepath_startup[0] = '\0';
- filepath_userdef[0] = '\0';
- from_memory = true;
+ use_factory_settings = true;
+ }
+
+ if (filepath_startup_override) {
+ BLI_strncpy(filepath_startup, filepath_startup_override, FILE_MAX);
}
}
-
- /* put aside screens to match with persistent windows later */
- wm_window_match_init(C, &wmbase);
-
+
/* load preferences before startup.blend */
- if (!from_memory && BLI_exists(filepath_userdef)) {
+ if (!use_factory_settings && BLI_exists(filepath_userdef)) {
UserDef *userdef = BKE_blendfile_userdef_read(filepath_userdef, NULL);
if (userdef != NULL) {
BKE_blender_userdef_set_data(userdef);
@@ -708,7 +719,43 @@ int wm_homefile_read(
}
}
- if (!from_memory) {
+ const char *app_template = NULL;
+
+ if (filepath_startup_override != NULL) {
+ /* pass */
+ }
+ else if (app_template_override) {
+ app_template = app_template_override;
+ }
+ else if (!use_factory_settings && U.app_template[0]) {
+ app_template = U.app_template;
+ }
+
+ if (app_template != NULL) {
+ BKE_appdir_app_template_id_search(app_template, app_template_system, sizeof(app_template_system));
+ BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL);
+ }
+
+ /* insert template name into startup file */
+ if (app_template != NULL) {
+ /* note that the path is being set even when 'use_factory_settings == true'
+ * this is done so we can load a templates factory-settings */
+ if (!use_factory_settings) {
+ BLI_path_join(filepath_startup, sizeof(filepath_startup), app_template_config, BLENDER_STARTUP_FILE, NULL);
+ if (BLI_access(filepath_startup, R_OK) != 0) {
+ filepath_startup[0] = '\0';
+ }
+ }
+ else {
+ filepath_startup[0] = '\0';
+ }
+
+ if (filepath_startup[0] == '\0') {
+ BLI_path_join(filepath_startup, sizeof(filepath_startup), app_template_system, BLENDER_STARTUP_FILE, NULL);
+ }
+ }
+
+ if (!use_factory_settings || (filepath_startup[0] != '\0')) {
if (BLI_access(filepath_startup, R_OK) == 0) {
success = (BKE_blendfile_read(C, filepath_startup, NULL, skip_flags) != BKE_BLENDFILE_READ_FAIL);
}
@@ -720,8 +767,8 @@ int wm_homefile_read(
}
if (success == false && filepath_startup_override && reports) {
+ /* We can not return from here because wm is already reset */
BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", filepath_startup_override);
- /*We can not return from here because wm is already reset*/
}
if (success == false) {
@@ -731,15 +778,50 @@ int wm_homefile_read(
if (BLI_listbase_is_empty(&wmbase)) {
wm_clear_default_size(C);
}
- BKE_tempdir_init(U.tempdir);
+ }
-#ifdef WITH_PYTHON_SECURITY
- /* use alternative setting for security nuts
- * otherwise we'd need to patch the binary blob - startup.blend.c */
- U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
-#endif
+ if (use_empty_data) {
+ BKE_blendfile_read_make_empty(C);
}
-
+
+ /* Load template preferences,
+ * unlike regular preferences we only use some of the settings,
+ * see: BKE_blender_userdef_set_app_template */
+ if (app_template_system[0] != '\0') {
+ char temp_path[FILE_MAX];
+ temp_path[0] = '\0';
+ if (!use_factory_settings) {
+ BLI_path_join(temp_path, sizeof(temp_path), app_template_config, BLENDER_USERPREF_FILE, NULL);
+ if (BLI_access(temp_path, R_OK) != 0) {
+ temp_path[0] = '\0';
+ }
+ }
+
+ if (temp_path[0] == '\0') {
+ BLI_path_join(temp_path, sizeof(temp_path), app_template_system, BLENDER_USERPREF_FILE, NULL);
+ }
+
+ UserDef *userdef_template = NULL;
+ /* just avoids missing file warning */
+ if (BLI_exists(temp_path)) {
+ userdef_template = BKE_blendfile_userdef_read(temp_path, NULL);
+ }
+ if (userdef_template == NULL) {
+ /* we need to have preferences load to overwrite preferences from previous template */
+ userdef_template = BKE_blendfile_userdef_read_from_memory(
+ datatoc_startup_blend, datatoc_startup_blend_size, NULL);
+ }
+ if (userdef_template) {
+ BKE_blender_userdef_set_app_template(userdef_template);
+ BKE_blender_userdef_free_data(userdef_template);
+ MEM_freeN(userdef_template);
+ }
+ }
+
+ if (app_template_override) {
+ BLI_strncpy(U.app_template, app_template_override, sizeof(U.app_template));
+ }
+
/* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise
* can remove this eventually, only in a 2.53 and older, now its not written */
G.fileflags &= ~G_FILE_RELATIVE_REMAP;
@@ -754,11 +836,14 @@ int wm_homefile_read(
G.main->name[0] = '\0';
/* When loading factory settings, the reset solid OpenGL lights need to be applied. */
- if (!G.background) GPU_default_lights();
-
- /* XXX */
- G.save_over = 0; // start with save preference untitled.blend
- G.fileflags &= ~G_FILE_AUTOPLAY; /* disable autoplay in startup.blend... */
+ if (!G.background) {
+ GPU_default_lights();
+ }
+
+ /* start with save preference untitled.blend */
+ G.save_over = 0;
+ /* disable auto-play in startup.blend... */
+ G.fileflags &= ~G_FILE_AUTOPLAY;
wm_file_read_post(C, true);
@@ -1274,6 +1359,13 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
char filepath[FILE_MAX];
int fileflags;
+ const char *app_template = U.app_template[0] ? U.app_template : NULL;
+ const char * const cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, app_template);
+ if (cfgdir == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create user config path");
+ return OPERATOR_CANCELLED;
+ }
+
BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
/* check current window and close it if temp */
@@ -1283,7 +1375,8 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
/* update keymaps in user preferences */
WM_keyconfig_update(wm);
- BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_STARTUP_FILE, NULL);
+
printf("trying to save homefile at %s ", filepath);
ED_editors_flush_edits(C, false);
@@ -1361,21 +1454,44 @@ static int wm_userpref_write_exec(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
char filepath[FILE_MAX];
+ const char *cfgdir;
+ bool ok = false;
/* update keymaps in user preferences */
WM_keyconfig_update(wm);
- BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE);
- printf("trying to save userpref at %s ", filepath);
-
- if (BKE_blendfile_userdef_write(filepath, op->reports) == 0) {
- printf("fail\n");
- return OPERATOR_CANCELLED;
+ if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL))) {
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ printf("trying to save userpref at %s ", filepath);
+ if (BKE_blendfile_userdef_write(filepath, op->reports) != 0) {
+ printf("ok\n");
+ ok = true;
+ }
+ else {
+ printf("fail\n");
+ }
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create userpref path");
}
- printf("ok\n");
+ if (U.app_template[0] && (cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) {
+ /* Also save app-template prefs */
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ printf("trying to save app-template userpref at %s ", filepath);
+ if (BKE_blendfile_userdef_write(filepath, op->reports) == 0) {
+ printf("fail\n");
+ ok = true;
+ }
+ else {
+ printf("ok\n");
+ }
+ }
+ else if (U.app_template[0]) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create app-template userpref path");
+ }
- return OPERATOR_FINISHED;
+ return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void WM_OT_save_userpref(wmOperatorType *ot)
@@ -1410,11 +1526,11 @@ void WM_OT_read_history(wmOperatorType *ot)
static int wm_homefile_read_exec(bContext *C, wmOperator *op)
{
- const bool from_memory = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
+ const bool use_factory_settings = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
char filepath_buf[FILE_MAX];
const char *filepath = NULL;
- if (!from_memory) {
+ if (!use_factory_settings) {
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
/* This can be used when loading of a start-up file should only change
@@ -1436,9 +1552,27 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
G.fileflags &= ~G_FILE_NO_UI;
}
- if (wm_homefile_read(C, op->reports, from_memory, filepath)) {
- /* Load a file but keep the splash open */
- if (!from_memory && RNA_boolean_get(op->ptr, "use_splash")) {
+ char app_template_buf[sizeof(U.app_template)];
+ const char *app_template;
+ PropertyRNA *prop_app_template = RNA_struct_find_property(op->ptr, "app_template");
+ const bool use_splash = !use_factory_settings && RNA_boolean_get(op->ptr, "use_splash");
+ const bool use_empty_data = RNA_boolean_get(op->ptr, "use_empty");
+
+ if (prop_app_template && RNA_property_is_set(op->ptr, prop_app_template)) {
+ RNA_property_string_get(op->ptr, prop_app_template, app_template_buf);
+ app_template = app_template_buf;
+ }
+ else if (!use_factory_settings) {
+ /* TODO: dont reset prefs on 'New File' */
+ BLI_strncpy(app_template_buf, U.app_template, sizeof(app_template_buf));
+ app_template = app_template_buf;
+ }
+ else {
+ app_template = NULL;
+ }
+
+ if (wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, filepath, app_template)) {
+ if (use_splash) {
WM_init_splash(C);
}
return OPERATOR_FINISHED;
@@ -1468,21 +1602,36 @@ void WM_OT_read_homefile(wmOperatorType *ot)
"Load user interface setup from the .blend file");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
/* So the splash can be kept open after loading a file (for templates). */
prop = RNA_def_boolean(ot->srna, "use_splash", false, "Splash", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
/* omit poll to run in background mode */
}
void WM_OT_read_factory_settings(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
ot->name = "Load Factory Settings";
ot->idname = "WM_OT_read_factory_settings";
ot->description = "Load default file and user preferences";
ot->invoke = WM_operator_confirm;
ot->exec = wm_homefile_read_exec;
+
+ prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
/* omit poll to run in background mode */
}
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index be74a0c7362..9bafe72d805 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -192,7 +192,7 @@ void WM_init(bContext *C, int argc, const char **argv)
wm_init_reports(C);
/* get the default database, plus a wm */
- wm_homefile_read(C, NULL, G.factory_startup, NULL);
+ wm_homefile_read(C, NULL, G.factory_startup, false, NULL, NULL);
BLT_lang_set(NULL);
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index e201fa433d4..db5fc23146f 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -121,6 +121,13 @@ static void wm_keymap_item_properties_update_ot(wmKeyMapItem *kmi)
if (ot->srna != kmi->ptr->type) {
/* matches wm_keymap_item_properties_set but doesnt alloc new ptr */
WM_operator_properties_create_ptr(kmi->ptr, ot);
+ /* 'kmi->ptr->data' NULL'd above, keep using existing properties.
+ * Note: the operators property types may have changed,
+ * we will need a more comprehensive sanitize function to support this properly.
+ */
+ if (kmi->properties) {
+ kmi->ptr->data = kmi->properties;
+ }
WM_operator_properties_sanitize(kmi->ptr, 1);
}
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 9d4c3986678..d827ccafda8 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -900,7 +900,7 @@ void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
{
- wmOperatorType *ot = WM_operatortype_find(opstring, 0);
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
if (ot)
WM_operator_properties_create_ptr(ptr, ot);
@@ -1403,20 +1403,6 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
}
}
-static void popup_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg))
-{
- wmOperator *op = op_ptr;
- if (op->type->check) {
- if (op->type->check(C, op)) {
- /* check for popup and re-layout buttons */
- ARegion *ar_menu = CTX_wm_menu(C);
- if (ar_menu) {
- ED_region_tag_refresh_ui(ar_menu);
- }
- }
- }
-}
-
/* Dialogs are popups that require user verification (click OK) before exec */
static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
{
@@ -1435,8 +1421,6 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
- UI_block_func_set(block, popup_check_cb, op, NULL);
-
uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE);
/* clear so the OK button is left alone */
@@ -1475,8 +1459,6 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData)
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
- UI_block_func_set(block, popup_check_cb, op, NULL);
-
/* since ui is defined the auto-layout args are not used */
uiLayoutOperatorButs(C, layout, op, NULL, 'V', 0);
@@ -1523,7 +1505,7 @@ int WM_operator_ui_popup(bContext *C, wmOperator *op, int width, int height)
data->width = width;
data->height = height;
data->free_op = true; /* if this runs and gets registered we may want not to free it */
- UI_popup_block_ex(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data);
+ UI_popup_block_ex(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -1553,7 +1535,7 @@ static int wm_operator_props_popup_ex(bContext *C, wmOperator *op,
if (!do_redo || !(U.uiflag & USER_GLOBALUNDO))
return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, UI_UNIT_Y);
- UI_popup_block_ex(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op);
+ UI_popup_block_ex(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op, op);
if (do_call)
wm_block_redo_cb(C, op, 0);
@@ -1595,7 +1577,7 @@ int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, int h
data->free_op = true; /* if this runs and gets registered we may want not to free it */
/* op is not executed until popup OK but is clicked */
- UI_popup_block_ex(C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data);
+ UI_popup_block_ex(C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -1762,6 +1744,36 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
ibuf = IMB_ibImageFromMemory((unsigned char *)datatoc_splash_png,
datatoc_splash_png_size, IB_rect, NULL, "<splash screen>");
}
+
+ /* overwrite splash with template image */
+ if (U.app_template[0] != '\0') {
+ ImBuf *ibuf_template = NULL;
+ char splash_filepath[FILE_MAX];
+ char template_directory[FILE_MAX];
+
+ if (BKE_appdir_app_template_id_search(
+ U.app_template,
+ template_directory, sizeof(template_directory)))
+ {
+ BLI_join_dirfile(
+ splash_filepath, sizeof(splash_filepath), template_directory,
+ (U.pixelsize == 2) ? "splash_2x.png" : "splash.png");
+ ibuf_template = IMB_loadiffname(splash_filepath, IB_rect, NULL);
+ if (ibuf_template) {
+ const int x_expect = ibuf->x;
+ const int y_expect = 230 * (int)U.pixelsize;
+ /* don't cover the header text */
+ if (ibuf_template->x == x_expect && ibuf_template->y == y_expect) {
+ memcpy(ibuf->rect, ibuf_template->rect, ibuf_template->x * ibuf_template->y * sizeof(char[4]));
+ }
+ else {
+ printf("Splash expected %dx%d found %dx%d, ignoring: %s\n",
+ x_expect, y_expect, ibuf_template->x, ibuf_template->y, splash_filepath);
+ }
+ IMB_freeImBuf(ibuf_template);
+ }
+ }
+ }
#endif
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 2d43c47679d..aaf77946412 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -77,6 +77,7 @@
#include "GPU_extensions.h"
#include "GPU_init_exit.h"
#include "GPU_glew.h"
+#include "BLF_api.h"
/* for assert */
#ifndef NDEBUG
@@ -311,7 +312,7 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
if (tmpwin == NULL)
do_exit = 1;
- if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved) {
+ if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved && !G.background) {
if (do_exit) {
if (!GHOST_confirmQuit(win->ghostwin))
return;
@@ -374,14 +375,39 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
}
}
-static float wm_window_get_virtual_pixelsize(void)
+static void wm_window_set_dpi(wmWindow *win)
{
- return ((U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1.0f : 2.0f);
-}
+ int auto_dpi = GHOST_GetDPIHint(win->ghostwin);
-float wm_window_pixelsize(wmWindow *win)
-{
- return (GHOST_GetNativePixelSize(win->ghostwin) * wm_window_get_virtual_pixelsize());
+ /* Lazily init UI scale size, preserving backwards compatibility by
+ * computing UI scale from ratio of previous DPI and auto DPI */
+ if (U.ui_scale == 0) {
+ int virtual_pixel = (U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1 : 2;
+
+ if (U.dpi == 0) {
+ U.ui_scale = virtual_pixel;
+ }
+ else {
+ U.ui_scale = (virtual_pixel * U.dpi * 96.0f) / (auto_dpi * 72.0f);
+ }
+
+ CLAMP(U.ui_scale, 0.25f, 4.0f);
+ }
+
+ /* Blender's UI drawing assumes DPI 72 as a good default following macOS
+ * while Windows and Linux use DPI 96. GHOST assumes a default 96 so we
+ * remap the DPI to Blender's convention. */
+ int dpi = auto_dpi * U.ui_scale * (72.0 / 96.0f);
+
+ /* Automatically set larger pixel size for high DPI. */
+ int pixelsize = MAX2(1, dpi / 54);
+
+ /* Set user preferences globals for drawing, and for forward compatibility. */
+ U.pixelsize = GHOST_GetNativePixelSize(win->ghostwin) * pixelsize;
+ U.dpi = dpi / pixelsize;
+ U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE;
+
+ BKE_blender_userdef_refresh();
}
/* belongs to below */
@@ -456,10 +482,8 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
glClear(GL_COLOR_BUFFER_BIT);
}
- /* displays with larger native pixels, like Macbook. Used to scale dpi with */
/* needed here, because it's used before it reads userdef */
- U.pixelsize = wm_window_pixelsize(win);
- BKE_blender_userdef_refresh();
+ wm_window_set_dpi(win);
wm_window_swap_buffers(win);
@@ -626,7 +650,6 @@ wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
Scene *scene = CTX_data_scene(C);
const char *title;
rcti rect = *rect_init;
- const short px_virtual = (short)wm_window_get_virtual_pixelsize();
/* changes rect to fit within desktop */
wm_window_check_position(&rect);
@@ -644,9 +667,8 @@ wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
win->posy = rect.ymin;
}
- /* multiply with virtual pixelsize, ghost handles native one (e.g. for retina) */
- win->sizex = BLI_rcti_size_x(&rect) * px_virtual;
- win->sizey = BLI_rcti_size_y(&rect) * px_virtual;
+ win->sizex = BLI_rcti_size_x(&rect);
+ win->sizey = BLI_rcti_size_y(&rect);
if (win->ghostwin) {
wm_window_set_size(win, win->sizex, win->sizey);
@@ -835,8 +857,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
GHOST_ActivateWindowDrawingContext(win->ghostwin);
/* this can change per window */
- U.pixelsize = wm_window_pixelsize(win);
- BKE_blender_userdef_refresh();
+ wm_window_set_dpi(win);
}
}
@@ -1035,6 +1056,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
if (type == GHOST_kEventWindowSize) {
WM_jobs_stop(wm, win->screen, NULL);
}
+
+ wm_window_set_dpi(win);
/* win32: gives undefined window size when minimized */
if (state != GHOST_kWindowStateMinimized) {
@@ -1118,7 +1141,19 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
}
break;
}
-
+
+ case GHOST_kEventWindowDPIHintChanged:
+ {
+ wm_window_set_dpi(win);
+ /* font's are stored at each DPI level, without this we can easy load 100's of fonts */
+ BLF_cache_clear();
+
+ BKE_blender_userdef_refresh();
+ WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
+ break;
+ }
+
case GHOST_kEventOpenMainFile:
{
PointerRNA props_ptr;
@@ -1199,11 +1234,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
{
// only update if the actual pixel size changes
float prev_pixelsize = U.pixelsize;
- U.pixelsize = wm_window_pixelsize(win);
+ wm_window_set_dpi(win);
if (U.pixelsize != prev_pixelsize) {
- BKE_blender_userdef_refresh();
-
// close all popups since they are positioned with the pixel
// size baked in and it's difficult to correct them
wmWindow *oldWindow = CTX_wm_window(C);
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index 954d35722f3..9a1518e15b0 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -37,7 +37,8 @@ struct wmOperatorType;
void wm_history_file_read(void);
int wm_homefile_read(
struct bContext *C, struct ReportList *reports,
- bool from_memory, const char *filepath_startup_override);
+ bool use_factory_settings, bool use_empty_data,
+ const char *filepath_startup_override, const char *app_template_override);
void wm_file_read_report(bContext *C);
void WM_OT_save_homefile(struct wmOperatorType *ot);
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index c106f9d7851..f70ec6b47f6 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -63,8 +63,6 @@ void wm_window_swap_buffers (wmWindow *win);
void wm_window_set_swap_interval(wmWindow *win, int interval);
bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
-float wm_window_pixelsize(wmWindow *win);
-
void wm_get_cursor_position (wmWindow *win, int *x, int *y);
void wm_cursor_position_from_ghost (wmWindow *win, int *x, int *y);
void wm_cursor_position_to_ghost (wmWindow *win, int *x, int *y);