diff options
Diffstat (limited to 'source')
524 files changed, 14254 insertions, 10216 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index 6f2b78e0845..818d4cd3d89 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -138,10 +138,6 @@ if(WITH_CODEC_AVI) add_subdirectory(avi) endif() -if(WITH_CODEC_QUICKTIME) - add_subdirectory(quicktime) -endif() - if(WITH_PYTHON) add_subdirectory(python) endif() diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc index 1d2bc689027..d6e7a80d174 100644 --- a/source/blender/alembic/intern/abc_customdata.cc +++ b/source/blender/alembic/intern/abc_customdata.cc @@ -252,7 +252,31 @@ static void read_uvs(const CDStreamConfig &config, void *data, } } -static void read_custom_data_mcols(const ICompoundProperty &arbGeomParams, +static size_t mcols_out_of_bounds_check( + const size_t color_index, + const size_t array_size, + const std::string & iobject_full_name, + const PropertyHeader &prop_header, + bool &r_bounds_warning_given) +{ + if (color_index < array_size) { + return color_index; + } + + if (!r_bounds_warning_given) { + std::cerr << "Alembic: color index out of bounds " + "reading face colors for object " + << iobject_full_name + << ", property " + << prop_header.getName() << std::endl; + r_bounds_warning_given = true; + } + + return 0; +} + +static void read_custom_data_mcols(const std::string & iobject_full_name, + const ICompoundProperty &arbGeomParams, const PropertyHeader &prop_header, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss) @@ -303,6 +327,8 @@ static void read_custom_data_mcols(const ICompoundProperty &arbGeomParams, size_t face_index = 0; size_t color_index; + bool bounds_warning_given = false; + for (int i = 0; i < config.totpoly; ++i) { MPoly *poly = &mpolys[i]; MCol *cface = &cfaces[poly->loopstart + poly->totloop]; @@ -311,9 +337,14 @@ static void read_custom_data_mcols(const ICompoundProperty &arbGeomParams, for (int j = 0; j < poly->totloop; ++j, ++face_index) { --cface; --mloop; - color_index = is_facevarying ? face_index : mloop->v; if (use_c3f_ptr) { + color_index = mcols_out_of_bounds_check( + is_facevarying ? face_index : mloop->v, + c3f_ptr->size(), + iobject_full_name, prop_header, + bounds_warning_given); + const Imath::C3f &color = (*c3f_ptr)[color_index]; cface->a = FTOCHAR(color[0]); cface->r = FTOCHAR(color[1]); @@ -321,6 +352,12 @@ static void read_custom_data_mcols(const ICompoundProperty &arbGeomParams, cface->b = 255; } else { + color_index = mcols_out_of_bounds_check( + is_facevarying ? face_index : mloop->v, + c4f_ptr->size(), + iobject_full_name, prop_header, + bounds_warning_given); + const Imath::C4f &color = (*c4f_ptr)[color_index]; cface->a = FTOCHAR(color[0]); cface->r = FTOCHAR(color[1]); @@ -356,7 +393,10 @@ static void read_custom_data_uvs(const ICompoundProperty &prop, read_uvs(config, cd_data, sample.getVals(), sample.getIndices()); } -void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss) +void read_custom_data(const std::string & iobject_full_name, + const ICompoundProperty &prop, + const CDStreamConfig &config, + const Alembic::Abc::ISampleSelector &iss) { if (!prop.valid()) { return; @@ -386,7 +426,7 @@ void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &confi continue; } - read_custom_data_mcols(prop, prop_header, config, iss); + read_custom_data_mcols(iobject_full_name, prop, prop_header, config, iss); continue; } } diff --git a/source/blender/alembic/intern/abc_customdata.h b/source/blender/alembic/intern/abc_customdata.h index 9e671fde386..b3072a2c9f7 100644 --- a/source/blender/alembic/intern/abc_customdata.h +++ b/source/blender/alembic/intern/abc_customdata.h @@ -96,7 +96,8 @@ void write_custom_data(const OCompoundProperty &prop, CustomData *data, int data_type); -void read_custom_data(const ICompoundProperty &prop, +void read_custom_data(const std::string & iobject_full_name, + const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss); diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index 9a4ca6f99a8..6545ced8e4a 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -681,17 +681,17 @@ static void assign_materials(Main *bmain, Object *ob, const std::map<std::string std::string mat_name = it->first; mat_iter = mat_map.find(mat_name.c_str()); - Material *assigned_name; + Material *assigned_mat; if (mat_iter == mat_map.end()) { - assigned_name = BKE_material_add(bmain, mat_name.c_str()); - mat_map[mat_name] = assigned_name; + assigned_mat = BKE_material_add(bmain, mat_name.c_str()); + mat_map[mat_name] = assigned_mat; } else { - assigned_name = mat_iter->second; + assigned_mat = mat_iter->second; } - assign_material(ob, assigned_name, it->second, BKE_MAT_ASSIGN_OBDATA); + assign_material(ob, assigned_mat, it->second, BKE_MAT_ASSIGN_OBDATA); } } } @@ -943,7 +943,8 @@ static void get_weight_and_index(CDStreamConfig &config, config.ceil_index = i1; } -static void read_mesh_sample(ImportSettings *settings, +static void read_mesh_sample(const std::string & iobject_full_name, + ImportSettings *settings, const IPolyMeshSchema &schema, const ISampleSelector &selector, CDStreamConfig &config, @@ -981,10 +982,9 @@ static void read_mesh_sample(ImportSettings *settings, } if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { - read_custom_data(schema.getArbGeomParams(), config, selector); + read_custom_data(iobject_full_name, + schema.getArbGeomParams(), config, selector); } - - /* TODO: face sets */ } CDStreamConfig get_config(DerivedMesh *dm) @@ -1112,7 +1112,8 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, config.time = sample_sel.getRequestedTime(); bool do_normals = false; - read_mesh_sample(&settings, m_schema, sample_sel, config, do_normals); + read_mesh_sample(m_iobject.getFullName(), + &settings, m_schema, sample_sel, config, do_normals); if (new_dm) { /* Check if we had ME_SMOOTH flag set to restore it. */ @@ -1123,6 +1124,16 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, CDDM_calc_normals(new_dm); CDDM_calc_edges(new_dm); + /* Here we assume that the number of materials doesn't change, i.e. that + * the material slots that were created when the object was loaded from + * Alembic are still valid now. */ + size_t num_polys = new_dm->getNumPolys(new_dm); + if (num_polys > 0) { + MPoly *dmpolies = new_dm->getPolyArray(new_dm); + std::map<std::string, int> mat_map; + assign_facesets_to_mpoly(sample_sel, 0, dmpolies, num_polys, mat_map); + } + return new_dm; } @@ -1133,8 +1144,11 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, return dm; } -void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, - const ISampleSelector &sample_sel) +void AbcMeshReader::assign_facesets_to_mpoly( + const ISampleSelector &sample_sel, + size_t poly_start, + MPoly *mpoly, int totpoly, + std::map<std::string, int> & r_mat_map) { std::vector<std::string> face_sets; m_schema.getFaceSetNames(face_sets); @@ -1143,21 +1157,21 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_star return; } - std::map<std::string, int> mat_map; int current_mat = 0; for (int i = 0; i < face_sets.size(); ++i) { const std::string &grp_name = face_sets[i]; - if (mat_map.find(grp_name) == mat_map.end()) { - mat_map[grp_name] = 1 + current_mat++; + if (r_mat_map.find(grp_name) == r_mat_map.end()) { + r_mat_map[grp_name] = 1 + current_mat++; } - const int assigned_mat = mat_map[grp_name]; + const int assigned_mat = r_mat_map[grp_name]; const IFaceSet faceset = m_schema.getFaceSet(grp_name); if (!faceset.valid()) { + std::cerr << " Face set " << grp_name << " invalid for " << m_object_name << "\n"; continue; } @@ -1169,16 +1183,25 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_star for (size_t l = 0; l < num_group_faces; l++) { size_t pos = (*group_faces)[l] + poly_start; - if (pos >= mesh->totpoly) { + if (pos >= totpoly) { std::cerr << "Faceset overflow on " << faceset.getName() << '\n'; break; } - MPoly &poly = mesh->mpoly[pos]; + MPoly &poly = mpoly[pos]; poly.mat_nr = assigned_mat - 1; } } +} + +void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, + const ISampleSelector &sample_sel) +{ + std::map<std::string, int> mat_map; + assign_facesets_to_mpoly(sample_sel, + poly_start, mesh->mpoly, mesh->totpoly, + mat_map); utils::assign_materials(bmain, m_object, mat_map); } @@ -1197,7 +1220,8 @@ ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2) return NULL; } -static void read_subd_sample(ImportSettings *settings, +static void read_subd_sample(const std::string & iobject_full_name, + ImportSettings *settings, const ISubDSchema &schema, const ISampleSelector &selector, CDStreamConfig &config) @@ -1232,10 +1256,9 @@ static void read_subd_sample(ImportSettings *settings, } if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { - read_custom_data(schema.getArbGeomParams(), config, selector); + read_custom_data(iobject_full_name, + schema.getArbGeomParams(), config, selector); } - - /* TODO: face sets */ } /* ************************************************************************** */ @@ -1364,7 +1387,8 @@ DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, /* Only read point data when streaming meshes, unless we need to create new ones. */ CDStreamConfig config = get_config(new_dm ? new_dm : dm); config.time = sample_sel.getRequestedTime(); - read_subd_sample(&settings, m_schema, sample_sel, config); + read_subd_sample(m_iobject.getFullName(), + &settings, m_schema, sample_sel, config); if (new_dm) { /* Check if we had ME_SMOOTH flag set to restore it. */ diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h index 6bf1dde3d1d..5c1eb01d8e0 100644 --- a/source/blender/alembic/intern/abc_mesh.h +++ b/source/blender/alembic/intern/abc_mesh.h @@ -112,6 +112,11 @@ public: private: void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, const Alembic::AbcGeom::ISampleSelector &sample_sel); + + void assign_facesets_to_mpoly(const Alembic::Abc::ISampleSelector &sample_sel, + size_t poly_start, + MPoly *mpoly, int totpoly, + std::map<std::string, int> & r_mat_map); }; /* ************************************************************************** */ diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc index 26eb7620fb1..24a508e8292 100644 --- a/source/blender/alembic/intern/abc_util.cc +++ b/source/blender/alembic/intern/abc_util.cc @@ -370,10 +370,10 @@ AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSe reader = new AbcCurveReader(object, settings); } else { - std::cerr << "Alembic: unknown how to handle objects of schema " + std::cerr << "Alembic: unknown how to handle objects of schema '" << md.get("schemaObjTitle") - << ", skipping object " - << object.getFullName() << std::endl; + << "', skipping object '" + << object.getFullName() << "'" << std::endl; } return reader; diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index bee8e92e969..5503dcb1527 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -990,6 +990,10 @@ CacheReader *CacheReader_open_alembic_object(AbcArchiveHandle *handle, CacheRead ImportSettings settings; AbcObjectReader *abc_reader = create_reader(iobject, settings); + if (abc_reader == NULL) { + /* This object is not supported */ + return NULL; + } abc_reader->object(object); abc_reader->incref(); diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 63ff1149a68..700bfe568f1 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -193,7 +193,9 @@ struct DerivedMesh { * \warning Typical access is done via #getLoopTriArray, #getNumLoopTri. */ struct { - struct MLoopTri *array; + /* WARNING! swapping between array (ready-to-be-used data) and array_wip (where data is actually computed) + * shall always be protected by same lock as one used for looptris computing. */ + struct MLoopTri *array, *array_wip; int num; int num_alloc; } looptris; @@ -220,7 +222,7 @@ struct DerivedMesh { /** Recalculates mesh tessellation */ void (*recalcTessellation)(DerivedMesh *dm); - /** Loop tessellation cache */ + /** Loop tessellation cache (WARNING! Only call inside threading-protected code!) */ void (*recalcLoopTri)(DerivedMesh *dm); /** accessor functions */ const struct MLoopTri *(*getLoopTriArray)(DerivedMesh * dm); @@ -625,7 +627,6 @@ void DM_ensure_normals(DerivedMesh *dm); void DM_ensure_tessface(DerivedMesh *dm); void DM_ensure_looptri_data(DerivedMesh *dm); -void DM_ensure_looptri(DerivedMesh *dm); void DM_verttri_from_looptri(MVertTri *verttri, const MLoop *mloop, const MLoopTri *looptri, int looptri_num); void DM_update_tessface_data(DerivedMesh *dm); @@ -832,11 +833,5 @@ struct MEdge *DM_get_edge_array(struct DerivedMesh *dm, bool *r_allocated); struct MLoop *DM_get_loop_array(struct DerivedMesh *dm, bool *r_allocated); struct MPoly *DM_get_poly_array(struct DerivedMesh *dm, bool *r_allocated); struct MFace *DM_get_tessface_array(struct DerivedMesh *dm, bool *r_allocated); -const MLoopTri *DM_get_looptri_array( - DerivedMesh *dm, - const MVert *mvert, - const MPoly *mpoly, int mpoly_len, - const MLoop *mloop, int mloop_len, - bool *r_allocated); #endif /* __BKE_DERIVEDMESH_H__ */ diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 5db0c3c9130..28be2b04c71 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -57,8 +57,9 @@ extern "C" { /* Allocate a new bAction with the given name */ struct bAction *add_empty_action(struct Main *bmain, const char name[]); -/* Allocate a copy of the given Action and all its data */ -struct bAction *BKE_action_copy(struct Main *bmain, const struct bAction *src); +void BKE_action_copy_data(struct Main *bmain, struct bAction *act_dst, const struct bAction *act_src, const int flag); +/* Allocate a copy of the given Action and all its data */ +struct bAction *BKE_action_copy(struct Main *bmain, const struct bAction *act_src); /* Deallocate all of the Action's data, but not the Action itself */ void BKE_action_free(struct bAction *act); @@ -150,6 +151,7 @@ void BKE_pose_free_data_ex(struct bPose *pose, bool do_id_user); void BKE_pose_free_data(struct bPose *pose); void BKE_pose_free(struct bPose *pose); void BKE_pose_free_ex(struct bPose *pose, bool do_id_user); +void BKE_pose_copy_data_ex(struct bPose **dst, const struct bPose *src, const int flag, const bool copy_constraints); void BKE_pose_copy_data(struct bPose **dst, const struct bPose *src, const bool copy_constraints); void BKE_pose_channel_copy_data(struct bPoseChannel *pchan, const struct bPoseChannel *pchan_from); struct bPoseChannel *BKE_pose_channel_find_name(const struct bPose *pose, const char *name); diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 420ae4bb12d..534a57765f6 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -67,10 +67,10 @@ bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct b void BKE_animdata_free(struct ID *id, const bool do_id_user); /* Copy AnimData */ -struct AnimData *BKE_animdata_copy(struct AnimData *adt, const bool do_action); +struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const bool do_action); /* Copy AnimData */ -bool BKE_animdata_copy_id(struct ID *id_to, struct ID *id_from, const bool do_action); +bool BKE_animdata_copy_id(struct Main *bmain, struct ID *id_to, struct ID *id_from, const bool do_action); /* Copy AnimData Actions */ void BKE_animdata_copy_id_action(struct ID *id, const bool set_newid); @@ -102,7 +102,7 @@ struct KS_Path *BKE_keyingset_add_path(struct KeyingSet *ks, struct ID *id, cons struct KS_Path *BKE_keyingset_find_path(struct KeyingSet *ks, struct ID *id, const char group_name[], const char rna_path[], int array_index, int group_mode); /* Copy all KeyingSets in the given list */ -void BKE_keyingsets_copy(struct ListBase *newlist, struct ListBase *list); +void BKE_keyingsets_copy(struct ListBase *newlist, const struct ListBase *list); /* Free the given Keying Set path */ void BKE_keyingset_free_path(struct KeyingSet *ks, struct KS_Path *ksp); diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 6bfc8c918d6..60fb79d75d5 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -77,6 +77,7 @@ int BKE_armature_bonelist_count(struct ListBase *lb); void BKE_armature_bonelist_free(struct ListBase *lb); void BKE_armature_free(struct bArmature *arm); void BKE_armature_make_local(struct Main *bmain, struct bArmature *arm, const bool lib_local); +void BKE_armature_copy_data(struct Main *bmain, struct bArmature *arm_dst, const struct bArmature *arm_src, const int flag); struct bArmature *BKE_armature_copy(struct Main *bmain, const struct bArmature *arm); /* Bounding box. */ @@ -171,6 +172,11 @@ void BKE_pose_eval_init(struct EvaluationContext *eval_ctx, struct Object *ob, struct bPose *pose); +void BKE_pose_eval_init_ik(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob, + struct bPose *pose); + void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 207631d36bd..f95b1963a91 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,8 +27,8 @@ /* these lines are grep'd, watch out for our not-so-awesome regex * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ -#define BLENDER_VERSION 278 -#define BLENDER_SUBVERSION 5 +#define BLENDER_VERSION 279 +#define BLENDER_SUBVERSION 1 /* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 6 diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 42e4e73f2d5..dedb75a080a 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -44,6 +44,7 @@ void BKE_brush_system_exit(void); void BKE_brush_init(struct Brush *brush); struct Brush *BKE_brush_add(struct Main *bmain, const char *name, short ob_mode); struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode); +void BKE_brush_copy_data(struct Main *bmain, struct Brush *brush_dst, const struct Brush *brush_src, const int flag); struct Brush *BKE_brush_copy(struct Main *bmain, const struct Brush *brush); void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool lib_local); void BKE_brush_unlink(struct Main *bmain, struct Brush *brush); diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h index f1e643c4a19..e9712681090 100644 --- a/source/blender/blenkernel/BKE_cachefile.h +++ b/source/blender/blenkernel/BKE_cachefile.h @@ -47,6 +47,8 @@ void BKE_cachefile_init(struct CacheFile *cache_file); void BKE_cachefile_free(struct CacheFile *cache_file); +void BKE_cachefile_copy_data( + struct Main *bmain, struct CacheFile *cache_file_dst, const struct CacheFile *cache_file_src, const int flag); struct CacheFile *BKE_cachefile_copy(struct Main *bmain, const struct CacheFile *cache_file); void BKE_cachefile_make_local(struct Main *bmain, struct CacheFile *cache_file, const bool lib_local); diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index b2f22aacb28..04dee70faa6 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -52,6 +52,7 @@ struct GPUFXSettings; void BKE_camera_init(struct Camera *cam); void *BKE_camera_add(struct Main *bmain, const char *name); +void BKE_camera_copy_data(struct Main *bmain, struct Camera *cam_dst, const struct Camera *cam_src, const int flag); struct Camera *BKE_camera_copy(struct Main *bmain, const struct Camera *cam); void BKE_camera_make_local(struct Main *bmain, struct Camera *cam, const bool lib_local); void BKE_camera_free(struct Camera *ca); diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 047d1787f76..4e0eb5c65ac 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -120,6 +120,7 @@ void BKE_constraint_unique_name(struct bConstraint *con, struct ListBase *list); void BKE_constraints_free(struct ListBase *list); void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user); void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern); +void BKE_constraints_copy_ex(struct ListBase *dst, const struct ListBase *src, const int flag, bool do_extern); void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, void *userdata); void BKE_constraint_free_data(struct bConstraint *con); void BKE_constraint_free_data_ex(struct bConstraint *con, bool do_id_user); diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 635e999dd95..a900ba43443 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -78,6 +78,7 @@ void BKE_curve_free(struct Curve *cu); void BKE_curve_editfont_free(struct Curve *cu); void BKE_curve_init(struct Curve *cu); struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type); +void BKE_curve_copy_data(struct Main *bmain, struct Curve *cu_dst, const struct Curve *cu_src, const int flag); struct Curve *BKE_curve_copy(struct Main *bmain, const struct Curve *cu); void BKE_curve_make_local(struct Main *bmain, struct Curve *cu, const bool lib_local); short BKE_curve_type_get(struct Curve *cu); @@ -92,8 +93,8 @@ void BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_rot[3], fl bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]); bool BKE_curve_center_median(struct Curve *cu, float cent[3]); bool BKE_curve_center_bounds(struct Curve *cu, float cent[3]); -void BKE_curve_transform_ex(struct Curve *cu, float mat[4][4], const bool do_keys, const float unit_scale); -void BKE_curve_transform(struct Curve *cu, float mat[4][4], const bool do_keys); +void BKE_curve_transform_ex(struct Curve *cu, float mat[4][4], const bool do_keys, const bool do_props, const float unit_scale); +void BKE_curve_transform(struct Curve *cu, float mat[4][4], const bool do_keys, const bool do_props); void BKE_curve_translate(struct Curve *cu, float offset[3], const bool do_keys); void BKE_curve_material_index_remove(struct Curve *cu, int index); void BKE_curve_material_index_clear(struct Curve *cu); @@ -217,7 +218,4 @@ struct EvaluationContext; void BKE_curve_eval_geometry(struct EvaluationContext *eval_ctx, struct Curve *curve); -void BKE_curve_eval_path(struct EvaluationContext *eval_ctx, - struct Curve *curve); - #endif /* __BKE_CURVE_H__ */ diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h index e7ae0f606e7..60ad061bf77 100644 --- a/source/blender/blenkernel/BKE_font.h +++ b/source/blender/blenkernel/BKE_font.h @@ -78,6 +78,7 @@ void BKE_vfont_builtin_register(void *mem, int size); void BKE_vfont_free_data(struct VFont *vfont); void BKE_vfont_free(struct VFont *sc); void BKE_vfont_init(struct VFont *vfont); +void BKE_vfont_copy_data(struct Main *bmain, struct VFont *vfont_dst, const struct VFont *vfont_src, const int flag); struct VFont *BKE_vfont_builtin_get(void); struct VFont *BKE_vfont_load(struct Main *bmain, const char *filepath); struct VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists); diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h index 50407f3bdfc..1045fde0039 100644 --- a/source/blender/blenkernel/BKE_freestyle.h +++ b/source/blender/blenkernel/BKE_freestyle.h @@ -50,7 +50,7 @@ typedef struct FreestyleModuleSettings FreestyleModuleSettings; /* FreestyleConfig */ void BKE_freestyle_config_init(FreestyleConfig *config); void BKE_freestyle_config_free(FreestyleConfig *config); -void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config); +void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag); /* FreestyleConfig.modules */ FreestyleModuleConfig *BKE_freestyle_module_add(FreestyleConfig *config); diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index 830518906ab..790c8051ace 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -83,8 +83,6 @@ typedef struct Global { /* debug flag, G_DEBUG, G_DEBUG_PYTHON & friends, set python or command line args */ int debug; - bool have_quicktime; - /* this variable is written to / read from FileGlobal->fileflags */ int fileflags; diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index bdd28baf137..b6de922c245 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -60,6 +60,7 @@ struct bGPdata *BKE_gpencil_data_addnew(const char name[]); struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src); struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src); +void BKE_gpencil_copy_data(struct Main *bmain, struct bGPdata *gpd_dst, const struct bGPdata *gpd_src, const int flag); struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, const struct bGPdata *gpd, bool internal_copy); void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local); diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h index 684251c9561..404d1704c78 100644 --- a/source/blender/blenkernel/BKE_group.h +++ b/source/blender/blenkernel/BKE_group.h @@ -42,6 +42,7 @@ struct Scene; void BKE_group_free(struct Group *group); struct Group *BKE_group_add(struct Main *bmain, const char *name); +void BKE_group_copy_data(struct Main *bmain, struct Group *group_dst, const struct Group *group_src, const int flag); struct Group *BKE_group_copy(struct Main *bmain, const struct Group *group); void BKE_group_make_local(struct Main *bmain, struct Group *group, const bool lib_local); bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index ab8728faedb..5d8cd02756d 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -58,7 +58,7 @@ typedef union IDPropertyTemplate { /* ----------- Property Array Type ---------- */ IDProperty *IDP_NewIDPArray(const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -IDProperty *IDP_CopyIDPArray(const IDProperty *array) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* shallow copies item */ void IDP_SetIndexArray(struct IDProperty *prop, int index, struct IDProperty *item) ATTR_NONNULL(); @@ -103,6 +103,7 @@ IDProperty *IDP_GetPropertyTypeFromGroup(struct IDProperty *prop, const char *na /*-------- Main Functions --------*/ struct IDProperty *IDP_GetProperties(struct ID *id, const bool create_if_needed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); struct IDProperty *IDP_CopyProperty(const struct IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +struct IDProperty *IDP_CopyProperty_ex(const struct IDProperty *prop, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is_strict) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index e155b0719cc..3c716f39dd0 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -58,6 +58,7 @@ void BKE_images_exit(void); void BKE_image_free_packedfiles(struct Image *image); void BKE_image_free_views(struct Image *image); void BKE_image_free_buffers(struct Image *image); +void BKE_image_free_buffers_ex(struct Image *image, bool do_lock); /* call from library */ void BKE_image_free(struct Image *image); @@ -250,6 +251,7 @@ void BKE_image_packfiles_from_mem(struct ReportList *reports, struct Image *ima, void BKE_image_print_memlist(void); /* empty image block, of similar type and filename */ +void BKE_image_copy_data(struct Main *bmain, struct Image *ima_dst, const struct Image *ima_src, const int flag); struct Image *BKE_image_copy(struct Main *bmain, const struct Image *ima); /* merge source into dest, and free source */ diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index 94e8a24fbc5..5eef44ef896 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -51,6 +51,7 @@ extern "C" { void BKE_key_free(struct Key *sc); void BKE_key_free_nolib(struct Key *key); struct Key *BKE_key_add(struct ID *id); +void BKE_key_copy_data(struct Main *bmain, struct Key *key_dst, const struct Key *key_src, const int flag); struct Key *BKE_key_copy(struct Main *bmain, const struct Key *key); struct Key *BKE_key_copy_nolib(struct Key *key); void BKE_key_sort(struct Key *key); diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h index 713ca80fb1a..b68da654520 100644 --- a/source/blender/blenkernel/BKE_lamp.h +++ b/source/blender/blenkernel/BKE_lamp.h @@ -44,6 +44,7 @@ struct Scene; void BKE_lamp_init(struct Lamp *la); struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT; +void BKE_lamp_copy_data(struct Main *bmain, struct Lamp *la_dst, const struct Lamp *la_src, const int flag); struct Lamp *BKE_lamp_copy(struct Main *bmain, const struct Lamp *la) ATTR_WARN_UNUSED_RESULT; struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT; void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la, const bool lib_local); diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index ec1cf79832d..f7d006785d2 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -47,6 +47,7 @@ struct MDeformVert; void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb); void BKE_lattice_init(struct Lattice *lt); struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name); +void BKE_lattice_copy_data(struct Main *bmain, struct Lattice *lt_dst, const struct Lattice *lt_src, const int flag); struct Lattice *BKE_lattice_copy(struct Main *bmain, const struct Lattice *lt); void BKE_lattice_free(struct Lattice *lt); void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt, const bool lib_local); diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 258dcc84449..b5104b35b3c 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -52,11 +52,38 @@ struct PropertyRNA; size_t BKE_libblock_get_alloc_info(short type, const char **name); void *BKE_libblock_alloc_notest(short type); -void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BKE_libblock_init_empty(struct ID *id); + +/** + * New ID creation/copying options. + */ +enum { + /* *** Generic options (should be handled by all ID types copying, ID creation, etc.). *** */ + /* Create datablock outside of any main database - similar to 'localize' functions of materials etc. */ + LIB_ID_CREATE_NO_MAIN = 1 << 0, + /* Do not affect user refcount of datablocks used by new one (which also gets zero usercount then). + * Implies LIB_ID_CREATE_NO_MAIN. */ + LIB_ID_CREATE_NO_USER_REFCOUNT = 1 << 1, + /* Assume given 'newid' already points to allocated memory for whole datablock (ID + data) - USE WITH CAUTION! + * Implies LIB_ID_CREATE_NO_MAIN. */ + LIB_ID_CREATE_NO_ALLOCATE = 1 << 2, + + LIB_ID_CREATE_NO_DEG_TAG = 1 << 8, /* Do not tag new ID for update in depsgraph. */ + + /* Specific options to some ID types or usages, may be ignored by unrelated ID copying functions. */ + LIB_ID_COPY_NO_PROXY_CLEAR = 1 << 16, /* Object only, needed by make_local code. */ + LIB_ID_COPY_NO_PREVIEW = 1 << 17, /* Do not copy preview data, when supported. */ + LIB_ID_COPY_CACHES = 1 << 18, /* Copy runtime data caches. */ + /* XXX TODO Do we want to keep that? would rather try to get rid of it... */ + LIB_ID_COPY_ACTIONS = 1 << 19, /* EXCEPTION! Deep-copy actions used by animdata of copied ID. */ +}; + +void BKE_libblock_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag); void *BKE_libblock_copy(struct Main *bmain, const struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +/* "Deprecated" old API. */ void *BKE_libblock_copy_nolib(const struct ID *id, const bool do_action) ATTR_NONNULL(); -void BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const bool do_action); + void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL(); void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL(); @@ -64,13 +91,45 @@ struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* library_remap.c (keep here since they're general functions) */ -void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL(); -void BKE_libblock_free_datablock(struct ID *id) ATTR_NONNULL(); +/** + * New freeing logic options. + */ +enum { + /* *** Generic options (should be handled by all ID types freeing). *** */ + /* Do not try to remove freed ID from given Main (passed Main may be NULL). */ + LIB_ID_FREE_NO_MAIN = 1 << 0, + /* Do not affect user refcount of datablocks used by freed one. + * Implies LIB_ID_FREE_NO_MAIN. */ + LIB_ID_FREE_NO_USER_REFCOUNT = 1 << 1, + /* Assume freed ID datablock memory is managed elsewhere, do not free it + * (still calls relevant ID type's freeing function though) - USE WITH CAUTION! + * Implies LIB_ID_FREE_NO_MAIN. */ + LIB_ID_FREE_NOT_ALLOCATED = 1 << 2, + + LIB_ID_FREE_NO_DEG_TAG = 1 << 8, /* Do not tag freed ID for update in depsgraph. */ + LIB_ID_FREE_NO_UI_USER = 1 << 9, /* Do not attempt to remove freed ID from UI data/notifiers/... */ +}; + +void BKE_id_free_ex(struct Main *bmain, void *idv, int flag, const bool use_flag_from_idtag); +void BKE_id_free(struct Main *bmain, void *idv); +/* Those three naming are bad actually, should be BKE_id_free... (since it goes beyond mere datablock). */ +/* "Deprecated" old API */ 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(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_libblock_free_us(struct Main *bmain, void *idv) ATTR_NONNULL(); -void BKE_libblock_free_data(struct ID *id, const bool do_id_user) ATTR_NONNULL(); + +void BKE_libblock_management_main_add(struct Main *bmain, void *idv); +void BKE_libblock_management_main_remove(struct Main *bmain, void *idv); + +void BKE_libblock_management_usercounts_set(struct Main *bmain, void *idv); +void BKE_libblock_management_usercounts_clear(struct Main *bmain, void *idv); + +/* TODO should be named "BKE_id_delete()". */ void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL(); +void BKE_libblock_free_datablock(struct ID *id, const int flag) ATTR_NONNULL(); +void BKE_libblock_free_data(struct ID *id, const bool do_id_user) ATTR_NONNULL(); + void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id); void id_lib_extern(struct ID *id); void BKE_library_filepath_set(struct Library *lib, const char *filepath); @@ -87,6 +146,7 @@ void BKE_id_make_local_generic(struct Main *bmain, struct ID *id, const bool id_ bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const bool force_local); bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop); bool id_copy(struct Main *bmain, const struct ID *id, struct ID **newid, bool test); +bool BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag, const bool test); void id_sort_by_name(struct ListBase *lb, struct ID *id); void BKE_id_expand_local(struct Main *bmain, struct ID *id); void BKE_id_copy_ensure_local(struct Main *bmain, const struct ID *old_id, struct ID *new_id); diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h index c7b323d0f6e..3ba4fbe0338 100644 --- a/source/blender/blenkernel/BKE_linestyle.h +++ b/source/blender/blenkernel/BKE_linestyle.h @@ -52,6 +52,9 @@ struct bContext; void BKE_linestyle_init(struct FreestyleLineStyle *linestyle); FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name); void BKE_linestyle_free(FreestyleLineStyle *linestyle); +void BKE_linestyle_copy_data( + struct Main *bmain, struct FreestyleLineStyle *linestyle_dst, const struct FreestyleLineStyle *linestyle_src, + const int flag); FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, const FreestyleLineStyle *linestyle); void BKE_linestyle_make_local(struct Main *bmain, struct FreestyleLineStyle *linestyle, const bool lib_local); @@ -63,10 +66,14 @@ LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyl LineStyleModifier *BKE_linestyle_thickness_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type); LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type); -LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m); -LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m); -LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m); -LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m); +LineStyleModifier *BKE_linestyle_color_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag); +LineStyleModifier *BKE_linestyle_alpha_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag); +LineStyleModifier *BKE_linestyle_thickness_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag); +LineStyleModifier *BKE_linestyle_geometry_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag); int BKE_linestyle_color_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier); int BKE_linestyle_alpha_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier); diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index 0735d2d97a1..5598f0dc473 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -32,6 +32,7 @@ * \ingroup bke */ +struct EvaluationContext; struct ImageUser; struct Image; struct ListBase; @@ -122,6 +123,7 @@ void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point, const eMask /* general */ struct Mask *BKE_mask_new(struct Main *bmain, const char *name); +void BKE_mask_copy_data(struct Main *bmain, struct Mask *mask_dst, const struct Mask *mask_src, const int flag); struct Mask *BKE_mask_copy_nolib(struct Mask *mask); struct Mask *BKE_mask_copy(struct Main *bmain, const struct Mask *mask); @@ -232,6 +234,12 @@ float *BKE_mask_point_segment_feather_diff(struct MaskSpline *spline, struct Mas int width, int height, unsigned int *tot_feather_point); +void BKE_mask_layer_evaluate_animation(struct MaskLayer *masklay, const float ctime); +void BKE_mask_layer_evaluate_deform(struct MaskLayer *masklay, const float ctime); + +void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, struct Mask *mask); +void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, struct Mask *mask); + /* mask_rasterize.c */ struct MaskRasterHandle; typedef struct MaskRasterHandle MaskRasterHandle; diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index 7da962dd6d6..c6ebda2c399 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -54,6 +54,7 @@ void BKE_material_init(struct Material *ma); void BKE_material_remap_object(struct Object *ob, const unsigned int *remap); void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst); struct Material *BKE_material_add(struct Main *bmain, const char *name); +void BKE_material_copy_data(struct Main *bmain, struct Material *ma_dst, const struct Material *ma_src, const int flag); struct Material *BKE_material_copy(struct Main *bmain, const struct Material *ma); struct Material *localize_material(struct Material *ma); struct Material *give_node_material(struct Material *ma); /* returns node material or self */ diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index c00a0743ebb..f02704ba903 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -41,6 +41,7 @@ struct MetaElem; void BKE_mball_free(struct MetaBall *mb); void BKE_mball_init(struct MetaBall *mb); struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name); +void BKE_mball_copy_data(struct Main *bmain, struct MetaBall *mb_dst, const struct MetaBall *mb_src, const int flag); struct MetaBall *BKE_mball_copy(struct Main *bmain, const struct MetaBall *mb); void BKE_mball_make_local(struct Main *bmain, struct MetaBall *mb, const bool lib_local); @@ -59,7 +60,7 @@ bool BKE_mball_minmax_ex(struct MetaBall *mb, float min[3], float max[3], float obmat[4][4], const short flag); bool BKE_mball_center_median(struct MetaBall *mb, float r_cent[3]); bool BKE_mball_center_bounds(struct MetaBall *mb, float r_cent[3]); -void BKE_mball_transform(struct MetaBall *mb, float mat[4][4]); +void BKE_mball_transform(struct MetaBall *mb, float mat[4][4], const bool do_props); void BKE_mball_translate(struct MetaBall *mb, const float offset[3]); struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index b55b8b2dd3c..f3b2b653e3d 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -87,6 +87,7 @@ int BKE_mesh_edge_other_vert(const struct MEdge *e, int v); void BKE_mesh_free(struct Mesh *me); void BKE_mesh_init(struct Mesh *me); struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name); +void BKE_mesh_copy_data(struct Main *bmain, struct Mesh *me_dst, const struct Mesh *me_src, const int flag); struct Mesh *BKE_mesh_copy(struct Main *bmain, const struct Mesh *me); void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd); void BKE_mesh_ensure_skin_customdata(struct Mesh *me); @@ -279,7 +280,8 @@ void BKE_mesh_poly_edgebitmap_insert( bool BKE_mesh_center_median(const struct Mesh *me, float r_cent[3]); bool BKE_mesh_center_bounds(const struct Mesh *me, float r_cent[3]); -bool BKE_mesh_center_centroid(const struct Mesh *me, float r_cent[3]); +bool BKE_mesh_center_of_surface(const struct Mesh *me, float r_cent[3]); +bool BKE_mesh_center_of_volume(const struct Mesh *me, float r_cent[3]); void BKE_mesh_calc_volume( const struct MVert *mverts, const int mverts_num, diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index b241b5ca5b7..30c47a4b192 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -344,6 +344,7 @@ bool modifier_unique_name(struct ListBase *modifiers, struct ModifierDa void modifier_copyData_generic(const struct ModifierData *md, struct ModifierData *target); void modifier_copyData(struct ModifierData *md, struct ModifierData *target); +void modifier_copyData_ex(struct ModifierData *md, struct ModifierData *target, const int flag); bool modifier_dependsOnTime(struct ModifierData *md); bool modifier_supportsMapping(struct ModifierData *md); bool modifier_supportsCage(struct Scene *scene, struct ModifierData *md); diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index 69fdad5ef7b..3ddf75f204e 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -41,6 +41,7 @@ struct MovieDistortion; void BKE_movieclip_free(struct MovieClip *clip); +void BKE_movieclip_copy_data(struct Main *bmain, struct MovieClip *clip_dst, const struct MovieClip *clip_src, const int flag); struct MovieClip *BKE_movieclip_copy(struct Main *bmain, const struct MovieClip *clip); void BKE_movieclip_make_local(struct Main *bmain, struct MovieClip *clip, const bool lib_local); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index d5279c5b0ce..81de70ca8a4 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -335,6 +335,7 @@ struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char /* copy/free funcs, need to manage ID users */ void ntreeFreeTree(struct bNodeTree *ntree); +void BKE_node_tree_copy_data(struct Main *bmain, struct bNodeTree *ntree_dst, const struct bNodeTree *ntree_src, const int flag); struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user); struct bNodeTree *ntreeCopyTree(struct Main *bmain, const struct bNodeTree *ntree); /* node->id user count */ @@ -452,6 +453,7 @@ void nodeUnlinkNode(struct bNodeTree *ntree, struct bNode *node); void nodeUniqueName(struct bNodeTree *ntree, struct bNode *node); void nodeFreeNode(struct bNodeTree *ntree, struct bNode *node); +struct bNode *BKE_node_copy_ex(struct bNodeTree *ntree, struct bNode *node_src, const int flag); struct bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node); struct bNodeLink *nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 0a5035f9a9b..d1a4033957b 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -53,10 +53,10 @@ void BKE_object_workob_clear(struct Object *workob); void BKE_object_workob_calc_parent(struct Scene *scene, struct Object *ob, struct Object *workob); void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src); -struct SoftBody *copy_softbody(const struct SoftBody *sb, bool copy_caches); -struct BulletSoftBody *copy_bulletsoftbody(const struct BulletSoftBody *sb); -struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys); -void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src); +struct SoftBody *copy_softbody(const struct SoftBody *sb, const int flag); +struct BulletSoftBody *copy_bulletsoftbody(const struct BulletSoftBody *sb, const int flag); +struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys, const int flag); +void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src, const int flag); void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src); void BKE_object_free_particlesystems(struct Object *ob); void BKE_object_free_softbody(struct Object *ob); @@ -105,7 +105,7 @@ bool BKE_object_lod_is_usable(struct Object *ob, struct Scene *scene); struct Object *BKE_object_lod_meshob_get(struct Object *ob, struct Scene *scene); struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene); -struct Object *BKE_object_copy_ex(struct Main *bmain, const struct Object *ob, bool copy_caches); +void BKE_object_copy_data(struct Main *bmain, struct Object *ob_dst, const struct Object *ob_src, const int flag); struct Object *BKE_object_copy(struct Main *bmain, const struct Object *ob); void BKE_object_make_local(struct Main *bmain, struct Object *ob, const bool lib_local); void BKE_object_make_local_ex(struct Main *bmain, struct Object *ob, const bool lib_local, const bool clear_proxy); diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 821dc211591..6cae8d28947 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -99,6 +99,8 @@ void BKE_paint_set_overlay_override(enum OverlayFlags flag); /* palettes */ void BKE_palette_free(struct Palette *palette); struct Palette *BKE_palette_add(struct Main *bmain, const char *name); +void BKE_palette_copy_data( + struct Main *bmain, struct Palette *palette_dst, const struct Palette *palette_src, const int flag); struct Palette *BKE_palette_copy(struct Main *bmain, const struct Palette *palette); void BKE_palette_make_local(struct Main *bmain, struct Palette *palette, const bool lib_local); struct PaletteColor *BKE_palette_color_add(struct Palette *palette); @@ -109,12 +111,14 @@ void BKE_palette_clear(struct Palette *palette); /* paint curves */ struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name); void BKE_paint_curve_free(struct PaintCurve *pc); +void BKE_paint_curve_copy_data( + struct Main *bmain, struct PaintCurve *pc_dst, const struct PaintCurve *pc_src, const int flag); struct PaintCurve *BKE_paint_curve_copy(struct Main *bmain, const struct PaintCurve *pc); void BKE_paint_curve_make_local(struct Main *bmain, struct PaintCurve *pc, const bool lib_local); void BKE_paint_init(struct Scene *sce, PaintMode mode, const char col[3]); void BKE_paint_free(struct Paint *p); -void BKE_paint_copy(struct Paint *src, struct Paint *tar); +void BKE_paint_copy(struct Paint *src, struct Paint *tar, const int flag); void BKE_paint_cavity_curve_preset(struct Paint *p, int preset); @@ -156,6 +160,14 @@ void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct B void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]); +/* Used for both vertex color and weight paint */ +struct SculptVertexPaintGeomMap { + int *vert_map_mem; + struct MeshElemMap *vert_to_loop; + int *poly_map_mem; + struct MeshElemMap *vert_to_poly; +}; + /* Session data (mode-specific) */ typedef struct SculptSession { @@ -201,10 +213,39 @@ typedef struct SculptSession { struct SculptStroke *stroke; struct StrokeCache *cache; + + union { + struct { + struct SculptVertexPaintGeomMap gmap; + + /* For non-airbrush painting to re-apply from the original (MLoop aligned). */ + unsigned int *previous_color; + float *previous_accum; + } vpaint; + + struct { + struct SculptVertexPaintGeomMap gmap; + + /* Vertex aligned arrays of weights. */ + float *previous_accum; + float *previous_weight; + /* Keep track of how much each vertex has been painted (non-airbrush only). */ + float *alpha_weight; + } wpaint; + + //struct { + //ToDo: identify sculpt-only fields + //} sculpt; + } mode; + int mode_type; + + /* This flag prevents PBVH from being freed when creating the vp_handle for texture paint. */ + bool building_vp_handle; } SculptSession; void BKE_sculptsession_free(struct Object *ob); void BKE_sculptsession_free_deformMats(struct SculptSession *ss); +void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss); void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder); void BKE_sculptsession_bm_to_me_for_render(struct Object *object); void BKE_sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob, diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index f9948ba500a..ddb4f9c37bd 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -324,6 +324,9 @@ struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct P struct ModifierData *object_add_particle_system(struct Scene *scene, struct Object *ob, const char *name); void object_remove_particle_system(struct Scene *scene, struct Object *ob); struct ParticleSettings *psys_new_settings(const char *name, struct Main *main); +void BKE_particlesettings_copy_data( + struct Main *bmain, struct ParticleSettings *part_dst, const struct ParticleSettings *part_src, + const int flag); struct ParticleSettings *BKE_particlesettings_copy(struct Main *bmain, const struct ParticleSettings *part); void BKE_particlesettings_make_local(struct Main *bmain, struct ParticleSettings *part, const bool lib_local); @@ -473,9 +476,8 @@ typedef struct ParticleRenderData { struct EvaluationContext; -void BKE_particle_system_eval(struct EvaluationContext *eval_ctx, - struct Scene *scene, - struct Object *ob, - struct ParticleSystem *psys); +void BKE_particle_system_eval_init(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob); #endif diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 927303f8b3c..cc84be6e2c1 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -32,6 +32,7 @@ struct CCGElem; struct CCGKey; +struct CCGDerivedMesh; struct CustomData; struct DMFlagMat; struct MPoly; @@ -71,7 +72,7 @@ void BKE_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems, struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats, unsigned int **grid_hidden); void BKE_pbvh_build_bmesh(PBVH *bvh, struct BMesh *bm, bool smooth_shading, struct BMLog *log, const int cd_vert_node_offset, const int cd_face_node_offset); - +void BKE_pbvh_set_ccgdm(PBVH *bvh, struct CCGDerivedMesh *ccgdm); void BKE_pbvh_free(PBVH *bvh); void BKE_pbvh_free_layer_disp(PBVH *bvh); @@ -118,6 +119,7 @@ void BKE_pbvh_raycast_project_ray_root( void BKE_pbvh_node_draw(PBVHNode *node, void *data); void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], int (*setMaterial)(int matnr, void *attribs), bool wireframe, bool fast); +void BKE_pbvh_draw_BB(PBVH *bvh); /* PBVH Access */ typedef enum { @@ -141,6 +143,7 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden, /* multires level, only valid for type == PBVH_GRIDS */ void BKE_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key); +struct CCGDerivedMesh *BKE_pbvh_get_ccgdm(const PBVH *bvh); /* Only valid for type == PBVH_BMESH */ struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh); diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 02f6c435ee2..f0819c8d79d 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -314,7 +314,7 @@ struct PointCache *BKE_ptcache_add(struct ListBase *ptcaches); void BKE_ptcache_free_mem(struct ListBase *mem_cache); void BKE_ptcache_free(struct PointCache *cache); void BKE_ptcache_free_list(struct ListBase *ptcaches); -struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const struct ListBase *ptcaches_old, bool copy_data); +struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const struct ListBase *ptcaches_old, const int flag); /********************** Baking *********************/ diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h index c72f067a111..3c7274ca3c5 100644 --- a/source/blender/blenkernel/BKE_rigidbody.h +++ b/source/blender/blenkernel/BKE_rigidbody.h @@ -49,8 +49,8 @@ void BKE_rigidbody_free_constraint(struct Object *ob); /* ...... */ -struct RigidBodyOb *BKE_rigidbody_copy_object(const struct Object *ob); -struct RigidBodyCon *BKE_rigidbody_copy_constraint(const struct Object *ob); +struct RigidBodyOb *BKE_rigidbody_copy_object(const struct Object *ob, const int flag); +struct RigidBodyCon *BKE_rigidbody_copy_constraint(const struct Object *ob, const int flag); /* Callback format for performing operations on ID-pointers for rigidbody world. */ typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw, struct ID **idpoin, void *userdata, int cb_flag); @@ -66,7 +66,7 @@ struct RigidBodyOb *BKE_rigidbody_create_object(struct Scene *scene, struct Obje struct RigidBodyCon *BKE_rigidbody_create_constraint(struct Scene *scene, struct Object *ob, short type); /* copy */ -struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw); +struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw, const int flag); void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw); /* 'validate' (i.e. make new or replace old) Physics-Engine objects */ diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h index 10cddd7b454..35bcd91a9b1 100644 --- a/source/blender/blenkernel/BKE_sca.h +++ b/source/blender/blenkernel/BKE_sca.h @@ -52,16 +52,16 @@ void free_actuators(struct ListBase *lb); void free_sensor(struct bSensor *sens); void free_sensors(struct ListBase *lb); -struct bSensor *copy_sensor(struct bSensor *sens); -void copy_sensors(struct ListBase *lbn, const struct ListBase *lbo); +struct bSensor *copy_sensor(struct bSensor *sens, const int flag); +void copy_sensors(struct ListBase *lbn, const struct ListBase *lbo, const int flag); void init_sensor(struct bSensor *sens); struct bSensor *new_sensor(int type); -struct bController *copy_controller(struct bController *cont); -void copy_controllers(struct ListBase *lbn, const struct ListBase *lbo); +struct bController *copy_controller(struct bController *cont, const int flag); +void copy_controllers(struct ListBase *lbn, const struct ListBase *lbo, const int flag); void init_controller(struct bController *cont); struct bController *new_controller(int type); -struct bActuator *copy_actuator(struct bActuator *act); -void copy_actuators(struct ListBase *lbn, const struct ListBase *lbo); +struct bActuator *copy_actuator(struct bActuator *act, const int flag); +void copy_actuators(struct ListBase *lbn, const struct ListBase *lbo, const int flag); void init_actuator(struct bActuator *act); struct bActuator *new_actuator(int type); void clear_sca_new_poins_ob(struct Object *ob); @@ -70,7 +70,7 @@ void set_sca_new_poins_ob(struct Object *ob); void set_sca_new_poins(void); void BKE_sca_logic_links_remap(struct Main *bmain, struct Object *ob_old, struct Object *ob_new); -void BKE_sca_logic_copy(struct Object *ob_new, const struct Object *ob); +void BKE_sca_logic_copy(struct Object *ob_new, const struct Object *ob, const int flag); void sca_move_sensor(struct bSensor *sens_to_move, struct Object *ob, int move_up); void sca_move_controller(struct bController *cont_to_move, struct Object *ob, int move_up); diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index d2152950bff..481aff3cfa6 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -42,7 +42,6 @@ struct Base; struct EvaluationContext; struct Main; struct Object; -struct QuicktimeCodecData; struct RenderData; struct SceneRenderLayer; struct Scene; @@ -64,7 +63,6 @@ struct Main; struct Base *_setlooper_base_step(struct Scene **sce_iter, struct Base *base); void free_avicodecdata(struct AviCodecData *acd); -void free_qtcodecdata(struct QuicktimeCodecData *acd); void BKE_scene_free(struct Scene *sce); void BKE_scene_init(struct Scene *sce); @@ -98,6 +96,7 @@ void BKE_scene_base_flag_from_objects(struct Scene *scene); void BKE_scene_set_background(struct Main *bmain, struct Scene *sce); struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name); +void BKE_scene_copy_data(struct Main *bmain, struct Scene *sce_dst, const struct Scene *sce_src, const int flag); struct Scene *BKE_scene_copy(struct Main *bmain, struct Scene *sce, int type); void BKE_scene_groups_relink(struct Scene *sce); @@ -151,6 +150,8 @@ bool BKE_scene_check_rigidbody_active(const struct Scene *scene); int BKE_scene_num_threads(const struct Scene *scene); int BKE_render_num_threads(const struct RenderData *r); +int BKE_render_preview_pixel_size(const struct RenderData *r); + double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value); /* multiview */ @@ -175,4 +176,3 @@ int BKE_scene_multiview_num_videos_get(const struct RenderData *rd); #endif #endif - diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 811e9136fc9..657e99f05d1 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -335,7 +335,8 @@ bool BKE_sequence_base_shuffle( bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, struct Scene *evil_scene); bool BKE_sequence_base_isolated_sel_check(struct ListBase *seqbase); void BKE_sequencer_free_imbuf(struct Scene *scene, struct ListBase *seqbasep, bool for_render); -struct Sequence *BKE_sequence_dupli_recursive(struct Scene *scene, struct Scene *scene_to, struct Sequence *seq, int dupe_flag); +struct Sequence *BKE_sequence_dupli_recursive( + const struct Scene *scene_src, struct Scene *scene_dst, struct Sequence *seq, int dupe_flag); int BKE_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str); bool BKE_sequence_check_depend(struct Sequence *seq, struct Sequence *cur); @@ -352,8 +353,8 @@ void BKE_sequencer_refresh_sound_length(struct Scene *scene); void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, struct Sequence *seq); void BKE_sequence_base_dupli_recursive( - struct Scene *scene, struct Scene *scene_to, ListBase *nseqbase, ListBase *seqbase, - int dupe_flag); + const struct Scene *scene_src, struct Scene *scene_dst, struct ListBase *nseqbase, const struct ListBase *seqbase, + int dupe_flag, const int flag); bool BKE_sequence_is_valid_check(struct Sequence *seq); void BKE_sequencer_clear_scene_in_allseqs(struct Main *bmain, struct Scene *sce); diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index a5c626e74d7..6f8274fabc8 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -80,6 +80,8 @@ void BKE_sound_load(struct Main *main, struct bSound *sound); void BKE_sound_free(struct bSound *sound); +void BKE_sound_copy_data(struct Main *bmain, struct bSound *sound_dst, const struct bSound *sound_src, const int flag); + void BKE_sound_make_local(struct Main *bmain, struct bSound *sound, const bool lib_local); #if defined(__AUD_C_API_H__) || defined(WITH_SYSTEM_AUDASPACE) diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h index 907558f9203..57f4c37f129 100644 --- a/source/blender/blenkernel/BKE_speaker.h +++ b/source/blender/blenkernel/BKE_speaker.h @@ -33,6 +33,7 @@ struct Speaker; void BKE_speaker_init(struct Speaker *spk); void *BKE_speaker_add(struct Main *bmain, const char *name); +void BKE_speaker_copy_data(struct Main *bmain, struct Speaker *spk_dst, const struct Speaker *spk_src, const int flag); struct Speaker *BKE_speaker_copy(struct Main *bmain, const struct Speaker *spk); void BKE_speaker_make_local(struct Main *bmain, struct Speaker *spk, const bool lib_local); void BKE_speaker_free(struct Speaker *spk); diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index c8fb483cdf2..14d3318e059 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -52,6 +52,7 @@ bool BKE_text_reload(struct Text *text); struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const char *relpath, const bool is_internal); struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath); +void BKE_text_copy_data(struct Main *bmain, struct Text *ta_dst, const struct Text *ta_src, const int flag); struct Text *BKE_text_copy (struct Main *bmain, const struct Text *ta); void BKE_text_make_local (struct Main *bmain, struct Text *text, const bool lib_local); void BKE_text_clear (struct Text *text); diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index 190fdeafaec..8a9171673ea 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -70,6 +70,7 @@ void colorband_update_sort(struct ColorBand *coba); void BKE_texture_free(struct Tex *tex); void BKE_texture_default(struct Tex *tex); +void BKE_texture_copy_data(struct Main *bmain, struct Tex *tex_dst, const struct Tex *tex_src, const int flag); struct Tex *BKE_texture_copy(struct Main *bmain, const struct Tex *tex); struct Tex *BKE_texture_add(struct Main *bmain, const char *name); struct Tex *BKE_texture_localize(struct Tex *tex); @@ -114,13 +115,13 @@ void BKE_texture_colormapping_default(struct ColorMapping *color void BKE_texture_envmap_free_data(struct EnvMap *env); void BKE_texture_envmap_free(struct EnvMap *env); struct EnvMap *BKE_texture_envmap_add(void); -struct EnvMap *BKE_texture_envmap_copy(const struct EnvMap *env); +struct EnvMap *BKE_texture_envmap_copy(const struct EnvMap *env, const int flag); void BKE_texture_pointdensity_init_data(struct PointDensity *pd); void BKE_texture_pointdensity_free_data(struct PointDensity *pd); void BKE_texture_pointdensity_free(struct PointDensity *pd); struct PointDensity *BKE_texture_pointdensity_add(void); -struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd); +struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd, const int flag); void BKE_texture_voxeldata_free_data(struct VoxelData *vd); void BKE_texture_voxeldata_free(struct VoxelData *vd); @@ -129,7 +130,7 @@ struct VoxelData *BKE_texture_voxeldata_copy(struct VoxelData *vd); void BKE_texture_ocean_free(struct OceanTex *ot); struct OceanTex *BKE_texture_ocean_add(void); -struct OceanTex *BKE_texture_ocean_copy(const struct OceanTex *ot); +struct OceanTex *BKE_texture_ocean_copy(const struct OceanTex *ot, const int flag); bool BKE_texture_dependsOnTime(const struct Tex *texture); bool BKE_texture_is_image_user(const struct Tex *tex); diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h index b48be382073..d05ed1800fb 100644 --- a/source/blender/blenkernel/BKE_tracking.h +++ b/source/blender/blenkernel/BKE_tracking.h @@ -52,7 +52,7 @@ struct rcti; /* **** Common functions **** */ void BKE_tracking_free(struct MovieTracking *tracking); -void BKE_tracking_copy(struct MovieTracking *tracking_dst, const struct MovieTracking *tracking_src); +void BKE_tracking_copy(struct MovieTracking *tracking_dst, const struct MovieTracking *tracking_src, const int flag); void BKE_tracking_settings_init(struct MovieTracking *tracking); diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h index 18ae61f7653..2a811496bb9 100644 --- a/source/blender/blenkernel/BKE_world.h +++ b/source/blender/blenkernel/BKE_world.h @@ -39,6 +39,7 @@ struct World; void BKE_world_free(struct World *sc); void BKE_world_init(struct World *wrld); struct World *add_world(struct Main *bmian, const char *name); +void BKE_world_copy_data(struct Main *bmain, struct World *wrld_dst, const struct World *wrld_src, const int flag); struct World *BKE_world_copy(struct Main *bmain, const struct World *wrld); struct World *localize_world(struct World *wrld); void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool lib_local); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 157c4408d6a..51598ede862 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -385,16 +385,6 @@ if(WITH_CODEC_AVI) add_definitions(-DWITH_AVI) endif() -if(WITH_CODEC_QUICKTIME) - list(APPEND INC - ../quicktime - ) - list(APPEND INC_SYS - ${QUICKTIME_INCLUDE_DIRS} - ) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_CODEC_FFMPEG) list(APPEND SRC intern/writeffmpeg.c diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 7eea8224ba1..9dae4c5eae7 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -93,6 +93,10 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm); # define ASSERT_IS_VALID_DM(dm) #endif + +static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER; + + static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *ob); static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid); @@ -235,6 +239,30 @@ static int dm_getNumLoopTri(DerivedMesh *dm) return numlooptris; } +static const MLoopTri *dm_getLoopTriArray(DerivedMesh *dm) +{ + MLoopTri *looptri; + + BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_READ); + looptri = dm->looptris.array; + BLI_rw_mutex_unlock(&loops_cache_lock); + + if (looptri != NULL) { + BLI_assert(dm->getNumLoopTri(dm) == dm->looptris.num); + } + else { + BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_WRITE); + /* We need to ensure array is still NULL inside mutex-protected code, some other thread might have already + * recomputed those looptris. */ + if (dm->looptris.array == NULL) { + dm->recalcLoopTri(dm); + } + looptri = dm->looptris.array; + BLI_rw_mutex_unlock(&loops_cache_lock); + } + return looptri; +} + static CustomData *dm_getVertCData(DerivedMesh *dm) { return &dm->vertData; @@ -278,6 +306,8 @@ void DM_init_funcs(DerivedMesh *dm) dm->dupLoopArray = dm_dupLoopArray; dm->dupPolyArray = dm_dupPolyArray; + dm->getLoopTriArray = dm_getLoopTriArray; + /* subtypes handle getting actual data */ dm->getNumLoopTri = dm_getNumLoopTri; @@ -471,6 +501,8 @@ void DM_ensure_tessface(DerivedMesh *dm) /** * Ensure the array is large enough + * + * /note This function must always be thread-protected by caller. It should only be used by internal code. */ void DM_ensure_looptri_data(DerivedMesh *dm) { @@ -478,18 +510,22 @@ void DM_ensure_looptri_data(DerivedMesh *dm) const unsigned int totloop = dm->numLoopData; const int looptris_num = poly_to_tri_count(totpoly, totloop); + BLI_assert(dm->looptris.array_wip == NULL); + + SWAP(MLoopTri *, dm->looptris.array, dm->looptris.array_wip); + if ((looptris_num > dm->looptris.num_alloc) || (looptris_num < dm->looptris.num_alloc * 2) || (totpoly == 0)) { - MEM_SAFE_FREE(dm->looptris.array); + MEM_SAFE_FREE(dm->looptris.array_wip); dm->looptris.num_alloc = 0; dm->looptris.num = 0; } if (totpoly) { - if (dm->looptris.array == NULL) { - dm->looptris.array = MEM_mallocN(sizeof(*dm->looptris.array) * looptris_num, __func__); + if (dm->looptris.array_wip == NULL) { + dm->looptris.array_wip = MEM_mallocN(sizeof(*dm->looptris.array_wip) * looptris_num, __func__); dm->looptris.num_alloc = looptris_num; } @@ -497,19 +533,6 @@ void DM_ensure_looptri_data(DerivedMesh *dm) } } -/** - * The purpose of this function is that we can call: - * `dm->getLoopTriArray(dm)` and get the array returned. - */ -void DM_ensure_looptri(DerivedMesh *dm) -{ - const int numPolys = dm->getNumPolys(dm); - - if ((dm->looptris.num == 0) && (numPolys != 0)) { - dm->recalcLoopTri(dm); - } -} - void DM_verttri_from_looptri(MVertTri *verttri, const MLoop *mloop, const MLoopTri *looptri, int looptri_num) { int i; @@ -2201,7 +2224,6 @@ static void mesh_calc_modifiers( if (dataMask & CD_MASK_MFACE) { DM_ensure_tessface(finaldm); } - DM_ensure_looptri(finaldm); /* without this, drawing ngon tri's faces will show ugly tessellated face * normals and will also have to calculate normals on the fly, try avoid @@ -2641,7 +2663,7 @@ static void mesh_build_data( ob->lastDataMask = dataMask; ob->lastNeedMapping = need_mapping; - if ((ob->mode & OB_MODE_SCULPT) && ob->sculpt) { + if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) { /* create PBVH immediately (would be created on the fly too, * but this avoids waiting on first stroke) */ @@ -4386,35 +4408,3 @@ MFace *DM_get_tessface_array(DerivedMesh *dm, bool *r_allocated) return mface; } - -const MLoopTri *DM_get_looptri_array( - DerivedMesh *dm, - const MVert *mvert, - const MPoly *mpoly, int mpoly_len, - const MLoop *mloop, int mloop_len, - bool *r_allocated) -{ - const MLoopTri *looptri = dm->getLoopTriArray(dm); - *r_allocated = false; - - if (looptri == NULL) { - if (mpoly_len > 0) { - const int looptris_num = poly_to_tri_count(mpoly_len, mloop_len); - MLoopTri *looptri_data; - - looptri_data = MEM_mallocN(sizeof(MLoopTri) * looptris_num, __func__); - - BKE_mesh_recalc_looptri( - mloop, mpoly, - mvert, - mloop_len, mpoly_len, - looptri_data); - - looptri = looptri_data; - - *r_allocated = true; - } - } - - return looptri; -} diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 885ea36d404..5bd6085c8f5 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -88,7 +88,7 @@ bAction *add_empty_action(Main *bmain, const char name[]) { bAction *act; - act = BKE_libblock_alloc(bmain, ID_AC, name); + act = BKE_libblock_alloc(bmain, ID_AC, name, 0); return act; } @@ -120,46 +120,56 @@ void BKE_action_free(bAction *act) /* .................................. */ -bAction *BKE_action_copy(Main *bmain, const bAction *src) +/** + * Only copy internal data of Action ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_action_copy_data(Main *UNUSED(bmain), bAction *act_dst, const bAction *act_src, const int UNUSED(flag)) { - bAction *dst = NULL; - bActionGroup *dgrp, *sgrp; - FCurve *dfcu, *sfcu; - - if (src == NULL) - return NULL; - dst = BKE_libblock_copy(bmain, &src->id); - + bActionGroup *grp_dst, *grp_src; + FCurve *fcu_dst, *fcu_src; + /* duplicate the lists of groups and markers */ - BLI_duplicatelist(&dst->groups, &src->groups); - BLI_duplicatelist(&dst->markers, &src->markers); - + BLI_duplicatelist(&act_dst->groups, &act_src->groups); + BLI_duplicatelist(&act_dst->markers, &act_src->markers); + /* copy F-Curves, fixing up the links as we go */ - BLI_listbase_clear(&dst->curves); - - for (sfcu = src->curves.first; sfcu; sfcu = sfcu->next) { + BLI_listbase_clear(&act_dst->curves); + + for (fcu_src = act_src->curves.first; fcu_src; fcu_src = fcu_src->next) { /* duplicate F-Curve */ - dfcu = copy_fcurve(sfcu); - BLI_addtail(&dst->curves, dfcu); - + fcu_dst = copy_fcurve(fcu_src); /* XXX TODO pass subdata flag? But surprisingly does not seem to be doing any ID refcounting... */ + BLI_addtail(&act_dst->curves, fcu_dst); + /* fix group links (kindof bad list-in-list search, but this is the most reliable way) */ - for (dgrp = dst->groups.first, sgrp = src->groups.first; dgrp && sgrp; dgrp = dgrp->next, sgrp = sgrp->next) { - if (sfcu->grp == sgrp) { - dfcu->grp = dgrp; - - if (dgrp->channels.first == sfcu) - dgrp->channels.first = dfcu; - if (dgrp->channels.last == sfcu) - dgrp->channels.last = dfcu; - + for (grp_dst = act_dst->groups.first, grp_src = act_src->groups.first; + grp_dst && grp_src; + grp_dst = grp_dst->next, grp_src = grp_src->next) + { + if (fcu_src->grp == grp_src) { + fcu_dst->grp = grp_dst; + + if (grp_dst->channels.first == fcu_src) { + grp_dst->channels.first = fcu_dst; + } + if (grp_dst->channels.last == fcu_src) { + grp_dst->channels.last = fcu_dst; + } break; } } } - - BKE_id_copy_ensure_local(bmain, &src->id, &dst->id); +} - return dst; +bAction *BKE_action_copy(Main *bmain, const bAction *act_src) +{ + bAction *act_copy; + BKE_id_copy_ex(bmain, &act_src->id, (ID **)&act_copy, 0, false); + return act_copy; } /* *************** Action Groups *************** */ @@ -523,7 +533,7 @@ const char *BKE_pose_ikparam_get_name(bPose *pose) * * \param dst Should be freed already, makes entire duplicate. */ -void BKE_pose_copy_data(bPose **dst, const bPose *src, const bool copy_constraints) +void BKE_pose_copy_data_ex(bPose **dst, const bPose *src, const int flag, const bool copy_constraints) { bPose *outPose; bPoseChannel *pchan; @@ -553,9 +563,8 @@ void BKE_pose_copy_data(bPose **dst, const bPose *src, const bool copy_constrain outPose->avs = src->avs; for (pchan = outPose->chanbase.first; pchan; pchan = pchan->next) { - - if (pchan->custom) { - id_us_plus(&pchan->custom->id); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)pchan->custom); } /* warning, O(n2) here, if done without the hash, but these are rarely used features. */ @@ -570,13 +579,13 @@ void BKE_pose_copy_data(bPose **dst, const bPose *src, const bool copy_constrain } if (copy_constraints) { - BKE_constraints_copy(&listb, &pchan->constraints, true); // BKE_constraints_copy NULLs listb + BKE_constraints_copy_ex(&listb, &pchan->constraints, flag, true); // BKE_constraints_copy NULLs listb pchan->constraints = listb; pchan->mpath = NULL; /* motion paths should not get copied yet... */ } if (pchan->prop) { - pchan->prop = IDP_CopyProperty(pchan->prop); + pchan->prop = IDP_CopyProperty_ex(pchan->prop, flag); } } @@ -588,6 +597,11 @@ void BKE_pose_copy_data(bPose **dst, const bPose *src, const bool copy_constrain *dst = outPose; } +void BKE_pose_copy_data(bPose **dst, const bPose *src, const bool copy_constraints) +{ + BKE_pose_copy_data_ex(dst, src, 0, copy_constraints); +} + void BKE_pose_itasc_init(bItasc *itasc) { if (itasc) { @@ -1115,9 +1129,13 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_ if (fcu->totvert) { float nmin, nmax; - /* get extents for this curve */ - /* TODO: allow enabling/disabling this? */ - calc_fcurve_range(fcu, &nmin, &nmax, false, true); + /* get extents for this curve + * - no "selected only", since this is often used in the backend + * - no "minimum length" (we will apply this later), otherwise + * single-keyframe curves will increase the overall length by + * a phantom frame (T50354) + */ + calc_fcurve_range(fcu, &nmin, &nmax, false, false); /* compare to the running tally */ min = min_ff(min, nmin); @@ -1170,7 +1188,9 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_ } if (foundvert || foundmod) { + /* ensure that action is at least 1 frame long (for NLA strips to have a valid length) */ if (min == max) max += 1.0f; + *start = min; *end = max; } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 539901a59d5..64b33326aa9 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -259,7 +259,7 @@ void BKE_animdata_free(ID *id, const bool do_id_user) /* Copying -------------------------------------------- */ /* Make a copy of the given AnimData - to be used when copying datablocks */ -AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action) +AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action) { AnimData *dadt; @@ -270,8 +270,9 @@ AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action) /* make a copy of action - at worst, user has to delete copies... */ if (do_action) { - dadt->action = BKE_action_copy(G.main, adt->action); - dadt->tmpact = BKE_action_copy(G.main, adt->tmpact); + BLI_assert(bmain != NULL); + BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, 0, false); + BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, 0, false); } else { id_us_plus((ID *)dadt->action); @@ -291,7 +292,7 @@ AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action) return dadt; } -bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action) +bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const bool do_action) { AnimData *adt; @@ -303,7 +304,7 @@ bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action) adt = BKE_animdata_from_id(id_from); if (adt) { IdAdtTemplate *iat = (IdAdtTemplate *)id_to; - iat->adt = BKE_animdata_copy(adt, do_action); + iat->adt = BKE_animdata_copy(bmain, adt, do_action); } return true; @@ -623,6 +624,8 @@ char *BKE_animdata_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *p } break; } + default: + break; } /* fix RNA pointer, as we've now changed the ID root by changing the paths */ @@ -1347,7 +1350,7 @@ void BKE_keyingset_free_path(KeyingSet *ks, KS_Path *ksp) } /* Copy all KeyingSets in the given list */ -void BKE_keyingsets_copy(ListBase *newlist, ListBase *list) +void BKE_keyingsets_copy(ListBase *newlist, const ListBase *list) { KeyingSet *ksn; KS_Path *kspn; diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 43fd47981b1..6dd852c7875 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -106,7 +106,8 @@ const char *BKE_appdir_folder_default(void) static char *blender_version_decimal(const int ver) { static char version_str[5]; - sprintf(version_str, "%d.%02d", ver / 100, ver % 100); + BLI_assert(ver < 1000); + BLI_snprintf(version_str, sizeof(version_str), "%d.%02d", ver / 100, ver % 100); return version_str; } @@ -212,8 +213,10 @@ static bool get_path_local( /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */ #ifdef __APPLE__ /* 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); + char osx_resourses[FILE_MAX]; + BLI_snprintf(osx_resourses, sizeof(osx_resourses), "%s../Resources", bprogdir); + /* Remove the '/../' added above. */ + BLI_cleanup_path(NULL, osx_resourses); return test_path(targetpath, targetpath_len, osx_resourses, blender_version_decimal(ver), relfolder); #else return test_path(targetpath, targetpath_len, bprogdir, blender_version_decimal(ver), relfolder); @@ -326,10 +329,12 @@ static bool get_path_system( return true; } } - /* try EXECUTABLE_DIR/release/folder_name */ - if (test_path(targetpath, targetpath_len, bprogdir, "release", relfolder)) + if (test_path(targetpath, targetpath_len, bprogdir, "release", relfolder)) { return true; + } + /* never use if not existing. */ + targetpath[0] = '\0'; /* end developer overrides */ @@ -591,6 +596,9 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name) else { BLI_path_program_search(fullname, maxlen, name); } + /* Remove "/./" and "/../" so string comparisons can be used on the path. */ + BLI_cleanup_path(NULL, fullname); + #if defined(DEBUG) if (!STREQ(name, fullname)) { printf("guessing '%s' == '%s'\n", name, fullname); @@ -683,13 +691,16 @@ bool BKE_appdir_program_python_search( return is_found; } +/** Keep in sync with `bpy.utils.app_template_paths()` */ 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] = { + /* Only 'USER' */ BLENDER_USER_SCRIPTS, + /* Covers 'LOCAL' & 'SYSTEM'. */ BLENDER_SYSTEM_SCRIPTS, }; diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 35b6fe113bd..669344e18d7 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -83,7 +83,7 @@ bArmature *BKE_armature_add(Main *bmain, const char *name) { bArmature *arm; - arm = BKE_libblock_alloc(bmain, ID_AR, name); + arm = BKE_libblock_alloc(bmain, ID_AR, name, 0); arm->deformflag = ARM_DEF_VGROUP | ARM_DEF_ENVELOPE; arm->flag = ARM_COL_CUSTOM; /* custom bone-group colors */ arm->layer = 1; @@ -150,54 +150,70 @@ void BKE_armature_make_local(Main *bmain, bArmature *arm, const bool lib_local) BKE_id_make_local_generic(bmain, &arm->id, true, lib_local); } -static void copy_bonechildren(Bone *newBone, const Bone *oldBone, const Bone *actBone, Bone **newActBone) +static void copy_bonechildren( + Bone *bone_dst, const Bone *bone_src, const Bone *bone_src_act, Bone **r_bone_dst_act, const int flag) { - Bone *curBone, *newChildBone; + Bone *bone_src_child, *bone_dst_child; - if (oldBone == actBone) - *newActBone = newBone; + if (bone_src == bone_src_act) { + *r_bone_dst_act = bone_dst; + } - if (oldBone->prop) - newBone->prop = IDP_CopyProperty(oldBone->prop); + if (bone_src->prop) { + bone_dst->prop = IDP_CopyProperty_ex(bone_src->prop, flag); + } /* Copy this bone's list */ - BLI_duplicatelist(&newBone->childbase, &oldBone->childbase); + BLI_duplicatelist(&bone_dst->childbase, &bone_src->childbase); /* For each child in the list, update it's children */ - newChildBone = newBone->childbase.first; - for (curBone = oldBone->childbase.first; curBone; curBone = curBone->next) { - newChildBone->parent = newBone; - copy_bonechildren(newChildBone, curBone, actBone, newActBone); - newChildBone = newChildBone->next; + for (bone_src_child = bone_src->childbase.first, bone_dst_child = bone_dst->childbase.first; + bone_src_child; + bone_src_child = bone_src_child->next, bone_dst_child = bone_dst_child->next) + { + bone_dst_child->parent = bone_dst; + copy_bonechildren(bone_dst_child, bone_src_child, bone_src_act, r_bone_dst_act, flag); } } -bArmature *BKE_armature_copy(Main *bmain, const bArmature *arm) +/** + * Only copy internal data of Armature ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_armature_copy_data(Main *UNUSED(bmain), bArmature *arm_dst, const bArmature *arm_src, const int flag) { - bArmature *newArm; - Bone *oldBone, *newBone; - Bone *newActBone = NULL; + Bone *bone_src, *bone_dst; + Bone *bone_dst_act = NULL; + + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; - newArm = BKE_libblock_copy(bmain, &arm->id); - BLI_duplicatelist(&newArm->bonebase, &arm->bonebase); + BLI_duplicatelist(&arm_dst->bonebase, &arm_src->bonebase); /* Duplicate the childrens' lists */ - newBone = newArm->bonebase.first; - for (oldBone = arm->bonebase.first; oldBone; oldBone = oldBone->next) { - newBone->parent = NULL; - copy_bonechildren(newBone, oldBone, arm->act_bone, &newActBone); - newBone = newBone->next; + bone_dst = arm_dst->bonebase.first; + for (bone_src = arm_src->bonebase.first; bone_src; bone_src = bone_src->next) { + bone_dst->parent = NULL; + copy_bonechildren(bone_dst, bone_src, arm_src->act_bone, &bone_dst_act, flag_subdata); + bone_dst = bone_dst->next; } - newArm->act_bone = newActBone; - - newArm->edbo = NULL; - newArm->act_edbone = NULL; - newArm->sketch = NULL; + arm_dst->act_bone = bone_dst_act; - BKE_id_copy_ensure_local(bmain, &arm->id, &newArm->id); + arm_dst->edbo = NULL; + arm_dst->act_edbone = NULL; + arm_dst->sketch = NULL; +} - return newArm; +bArmature *BKE_armature_copy(Main *bmain, const bArmature *arm) +{ + bArmature *arm_copy; + BKE_id_copy_ex(bmain, &arm->id, (ID **)&arm_copy, 0, false); + return arm_copy; } static Bone *get_named_bone_bonechildren(ListBase *lb, const char *name) diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index a4714041edf..45d1d36aeca 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -559,11 +559,10 @@ void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_roo /* *************** Depsgraph evaluation callbacks ************ */ void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx), - Scene *scene, + Scene *UNUSED(scene), Object *ob, bPose *pose) { - float ctime = BKE_scene_frame_get(scene); /* not accurate... */ bPoseChannel *pchan; DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); @@ -581,6 +580,16 @@ void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx), for (pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) { pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE); } +} + +void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob, + bPose *UNUSED(pose)) +{ + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); /* 2a. construct the IK tree (standard IK) */ BIK_initialize_tree(scene, ob, ctime); diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 05ea7983b8e..980df05aca2 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -114,6 +114,7 @@ static void setup_app_data( const char *filepath, ReportList *reports) { Scene *curscene = NULL; + const bool is_startup = (bfd->filename[0] == '\0'); const bool recover = (G.fileflags & G_FILE_RECOVER) != 0; enum { LOAD_UI = 1, @@ -129,7 +130,7 @@ static void setup_app_data( else if (BLI_listbase_is_empty(&bfd->main->screen)) { mode = LOAD_UNDO; } - else if (G.fileflags & G_FILE_NO_UI) { + else if ((G.fileflags & G_FILE_NO_UI) && (is_startup == false)) { mode = LOAD_UI_OFF; } else { @@ -250,7 +251,9 @@ static void setup_app_data( CTX_data_scene_set(C, curscene); } else { - G.fileflags = bfd->fileflags; + /* Keep state from preferences. */ + const int fileflags_skip = G_FILE_FLAGS_RUNTIME; + G.fileflags = (G.fileflags & fileflags_skip) | (bfd->fileflags & ~fileflags_skip); CTX_wm_manager_set(C, G.main->wm.first); CTX_wm_screen_set(C, bfd->curscreen); CTX_data_scene_set(C, bfd->curscene); diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index aae323a5056..03b0710c8fc 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -152,7 +152,7 @@ Brush *BKE_brush_add(Main *bmain, const char *name, short ob_mode) { Brush *brush; - brush = BKE_libblock_alloc(bmain, ID_BR, name); + brush = BKE_libblock_alloc(bmain, ID_BR, name, 0); BKE_brush_init(brush); @@ -172,34 +172,38 @@ struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode) return NULL; } -Brush *BKE_brush_copy(Main *bmain, const Brush *brush) +/** + * Only copy internal data of Brush ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_brush_copy_data(Main *UNUSED(bmain), Brush *brush_dst, const Brush *brush_src, const int flag) { - Brush *brushn; - - brushn = BKE_libblock_copy(bmain, &brush->id); - - if (brush->mtex.tex) - id_us_plus((ID *)brush->mtex.tex); - - if (brush->mask_mtex.tex) - id_us_plus((ID *)brush->mask_mtex.tex); - - if (brush->paint_curve) - id_us_plus((ID *)brush->paint_curve); - - if (brush->icon_imbuf) - brushn->icon_imbuf = IMB_dupImBuf(brush->icon_imbuf); + if (brush_src->icon_imbuf) { + brush_dst->icon_imbuf = IMB_dupImBuf(brush_src->icon_imbuf); + } - brushn->preview = NULL; + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { + BKE_previewimg_id_copy(&brush_dst->id, &brush_src->id); + } + else { + brush_dst->preview = NULL; + } - brushn->curve = curvemapping_copy(brush->curve); + brush_dst->curve = curvemapping_copy(brush_src->curve); /* enable fake user by default */ - id_fake_user_set(&brushn->id); - - BKE_id_copy_ensure_local(bmain, &brush->id, &brushn->id); + id_fake_user_set(&brush_dst->id); +} - return brushn; +Brush *BKE_brush_copy(Main *bmain, const Brush *brush) +{ + Brush *brush_copy; + BKE_id_copy_ex(bmain, &brush->id, (ID **)&brush_copy, 0, false); + return brush_copy; } /** Free (or release) any data used by this brush (does not free the brush itself). */ diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index c1fad4f80c8..775499304d4 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -1137,7 +1137,6 @@ BVHTree *bvhtree_from_mesh_looptri( const MLoopTri *looptri = NULL; bool vert_allocated = false; bool loop_allocated = false; - bool looptri_allocated = false; BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI); @@ -1150,12 +1149,7 @@ BVHTree *bvhtree_from_mesh_looptri( mpoly = DM_get_poly_array(dm, &poly_allocated); mloop = DM_get_loop_array(dm, &loop_allocated); - looptri = DM_get_looptri_array( - dm, - mvert, - mpoly, dm->getNumPolys(dm), - mloop, dm->getNumLoops(dm), - &looptri_allocated); + looptri = dm->getLoopTriArray(dm); if (poly_allocated) { MEM_freeN(mpoly); @@ -1193,7 +1187,7 @@ BVHTree *bvhtree_from_mesh_looptri( data, tree, true, epsilon, mvert, vert_allocated, mloop, loop_allocated, - looptri, looptri_allocated); + looptri, false); } else { if (vert_allocated) { @@ -1202,9 +1196,6 @@ BVHTree *bvhtree_from_mesh_looptri( if (loop_allocated) { MEM_freeN(mloop); } - if (looptri_allocated) { - MEM_freeN((void *)looptri); - } memset(data, 0, sizeof(*data)); } diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index cf619a32783..1916531b066 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -66,7 +66,7 @@ void BKE_cachefiles_exit(void) void *BKE_cachefile_add(Main *bmain, const char *name) { - CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name); + CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name, 0); BKE_cachefile_init(cache_file); @@ -100,16 +100,26 @@ void BKE_cachefile_free(CacheFile *cache_file) BLI_freelistN(&cache_file->object_paths); } -CacheFile *BKE_cachefile_copy(Main *bmain, const CacheFile *cache_file) +/** + * Only copy internal data of CacheFile ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_cachefile_copy_data( + Main *UNUSED(bmain), CacheFile *cache_file_dst, const CacheFile *UNUSED(cache_file_src), const int UNUSED(flag)) { - CacheFile *new_cache_file = BKE_libblock_copy(bmain, &cache_file->id); - new_cache_file->handle = NULL; - - BLI_listbase_clear(&new_cache_file->object_paths); - - BKE_id_copy_ensure_local(bmain, &cache_file->id, &new_cache_file->id); + cache_file_dst->handle = NULL; + BLI_listbase_clear(&cache_file_dst->object_paths); +} - return new_cache_file; +CacheFile *BKE_cachefile_copy(Main *bmain, const CacheFile *cache_file) +{ + CacheFile *cache_file_copy; + BKE_id_copy_ex(bmain, &cache_file->id, (ID **)&cache_file_copy, 0, false); + return cache_file_copy; } void BKE_cachefile_make_local(Main *bmain, CacheFile *cache_file, const bool lib_local) diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 915c08674a4..719125b3317 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -86,22 +86,31 @@ void *BKE_camera_add(Main *bmain, const char *name) { Camera *cam; - cam = BKE_libblock_alloc(bmain, ID_CA, name); + cam = BKE_libblock_alloc(bmain, ID_CA, name, 0); BKE_camera_init(cam); return cam; } -Camera *BKE_camera_copy(Main *bmain, const Camera *cam) +/** + * Only copy internal data of Camera ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_camera_copy_data(Main *UNUSED(bmain), Camera *UNUSED(cam_dst), const Camera *UNUSED(cam_src), const int UNUSED(flag)) { - Camera *camn; - - camn = BKE_libblock_copy(bmain, &cam->id); - - BKE_id_copy_ensure_local(bmain, &cam->id, &camn->id); + /* Nothing to do! */ +} - return camn; +Camera *BKE_camera_copy(Main *bmain, const Camera *cam) +{ + Camera *cam_copy; + BKE_id_copy_ex(bmain, &cam->id, (ID **)&cam_copy, 0, false); + return cam_copy; } void BKE_camera_make_local(Main *bmain, Camera *cam, const bool lib_local) diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 46a067ea0bc..2ed5cc450a4 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -34,10 +34,12 @@ * \ingroup bke */ +#include "atomic_ops.h" + #include "BLI_math.h" #include "BLI_edgehash.h" #include "BLI_utildefines.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BKE_pbvh.h" #include "BKE_cdderivedmesh.h" @@ -660,6 +662,11 @@ static void cdDM_drawMappedFaces( const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); + if (cddm->pbvh) { + if (G.debug_value == 14) + BKE_pbvh_draw_BB(cddm->pbvh); + } + /* fist, setup common buffers */ GPU_vertex_setup(dm); GPU_triangle_setup(dm); @@ -745,8 +752,18 @@ static void cdDM_drawMappedFaces( /* avoid buffer problems in following code */ } else if (setDrawOptions == NULL) { + const bool show_alpha = true; + if (show_alpha) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + /* just draw the entire face array */ GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, 0, tot_tri_elem); + + if (show_alpha) { + glDisable(GL_BLEND); + } } else { for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) { @@ -1518,8 +1535,8 @@ static void cdDM_buffer_copy_mcol( for (i = 0; i < totpoly; i++, mpoly++) { for (j = 0; j < mpoly->totloop; j++) { - copy_v3_v3_uchar(&varray[start], &mloopcol[mpoly->loopstart + j].r); - start += 3; + copy_v4_v4_uchar(&varray[start], &mloopcol[mpoly->loopstart + j].r); + start += 4; } } } @@ -1919,25 +1936,17 @@ void CDDM_recalc_looptri(DerivedMesh *dm) const unsigned int totloop = dm->numLoopData; DM_ensure_looptri_data(dm); + BLI_assert(totpoly == 0 || cddm->dm.looptris.array_wip != NULL); BKE_mesh_recalc_looptri( cddm->mloop, cddm->mpoly, cddm->mvert, totloop, totpoly, - cddm->dm.looptris.array); -} - -static const MLoopTri *cdDM_getLoopTriArray(DerivedMesh *dm) -{ - if (dm->looptris.array) { - BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); - } - else { - dm->recalcLoopTri(dm); + cddm->dm.looptris.array_wip); - /* ccdm is an exception here, that recalcLoopTri will fill in the array too */ - } - return dm->looptris.array; + BLI_assert(cddm->dm.looptris.array == NULL); + atomic_cas_ptr((void **)&cddm->dm.looptris.array, cddm->dm.looptris.array, cddm->dm.looptris.array_wip); + cddm->dm.looptris.array_wip = NULL; } static void cdDM_free_internal(CDDerivedMesh *cddm) @@ -1990,8 +1999,6 @@ static CDDerivedMesh *cdDM_create(const char *desc) dm->getEdgeDataArray = DM_get_edge_data_layer; dm->getTessFaceDataArray = DM_get_tessface_data_layer; - dm->getLoopTriArray = cdDM_getLoopTriArray; - dm->calcNormals = CDDM_calc_normals; dm->calcLoopNormals = CDDM_calc_loop_normals; dm->calcLoopNormalsSpaceArray = CDDM_calc_loop_normals_spacearr; @@ -3184,7 +3191,7 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int MPoly *target_poly = cddm->mpoly + *(cddm->pmap[v_target].indices + i_poly); if (cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, +1) || - cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, -1)) + cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, -1)) { found = true; break; diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index ee0fde1ea61..dd93606a67c 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -807,7 +807,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d if ( !dm ) return 0; - DM_ensure_looptri(dm); cloth_from_mesh ( clmd, dm ); // create springs diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 07a6b304dff..7ad2ed91e87 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -1019,7 +1019,7 @@ static void vectomat(const float vec[3], const float target_up[3], short axis, s } /* project the up vector onto the plane specified by n */ - project_v3_v3v3(proj, u, n); /* first u onto n... */ + project_v3_v3v3_normalized(proj, u, n); /* first u onto n... */ sub_v3_v3v3(proj, u, proj); /* then onto the plane */ /* proj specifies the transformation of the up axis */ @@ -1930,7 +1930,7 @@ static void samevolume_evaluate(bConstraint *con, bConstraintOb *cob, ListBase * /* calculate normalizing scale factor for non-essential values */ if (obsize[data->flag] != 0) - fac = sqrtf(volume / obsize[data->flag]) / obsize[data->flag]; + fac = sqrtf(volume / obsize[data->flag]); /* apply scaling factor to the channels not being kept */ switch (data->flag) { @@ -4737,29 +4737,30 @@ static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool i } /* duplicate all of the constraints in a constraint stack */ -void BKE_constraints_copy(ListBase *dst, const ListBase *src, bool do_extern) +void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern) { bConstraint *con, *srccon; - + BLI_listbase_clear(dst); BLI_duplicatelist(dst, src); - + for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - + /* make a new copy of the constraint's data */ con->data = MEM_dupallocN(con->data); - + /* only do specific constraints if required */ if (cti) { /* perform custom copying operations if needed */ if (cti->copy_data) cti->copy_data(con, srccon); - - /* fix usercounts for all referenced data in referenced data */ - if (cti->id_looper) + + /* Fix usercounts for all referenced data that need it. */ + if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { cti->id_looper(con, con_fix_copied_refs_cb, NULL); - + } + /* for proxies we don't want to make extern */ if (do_extern) { /* go over used ID-links for this constraint to ensure that they are valid for proxies */ @@ -4770,6 +4771,11 @@ void BKE_constraints_copy(ListBase *dst, const ListBase *src, bool do_extern) } } +void BKE_constraints_copy(ListBase *dst, const ListBase *src, bool do_extern) +{ + BKE_constraints_copy_ex(dst, src, 0, do_extern); +} + /* ......... */ bConstraint *BKE_constraints_find_name(ListBase *list, const char *name) diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 7c22a34c7d1..9c7473f24d1 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -179,7 +179,7 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type) { Curve *cu; - cu = BKE_libblock_alloc(bmain, ID_CU, name); + cu = BKE_libblock_alloc(bmain, ID_CU, name, 0); cu->type = type; BKE_curve_init(cu); @@ -187,42 +187,39 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type) return cu; } -Curve *BKE_curve_copy(Main *bmain, const Curve *cu) +/** + * Only copy internal data of Curve ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const int flag) { - Curve *cun; - int a; + BLI_listbase_clear(&cu_dst->nurb); + BKE_nurbList_duplicate(&(cu_dst->nurb), &(cu_src->nurb)); - cun = BKE_libblock_copy(bmain, &cu->id); + cu_dst->mat = MEM_dupallocN(cu_src->mat); - BLI_listbase_clear(&cun->nurb); - BKE_nurbList_duplicate(&(cun->nurb), &(cu->nurb)); + cu_dst->str = MEM_dupallocN(cu_src->str); + cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo); + cu_dst->tb = MEM_dupallocN(cu_src->tb); + cu_dst->bb = MEM_dupallocN(cu_src->bb); - cun->mat = MEM_dupallocN(cu->mat); - for (a = 0; a < cun->totcol; a++) { - id_us_plus((ID *)cun->mat[a]); + if (cu_src->key) { + BKE_id_copy_ex(bmain, &cu_src->key->id, (ID **)&cu_dst->key, flag, false); } - cun->str = MEM_dupallocN(cu->str); - cun->strinfo = MEM_dupallocN(cu->strinfo); - cun->tb = MEM_dupallocN(cu->tb); - cun->bb = MEM_dupallocN(cu->bb); - - if (cu->key) { - cun->key = BKE_key_copy(bmain, cu->key); - cun->key->from = (ID *)cun; - } - - cun->editnurb = NULL; - cun->editfont = NULL; - - id_us_plus((ID *)cun->vfont); - id_us_plus((ID *)cun->vfontb); - id_us_plus((ID *)cun->vfonti); - id_us_plus((ID *)cun->vfontbi); - - BKE_id_copy_ensure_local(bmain, &cu->id, &cun->id); + cu_dst->editnurb = NULL; + cu_dst->editfont = NULL; +} - return cun; +Curve *BKE_curve_copy(Main *bmain, const Curve *cu) +{ + Curve *cu_copy; + BKE_id_copy_ex(bmain, &cu->id, (ID **)&cu_copy, 0, false); + return cu_copy; } void BKE_curve_make_local(Main *bmain, Curve *cu, const bool lib_local) @@ -4042,7 +4039,7 @@ bool BKE_nurb_check_valid_u(struct Nurb *nu) return true; /* not a nurb, lets assume its valid */ if (nu->pntsu < nu->orderu) return false; - if (((nu->flag & CU_NURB_CYCLIC) == 0) && (nu->flagu & CU_NURB_BEZIER)) { /* Bezier U Endpoints */ + if (((nu->flagu & CU_NURB_CYCLIC) == 0) && (nu->flagu & CU_NURB_BEZIER)) { /* Bezier U Endpoints */ if (nu->orderu == 4) { if (nu->pntsu < 5) return false; /* bezier with 4 orderu needs 5 points */ @@ -4063,7 +4060,7 @@ bool BKE_nurb_check_valid_v(struct Nurb *nu) if (nu->pntsv < nu->orderv) return false; - if (((nu->flag & CU_NURB_CYCLIC) == 0) && (nu->flagv & CU_NURB_BEZIER)) { /* Bezier V Endpoints */ + if (((nu->flagv & CU_NURB_CYCLIC) == 0) && (nu->flagv & CU_NURB_BEZIER)) { /* Bezier V Endpoints */ if (nu->orderv == 4) { if (nu->pntsv < 5) return false; /* bezier with 4 orderu needs 5 points */ @@ -4445,7 +4442,9 @@ bool BKE_curve_center_bounds(Curve *cu, float cent[3]) } -void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, const float unit_scale) +void BKE_curve_transform_ex( + Curve *cu, float mat[4][4], + const bool do_keys, const bool do_props, const float unit_scale) { Nurb *nu; BPoint *bp; @@ -4459,7 +4458,9 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons mul_m4_v3(mat, bezt->vec[0]); mul_m4_v3(mat, bezt->vec[1]); mul_m4_v3(mat, bezt->vec[2]); - bezt->radius *= unit_scale; + if (do_props) { + bezt->radius *= unit_scale; + } } BKE_nurb_handles_calc(nu); } @@ -4467,7 +4468,9 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons i = nu->pntsu * nu->pntsv; for (bp = nu->bp; i--; bp++) { mul_m4_v3(mat, bp->vec); - bp->radius *= unit_scale; + if (do_props) { + bp->radius *= unit_scale; + } } } } @@ -4483,10 +4486,12 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons } } -void BKE_curve_transform(Curve *cu, float mat[4][4], const bool do_keys) +void BKE_curve_transform( + Curve *cu, float mat[4][4], + const bool do_keys, const bool do_props) { float unit_scale = mat4_to_scale(mat); - BKE_curve_transform_ex(cu, mat, do_keys, unit_scale); + BKE_curve_transform_ex(cu, mat, do_keys, do_props, unit_scale); } void BKE_curve_translate(Curve *cu, float offset[3], const bool do_keys) @@ -4675,14 +4680,3 @@ void BKE_curve_eval_geometry(EvaluationContext *UNUSED(eval_ctx), BKE_curve_texspace_calc(curve); } } - -void BKE_curve_eval_path(EvaluationContext *UNUSED(eval_ctx), - Curve *curve) -{ - /* TODO(sergey): This will probably need to be a part of - * the modifier stack still. - */ - if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s on %s\n", __func__, curve->id.name); - } -} diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 0939d35ed8d..68acb60f21a 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -828,10 +828,10 @@ static void layerInterp_mloopcol( * although weights should also not cause this situation */ /* 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); + mc->r = round_fl_to_uchar_clamp(col.r); + mc->g = round_fl_to_uchar_clamp(col.g); + mc->b = round_fl_to_uchar_clamp(col.b); + mc->a = round_fl_to_uchar_clamp(col.a); } static int layerMaxNum_mloopcol(void) @@ -1054,10 +1054,10 @@ static void layerInterp_mcol( /* Subdivide smooth or fractal can cause problems without clamping * although weights should also not cause this situation */ - 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); + mc[j].a = round_fl_to_uchar_clamp(col[j].a); + mc[j].r = round_fl_to_uchar_clamp(col[j].r); + mc[j].g = round_fl_to_uchar_clamp(col[j].g); + mc[j].b = round_fl_to_uchar_clamp(col[j].b); } } diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 69baaf5e58a..eec8d2478da 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -621,8 +621,17 @@ float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup) */ float defvert_array_find_weight_safe(const struct MDeformVert *dvert, const int index, const int defgroup) { - if (defgroup == -1 || dvert == NULL) + /* Invalid defgroup index means the vgroup selected is invalid, does not exist, in that case it is OK to return 1.0 + * (i.e. maximum weight, as if no vgroup was selected). + * But in case of valid defgroup and NULL dvert data pointer, it means that vgroup **is** valid, + * and just totally empty, so we shall return '0.0' value then! + */ + if (defgroup == -1) { return 1.0f; + } + else if (dvert == NULL) { + return 0.0f; + } return defvert_find_weight(dvert + index, defgroup); } diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 019e0df1623..3ddf0f43d30 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -2018,6 +2018,7 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho int lasttime; if (!DEG_depsgraph_use_legacy()) { + DEG_scene_flush_update(bmain, sce); return; } diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 1db69d23607..ae896176b6d 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -2060,9 +2060,6 @@ DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scen if (pmd->canvas) { DerivedMesh *ret; - /* For now generate looptris in every case */ - DM_ensure_looptri(dm); - /* Update canvas data for a new frame */ dynamicPaint_frameUpdate(pmd, scene, ob, dm); @@ -2072,9 +2069,6 @@ DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scen return ret; } else { - /* For now generate looptris in every case */ - DM_ensure_looptri(dm); - /* Update canvas data for a new frame */ dynamicPaint_frameUpdate(pmd, scene, ob, dm); diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index ab614b8f460..d810dac7365 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -41,6 +41,8 @@ * is likely to be a little slow. */ +#include "atomic_ops.h" + #include "BLI_math.h" #include "BLI_jitter.h" #include "BLI_bitmap.h" @@ -641,8 +643,9 @@ static void emDM_recalcLoopTri(DerivedMesh *dm) int i; DM_ensure_looptri_data(dm); - mlooptri = dm->looptris.array; + mlooptri = dm->looptris.array_wip; + BLI_assert(tottri == 0 || mlooptri != NULL); BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); BLI_assert(tottri == dm->looptris.num); @@ -659,18 +662,10 @@ static void emDM_recalcLoopTri(DerivedMesh *dm) BM_elem_index_get(ltri[2])); lt->poly = BM_elem_index_get(ltri[0]->f); } -} - -static const MLoopTri *emDM_getLoopTriArray(DerivedMesh *dm) -{ - if (dm->looptris.array) { - BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); - } - else { - dm->recalcLoopTri(dm); - } - return dm->looptris.array; + BLI_assert(dm->looptris.array == NULL); + atomic_cas_ptr((void **)&dm->looptris.array, dm->looptris.array, dm->looptris.array_wip); + dm->looptris.array_wip = NULL; } static void emDM_foreachMappedVert( @@ -2259,8 +2254,6 @@ DerivedMesh *getEditDerivedBMesh( bmdm->dm.getNumLoops = emDM_getNumLoops; bmdm->dm.getNumPolys = emDM_getNumPolys; - bmdm->dm.getLoopTriArray = emDM_getLoopTriArray; - bmdm->dm.getVert = emDM_getVert; bmdm->dm.getVertCo = emDM_getVertCo; bmdm->dm.getVertNo = emDM_getVertNo; diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c index 8247336d915..8e98a9f672d 100644 --- a/source/blender/blenkernel/intern/fluidsim.c +++ b/source/blender/blenkernel/intern/fluidsim.c @@ -80,8 +80,6 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob, dm = mesh_create_derived_index_render(scene, ob, CD_MASK_BAREMESH, modifierIndex); - DM_ensure_looptri(dm); - mvert = dm->getVertArray(dm); mloop = dm->getLoopArray(dm); looptri = dm->getLoopTriArray(dm); diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 401fed74c52..d6b28cfaf70 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -106,6 +106,23 @@ void BKE_vfont_free(struct VFont *vf) } } +void BKE_vfont_copy_data(Main *UNUSED(bmain), VFont *vfont_dst, const VFont *UNUSED(vfont_src), const int flag) +{ + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; + + /* Just to be sure, should not have any value actually after reading time. */ + vfont_dst->temp_pf = NULL; + + if (vfont_dst->packedfile) { + vfont_dst->packedfile = dupPackedFile(vfont_dst->packedfile); + } + + if (vfont_dst->data) { + vfont_dst->data = BLI_vfontdata_copy(vfont_dst->data, flag_subdata); + } +} + static void *builtin_font_data = NULL; static int builtin_font_size = 0; @@ -249,7 +266,7 @@ VFont *BKE_vfont_load(Main *bmain, const char *filepath) vfd = BLI_vfontdata_from_freetypefont(pf); if (vfd) { - vfont = BKE_libblock_alloc(bmain, ID_VF, filename); + vfont = BKE_libblock_alloc(bmain, ID_VF, filename, 0); vfont->data = vfd; /* if there's a font name, use it for the ID name */ diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c index 0a0b023df82..e45a938a4fc 100644 --- a/source/blender/blenkernel/intern/freestyle.c +++ b/source/blender/blenkernel/intern/freestyle.c @@ -44,7 +44,7 @@ // function declarations static FreestyleLineSet *alloc_lineset(void); -static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset); +static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset, const int flag); static FreestyleModuleConfig *alloc_module(void); static void copy_module(FreestyleModuleConfig *new_module, FreestyleModuleConfig *module); @@ -79,7 +79,7 @@ void BKE_freestyle_config_free(FreestyleConfig *config) BLI_freelistN(&config->modules); } -void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config) +void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag) { FreestyleLineSet *lineset, *new_lineset; FreestyleModuleConfig *module, *new_module; @@ -93,7 +93,7 @@ void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *con BLI_listbase_clear(&new_config->linesets); for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) { new_lineset = alloc_lineset(); - copy_lineset(new_lineset, lineset); + copy_lineset(new_lineset, lineset, flag); BLI_addtail(&new_config->linesets, (void *)new_lineset); } @@ -105,11 +105,9 @@ void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *con } } -static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset) +static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset, const int flag) { new_lineset->linestyle = lineset->linestyle; - if (new_lineset->linestyle) - id_us_plus(&new_lineset->linestyle->id); new_lineset->flags = lineset->flags; new_lineset->selection = lineset->selection; new_lineset->qi = lineset->qi; @@ -118,10 +116,12 @@ static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *linese new_lineset->edge_types = lineset->edge_types; new_lineset->exclude_edge_types = lineset->exclude_edge_types; new_lineset->group = lineset->group; - if (new_lineset->group) { - id_us_plus(&new_lineset->group->id); - } strcpy(new_lineset->name, lineset->name); + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)new_lineset->linestyle); + id_us_plus((ID *)new_lineset->group); + } } static FreestyleModuleConfig *alloc_module(void) diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 758438bb051..ee0d0b41898 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -627,7 +627,7 @@ bGPdata *BKE_gpencil_data_addnew(const char name[]) bGPdata *gpd; /* allocate memory for a new block */ - gpd = BKE_libblock_alloc(G.main, ID_GD, name); + gpd = BKE_libblock_alloc(G.main, ID_GD, name, 0); /* initial settings */ gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND); @@ -753,47 +753,62 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) return gpl_dst; } -/* make a copy of a given gpencil datablock */ -bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy) +/** + * Only copy internal data of GreasePencil ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata *gpd_src, const int UNUSED(flag)) { - const bGPDlayer *gpl_src; - bGPDlayer *gpl_dst; - bGPdata *gpd_dst; + /* copy layers */ + BLI_listbase_clear(&gpd_dst->layers); + for (const bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) { + /* make a copy of source layer and its data */ + bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(gpl_src); /* TODO here too could add unused flags... */ + BLI_addtail(&gpd_dst->layers, gpl_dst); + } - /* error checking */ - if (gpd_src == NULL) { - return NULL; + /* copy palettes */ + BLI_listbase_clear(&gpd_dst->palettes); + for (const bGPDpalette *palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) { + bGPDpalette *palette_dst = BKE_gpencil_palette_duplicate(palette_src); /* TODO here too could add unused flags... */ + BLI_addtail(&gpd_dst->palettes, palette_dst); } - - /* make a copy of the base-data */ +} + +/* make a copy of a given gpencil datablock */ +bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy) +{ + /* Yuck and super-uber-hyper yuck!!! + * Should be replaceable with a no-main copy (LIB_ID_COPY_NO_MAIN etc.), but not sure about it, + * so for now keep old code for that one. */ if (internal_copy) { + const bGPDlayer *gpl_src; + bGPDlayer *gpl_dst; + bGPdata *gpd_dst; + /* make a straight copy for undo buffers used during stroke drawing */ gpd_dst = MEM_dupallocN(gpd_src); + + /* copy layers */ + BLI_listbase_clear(&gpd_dst->layers); + for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) { + /* make a copy of source layer and its data */ + gpl_dst = BKE_gpencil_layer_duplicate(gpl_src); + BLI_addtail(&gpd_dst->layers, gpl_dst); + } + + /* return new */ + return gpd_dst; } else { - /* make a copy when others use this */ - gpd_dst = BKE_libblock_copy(bmain, &gpd_src->id); - } - - /* copy layers */ - BLI_listbase_clear(&gpd_dst->layers); - for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) { - /* make a copy of source layer and its data */ - gpl_dst = BKE_gpencil_layer_duplicate(gpl_src); - BLI_addtail(&gpd_dst->layers, gpl_dst); - } - if (!internal_copy) { - /* copy palettes */ - bGPDpalette *palette_src, *palette_dst; - BLI_listbase_clear(&gpd_dst->palettes); - for (palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) { - palette_dst = BKE_gpencil_palette_duplicate(palette_src); - BLI_addtail(&gpd_dst->palettes, palette_dst); - } + bGPdata *gpd_copy; + BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_copy, 0, false); + return gpd_copy; } - - /* return new */ - return gpd_dst; } void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local) diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index 932f41ac4ba..fd6e9681e64 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -79,7 +79,7 @@ Group *BKE_group_add(Main *bmain, const char *name) { Group *group; - group = BKE_libblock_alloc(bmain, ID_GR, name); + group = BKE_libblock_alloc(bmain, ID_GR, name, 0); id_us_min(&group->id); id_us_ensure_real(&group->id); group->layer = (1 << 20) - 1; @@ -89,19 +89,32 @@ Group *BKE_group_add(Main *bmain, const char *name) return group; } -Group *BKE_group_copy(Main *bmain, const Group *group) +/** + * Only copy internal data of Group ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *group_src, const int flag) { - Group *groupn; - - groupn = BKE_libblock_copy(bmain, &group->id); - BLI_duplicatelist(&groupn->gobject, &group->gobject); + BLI_duplicatelist(&group_dst->gobject, &group_src->gobject); /* Do not copy group's preview (same behavior as for objects). */ - groupn->preview = NULL; - - BKE_id_copy_ensure_local(bmain, &group->id, &groupn->id); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */ + BKE_previewimg_id_copy(&group_dst->id, &group_src->id); + } + else { + group_dst->preview = NULL; + } +} - return groupn; +Group *BKE_group_copy(Main *bmain, const Group *group) +{ + Group *group_copy; + BKE_id_copy_ex(bmain, &group->id, (ID **)&group_copy, 0, false); + return group_copy; } void BKE_group_make_local(Main *bmain, Group *group, const bool lib_local) diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index bccf9307912..a98a1b13402 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -253,6 +253,8 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id) ID_PRV_CASE(ID_GR, Group); ID_PRV_CASE(ID_SCE, Scene); #undef ID_PRV_CASE + default: + break; } return NULL; diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index e98181be444..45b41fa01ed 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -90,7 +90,7 @@ IDProperty *IDP_NewIDPArray(const char *name) return prop; } -IDProperty *IDP_CopyIDPArray(const IDProperty *array) +IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag) { /* don't use MEM_dupallocN because this may be part of an array */ IDProperty *narray, *tmp; @@ -109,7 +109,7 @@ IDProperty *IDP_CopyIDPArray(const IDProperty *array) * then free it. this makes for more maintainable * code than simply reimplementing the copy functions * in this loop.*/ - tmp = IDP_CopyProperty(GETPROP(narray, i)); + tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag); memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty)); MEM_freeN(tmp); } @@ -285,9 +285,9 @@ void IDP_FreeArray(IDProperty *prop) } -static IDProperty *idp_generic_copy(const IDProperty *prop) +static IDProperty *idp_generic_copy(const IDProperty *prop, const int UNUSED(flag)) { - IDProperty *newp = MEM_callocN(sizeof(IDProperty), "IDProperty array dup"); + IDProperty *newp = MEM_callocN(sizeof(IDProperty), __func__); BLI_strncpy(newp->name, prop->name, MAX_IDPROP_NAME); newp->type = prop->type; @@ -298,9 +298,9 @@ static IDProperty *idp_generic_copy(const IDProperty *prop) return newp; } -static IDProperty *IDP_CopyArray(const IDProperty *prop) +static IDProperty *IDP_CopyArray(const IDProperty *prop, const int flag) { - IDProperty *newp = idp_generic_copy(prop); + IDProperty *newp = idp_generic_copy(prop, flag); if (prop->data.pointer) { newp->data.pointer = MEM_dupallocN(prop->data.pointer); @@ -310,7 +310,7 @@ static IDProperty *IDP_CopyArray(const IDProperty *prop) int a; for (a = 0; a < prop->len; a++) - array[a] = IDP_CopyProperty(array[a]); + array[a] = IDP_CopyProperty_ex(array[a], flag); } } newp->len = prop->len; @@ -363,12 +363,12 @@ IDProperty *IDP_NewString(const char *st, const char *name, int maxlen) return prop; } -static IDProperty *IDP_CopyString(const IDProperty *prop) +static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag) { IDProperty *newp; BLI_assert(prop->type == IDP_STRING); - newp = idp_generic_copy(prop); + newp = idp_generic_copy(prop, flag); if (prop->data.pointer) newp->data.pointer = MEM_dupallocN(prop->data.pointer); @@ -442,15 +442,17 @@ void IDP_FreeString(IDProperty *prop) /** \name IDProperty ID API * \{ */ -static IDProperty *IDP_CopyID(const IDProperty *prop) +static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag) { IDProperty *newp; BLI_assert(prop->type == IDP_ID); - newp = idp_generic_copy(prop); + newp = idp_generic_copy(prop, flag); newp->data.pointer = prop->data.pointer; - id_us_plus(IDP_Id(newp)); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus(IDP_Id(newp)); + } return newp; } @@ -467,16 +469,16 @@ static IDProperty *IDP_CopyID(const IDProperty *prop) /** * Checks if a property with the same name as prop exists, and if so replaces it. */ -static IDProperty *IDP_CopyGroup(const IDProperty *prop) +static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag) { IDProperty *newp, *link; BLI_assert(prop->type == IDP_GROUP); - newp = idp_generic_copy(prop); + newp = idp_generic_copy(prop, flag); newp->len = prop->len; for (link = prop->data.group.first; link; link = link->next) { - BLI_addtail(&newp->data.group, IDP_CopyProperty(link)); + BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag)); } return newp; @@ -730,18 +732,23 @@ static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user) /** \name IDProperty Main API * \{ */ -IDProperty *IDP_CopyProperty(const IDProperty *prop) +IDProperty *IDP_CopyProperty_ex(const IDProperty *prop, const int flag) { 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); + case IDP_GROUP: return IDP_CopyGroup(prop, flag); + case IDP_STRING: return IDP_CopyString(prop, flag); + case IDP_ID: return IDP_CopyID(prop, flag); + case IDP_ARRAY: return IDP_CopyArray(prop, flag); + case IDP_IDPARRAY: return IDP_CopyIDPArray(prop, flag); + default: return idp_generic_copy(prop, flag); } } +IDProperty *IDP_CopyProperty(const IDProperty *prop) +{ + return IDP_CopyProperty_ex(prop, 0); +} + /* 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) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index abe08def197..90f2fe3d547 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -303,8 +303,11 @@ static void image_free_anims(Image *ima) * Simply free the image data from memory, * on display the image can load again (except for render buffers). */ -void BKE_image_free_buffers(Image *ima) +void BKE_image_free_buffers_ex(Image *ima, bool do_lock) { + if (do_lock) { + BLI_spin_lock(&image_spin); + } image_free_cached_frames(ima); image_free_anims(ima); @@ -323,6 +326,15 @@ void BKE_image_free_buffers(Image *ima) } ima->ok = IMA_OK; + + if (do_lock) { + BLI_spin_unlock(&image_spin); + } +} + +void BKE_image_free_buffers(Image *ima) +{ + BKE_image_free_buffers_ex(ima, false); } /** Free (or release) any data used by this image (does not free the image itself). */ @@ -382,7 +394,7 @@ static Image *image_alloc(Main *bmain, const char *name, short source, short typ { Image *ima; - ima = BKE_libblock_alloc(bmain, ID_IM, name); + ima = BKE_libblock_alloc(bmain, ID_IM, name, 0); if (ima) { image_init(ima, source, type); } @@ -433,39 +445,53 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src) } } -/* empty image block, of similar type and filename */ -Image *BKE_image_copy(Main *bmain, const Image *ima) +/** + * Only copy internal data of Image ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_image_copy_data(Main *UNUSED(bmain), Image *ima_dst, const Image *ima_src, const int flag) { - Image *nima = image_alloc(bmain, ima->id.name + 2, ima->source, ima->type); - - BLI_strncpy(nima->name, ima->name, sizeof(ima->name)); - - nima->flag = ima->flag; - nima->tpageflag = ima->tpageflag; - - nima->gen_x = ima->gen_x; - nima->gen_y = ima->gen_y; - nima->gen_type = ima->gen_type; - copy_v4_v4(nima->gen_color, ima->gen_color); + BKE_color_managed_colorspace_settings_copy(&ima_dst->colorspace_settings, &ima_src->colorspace_settings); - nima->animspeed = ima->animspeed; + copy_image_packedfiles(&ima_dst->packedfiles, &ima_src->packedfiles); - nima->aspx = ima->aspx; - nima->aspy = ima->aspy; + ima_dst->stereo3d_format = MEM_dupallocN(ima_src->stereo3d_format); + BLI_duplicatelist(&ima_dst->views, &ima_src->views); - BKE_color_managed_colorspace_settings_copy(&nima->colorspace_settings, &ima->colorspace_settings); - - copy_image_packedfiles(&nima->packedfiles, &ima->packedfiles); + /* Cleanup stuff that cannot be copied. */ + ima_dst->cache = NULL; + ima_dst->rr = NULL; + for (int i = 0; i < IMA_MAX_RENDER_SLOT; i++) { + ima_dst->renders[i] = NULL; + } - /* nima->stere3d_format is already allocated by image_alloc... */ - *nima->stereo3d_format = *ima->stereo3d_format; - BLI_duplicatelist(&nima->views, &ima->views); + BLI_listbase_clear(&ima_dst->anims); - BKE_previewimg_id_copy(&nima->id, &ima->id); + ima_dst->totbind = 0; + for (int i = 0; i < TEXTARGET_COUNT; i++) { + ima_dst->bindcode[i] = 0; + ima_dst->gputexture[i] = NULL; + } + ima_dst->repbind = NULL; - BKE_id_copy_ensure_local(bmain, &ima->id, &nima->id); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { + BKE_previewimg_id_copy(&ima_dst->id, &ima_src->id); + } + else { + ima_dst->preview = NULL; + } +} - return nima; +/* empty image block, of similar type and filename */ +Image *BKE_image_copy(Main *bmain, const Image *ima) +{ + Image *ima_copy; + BKE_id_copy_ex(bmain, &ima->id, (ID **)&ima_copy, 0, false); + return ima_copy; } void BKE_image_make_local(Main *bmain, Image *ima, const bool lib_local) @@ -1177,7 +1203,6 @@ bool BKE_imtype_is_movie(const char imtype) switch (imtype) { case R_IMF_IMTYPE_AVIRAW: case R_IMF_IMTYPE_AVIJPEG: - case R_IMF_IMTYPE_QUICKTIME: case R_IMF_IMTYPE_FFMPEG: case R_IMF_IMTYPE_H264: case R_IMF_IMTYPE_THEORA: @@ -1249,7 +1274,6 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file) case R_IMF_IMTYPE_MULTILAYER: case R_IMF_IMTYPE_DDS: case R_IMF_IMTYPE_JP2: - case R_IMF_IMTYPE_QUICKTIME: case R_IMF_IMTYPE_DPX: chan_flag |= IMA_CHAN_FLAG_ALPHA; break; @@ -1312,7 +1336,6 @@ char BKE_imtype_from_arg(const char *imtype_arg) else if (STREQ(imtype_arg, "AVIRAW")) return R_IMF_IMTYPE_AVIRAW; else if (STREQ(imtype_arg, "AVIJPEG")) return R_IMF_IMTYPE_AVIJPEG; else if (STREQ(imtype_arg, "PNG")) return R_IMF_IMTYPE_PNG; - else if (STREQ(imtype_arg, "QUICKTIME")) return R_IMF_IMTYPE_QUICKTIME; else if (STREQ(imtype_arg, "BMP")) return R_IMF_IMTYPE_BMP; #ifdef WITH_HDR else if (STREQ(imtype_arg, "HDR")) return R_IMF_IMTYPE_RADHDR; @@ -1423,7 +1446,7 @@ static bool do_add_image_extension(char *string, const char imtype, const ImageF } } #endif - else { // R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG, R_IMF_IMTYPE_JPEG90, R_IMF_IMTYPE_QUICKTIME etc + else { // R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG, R_IMF_IMTYPE_JPEG90 etc if (!(BLI_testextensie_n(string, extension_test = ".jpg", ".jpeg", NULL))) extension = extension_test; } @@ -1431,8 +1454,7 @@ static bool do_add_image_extension(char *string, const char imtype, const ImageF if (extension) { /* prefer this in many cases to avoid .png.tga, but in certain cases it breaks */ /* remove any other known image extension */ - if (BLI_testextensie_array(string, imb_ext_image) || - (G.have_quicktime && BLI_testextensie_array(string, imb_ext_image_qt))) + if (BLI_testextensie_array(string, imb_ext_image)) { return BLI_replace_extension(string, FILE_MAX, extension); } @@ -1709,7 +1731,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d } { - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); RenderStats *stats = re ? RE_GetStats(re) : NULL; if (stats && (scene->r.stamp & R_STAMP_RENDERTIME)) { @@ -2903,7 +2925,7 @@ RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima) } else if (ima->type == IMA_TYPE_R_RESULT) { if (ima->render_slot == ima->last_render_slot) - rr = RE_AcquireResultRead(RE_GetRender(scene->id.name)); + rr = RE_AcquireResultRead(RE_GetSceneRender(scene)); else rr = ima->renders[ima->render_slot]; @@ -2921,7 +2943,7 @@ void BKE_image_release_renderresult(Scene *scene, Image *ima) } else if (ima->type == IMA_TYPE_R_RESULT) { if (ima->render_slot == ima->last_render_slot) - RE_ReleaseResult(RE_GetRender(scene->id.name)); + RE_ReleaseResult(RE_GetSceneRender(scene)); } } @@ -2941,7 +2963,7 @@ void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot) { /* called right before rendering, ima->renders contains render * result pointers for everything but the current render */ - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); int slot = ima->render_slot, last = ima->last_render_slot; if (slot != last) { @@ -3666,7 +3688,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc if (!r_lock) return NULL; - re = RE_GetRender(iuser->scene->id.name); + re = RE_GetSceneRender(iuser->scene); channels = 4; layer = iuser->layer; diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c index 2c8399adece..1f1f4c9d341 100644 --- a/source/blender/blenkernel/intern/image_gen.c +++ b/source/blender/blenkernel/intern/image_gen.c @@ -132,7 +132,7 @@ static void image_buf_fill_checker_slice(unsigned char *rect, float hsv[3] = {0.0f, 0.9f, 0.9f}; float rgb[3]; - float dark_linear_color, bright_linear_color; + float dark_linear_color = 0.0f, bright_linear_color = 0.0f; if (rect_float != NULL) { dark_linear_color = srgb_to_linearrgb(0.25f); bright_linear_color = srgb_to_linearrgb(0.58f); diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 98b251294ae..fd42556067e 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -107,7 +107,7 @@ Key *BKE_key_add(ID *id) /* common function */ Key *key; char *el; - key = BKE_libblock_alloc(G.main, ID_KE, "Key"); + key = BKE_libblock_alloc(G.main, ID_KE, "Key", 0); key->type = KEY_NORMAL; key->from = id; @@ -146,36 +146,48 @@ Key *BKE_key_add(ID *id) /* common function */ key->elemsize = 16; break; + + default: + break; } return key; } -Key *BKE_key_copy(Main *bmain, const Key *key) +/** + * Only copy internal data of ShapeKey ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_key_copy_data(Main *UNUSED(bmain), Key *key_dst, const Key *key_src, const int UNUSED(flag)) { - Key *keyn; - KeyBlock *kbn, *kb; - - keyn = BKE_libblock_copy(bmain, &key->id); - - BLI_duplicatelist(&keyn->block, &key->block); - - kb = key->block.first; - kbn = keyn->block.first; - while (kbn) { - - if (kbn->data) kbn->data = MEM_dupallocN(kbn->data); - if (kb == key->refkey) keyn->refkey = kbn; - - kbn = kbn->next; - kb = kb->next; - } + BLI_duplicatelist(&key_dst->block, &key_src->block); - BKE_id_copy_ensure_local(bmain, &key->id, &keyn->id); + KeyBlock *kb_dst, *kb_src; + for (kb_src = key_src->block.first, kb_dst = key_dst->block.first; + kb_dst; + kb_src = kb_src->next, kb_dst = kb_dst->next) + { + if (kb_dst->data) { + kb_dst->data = MEM_dupallocN(kb_dst->data); + } + if (kb_src == key_src->refkey) { + key_dst->refkey = kb_dst; + } + } +} - return keyn; +Key *BKE_key_copy(Main *bmain, const Key *key) +{ + Key *key_copy; + BKE_id_copy_ex(bmain, &key->id, (ID **)&key_copy, 0, false); + return key_copy; } +/* XXX TODO get rid of this! */ Key *BKE_key_copy_nolib(Key *key) { Key *keyn; @@ -1397,6 +1409,8 @@ Key **BKE_key_from_id_p(ID *id) Lattice *lt = (Lattice *)id; return <->key; } + default: + break; } return NULL; diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 2242ba379fb..e8ef346927e 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -109,42 +109,60 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name) { Lamp *la; - la = BKE_libblock_alloc(bmain, ID_LA, name); + la = BKE_libblock_alloc(bmain, ID_LA, name, 0); BKE_lamp_init(la); return la; } -Lamp *BKE_lamp_copy(Main *bmain, const Lamp *la) +/** + * Only copy internal data of Lamp ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_lamp_copy_data(Main *bmain, Lamp *la_dst, const Lamp *la_src, const int flag) { - Lamp *lan; - int a; - - lan = BKE_libblock_copy(bmain, &la->id); - - for (a = 0; a < MAX_MTEX; a++) { - if (lan->mtex[a]) { - lan->mtex[a] = MEM_mallocN(sizeof(MTex), "copylamptex"); - memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex)); - id_us_plus((ID *)lan->mtex[a]->tex); + for (int a = 0; a < MAX_MTEX; a++) { + if (la_dst->mtex[a]) { + la_dst->mtex[a] = MEM_mallocN(sizeof(*la_dst->mtex[a]), __func__); + *la_dst->mtex[a] = *la_src->mtex[a]; } } - - lan->curfalloff = curvemapping_copy(la->curfalloff); - if (la->nodetree) - lan->nodetree = ntreeCopyTree(bmain, la->nodetree); + la_dst->curfalloff = curvemapping_copy(la_src->curfalloff); - BKE_previewimg_id_copy(&lan->id, &la->id); + if (la_src->nodetree) { + BKE_id_copy_ex(bmain, (ID *)la_src->nodetree, (ID **)&la_dst->nodetree, flag, false); + } - BKE_id_copy_ensure_local(bmain, &la->id, &lan->id); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { + BKE_previewimg_id_copy(&la_dst->id, &la_src->id); + } + else { + la_dst->preview = NULL; + } +} - return lan; +Lamp *BKE_lamp_copy(Main *bmain, const Lamp *la) +{ + Lamp *la_copy; + BKE_id_copy_ex(bmain, &la->id, (ID **)&la_copy, 0, false); + return la_copy; } Lamp *localize_lamp(Lamp *la) { + /* TODO replace with something like + * Lamp *la_copy; + * BKE_id_copy_ex(bmain, &la->id, (ID **)&la_copy, LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT, false); + * return la_copy; + * + * ... Once f*** nodes are fully converted to that too :( */ + Lamp *lan; int a; diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index c9d7dddf25a..ea4c3f380ff 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -270,39 +270,46 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name) { Lattice *lt; - lt = BKE_libblock_alloc(bmain, ID_LT, name); + lt = BKE_libblock_alloc(bmain, ID_LT, name, 0); BKE_lattice_init(lt); return lt; } -Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt) +/** + * Only copy internal data of Lattice ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_lattice_copy_data(Main *bmain, Lattice *lt_dst, const Lattice *lt_src, const int flag) { - Lattice *ltn; - - ltn = BKE_libblock_copy(bmain, <->id); - ltn->def = MEM_dupallocN(lt->def); + lt_dst->def = MEM_dupallocN(lt_src->def); - if (lt->key) { - ltn->key = BKE_key_copy(bmain, ltn->key); - ltn->key->from = (ID *)ltn; - } - - if (lt->dvert) { - int tot = lt->pntsu * lt->pntsv * lt->pntsw; - ltn->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); - BKE_defvert_array_copy(ltn->dvert, lt->dvert, tot); + if (lt_src->key) { + BKE_id_copy_ex(bmain, <_src->key->id, (ID **)<_dst->key, flag, false); } - ltn->editlatt = NULL; + if (lt_src->dvert) { + int tot = lt_src->pntsu * lt_src->pntsv * lt_src->pntsw; + lt_dst->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); + BKE_defvert_array_copy(lt_dst->dvert, lt_src->dvert, tot); + } - BKE_id_copy_ensure_local(bmain, <->id, <n->id); + lt_dst->editlatt = NULL; +} - return ltn; +Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt) +{ + Lattice *lt_copy; + BKE_id_copy_ex(bmain, <->id, (ID **)<_copy, 0, false); + return lt_copy; } -/** Free (or release) any data used by this lattice (does not free the lattice itself). */ + /** Free (or release) any data used by this lattice (does not free the lattice itself). */ void BKE_lattice_free(Lattice *lt) { BKE_animdata_free(<->id, false); diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 2ea7342ff34..d5dfc63b317 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -383,7 +383,6 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) switch ((ID_Type)GS(id->name)) { case ID_SCE: - /* Partially implemented (has no copy...). */ if (!test) BKE_scene_make_local(bmain, (Scene *)id, lib_local); return true; case ID_OB: @@ -423,14 +422,12 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) if (!test) BKE_world_make_local(bmain, (World *)id, lib_local); return true; case ID_VF: - /* Partially implemented (has no copy...). */ if (!test) BKE_vfont_make_local(bmain, (VFont *)id, lib_local); return true; case ID_TXT: if (!test) BKE_text_make_local(bmain, (Text *)id, lib_local); return true; case ID_SO: - /* Partially implemented (has no copy...). */ if (!test) BKE_sound_make_local(bmain, (bSound *)id, lib_local); return true; case ID_GR: @@ -484,114 +481,189 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) return false; } +struct IDCopyLibManagementData { + const ID *id_src; + ID *id_dst; + int flag; +}; + +/* Increases usercount as required, and remap self ID pointers. */ +static int id_copy_libmanagement_cb(void *user_data, ID *UNUSED(id_self), ID **id_pointer, int cb_flag) +{ + struct IDCopyLibManagementData *data = user_data; + ID *id = *id_pointer; + + /* Remap self-references to new copied ID. */ + if (id == data->id_src) { + /* We cannot use id_self here, it is not *always* id_dst (thanks to $£!+@#&/? nodetrees). */ + id = *id_pointer = data->id_dst; + } + + /* Increase used IDs refcount if needed and required. */ + if ((data->flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0 && (cb_flag & IDWALK_CB_USER)) { + id_us_plus(id); + } + + return IDWALK_RET_NOP; +} + /** - * Invokes the appropriate copy method for the block and returns the result in - * newid, unless test. Returns true if the block can be copied. + * Generic entry point for copying a datablock (new API). + * + * \note Copy is only affecting given data-block (no ID used by copied one will be affected, besides usercount). + * There is only one exception, if LIB_ID_COPY_ACTIONS is defined, actions used by animdata will be duplicated. + * + * \note Usercount of new copy is always set to 1. + * + * \param bmain Main database, may be NULL only if LIB_ID_COPY_NO_MAIN is specified. + * \param id Source datablock. + * \param r_newid Pointer to new (copied) ID pointer. + * \param flag Set of copy options, see DNA_ID.h enum for details (leave to zero for default, full copy). + * \param test If set, do not do any copy, just test whether copy is supported. + * \return False when copying that ID type is not supported, true otherwise. */ -bool id_copy(Main *bmain, const ID *id, ID **newid, bool test) +/* XXX TODO remove test thing, *all* IDs should be copyable that way! */ +bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, const bool test) { - if (!test) { - *newid = NULL; +#define LIB_ID_TYPES_NOCOPY ID_LI, ID_SCR, ID_WM, /* Not supported */ \ + ID_IP /* Deprecated */ + + BLI_assert(test || (r_newid != NULL)); + if (r_newid != NULL) { + *r_newid = NULL; + } + if (id == NULL) { + return false; + } + + if (ELEM(GS(id->name), LIB_ID_TYPES_NOCOPY)) { + return false; + } + else if (test) { + return true; } - /* conventions: - * - make shallow copy, only this ID block - * - id.us of the new ID is set to 1 */ + BKE_libblock_copy_ex(bmain, id, r_newid, flag); + switch ((ID_Type)GS(id->name)) { + case ID_SCE: + BKE_scene_copy_data(bmain, (Scene *)*r_newid, (Scene *)id, flag); + break; case ID_OB: - if (!test) *newid = (ID *)BKE_object_copy(bmain, (Object *)id); - return true; + BKE_object_copy_data(bmain, (Object *)*r_newid, (Object *)id, flag); + break; case ID_ME: - if (!test) *newid = (ID *)BKE_mesh_copy(bmain, (Mesh *)id); - return true; + BKE_mesh_copy_data(bmain, (Mesh *)*r_newid, (Mesh *)id, flag); + break; case ID_CU: - if (!test) *newid = (ID *)BKE_curve_copy(bmain, (Curve *)id); - return true; + BKE_curve_copy_data(bmain, (Curve *)*r_newid, (Curve *)id, flag); + break; case ID_MB: - if (!test) *newid = (ID *)BKE_mball_copy(bmain, (MetaBall *)id); - return true; + BKE_mball_copy_data(bmain, (MetaBall *)*r_newid, (MetaBall *)id, flag); + break; case ID_MA: - if (!test) *newid = (ID *)BKE_material_copy(bmain, (Material *)id); - return true; + BKE_material_copy_data(bmain, (Material *)*r_newid, (Material *)id, flag); + break; case ID_TE: - if (!test) *newid = (ID *)BKE_texture_copy(bmain, (Tex *)id); - return true; + BKE_texture_copy_data(bmain, (Tex *)*r_newid, (Tex *)id, flag); + break; case ID_IM: - if (!test) *newid = (ID *)BKE_image_copy(bmain, (Image *)id); - return true; + BKE_image_copy_data(bmain, (Image *)*r_newid, (Image *)id, flag); + break; case ID_LT: - if (!test) *newid = (ID *)BKE_lattice_copy(bmain, (Lattice *)id); - return true; + BKE_lattice_copy_data(bmain, (Lattice *)*r_newid, (Lattice *)id, flag); + break; case ID_LA: - if (!test) *newid = (ID *)BKE_lamp_copy(bmain, (Lamp *)id); - return true; + BKE_lamp_copy_data(bmain, (Lamp *)*r_newid, (Lamp *)id, flag); + break; case ID_SPK: - if (!test) *newid = (ID *)BKE_speaker_copy(bmain, (Speaker *)id); - return true; + BKE_speaker_copy_data(bmain, (Speaker *)*r_newid, (Speaker *)id, flag); + break; case ID_CA: - if (!test) *newid = (ID *)BKE_camera_copy(bmain, (Camera *)id); - return true; + BKE_camera_copy_data(bmain, (Camera *)*r_newid, (Camera *)id, flag); + break; case ID_KE: - if (!test) *newid = (ID *)BKE_key_copy(bmain, (Key *)id); - return true; + BKE_key_copy_data(bmain, (Key *)*r_newid, (Key *)id, flag); + break; case ID_WO: - if (!test) *newid = (ID *)BKE_world_copy(bmain, (World *)id); - return true; + BKE_world_copy_data(bmain, (World *)*r_newid, (World *)id, flag); + break; case ID_TXT: - if (!test) *newid = (ID *)BKE_text_copy(bmain, (Text *)id); - return true; + BKE_text_copy_data(bmain, (Text *)*r_newid, (Text *)id, flag); + break; case ID_GR: - if (!test) *newid = (ID *)BKE_group_copy(bmain, (Group *)id); - return true; + BKE_group_copy_data(bmain, (Group *)*r_newid, (Group *)id, flag); + break; case ID_AR: - if (!test) *newid = (ID *)BKE_armature_copy(bmain, (bArmature *)id); - return true; + BKE_armature_copy_data(bmain, (bArmature *)*r_newid, (bArmature *)id, flag); + break; case ID_AC: - if (!test) *newid = (ID *)BKE_action_copy(bmain, (bAction *)id); - return true; + BKE_action_copy_data(bmain, (bAction *)*r_newid, (bAction *)id, flag); + break; case ID_NT: - if (!test) *newid = (ID *)ntreeCopyTree(bmain, (bNodeTree *)id); - return true; + BKE_node_tree_copy_data(bmain, (bNodeTree *)*r_newid, (bNodeTree *)id, flag); + break; case ID_BR: - if (!test) *newid = (ID *)BKE_brush_copy(bmain, (Brush *)id); - return true; + BKE_brush_copy_data(bmain, (Brush *)*r_newid, (Brush *)id, flag); + break; case ID_PA: - if (!test) *newid = (ID *)BKE_particlesettings_copy(bmain, (ParticleSettings *)id); - return true; + BKE_particlesettings_copy_data(bmain, (ParticleSettings *)*r_newid, (ParticleSettings *)id, flag); + break; case ID_GD: - if (!test) *newid = (ID *)BKE_gpencil_data_duplicate(bmain, (bGPdata *)id, false); - return true; + BKE_gpencil_copy_data(bmain, (bGPdata *)*r_newid, (bGPdata *)id, flag); + break; case ID_MC: - if (!test) *newid = (ID *)BKE_movieclip_copy(bmain, (MovieClip *)id); - return true; + BKE_movieclip_copy_data(bmain, (MovieClip *)*r_newid, (MovieClip *)id, flag); + break; case ID_MSK: - if (!test) *newid = (ID *)BKE_mask_copy(bmain, (Mask *)id); - return true; + BKE_mask_copy_data(bmain, (Mask *)*r_newid, (Mask *)id, flag); + break; case ID_LS: - if (!test) *newid = (ID *)BKE_linestyle_copy(bmain, (FreestyleLineStyle *)id); - return true; + BKE_linestyle_copy_data(bmain, (FreestyleLineStyle *)*r_newid, (FreestyleLineStyle *)id, flag); + break; case ID_PAL: - if (!test) *newid = (ID *)BKE_palette_copy(bmain, (Palette *)id); - return true; + BKE_palette_copy_data(bmain, (Palette *)*r_newid, (Palette *)id, flag); + break; case ID_PC: - if (!test) *newid = (ID *)BKE_paint_curve_copy(bmain, (PaintCurve *)id); - return true; + BKE_paint_curve_copy_data(bmain, (PaintCurve *)*r_newid, (PaintCurve *)id, flag); + break; case ID_CF: - if (!test) *newid = (ID *)BKE_cachefile_copy(bmain, (CacheFile *)id); - return true; - case ID_SCE: + BKE_cachefile_copy_data(bmain, (CacheFile *)*r_newid, (CacheFile *)id, flag); + break; + case ID_SO: + BKE_sound_copy_data(bmain, (bSound *)*r_newid, (bSound *)id, flag); + break; + case ID_VF: + BKE_vfont_copy_data(bmain, (VFont *)*r_newid, (VFont *)id, flag); + break; case ID_LI: case ID_SCR: case ID_WM: - return false; /* can't be copied from here */ - case ID_VF: - case ID_SO: - return false; /* not implemented */ case ID_IP: - return false; /* deprecated */ + BLI_assert(0); /* Should have been rejected at start of function! */ + break; } - - return false; + + /* Update ID refcount, remap pointers to self in new ID. */ + struct IDCopyLibManagementData data = {.id_src = id, .id_dst = *r_newid, .flag = flag}; + BKE_library_foreach_ID_link(bmain, *r_newid, id_copy_libmanagement_cb, &data, IDWALK_NOP); + + /* Do not make new copy local in case we are copying outside of main... + * XXX TODO: is this behavior OK, or should we need own flag to control that? */ + if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { + BKE_id_copy_ensure_local(bmain, id, *r_newid); + } + + return true; +} + +/** + * Invokes the appropriate copy method for the block and returns the result in + * newid, unless test. Returns true if the block can be copied. + */ +bool id_copy(Main *bmain, const ID *id, ID **newid, bool test) +{ + return BKE_id_copy_ex(bmain, id, newid, 0, test); } /** Does *not* set ID->newid pointer. */ @@ -623,6 +695,101 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) return false; } +static int libblock_management_us_plus(void *UNUSED(user_data), ID *UNUSED(id_self), ID **id_pointer, int cb_flag) +{ + if (cb_flag & IDWALK_CB_USER) { + id_us_plus(*id_pointer); + } + if (cb_flag & IDWALK_CB_USER_ONE) { + id_us_ensure_real(*id_pointer); + } + + return IDWALK_RET_NOP; +} + +static int libblock_management_us_min(void *UNUSED(user_data), ID *UNUSED(id_self), ID **id_pointer, int cb_flag) +{ + if (cb_flag & IDWALK_CB_USER) { + id_us_min(*id_pointer); + } + /* We can do nothing in IDWALK_CB_USER_ONE case! */ + + return IDWALK_RET_NOP; +} + +/** Add a 'NO_MAIN' datablock to given main (also sets usercounts of its IDs if needed). */ +void BKE_libblock_management_main_add(Main *bmain, void *idv) +{ + ID *id = idv; + + BLI_assert(bmain != NULL); + if ((id->tag & LIB_TAG_NO_MAIN) == 0) { + return; + } + + if ((id->tag & LIB_TAG_NOT_ALLOCATED) != 0) { + /* We cannot add non-allocated ID to Main! */ + return; + } + + /* We cannot allow non-userrefcounting IDs in Main database! */ + if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0) { + BKE_library_foreach_ID_link(bmain, id, libblock_management_us_plus, NULL, IDWALK_NOP); + } + + ListBase *lb = which_libbase(bmain, GS(id->name)); + BKE_main_lock(bmain); + BLI_addtail(lb, id); + new_id(lb, id, NULL); + /* alphabetic insertion: is in new_id */ + id->tag &= ~(LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT); + BKE_main_unlock(bmain); +} + +/** Remove a datablock from given main (set it to 'NO_MAIN' status). */ +void BKE_libblock_management_main_remove(Main *bmain, void *idv) +{ + ID *id = idv; + + BLI_assert(bmain != NULL); + if ((id->tag & LIB_TAG_NO_MAIN) != 0) { + return; + } + + /* For now, allow userrefcounting IDs to get out of Main - can be handy in some cases... */ + + ListBase *lb = which_libbase(bmain, GS(id->name)); + BKE_main_lock(bmain); + BLI_remlink(lb, id); + id->tag |= LIB_TAG_NO_MAIN; + BKE_main_unlock(bmain); +} + +void BKE_libblock_management_usercounts_set(Main *bmain, void *idv) +{ + ID *id = idv; + + if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) == 0) { + return; + } + + BKE_library_foreach_ID_link(bmain, id, libblock_management_us_plus, NULL, IDWALK_NOP); + id->tag &= ~LIB_TAG_NO_USER_REFCOUNT; +} + +void BKE_libblock_management_usercounts_clear(Main *bmain, void *idv) +{ + ID *id = idv; + + /* We do not allow IDs in Main database to not be userrefcounting. */ + if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0 || (id->tag & LIB_TAG_NO_MAIN) != 0) { + return; + } + + BKE_library_foreach_ID_link(bmain, id, libblock_management_us_min, NULL, IDWALK_NOP); + id->tag |= LIB_TAG_NO_USER_REFCOUNT; +} + ListBase *which_libbase(Main *mainlib, short type) { switch ((ID_Type)type) { @@ -932,23 +1099,44 @@ void *BKE_libblock_alloc_notest(short type) * The user count is set to 1, all other content (apart from name and links) being * initialized to zero. */ -void *BKE_libblock_alloc(Main *bmain, short type, const char *name) +void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int flag) { - ID *id = NULL; - ListBase *lb = which_libbase(bmain, type); - - id = BKE_libblock_alloc_notest(type); + BLI_assert((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0); + + ID *id = BKE_libblock_alloc_notest(type); + if (id) { - BKE_main_lock(bmain); - BLI_addtail(lb, id); - id->us = 1; + if ((flag & LIB_ID_CREATE_NO_MAIN) != 0) { + id->tag |= LIB_TAG_NO_MAIN; + } + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0) { + id->tag |= LIB_TAG_NO_USER_REFCOUNT; + } + id->icon_id = 0; - *( (short *)id->name) = type; - new_id(lb, id, name); - /* alphabetic insertion: is in new_id */ - BKE_main_unlock(bmain); + *((short *)id->name) = type; + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id->us = 1; + } + if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { + ListBase *lb = which_libbase(bmain, type); + + BKE_main_lock(bmain); + BLI_addtail(lb, id); + new_id(lb, id, name); + /* alphabetic insertion: is in new_id */ + BKE_main_unlock(bmain); + + /* TODO to be removed from here! */ + if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0) { + DAG_id_type_tag(bmain, type); + } + } + else { + BLI_strncpy(id->name + 2, name, sizeof(id->name) - 2); + } } - DAG_id_type_tag(bmain, type); + return id; } @@ -1071,70 +1259,80 @@ void BKE_libblock_init_empty(ID *id) /* by spec, animdata is first item after ID */ /* and, trust that BKE_animdata_from_id() will only find AnimData for valid ID-types */ -static void id_copy_animdata(ID *id, const bool do_action) +static void id_copy_animdata(Main *bmain, ID *id, const bool do_action) { AnimData *adt = BKE_animdata_from_id(id); if (adt) { IdAdtTemplate *iat = (IdAdtTemplate *)id; - iat->adt = BKE_animdata_copy(iat->adt, do_action); /* could be set to false, need to investigate */ + iat->adt = BKE_animdata_copy(bmain, iat->adt, do_action); /* could be set to false, need to investigate */ } } -/* material nodes use this since they are not treated as libdata */ -void BKE_libblock_copy_data(ID *id, const ID *id_from, const bool do_action) +void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag) { - if (id_from->properties) - id->properties = IDP_CopyProperty(id_from->properties); + ID *new_id = *r_newid; + + /* Grrrrrrrrr... Not adding 'root' nodetrees to bmain.... grrrrrrrrrrrrrrrrrrrr! */ + /* This is taken from original ntree copy code, might be weak actually? */ + const bool use_nodetree_alloc_exception = ((GS(id->name) == ID_NT) && (bmain != NULL) && + (BLI_findindex(&bmain->nodetree, id) < 0)); + + BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != NULL); + BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0); + BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0); + + if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) { + /* r_newid already contains pointer to allocated memory. */ + /* TODO do we want to memset(0) whole mem before filling it? */ + BLI_strncpy(new_id->name, id->name, sizeof(new_id->name)); + new_id->us = 0; + new_id->tag |= LIB_TAG_NOT_ALLOCATED | LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT; + /* TODO Do we want/need to copy more from ID struct itself? */ + } + else { + new_id = BKE_libblock_alloc(bmain, GS(id->name), id->name + 2, flag | (use_nodetree_alloc_exception ? LIB_ID_CREATE_NO_MAIN : 0)); + } + BLI_assert(new_id != NULL); + + const size_t id_len = BKE_libblock_get_alloc_info(GS(new_id->name), NULL); + const size_t id_offset = sizeof(ID); + if ((int)id_len - (int)id_offset > 0) { /* signed to allow neg result */ /* XXX ????? */ + const char *cp = (const char *)id; + char *cpn = (char *)new_id; + + memcpy(cpn + id_offset, cp + id_offset, id_len - id_offset); + } + + if (id->properties) { + new_id->properties = IDP_CopyProperty_ex(id->properties, flag); + } /* the duplicate should get a copy of the animdata */ - id_copy_animdata(id, do_action); + id_copy_animdata(bmain, new_id, (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0); + + if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0) { + DAG_id_type_tag(bmain, GS(new_id->name)); + } + + *r_newid = new_id; } /* used everywhere in blenkernel */ void *BKE_libblock_copy(Main *bmain, const ID *id) { ID *idn; - size_t idn_len; - - idn = BKE_libblock_alloc(bmain, GS(id->name), id->name + 2); - assert(idn != NULL); + BKE_libblock_copy_ex(bmain, id, &idn, 0); - idn_len = MEM_allocN_len(idn); - if ((int)idn_len - (int)sizeof(ID) > 0) { /* signed to allow neg result */ - const char *cp = (const char *)id; - char *cpn = (char *)idn; - - memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID)); - } - - BKE_libblock_copy_data(idn, id, false); - return idn; } void *BKE_libblock_copy_nolib(const ID *id, const bool do_action) { ID *idn; - size_t idn_len; - - idn = BKE_libblock_alloc_notest(GS(id->name)); - assert(idn != NULL); - - BLI_strncpy(idn->name, id->name, sizeof(idn->name)); - - idn_len = MEM_allocN_len(idn); - if ((int)idn_len - (int)sizeof(ID) > 0) { /* signed to allow neg result */ - const char *cp = (const char *)id; - char *cpn = (char *)idn; - - memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID)); - } - - idn->us = 1; - BKE_libblock_copy_data(idn, id, do_action); + BKE_libblock_copy_ex(NULL, id, &idn, LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | (do_action ? LIB_ID_COPY_ACTIONS : 0)); return idn; } diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 5e5ba44f039..f8c193fe108 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -186,8 +186,8 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0; #ifdef DEBUG_PRINT - printf("In %s: Remapping %s (%p) to %s (%p) (skip_indirect: %d)\n", - id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, skip_indirect); + printf("In %s: Remapping %s (%p) to %s (%p) (is_indirect: %d, skip_indirect: %d)\n", + id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, is_indirect, skip_indirect); #endif if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) { @@ -201,6 +201,14 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id { if (is_indirect) { id_remap_data->skipped_indirect++; + if (is_obj) { + Object *ob = (Object *)id; + if (ob->data == *id_p && ob->proxy != NULL) { + /* And another 'Proudly brought to you by Proxy Hell' hack! + * This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */ + id_remap_data->skipped_direct++; + } + } } else if (is_never_null || is_obj_editmode) { id_remap_data->skipped_direct++; @@ -241,7 +249,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id return IDWALK_RET_NOP; } -/* Some reamapping unfortunately require extra and/or specific handling, tackle those here. */ +/* Some remapping unfortunately require extra and/or specific handling, tackle those here. */ static void libblock_remap_data_preprocess_scene_base_unlink( IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool skip_indirect, const bool is_indirect) { @@ -318,7 +326,7 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) } } -static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain, Object *old_ob, Object *new_ob) +static void libblock_remap_data_postprocess_object_update(Main *bmain, Object *old_ob, Object *new_ob) { if (old_ob->flag & OB_FROMGROUP) { /* Note that for Scene's BaseObject->flag, either we: @@ -337,6 +345,13 @@ static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain, new_ob->flag |= OB_FROMGROUP; } } + if (old_ob->type == OB_MBALL) { + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + if (ob->type == OB_MBALL && BKE_mball_is_basis_for(ob, old_ob)) { + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + } + } + } } static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmain), Scene *sce, ID *old_id) @@ -547,7 +562,7 @@ void BKE_libblock_remap_locked( */ switch (GS(old_id->name)) { case ID_OB: - libblock_remap_data_postprocess_object_fromgroup_update(bmain, (Object *)old_id, (Object *)new_id); + libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id); break; case ID_GR: if (!new_id) { /* Only affects us in case group was unlinked. */ @@ -657,8 +672,7 @@ void BKE_libblock_relink_ex( switch (GS(old_id->name)) { case ID_OB: { - libblock_remap_data_postprocess_object_fromgroup_update( - bmain, (Object *)old_id, (Object *)new_id); + libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id); break; } case ID_GR: @@ -673,7 +687,7 @@ void BKE_libblock_relink_ex( else { /* No choice but to check whole objects/groups. */ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { - libblock_remap_data_postprocess_object_fromgroup_update(bmain, ob, NULL); + libblock_remap_data_postprocess_object_update(bmain, ob, NULL); } for (Group *grp = bmain->group.first; grp; grp = grp->id.next) { libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL); @@ -730,9 +744,11 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user) IDP_FreeProperty_ex(id->properties, do_id_user); MEM_freeN(id->properties); } + + /* XXX TODO remove animdata handling from each type's freeing func, and do it here, like for copy! */ } -void BKE_libblock_free_datablock(ID *id) +void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag)) { const short type = GS(id->name); switch (type) { @@ -842,6 +858,90 @@ void BKE_libblock_free_datablock(ID *id) } } + +void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_idtag) +{ + ID *id = idv; + + if (use_flag_from_idtag) { + if ((id->tag & LIB_TAG_NO_MAIN) != 0) { + flag |= LIB_ID_FREE_NO_MAIN; + } + else { + flag &= ~LIB_ID_FREE_NO_MAIN; + } + + if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0) { + flag |= LIB_ID_FREE_NO_USER_REFCOUNT; + } + else { + flag &= ~LIB_ID_FREE_NO_USER_REFCOUNT; + } + + if ((id->tag & LIB_TAG_NOT_ALLOCATED) != 0) { + flag |= LIB_ID_FREE_NOT_ALLOCATED; + } + else { + flag &= ~LIB_ID_FREE_NOT_ALLOCATED; + } + } + + BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || bmain != NULL); + BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || (flag & LIB_ID_FREE_NOT_ALLOCATED) == 0); + BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0); + + const short type = GS(id->name); + + if (bmain && (flag & LIB_ID_FREE_NO_DEG_TAG) == 0) { + DAG_id_type_tag(bmain, type); + } + +#ifdef WITH_PYTHON + BPY_id_release(id); +#endif + + if ((flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0) { + BKE_libblock_relink_ex(bmain, id, NULL, NULL, true); + } + + BKE_libblock_free_datablock(id, flag); + + /* avoid notifying on removed data */ + if (bmain) { + BKE_main_lock(bmain); + } + + if ((flag & LIB_ID_FREE_NO_UI_USER) == 0) { + if (free_notifier_reference_cb) { + free_notifier_reference_cb(id); + } + + if (remap_editor_id_reference_cb) { + remap_editor_id_reference_cb(id, NULL); + } + } + + if ((flag & LIB_ID_FREE_NO_MAIN) == 0) { + ListBase *lb = which_libbase(bmain, type); + BLI_remlink(lb, id); + } + + BKE_libblock_free_data(id, (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0); + + if (bmain) { + BKE_main_unlock(bmain); + } + + if ((flag & LIB_ID_FREE_NOT_ALLOCATED) == 0) { + MEM_freeN(id); + } +} + +void BKE_id_free(Main *bmain, void *idv) +{ + BKE_id_free_ex(bmain, idv, 0, true); +} + /** * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c * @@ -866,7 +966,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b BKE_libblock_relink_ex(bmain, id, NULL, NULL, true); } - BKE_libblock_free_datablock(id); + BKE_libblock_free_datablock(id, 0); /* avoid notifying on removed data */ BKE_main_lock(bmain); diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index 771e81ddc4f..1b1a12e702a 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -119,7 +119,7 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name) { FreestyleLineStyle *linestyle; - linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(bmain, ID_LS, name); + linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(bmain, ID_LS, name, 0); BKE_linestyle_init(linestyle); @@ -155,73 +155,54 @@ void BKE_linestyle_free(FreestyleLineStyle *linestyle) BKE_linestyle_geometry_modifier_remove(linestyle, m); } -FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, const FreestyleLineStyle *linestyle) +/** + * Only copy internal data of Linestyle ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_linestyle_copy_data( + struct Main *bmain, FreestyleLineStyle *linestyle_dst, const FreestyleLineStyle *linestyle_src, const int flag) { - FreestyleLineStyle *new_linestyle; - LineStyleModifier *m; - int a; + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; - new_linestyle = BKE_linestyle_new(bmain, linestyle->id.name + 2); - BKE_linestyle_free(new_linestyle); - - for (a = 0; a < MAX_MTEX; a++) { - if (linestyle->mtex[a]) { - new_linestyle->mtex[a] = MEM_mallocN(sizeof(MTex), "BKE_linestyle_copy"); - memcpy(new_linestyle->mtex[a], linestyle->mtex[a], sizeof(MTex)); - id_us_plus((ID *)new_linestyle->mtex[a]->tex); + for (int a = 0; a < MAX_MTEX; a++) { + if (linestyle_src->mtex[a]) { + linestyle_dst->mtex[a] = MEM_mallocN(sizeof(*linestyle_dst->mtex[a]), __func__); + *linestyle_dst->mtex[a] = *linestyle_src->mtex[a]; } } - if (linestyle->nodetree) { - new_linestyle->nodetree = ntreeCopyTree(bmain, linestyle->nodetree); + if (linestyle_src->nodetree) { + BKE_id_copy_ex(bmain, (ID *)linestyle_src->nodetree, (ID **)&linestyle_dst->nodetree, flag, false); } - new_linestyle->r = linestyle->r; - new_linestyle->g = linestyle->g; - new_linestyle->b = linestyle->b; - new_linestyle->alpha = linestyle->alpha; - new_linestyle->thickness = linestyle->thickness; - new_linestyle->thickness_position = linestyle->thickness_position; - new_linestyle->thickness_ratio = linestyle->thickness_ratio; - new_linestyle->flag = linestyle->flag; - new_linestyle->caps = linestyle->caps; - new_linestyle->chaining = linestyle->chaining; - new_linestyle->rounds = linestyle->rounds; - new_linestyle->split_length = linestyle->split_length; - new_linestyle->min_angle = linestyle->min_angle; - new_linestyle->max_angle = linestyle->max_angle; - new_linestyle->min_length = linestyle->min_length; - new_linestyle->max_length = linestyle->max_length; - new_linestyle->chain_count = linestyle->chain_count; - new_linestyle->split_dash1 = linestyle->split_dash1; - new_linestyle->split_gap1 = linestyle->split_gap1; - new_linestyle->split_dash2 = linestyle->split_dash2; - new_linestyle->split_gap2 = linestyle->split_gap2; - new_linestyle->split_dash3 = linestyle->split_dash3; - new_linestyle->split_gap3 = linestyle->split_gap3; - new_linestyle->dash1 = linestyle->dash1; - new_linestyle->gap1 = linestyle->gap1; - new_linestyle->dash2 = linestyle->dash2; - new_linestyle->gap2 = linestyle->gap2; - new_linestyle->dash3 = linestyle->dash3; - new_linestyle->gap3 = linestyle->gap3; - new_linestyle->panel = linestyle->panel; - new_linestyle->sort_key = linestyle->sort_key; - new_linestyle->integration_type = linestyle->integration_type; - new_linestyle->texstep = linestyle->texstep; - new_linestyle->pr_texture = linestyle->pr_texture; - new_linestyle->use_nodes = linestyle->use_nodes; - for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) - BKE_linestyle_color_modifier_copy(new_linestyle, m); - for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next) - BKE_linestyle_alpha_modifier_copy(new_linestyle, m); - for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next) - BKE_linestyle_thickness_modifier_copy(new_linestyle, m); - for (m = (LineStyleModifier *)linestyle->geometry_modifiers.first; m; m = m->next) - BKE_linestyle_geometry_modifier_copy(new_linestyle, m); - - BKE_id_copy_ensure_local(bmain, &linestyle->id, &new_linestyle->id); - - return new_linestyle; + LineStyleModifier *m; + BLI_listbase_clear(&linestyle_dst->color_modifiers); + for (m = (LineStyleModifier *)linestyle_src->color_modifiers.first; m; m = m->next) { + BKE_linestyle_color_modifier_copy(linestyle_dst, m, flag_subdata); + } + BLI_listbase_clear(&linestyle_dst->alpha_modifiers); + for (m = (LineStyleModifier *)linestyle_src->alpha_modifiers.first; m; m = m->next) { + BKE_linestyle_alpha_modifier_copy(linestyle_dst, m, flag_subdata); + } + BLI_listbase_clear(&linestyle_dst->thickness_modifiers); + for (m = (LineStyleModifier *)linestyle_src->thickness_modifiers.first; m; m = m->next) { + BKE_linestyle_thickness_modifier_copy(linestyle_dst, m, flag_subdata); + } + BLI_listbase_clear(&linestyle_dst->geometry_modifiers); + for (m = (LineStyleModifier *)linestyle_src->geometry_modifiers.first; m; m = m->next) { + BKE_linestyle_geometry_modifier_copy(linestyle_dst, m, flag_subdata); + } +} + +FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, const FreestyleLineStyle *linestyle) +{ + FreestyleLineStyle *linestyle_copy; + BKE_id_copy_ex(bmain, &linestyle->id, (ID **)&linestyle_copy, 0, false); + return linestyle_copy; } void BKE_linestyle_make_local(struct Main *bmain, FreestyleLineStyle *linestyle, const bool lib_local) @@ -355,7 +336,8 @@ LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyl return m; } -LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m) +LineStyleModifier *BKE_linestyle_color_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag) { LineStyleModifier *new_m; @@ -388,9 +370,10 @@ LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linesty { LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)m; LineStyleColorModifier_DistanceFromObject *q = (LineStyleColorModifier_DistanceFromObject *)new_m; - if (p->target) - id_us_plus(&p->target->id); q->target = p->target; + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)q->target); + } q->color_ramp = MEM_dupallocN(p->color_ramp); q->range_min = p->range_min; q->range_max = p->range_max; @@ -594,7 +577,8 @@ LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyl return m; } -LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m) +LineStyleModifier *BKE_linestyle_alpha_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int UNUSED(flag)) { LineStyleModifier *new_m; @@ -863,7 +847,8 @@ LineStyleModifier *BKE_linestyle_thickness_modifier_add(FreestyleLineStyle *line return m; } -LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m) +LineStyleModifier *BKE_linestyle_thickness_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag) { LineStyleModifier *new_m; @@ -901,9 +886,10 @@ LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *lin { LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)m; LineStyleThicknessModifier_DistanceFromObject *q = (LineStyleThicknessModifier_DistanceFromObject *)new_m; - if (p->target) - id_us_plus(&p->target->id); q->target = p->target; + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)q->target); + } q->curve = curvemapping_copy(p->curve); q->flags = p->flags; q->range_min = p->range_min; @@ -1195,7 +1181,8 @@ LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *lines return m; } -LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m) +LineStyleModifier *BKE_linestyle_geometry_modifier_copy( + FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int UNUSED(flag)) { LineStyleModifier *new_m; diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index ae27e9bcd34..8b8b48db279 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -51,6 +51,7 @@ #include "BKE_animsys.h" #include "BKE_curve.h" +#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" @@ -794,7 +795,7 @@ static Mask *mask_alloc(Main *bmain, const char *name) { Mask *mask; - mask = BKE_libblock_alloc(bmain, ID_MSK, name); + mask = BKE_libblock_alloc(bmain, ID_MSK, name, 0); id_fake_user_set(&mask->id); @@ -817,10 +818,13 @@ Mask *BKE_mask_new(Main *bmain, const char *name) mask->sfra = 1; mask->efra = 100; + DAG_relations_tag_update(bmain); + return mask; } /* TODO(sergey): Use generic BKE_libblock_copy_nolib() instead. */ +/* TODO(bastien): Use new super cool & generic BKE_id_copy_ex() instead! */ Mask *BKE_mask_copy_nolib(Mask *mask) { Mask *mask_new; @@ -840,22 +844,29 @@ Mask *BKE_mask_copy_nolib(Mask *mask) return mask_new; } -Mask *BKE_mask_copy(Main *bmain, const Mask *mask) +/** + * Only copy internal data of Mask ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_mask_copy_data(Main *UNUSED(bmain), Mask *mask_dst, const Mask *mask_src, const int UNUSED(flag)) { - Mask *mask_new; + BLI_listbase_clear(&mask_dst->masklayers); - mask_new = BKE_libblock_copy(bmain, &mask->id); - - BLI_listbase_clear(&mask_new->masklayers); - - BKE_mask_layer_copy_list(&mask_new->masklayers, &mask->masklayers); + BKE_mask_layer_copy_list(&mask_dst->masklayers, &mask_src->masklayers); /* TODO add unused flag to those as well. */ /* enable fake user by default */ - id_fake_user_set(&mask_new->id); - - BKE_id_copy_ensure_local(bmain, &mask->id, &mask_new->id); + id_fake_user_set(&mask_dst->id); +} - return mask_new; +Mask *BKE_mask_copy(Main *bmain, const Mask *mask) +{ + Mask *mask_copy; + BKE_id_copy_ex(bmain, &mask->id, (ID **)&mask_copy, 0, false); + return mask_copy; } void BKE_mask_make_local(Main *bmain, Mask *mask, const bool lib_local) @@ -1171,17 +1182,6 @@ void BKE_mask_point_parent_matrix_get(MaskSplinePoint *point, float ctime, float } } -static void mask_evaluate_apply_point_parent(MaskSplinePoint *point, float ctime) -{ - float parent_matrix[3][3]; - - BKE_mask_point_parent_matrix_get(point, ctime, parent_matrix); - - mul_m3_v2(parent_matrix, point->bezt.vec[0]); - mul_m3_v2(parent_matrix, point->bezt.vec[1]); - mul_m3_v2(parent_matrix, point->bezt.vec[2]); -} - static void mask_calc_point_handle(MaskSplinePoint *point, MaskSplinePoint *point_prev, MaskSplinePoint *point_next) { BezTriple *bezt = &point->bezt; @@ -1397,80 +1397,12 @@ void BKE_mask_spline_ensure_deform(MaskSpline *spline) void BKE_mask_layer_evaluate(MaskLayer *masklay, const float ctime, const bool do_newframe) { - /* animation if available */ + /* Animation if available. */ if (do_newframe) { - MaskLayerShape *masklay_shape_a; - MaskLayerShape *masklay_shape_b; - int found; - - if ((found = BKE_mask_layer_shape_find_frame_range(masklay, ctime, - &masklay_shape_a, &masklay_shape_b))) - { - if (found == 1) { -#if 0 - printf("%s: exact %d %d (%d)\n", __func__, (int)ctime, BLI_listbase_count(&masklay->splines_shapes), - masklay_shape_a->frame); -#endif - - BKE_mask_layer_shape_to_mask(masklay, masklay_shape_a); - } - else if (found == 2) { - float w = masklay_shape_b->frame - masklay_shape_a->frame; -#if 0 - printf("%s: tween %d %d (%d %d)\n", __func__, (int)ctime, BLI_listbase_count(&masklay->splines_shapes), - masklay_shape_a->frame, masklay_shape_b->frame); -#endif - BKE_mask_layer_shape_to_mask_interp(masklay, masklay_shape_a, masklay_shape_b, - (ctime - masklay_shape_a->frame) / w); - } - else { - /* always fail, should never happen */ - BLI_assert(found == 2); - } - } - } - /* animation done... */ - - BKE_mask_layer_calc_handles(masklay); - - /* update deform */ - { - MaskSpline *spline; - - for (spline = masklay->splines.first; spline; spline = spline->next) { - int i; - bool need_handle_recalc = false; - - BKE_mask_spline_ensure_deform(spline); - - for (i = 0; i < spline->tot_point; i++) { - MaskSplinePoint *point = &spline->points[i]; - MaskSplinePoint *point_deform = &spline->points_deform[i]; - - BKE_mask_point_free(point_deform); - - *point_deform = *point; - point_deform->uw = point->uw ? MEM_dupallocN(point->uw) : NULL; - - mask_evaluate_apply_point_parent(point_deform, ctime); - - if (ELEM(point->bezt.h1, HD_AUTO, HD_VECT)) { - need_handle_recalc = true; - } - } - - /* if the spline has auto or vector handles, these need to be recalculated after deformation */ - if (need_handle_recalc) { - for (i = 0; i < spline->tot_point; i++) { - MaskSplinePoint *point_deform = &spline->points_deform[i]; - if (ELEM(point_deform->bezt.h1, HD_AUTO, HD_VECT)) { - BKE_mask_calc_handle_point(spline, point_deform); - } - } - } - /* end extra calc handles loop */ - } + BKE_mask_layer_evaluate_animation(masklay, ctime); } + /* Update deform. */ + BKE_mask_layer_evaluate_deform(masklay, ctime); } void BKE_mask_evaluate(Mask *mask, const float ctime, const bool do_newframe) diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c index 1b275f455f4..0d71cc548c7 100644 --- a/source/blender/blenkernel/intern/mask_evaluate.c +++ b/source/blender/blenkernel/intern/mask_evaluate.c @@ -42,6 +42,8 @@ #include "DNA_mask_types.h" #include "BKE_curve.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" #include "BKE_mask.h" @@ -810,3 +812,111 @@ float *BKE_mask_point_segment_diff(MaskSpline *spline, MaskSplinePoint *point, return diff_points; } + +static void mask_evaluate_apply_point_parent(MaskSplinePoint *point, float ctime) +{ + float parent_matrix[3][3]; + BKE_mask_point_parent_matrix_get(point, ctime, parent_matrix); + mul_m3_v2(parent_matrix, point->bezt.vec[0]); + mul_m3_v2(parent_matrix, point->bezt.vec[1]); + mul_m3_v2(parent_matrix, point->bezt.vec[2]); +} + +void BKE_mask_layer_evaluate_animation(MaskLayer *masklay, const float ctime) +{ + /* animation if available */ + MaskLayerShape *masklay_shape_a; + MaskLayerShape *masklay_shape_b; + int found; + if ((found = BKE_mask_layer_shape_find_frame_range( + masklay, ctime, &masklay_shape_a, &masklay_shape_b))) + { + if (found == 1) { +#if 0 + printf("%s: exact %d %d (%d)\n", + __func__, + (int)ctime, + BLI_listbase_count(&masklay->splines_shapes), + masklay_shape_a->frame); +#endif + BKE_mask_layer_shape_to_mask(masklay, masklay_shape_a); + } + else if (found == 2) { + float w = masklay_shape_b->frame - masklay_shape_a->frame; +#if 0 + printf("%s: tween %d %d (%d %d)\n", + __func__, + (int)ctime, + BLI_listbase_count(&masklay->splines_shapes), + masklay_shape_a->frame, masklay_shape_b->frame); +#endif + BKE_mask_layer_shape_to_mask_interp( + masklay, + masklay_shape_a, masklay_shape_b, + (ctime - masklay_shape_a->frame) / w); + } + else { + /* always fail, should never happen */ + BLI_assert(found == 2); + } + } +} + +void BKE_mask_layer_evaluate_deform(MaskLayer *masklay, const float ctime) +{ + BKE_mask_layer_calc_handles(masklay); + for (MaskSpline *spline = masklay->splines.first; + spline != NULL; + spline = spline->next) + { + bool need_handle_recalc = false; + BKE_mask_spline_ensure_deform(spline); + for (int i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &spline->points[i]; + MaskSplinePoint *point_deform = &spline->points_deform[i]; + BKE_mask_point_free(point_deform); + *point_deform = *point; + point_deform->uw = point->uw ? MEM_dupallocN(point->uw) : NULL; + mask_evaluate_apply_point_parent(point_deform, ctime); + if (ELEM(point->bezt.h1, HD_AUTO, HD_VECT)) { + need_handle_recalc = true; + } + } + /* if the spline has auto or vector handles, these need to be + * recalculated after deformation. + */ + if (need_handle_recalc) { + for (int i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point_deform = &spline->points_deform[i]; + if (ELEM(point_deform->bezt.h1, HD_AUTO, HD_VECT)) { + BKE_mask_calc_handle_point(spline, point_deform); + } + } + } + /* end extra calc handles loop */ + } +} + +#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf + +void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask) +{ + DEBUG_PRINT("%s on %s (%p)\n", __func__, mask->id.name, mask); + for (MaskLayer *mask_layer = mask->masklayers.first; + mask_layer != NULL; + mask_layer = mask_layer->next) + { + BKE_mask_layer_evaluate_animation(mask_layer, eval_ctx->ctime); + } +} + +void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, Mask *mask) +{ + DEBUG_PRINT("%s on %s (%p)\n", __func__, mask->id.name, mask); + for (MaskLayer *mask_layer = mask->masklayers.first; + mask_layer != NULL; + mask_layer = mask_layer->next) + { + BKE_mask_layer_evaluate_deform(mask_layer, eval_ctx->ctime); + } +} diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index f21efb71180..f5be72c6b4d 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -212,50 +212,68 @@ Material *BKE_material_add(Main *bmain, const char *name) { Material *ma; - ma = BKE_libblock_alloc(bmain, ID_MA, name); + ma = BKE_libblock_alloc(bmain, ID_MA, name, 0); BKE_material_init(ma); return ma; } -/* XXX keep synced with next function */ -Material *BKE_material_copy(Main *bmain, const Material *ma) +/** + * Only copy internal data of Material ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_src, const int flag) { - Material *man; - int a; - - man = BKE_libblock_copy(bmain, &ma->id); - - id_lib_extern((ID *)man->group); - - for (a = 0; a < MAX_MTEX; a++) { - if (ma->mtex[a]) { - man->mtex[a] = MEM_mallocN(sizeof(MTex), "copymaterial"); - memcpy(man->mtex[a], ma->mtex[a], sizeof(MTex)); - id_us_plus((ID *)man->mtex[a]->tex); + for (int a = 0; a < MAX_MTEX; a++) { + if (ma_src->mtex[a]) { + ma_dst->mtex[a] = MEM_mallocN(sizeof(*ma_dst->mtex[a]), __func__); + *ma_dst->mtex[a] = *ma_src->mtex[a]; } } - - if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col); - if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec); - - if (ma->nodetree) { - man->nodetree = ntreeCopyTree(bmain, ma->nodetree); + + if (ma_src->ramp_col) { + ma_dst->ramp_col = MEM_dupallocN(ma_src->ramp_col); + } + if (ma_src->ramp_spec) { + ma_dst->ramp_spec = MEM_dupallocN(ma_src->ramp_spec); } - BKE_previewimg_id_copy(&man->id, &ma->id); + if (ma_src->nodetree) { + BKE_id_copy_ex(bmain, (ID *)ma_src->nodetree, (ID **)&ma_dst->nodetree, flag, false); + } - BLI_listbase_clear(&man->gpumaterial); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { + BKE_previewimg_id_copy(&ma_dst->id, &ma_src->id); + } + else { + ma_dst->preview = NULL; + } - BKE_id_copy_ensure_local(bmain, &ma->id, &man->id); + BLI_listbase_clear(&ma_dst->gpumaterial); +} - return man; +Material *BKE_material_copy(Main *bmain, const Material *ma) +{ + Material *ma_copy; + BKE_id_copy_ex(bmain, &ma->id, (ID **)&ma_copy, 0, false); + return ma_copy; } /* XXX (see above) material copy without adding to main dbase */ Material *localize_material(Material *ma) { + /* TODO replace with something like + * Material *ma_copy; + * BKE_id_copy_ex(bmain, &ma->id, (ID **)&ma_copy, LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT, false); + * return ma_copy; + * + * ... Once f*** nodes are fully converted to that too :( */ + Material *man; int a; @@ -343,6 +361,8 @@ Material ***give_matarar_id(ID *id) return &(((Curve *)id)->mat); case ID_MB: return &(((MetaBall *)id)->mat); + default: + break; } return NULL; } @@ -359,6 +379,8 @@ short *give_totcolp_id(ID *id) return &(((Curve *)id)->totcol); case ID_MB: return &(((MetaBall *)id)->totcol); + default: + break; } return NULL; } @@ -378,6 +400,8 @@ static void material_data_index_remove_id(ID *id, short index) case ID_MB: /* meta-elems don't have materials atm */ break; + default: + break; } } @@ -396,6 +420,8 @@ static void material_data_index_clear_id(ID *id) case ID_MB: /* meta-elems don't have materials atm */ break; + default: + break; } } diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index b80579014d6..dfc49c996b1 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -96,33 +96,36 @@ MetaBall *BKE_mball_add(Main *bmain, const char *name) { MetaBall *mb; - mb = BKE_libblock_alloc(bmain, ID_MB, name); + mb = BKE_libblock_alloc(bmain, ID_MB, name, 0); BKE_mball_init(mb); return mb; } -MetaBall *BKE_mball_copy(Main *bmain, const MetaBall *mb) +/** + * Only copy internal data of MetaBall ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_mball_copy_data(Main *UNUSED(bmain), MetaBall *mb_dst, const MetaBall *mb_src, const int UNUSED(flag)) { - MetaBall *mbn; - int a; - - mbn = BKE_libblock_copy(bmain, &mb->id); + BLI_duplicatelist(&mb_dst->elems, &mb_src->elems); - BLI_duplicatelist(&mbn->elems, &mb->elems); - - mbn->mat = MEM_dupallocN(mb->mat); - for (a = 0; a < mbn->totcol; a++) { - id_us_plus((ID *)mbn->mat[a]); - } + mb_dst->mat = MEM_dupallocN(mb_src->mat); - mbn->editelems = NULL; - mbn->lastelem = NULL; - - BKE_id_copy_ensure_local(bmain, &mb->id, &mbn->id); + mb_dst->editelems = NULL; + mb_dst->lastelem = NULL; +} - return mbn; +MetaBall *BKE_mball_copy(Main *bmain, const MetaBall *mb) +{ + MetaBall *mb_copy; + BKE_id_copy_ex(bmain, &mb->id, (ID **)&mb_copy, 0, false); + return mb_copy; } void BKE_mball_make_local(Main *bmain, MetaBall *mb, const bool lib_local) @@ -470,7 +473,7 @@ bool BKE_mball_center_bounds(MetaBall *mb, float r_cent[3]) return false; } -void BKE_mball_transform(MetaBall *mb, float mat[4][4]) +void BKE_mball_transform(MetaBall *mb, float mat[4][4], const bool do_props) { MetaElem *me; float quat[4]; @@ -482,14 +485,17 @@ void BKE_mball_transform(MetaBall *mb, float mat[4][4]) for (me = mb->elems.first; me; me = me->next) { mul_m4_v3(mat, &me->x); mul_qt_qtqt(me->quat, quat, me->quat); - me->rad *= scale; - /* hrmf, probably elems shouldn't be - * treating scale differently - campbell */ - if (!MB_TYPE_SIZE_SQUARED(me->type)) { - mul_v3_fl(&me->expx, scale); - } - else { - mul_v3_fl(&me->expx, scale_sqrt); + + if (do_props) { + me->rad *= scale; + /* hrmf, probably elems shouldn't be + * treating scale differently - campbell */ + if (!MB_TYPE_SIZE_SQUARED(me->type)) { + mul_v3_fl(&me->expx, scale); + } + else { + mul_v3_fl(&me->expx, scale_sqrt); + } } } } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 6233caa43fa..0d01fe77453 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -494,53 +494,56 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name) { Mesh *me; - me = BKE_libblock_alloc(bmain, ID_ME, name); + me = BKE_libblock_alloc(bmain, ID_ME, name, 0); BKE_mesh_init(me); return me; } -Mesh *BKE_mesh_copy(Main *bmain, const Mesh *me) +/** + * Only copy internal data of Mesh ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int flag) { - Mesh *men; - int a; - const int do_tessface = ((me->totface != 0) && (me->totpoly == 0)); /* only do tessface if we have no polys */ - - men = BKE_libblock_copy(bmain, &me->id); - - men->mat = MEM_dupallocN(me->mat); - for (a = 0; a < men->totcol; a++) { - id_us_plus((ID *)men->mat[a]); - } - id_us_plus((ID *)men->texcomesh); + const bool do_tessface = ((me_src->totface != 0) && (me_src->totpoly == 0)); /* only do tessface if we have no polys */ + + me_dst->mat = MEM_dupallocN(me_src->mat); - CustomData_copy(&me->vdata, &men->vdata, CD_MASK_MESH, CD_DUPLICATE, men->totvert); - CustomData_copy(&me->edata, &men->edata, CD_MASK_MESH, CD_DUPLICATE, men->totedge); - CustomData_copy(&me->ldata, &men->ldata, CD_MASK_MESH, CD_DUPLICATE, men->totloop); - CustomData_copy(&me->pdata, &men->pdata, CD_MASK_MESH, CD_DUPLICATE, men->totpoly); + CustomData_copy(&me_src->vdata, &me_dst->vdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totvert); + CustomData_copy(&me_src->edata, &me_dst->edata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totedge); + CustomData_copy(&me_src->ldata, &me_dst->ldata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totloop); + CustomData_copy(&me_src->pdata, &me_dst->pdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totpoly); if (do_tessface) { - CustomData_copy(&me->fdata, &men->fdata, CD_MASK_MESH, CD_DUPLICATE, men->totface); + CustomData_copy(&me_src->fdata, &me_dst->fdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totface); } else { - mesh_tessface_clear_intern(men, false); + mesh_tessface_clear_intern(me_dst, false); } - BKE_mesh_update_customdata_pointers(men, do_tessface); + BKE_mesh_update_customdata_pointers(me_dst, do_tessface); - men->edit_btmesh = NULL; + me_dst->edit_btmesh = NULL; - men->mselect = MEM_dupallocN(men->mselect); - men->bb = MEM_dupallocN(men->bb); + me_dst->mselect = MEM_dupallocN(me_dst->mselect); + me_dst->bb = MEM_dupallocN(me_dst->bb); - if (me->key) { - men->key = BKE_key_copy(bmain, me->key); - men->key->from = (ID *)men; + /* TODO Do we want to add flag to prevent this? */ + if (me_src->key) { + BKE_id_copy_ex(bmain, &me_src->key->id, (ID **)&me_dst->key, flag, false); } +} - BKE_id_copy_ensure_local(bmain, &me->id, &men->id); - - return men; +Mesh *BKE_mesh_copy(Main *bmain, const Mesh *me) +{ + Mesh *me_copy; + BKE_id_copy_ex(bmain, &me->id, (ID **)&me_copy, 0, false); + return me_copy; } BMesh *BKE_mesh_to_bmesh( @@ -2056,6 +2059,12 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type) (me->mselect[me->totselect - 1].type == type)); } +/** + * Compute 'split' (aka loop, or per face corner's) normals. + * + * \param r_lnors_spacearr Allows to get computed loop normal space array. That data, among other things, + * contains 'smooth fan' info, useful e.g. to split geometry along sharp edges... + */ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr) { float (*r_loopnors)[3]; @@ -2063,6 +2072,11 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac short (*clnors)[2] = NULL; bool free_polynors = false; + /* Note that we enforce computing clnors when the clnor space array is requested by caller here. + * However, we obviously only use the autosmooth angle threshold only in case autosmooth is enabled. */ + const bool use_split_normals = (r_lnors_spacearr != NULL) || ((mesh->flag & ME_AUTOSMOOTH) != 0); + const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI; + if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop); @@ -2091,7 +2105,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac BKE_mesh_normals_loop_split( mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge, mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly, - (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, r_lnors_spacearr, clnors, NULL); + use_split_normals, split_angle, r_lnors_spacearr, clnors, NULL); if (free_polynors) { MEM_freeN(polynors); @@ -2123,118 +2137,70 @@ typedef struct SplitFaceNewEdge { /* Detect needed new vertices, and update accordingly loops' vertex indices. * WARNING! Leaves mesh in invalid state. */ static int split_faces_prepare_new_verts( - const Mesh *mesh, MLoopNorSpaceArray *lnors_spacearr, SplitFaceNewVert **new_verts, MemArena *memarena, - bool *r_need_vnors_recalc) + const Mesh *mesh, MLoopNorSpaceArray *lnors_spacearr, SplitFaceNewVert **new_verts, MemArena *memarena) { - /* Note: if lnors_spacearr is NULL, ther is no autosmooth handling, and we only split out flat polys. */ + /* This is now mandatory, trying to do the job in simple way without that data is doomed to fail, even when only + * dealing with smooth/flat faces one can find cases that no simple algorithm can handle properly. */ + BLI_assert(lnors_spacearr != NULL); + const int num_loops = mesh->totloop; int num_verts = mesh->totvert; MVert *mvert = mesh->mvert; MLoop *mloop = mesh->mloop; BLI_bitmap *verts_used = BLI_BITMAP_NEW(num_verts, __func__); + BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__); - if (lnors_spacearr) { - BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__); - - MLoop *ml = mloop; - MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr; - for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) { - if (!BLI_BITMAP_TEST(done_loops, loop_idx)) { - const int vert_idx = ml->v; - const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx); - /* If vert is already used by another smooth fan, we need a new vert for this one. */ - const int new_vert_idx = vert_used ? num_verts++ : vert_idx; - - BLI_assert(*lnor_space); - - if ((*lnor_space)->loops) { - for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) { - const int ml_fan_idx = GET_INT_FROM_POINTER(lnode->link); - BLI_BITMAP_ENABLE(done_loops, ml_fan_idx); - if (vert_used) { - mloop[ml_fan_idx].v = new_vert_idx; - } - } - } - else { - /* Single loop in this fan... */ - BLI_BITMAP_ENABLE(done_loops, loop_idx); + MLoop *ml = mloop; + MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr; + + for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) { + if (!BLI_BITMAP_TEST(done_loops, loop_idx)) { + const int vert_idx = ml->v; + const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx); + /* If vert is already used by another smooth fan, we need a new vert for this one. */ + const int new_vert_idx = vert_used ? num_verts++ : vert_idx; + + BLI_assert(*lnor_space); + + if ((*lnor_space)->loops) { + for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) { + const int ml_fan_idx = GET_INT_FROM_POINTER(lnode->link); + BLI_BITMAP_ENABLE(done_loops, ml_fan_idx); if (vert_used) { - ml->v = new_vert_idx; + mloop[ml_fan_idx].v = new_vert_idx; } } - - if (!vert_used) { - BLI_BITMAP_ENABLE(verts_used, vert_idx); - /* We need to update that vertex's normal here, we won't go over it again. */ - /* This is important! *DO NOT* set vnor to final computed lnor, vnor should always be defined to - * 'automatic normal' value computed from its polys, not some custom normal. - * Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */ - normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor); - } - else { - /* Add new vert to list. */ - SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert)); - new_vert->orig_index = vert_idx; - new_vert->new_index = new_vert_idx; - new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */ - new_vert->next = *new_verts; - *new_verts = new_vert; - } } - } - - MEM_freeN(done_loops); - } - else { - /* No loop normal spaces available, we only split out flat polys. */ - const int num_polys = mesh->totpoly; - const MPoly *mpoly = mesh->mpoly; - - /* We do that in two loops, to keep original edges/verts to smooth polys preferencially. */ - const MPoly *mp = mpoly; - for (int i = 0; i < num_polys; i++, mp++) { - if (mp->flag & ME_SMOOTH) { - const MLoop *ml = &mloop[mp->loopstart]; - for (int j = 0; j < mp->totloop; j++, ml++) { - /* Just mark the vertex as used/reserved, that way neighbor flat polys, if any, - * will have to create their own. */ - BLI_BITMAP_ENABLE(verts_used, ml->v); + else { + /* Single loop in this fan... */ + BLI_BITMAP_ENABLE(done_loops, loop_idx); + if (vert_used) { + ml->v = new_vert_idx; } } - } - mp = mpoly; - for (int i = 0; i < num_polys; i++, mp++) { - if (!(mp->flag & ME_SMOOTH)) { - MLoop *ml = &mloop[mp->loopstart]; - for (int j = 0; j < mp->totloop; j++, ml++) { - const int vert_idx = ml->v; - - if (BLI_BITMAP_TEST(verts_used, vert_idx)) { - /* Add new vert to list. */ - const int new_vert_idx = num_verts++; - ml->v = new_vert_idx; - - SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert)); - new_vert->orig_index = vert_idx; - new_vert->new_index = new_vert_idx; - new_vert->vnor = NULL; /* See note below about normals. */ - new_vert->next = *new_verts; - *new_verts = new_vert; - } - else { - BLI_BITMAP_ENABLE(verts_used, vert_idx); - } - } - /* Note: there is no way to get new normals for smooth vertices here (and we don't have direct access - * to poly normals either for flat ones), so we'll have to recompute all vnors at the end... */ - *r_need_vnors_recalc = true; + if (!vert_used) { + BLI_BITMAP_ENABLE(verts_used, vert_idx); + /* We need to update that vertex's normal here, we won't go over it again. */ + /* This is important! *DO NOT* set vnor to final computed lnor, vnor should always be defined to + * 'automatic normal' value computed from its polys, not some custom normal. + * Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */ + normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor); + } + else { + /* Add new vert to list. */ + SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert)); + new_vert->orig_index = vert_idx; + new_vert->new_index = new_vert_idx; + new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */ + new_vert->next = *new_verts; + *new_verts = new_vert; } } } + MEM_freeN(done_loops); MEM_freeN(verts_used); return num_verts - mesh->totvert; @@ -2353,27 +2319,17 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) } BKE_mesh_tessface_clear(mesh); - MLoopNorSpaceArray *lnors_spacearr = NULL; - MemArena *memarena; - bool need_vnors_recalc = false; - - if (mesh->flag & ME_AUTOSMOOTH) { - lnors_spacearr = MEM_callocN(sizeof(*lnors_spacearr), __func__); - /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */ - BKE_mesh_calc_normals_split_ex(mesh, lnors_spacearr); - /* Stealing memarena from loop normals space array. */ - memarena = lnors_spacearr->mem; - } - else { - /* We still have to split out flat faces... */ - memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - } + MLoopNorSpaceArray lnors_spacearr = {NULL}; + /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */ + BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr); + /* Stealing memarena from loop normals space array. */ + MemArena *memarena = lnors_spacearr.mem; SplitFaceNewVert *new_verts = NULL; SplitFaceNewEdge *new_edges = NULL; /* Detect loop normal spaces (a.k.a. smooth fans) that will need a new vert. */ - const int num_new_verts = split_faces_prepare_new_verts(mesh, lnors_spacearr, &new_verts, memarena, &need_vnors_recalc); + const int num_new_verts = split_faces_prepare_new_verts(mesh, &lnors_spacearr, &new_verts, memarena); if (num_new_verts > 0) { /* Reminder: beyond this point, there is no way out, mesh is in invalid state (due to early-reassignment of @@ -2385,9 +2341,9 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) /* Reallocate all vert and edge related data. */ mesh->totvert += num_new_verts; - mesh->totedge += num_new_edges; CustomData_realloc(&mesh->vdata, mesh->totvert); if (do_edges) { + mesh->totedge += num_new_edges; CustomData_realloc(&mesh->edata, mesh->totedge); } /* Update pointers to a newly allocated memory. */ @@ -2407,18 +2363,9 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop); } - if (lnors_spacearr) { - /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */ - BKE_lnor_spacearr_free(lnors_spacearr); - MEM_freeN(lnors_spacearr); - } - else { - BLI_memarena_free(memarena); - } + /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */ + BKE_lnor_spacearr_free(&lnors_spacearr); - if (need_vnors_recalc) { - BKE_mesh_calc_normals(mesh); - } #ifdef VALIDATE_MESH BKE_mesh_validate(mesh, true, true); #endif @@ -2447,7 +2394,9 @@ Mesh *BKE_mesh_new_from_object( int uv_from_orco; /* copies object and modifiers (but not the data) */ - Object *tmpobj = BKE_object_copy_ex(bmain, ob, true); + Object *tmpobj; + /* TODO: make it temp copy outside bmain! */ + BKE_id_copy_ex(bmain, &ob->id, (ID **)&tmpobj, LIB_ID_COPY_CACHES, false); tmpcu = (Curve *)tmpobj->data; id_us_min(&tmpcu->id); diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 5dfcef9f9bf..643ca3ee536 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -2002,11 +2002,14 @@ float BKE_mesh_calc_poly_area( * - http://forums.cgsociety.org/archive/index.php?t-756235.html * - http://www.globalspec.com/reference/52702/203279/4-8-the-centroid-of-a-tetrahedron * - * \note volume is 6x actual volume, and centroid is 4x actual volume-weighted centroid - * (so division can be done once at the end) - * \note results will have bias if polygon is non-planar. + * \note + * - Volume is 6x actual volume, and centroid is 4x actual volume-weighted centroid + * (so division can be done once at the end). + * - Results will have bias if polygon is non-planar. + * - The resulting volume will only be correct if the mesh is manifold and has consistent face winding + * (non-contiguous face normals or holes in the mesh surface). */ -static float mesh_calc_poly_volume_and_weighted_centroid( +static float mesh_calc_poly_volume_centroid( const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray, float r_cent[3]) { @@ -2043,6 +2046,43 @@ static float mesh_calc_poly_volume_and_weighted_centroid( return total_volume; } +/** + * \note + * - Results won't be correct if polygon is non-planar. + * - This has the advantage over #mesh_calc_poly_volume_centroid + * that it doesn't depend on solid geometry, instead it weights the surface by volume. + */ +static float mesh_calc_poly_area_centroid( + const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray, + float r_cent[3]) +{ + int i; + float tri_area; + float total_area = 0.0f; + float v1[3], v2[3], v3[3], normal[3], tri_cent[3]; + + BKE_mesh_calc_poly_normal(mpoly, loopstart, mvarray, normal); + copy_v3_v3(v1, mvarray[loopstart[0].v].co); + copy_v3_v3(v2, mvarray[loopstart[1].v].co); + zero_v3(r_cent); + + for (i = 2; i < mpoly->totloop; i++) { + copy_v3_v3(v3, mvarray[loopstart[i].v].co); + + tri_area = area_tri_signed_v3(v1, v2, v3, normal); + total_area += tri_area; + + mid_v3_v3v3v3(tri_cent, v1, v2, v3); + madd_v3_v3fl(r_cent, tri_cent, tri_area); + + copy_v3_v3(v2, v3); + } + + mul_v3_fl(r_cent, 1.0f / total_area); + + return total_area; +} + #if 0 /* slow version of the function below */ void BKE_mesh_calc_poly_angles(MPoly *mpoly, MLoop *loopstart, MVert *mvarray, float angles[]) @@ -2157,7 +2197,40 @@ bool BKE_mesh_center_bounds(const Mesh *me, float r_cent[3]) return false; } -bool BKE_mesh_center_centroid(const Mesh *me, float r_cent[3]) +bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3]) +{ + int i = me->totpoly; + MPoly *mpoly; + float poly_area; + float total_area = 0.0f; + float poly_cent[3]; + + zero_v3(r_cent); + + /* calculate a weighted average of polygon centroids */ + for (mpoly = me->mpoly; i--; mpoly++) { + poly_area = mesh_calc_poly_area_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent); + + madd_v3_v3fl(r_cent, poly_cent, poly_area); + total_area += poly_area; + } + /* otherwise we get NAN for 0 polys */ + if (me->totpoly) { + mul_v3_fl(r_cent, 1.0f / total_area); + } + + /* zero area faces cause this, fallback to median */ + if (UNLIKELY(!is_finite_v3(r_cent))) { + return BKE_mesh_center_median(me, r_cent); + } + + return (me->totpoly != 0); +} + +/** + * \note Mesh must be manifold with consistent face-winding, see #mesh_calc_poly_volume_centroid for details. + */ +bool BKE_mesh_center_of_volume(const Mesh *me, float r_cent[3]) { int i = me->totpoly; MPoly *mpoly; @@ -2169,7 +2242,7 @@ bool BKE_mesh_center_centroid(const Mesh *me, float r_cent[3]) /* calculate a weighted average of polyhedron centroids */ for (mpoly = me->mpoly; i--; mpoly++) { - poly_volume = mesh_calc_poly_volume_and_weighted_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent); + poly_volume = mesh_calc_poly_volume_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent); /* poly_cent is already volume-weighted, so no need to multiply by the volume */ add_v3_v3(r_cent, poly_cent); @@ -2189,6 +2262,7 @@ bool BKE_mesh_center_centroid(const Mesh *me, float r_cent[3]) return (me->totpoly != 0); } + /** \} */ diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index c5fa9b15896..d2fe8f27f4a 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -1184,7 +1184,6 @@ void BKE_mesh_remap_calc_loops_from_dm( bool polys_allocated_src; MPoly *polys_src = DM_get_poly_array(dm_src, &polys_allocated_src); const int num_polys_src = dm_src->getNumPolys(dm_src); - bool looptri_allocated_src = false; const MLoopTri *looptri_src = NULL; int num_looptri_src = 0; @@ -1374,17 +1373,11 @@ void BKE_mesh_remap_calc_loops_from_dm( if (dirty_tess_flag) { dm_src->dirty &= ~dirty_tess_flag; } - DM_ensure_looptri(dm_src); if (dirty_tess_flag) { dm_src->dirty |= dirty_tess_flag; } - looptri_src = DM_get_looptri_array( - dm_src, - verts_src, - polys_src, num_polys_src, - loops_src, num_loops_src, - &looptri_allocated_src); + looptri_src = dm_src->getLoopTriArray(dm_src); num_looptri_src = dm_src->getNumLoopTri(dm_src); looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__); @@ -1403,7 +1396,7 @@ void BKE_mesh_remap_calc_loops_from_dm( &treedata[tindex], verts_src, verts_allocated_src, loops_src, loops_allocated_src, - looptri_src, num_looptri_src, looptri_allocated_src, + looptri_src, num_looptri_src, false, looptri_active, num_looptri_active, bvh_epsilon, 2, 6); if (verts_allocated_src) { verts_allocated_src = false; /* Only 'give' our verts once, to first tree! */ @@ -1411,9 +1404,6 @@ void BKE_mesh_remap_calc_loops_from_dm( if (loops_allocated_src) { loops_allocated_src = false; /* Only 'give' our loops once, to first tree! */ } - if (looptri_allocated_src) { - looptri_allocated_src = false; /* Only 'give' our looptri once, to first tree! */ - } } MEM_freeN(looptri_active); @@ -1928,9 +1918,6 @@ void BKE_mesh_remap_calc_loops_from_dm( if (polys_allocated_src) { MEM_freeN(polys_src); } - if (looptri_allocated_src) { - MEM_freeN((void *)looptri_src); - } if (vert_to_loop_map_src) { MEM_freeN(vert_to_loop_map_src); } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 2276d56b9c6..118bafa94d2 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -59,6 +59,8 @@ #include "BKE_appdir.h" #include "BKE_key.h" +#include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_multires.h" #include "BKE_DerivedMesh.h" @@ -269,14 +271,37 @@ void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst) memcpy(md_dst_data, md_src_data, (size_t)mti->structSize - data_size); } -void modifier_copyData(ModifierData *md, ModifierData *target) +static void modifier_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag) +{ + ID *id = *idpoin; + if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) { + id_us_plus(id); + } +} + +void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); target->mode = md->mode; - if (mti->copyData) + if (mti->copyData) { mti->copyData(md, target); + } + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + if (mti->foreachIDLink) { + mti->foreachIDLink(target, NULL, modifier_copy_data_id_us_cb, NULL); + } + else if (mti->foreachObjectLink) { + mti->foreachObjectLink(target, NULL, (ObjectWalkFunc)modifier_copy_data_id_us_cb, NULL); + } + } +} + +void modifier_copyData(ModifierData *md, ModifierData *target) +{ + modifier_copyData_ex(md, target, 0); } diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index dfa8742a295..16d597e25fa 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -588,7 +588,7 @@ static MovieClip *movieclip_alloc(Main *bmain, const char *name) { MovieClip *clip; - clip = BKE_libblock_alloc(bmain, ID_MC, name); + clip = BKE_libblock_alloc(bmain, ID_MC, name, 0); clip->aspx = clip->aspy = 1.0f; @@ -1488,25 +1488,33 @@ void BKE_movieclip_free(MovieClip *clip) BKE_animdata_free((ID *) clip, false); } -MovieClip *BKE_movieclip_copy(Main *bmain, const MovieClip *clip) +/** + * Only copy internal data of MovieClip ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_movieclip_copy_data(Main *UNUSED(bmain), MovieClip *clip_dst, const MovieClip *clip_src, const int flag) { - MovieClip *clip_new; - - clip_new = BKE_libblock_copy(bmain, &clip->id); + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; - clip_new->anim = NULL; - clip_new->cache = NULL; + clip_dst->anim = NULL; + clip_dst->cache = NULL; - BKE_tracking_copy(&clip_new->tracking, &clip->tracking); - clip_new->tracking_context = NULL; + BKE_tracking_copy(&clip_dst->tracking, &clip_src->tracking, flag_subdata); + clip_dst->tracking_context = NULL; - id_us_plus((ID *)clip_new->gpd); - - BKE_color_managed_colorspace_settings_copy(&clip_new->colorspace_settings, &clip->colorspace_settings); - - BKE_id_copy_ensure_local(bmain, &clip->id, &clip_new->id); + BKE_color_managed_colorspace_settings_copy(&clip_dst->colorspace_settings, &clip_src->colorspace_settings); +} - return clip_new; +MovieClip *BKE_movieclip_copy(Main *bmain, const MovieClip *clip) +{ + MovieClip *clip_copy; + BKE_id_copy_ex(bmain, &clip->id, (ID **)&clip_copy, 0, false); + return clip_copy; } void BKE_movieclip_make_local(Main *bmain, MovieClip *clip, const bool lib_local) diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 5acfe4a0aa4..54afe76ec07 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -902,80 +902,100 @@ bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type) return nodeAddNode(C, ntree, idname); } -static void node_socket_copy(bNodeSocket *dst, bNodeSocket *src) +static void node_socket_copy(bNodeSocket *sock_dst, bNodeSocket *sock_src, const int flag) { - src->new_sock = dst; - - if (src->prop) - dst->prop = IDP_CopyProperty(src->prop); - - if (src->default_value) - dst->default_value = MEM_dupallocN(src->default_value); - - dst->stack_index = 0; + sock_src->new_sock = sock_dst; + + if (sock_src->prop) { + sock_dst->prop = IDP_CopyProperty_ex(sock_src->prop, flag); + } + + if (sock_src->default_value) { + sock_dst->default_value = MEM_dupallocN(sock_src->default_value); + } + + sock_dst->stack_index = 0; /* XXX some compositor node (e.g. image, render layers) still store * some persistent buffer data here, need to clear this to avoid dangling pointers. */ - dst->cache = NULL; + sock_dst->cache = NULL; } /* keep socket listorder identical, for copying links */ /* ntree is the target tree */ -bNode *nodeCopyNode(bNodeTree *ntree, bNode *node) +bNode *BKE_node_copy_ex(bNodeTree *ntree, bNode *node_src, const int flag) { - bNode *nnode = MEM_callocN(sizeof(bNode), "dupli node"); - bNodeSocket *sock, *oldsock; - bNodeLink *link, *oldlink; + bNode *node_dst = MEM_callocN(sizeof(bNode), "dupli node"); + bNodeSocket *sock_dst, *sock_src; + bNodeLink *link_dst, *link_src; - *nnode = *node; + *node_dst = *node_src; /* can be called for nodes outside a node tree (e.g. clipboard) */ if (ntree) { - nodeUniqueName(ntree, nnode); + nodeUniqueName(ntree, node_dst); - BLI_addtail(&ntree->nodes, nnode); + BLI_addtail(&ntree->nodes, node_dst); } - BLI_duplicatelist(&nnode->inputs, &node->inputs); - oldsock = node->inputs.first; - for (sock = nnode->inputs.first; sock; sock = sock->next, oldsock = oldsock->next) - node_socket_copy(sock, oldsock); - - BLI_duplicatelist(&nnode->outputs, &node->outputs); - oldsock = node->outputs.first; - for (sock = nnode->outputs.first; sock; sock = sock->next, oldsock = oldsock->next) - node_socket_copy(sock, oldsock); - - if (node->prop) - nnode->prop = IDP_CopyProperty(node->prop); - - BLI_duplicatelist(&nnode->internal_links, &node->internal_links); - oldlink = node->internal_links.first; - for (link = nnode->internal_links.first; link; link = link->next, oldlink = oldlink->next) { - link->fromnode = nnode; - link->tonode = nnode; - link->fromsock = link->fromsock->new_sock; - link->tosock = link->tosock->new_sock; + BLI_duplicatelist(&node_dst->inputs, &node_src->inputs); + for (sock_dst = node_dst->inputs.first, sock_src = node_src->inputs.first; + sock_dst != NULL; + sock_dst = sock_dst->next, sock_src = sock_src->next) + { + node_socket_copy(sock_dst, sock_src, flag); } - - /* don't increase node->id users, freenode doesn't decrement either */ - - if (node->typeinfo->copyfunc) - node->typeinfo->copyfunc(ntree, nnode, node); - - node->new_node = nnode; - nnode->new_node = NULL; - - if (nnode->typeinfo->copyfunc_api) { + + BLI_duplicatelist(&node_dst->outputs, &node_src->outputs); + for (sock_dst = node_dst->outputs.first, sock_src = node_src->outputs.first; + sock_dst != NULL; + sock_dst = sock_dst->next, sock_src = sock_src->next) + { + node_socket_copy(sock_dst, sock_src, flag); + } + + if (node_src->prop) { + node_dst->prop = IDP_CopyProperty_ex(node_src->prop, flag); + } + + BLI_duplicatelist(&node_dst->internal_links, &node_src->internal_links); + for (link_dst = node_dst->internal_links.first, link_src = node_src->internal_links.first; + link_dst != NULL; + link_dst = link_dst->next, link_src = link_src->next) + { + link_dst->fromnode = node_dst; + link_dst->tonode = node_dst; + link_dst->fromsock = link_dst->fromsock->new_sock; + link_dst->tosock = link_dst->tosock->new_sock; + } + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus(node_dst->id); + } + + if (node_src->typeinfo->copyfunc) { + node_src->typeinfo->copyfunc(ntree, node_dst, node_src); + } + + node_src->new_node = node_dst; + node_dst->new_node = NULL; + + if (node_dst->typeinfo->copyfunc_api) { PointerRNA ptr; - RNA_pointer_create((ID *)ntree, &RNA_Node, nnode, &ptr); - - nnode->typeinfo->copyfunc_api(&ptr, node); + RNA_pointer_create((ID *)ntree, &RNA_Node, node_dst, &ptr); + + node_dst->typeinfo->copyfunc_api(&ptr, node_src); } - - if (ntree) + + if (ntree) { ntree->update |= NTREE_UPDATE_NODES; - - return nnode; + } + + return node_dst; +} + +bNode *nodeCopyNode(bNodeTree *ntree, bNode *node) +{ + return BKE_node_copy_ex(ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT); } /* also used via rna api, so we check for proper input output direction */ @@ -1172,7 +1192,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) * node groups and other tree types are created as library data. */ if (bmain) { - ntree = BKE_libblock_alloc(bmain, ID_NT, name); + ntree = BKE_libblock_alloc(bmain, ID_NT, name, 0); } else { ntree = MEM_callocN(sizeof(bNodeTree), "new node tree"); @@ -1191,119 +1211,96 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) return ntree; } -/* Warning: this function gets called during some rather unexpected times - * - this gets called when executing compositing updates (for threaded previews) - * - when the nodetree datablock needs to be copied (i.e. when users get copied) - * - for scene duplication use ntreeSwapID() after so we don't have stale pointers. +/** + * Only copy internal data of NodeTree ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! * - * do_make_extern: keep enabled for general use, only reason _not_ to enable is when - * copying for internal use (threads for eg), where you wont want it to modify the - * scene data. + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */ -static bNodeTree *ntreeCopyTree_internal( - const bNodeTree *ntree, Main *bmain, - bool skip_database, bool do_id_user, bool do_make_extern, bool copy_previews) +void BKE_node_tree_copy_data(Main *UNUSED(bmain), bNodeTree *ntree_dst, const bNodeTree *ntree_src, const int flag) { - bNodeTree *newtree; - bNode *node /*, *nnode */ /* UNUSED */, *last; - bNodeSocket *sock, *oldsock; - bNodeLink *link; - - if (ntree == NULL) return NULL; - - /* is ntree part of library? */ - if (bmain && !skip_database && BLI_findindex(&bmain->nodetree, ntree) >= 0) { - newtree = BKE_libblock_copy(bmain, &ntree->id); - } - else { - newtree = BKE_libblock_copy_nolib(&ntree->id, true); - } + bNodeSocket *sock_dst, *sock_src; + bNodeLink *link_dst; - id_us_plus((ID *)newtree->gpd); + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; /* in case a running nodetree is copied */ - newtree->execdata = NULL; - - newtree->duplilock = NULL; - - BLI_listbase_clear(&newtree->nodes); - BLI_listbase_clear(&newtree->links); - - last = ntree->nodes.last; - for (node = ntree->nodes.first; node; node = node->next) { + ntree_dst->execdata = NULL; - /* ntreeUserDecrefID inline */ - if (do_id_user) { - id_us_plus(node->id); - } + ntree_dst->duplilock = NULL; - if (do_make_extern) { - id_lib_extern(node->id); - } + BLI_listbase_clear(&ntree_dst->nodes); + BLI_listbase_clear(&ntree_dst->links); - node->new_node = NULL; - /* nnode = */ nodeCopyNode(newtree, node); /* sets node->new */ - - /* make sure we don't copy new nodes again! */ - if (node == last) - break; + for (bNode *node_src = ntree_src->nodes.first; node_src; node_src = node_src->next) { + BKE_node_copy_ex(ntree_dst, node_src, flag_subdata); } - + /* copy links */ - BLI_duplicatelist(&newtree->links, &ntree->links); - for (link = newtree->links.first; link; link = link->next) { - link->fromnode = (link->fromnode ? link->fromnode->new_node : NULL); - link->fromsock = (link->fromsock ? link->fromsock->new_sock : NULL); - link->tonode = (link->tonode ? link->tonode->new_node : NULL); - link->tosock = (link->tosock ? link->tosock->new_sock : NULL); + BLI_duplicatelist(&ntree_dst->links, &ntree_src->links); + for (link_dst = ntree_dst->links.first; link_dst; link_dst = link_dst->next) { + link_dst->fromnode = (link_dst->fromnode ? link_dst->fromnode->new_node : NULL); + link_dst->fromsock = (link_dst->fromsock ? link_dst->fromsock->new_sock : NULL); + link_dst->tonode = (link_dst->tonode ? link_dst->tonode->new_node : NULL); + link_dst->tosock = (link_dst->tosock ? link_dst->tosock->new_sock : NULL); /* update the link socket's pointer */ - if (link->tosock) - link->tosock->link = link; + if (link_dst->tosock) { + link_dst->tosock->link = link_dst; + } } - + /* copy interface sockets */ - BLI_duplicatelist(&newtree->inputs, &ntree->inputs); - oldsock = ntree->inputs.first; - for (sock = newtree->inputs.first; sock; sock = sock->next, oldsock = oldsock->next) - node_socket_copy(sock, oldsock); - - BLI_duplicatelist(&newtree->outputs, &ntree->outputs); - oldsock = ntree->outputs.first; - for (sock = newtree->outputs.first; sock; sock = sock->next, oldsock = oldsock->next) - node_socket_copy(sock, oldsock); - + BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs); + for (sock_dst = ntree_dst->inputs.first, sock_src = ntree_src->inputs.first; + sock_dst != NULL; + sock_dst = sock_dst->next, sock_src = sock_src->next) + { + node_socket_copy(sock_dst, sock_src, flag_subdata); + } + + BLI_duplicatelist(&ntree_dst->outputs, &ntree_src->outputs); + for (sock_dst = ntree_dst->outputs.first, sock_src = ntree_src->outputs.first; + sock_dst != NULL; + sock_dst = sock_dst->next, sock_src = sock_src->next) + { + node_socket_copy(sock_dst, sock_src, flag_subdata); + } + /* copy preview hash */ - if (ntree->previews && copy_previews) { + if (ntree_src->previews && (flag & LIB_ID_COPY_NO_PREVIEW) == 0) { bNodeInstanceHashIterator iter; - - newtree->previews = BKE_node_instance_hash_new("node previews"); - - NODE_INSTANCE_HASH_ITER(iter, ntree->previews) { + + ntree_dst->previews = BKE_node_instance_hash_new("node previews"); + + NODE_INSTANCE_HASH_ITER(iter, ntree_src->previews) { bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter); - BKE_node_instance_hash_insert(newtree->previews, key, BKE_node_preview_copy(preview)); + BKE_node_instance_hash_insert(ntree_dst->previews, key, BKE_node_preview_copy(preview)); } } - else - newtree->previews = NULL; - + else { + ntree_dst->previews = NULL; + } + /* update node->parent pointers */ - for (node = newtree->nodes.first; node; node = node->next) { - if (node->parent) - node->parent = node->parent->new_node; + for (bNode *node_dst = ntree_dst->nodes.first, *node_src = ntree_src->nodes.first; node_dst; node_dst = node_dst->next, node_src = node_src->next) { + if (node_dst->parent) { + node_dst->parent = node_dst->parent->new_node; + } } - - /* node tree will generate its own interface type */ - newtree->interface_type = NULL; - - BKE_id_copy_ensure_local(bmain, &ntree->id, &newtree->id); - return newtree; + /* node tree will generate its own interface type */ + ntree_dst->interface_type = NULL; } bNodeTree *ntreeCopyTree_ex(const bNodeTree *ntree, Main *bmain, const bool do_id_user) { - return ntreeCopyTree_internal(ntree, bmain, false, do_id_user, true, true); + bNodeTree *ntree_copy; + BKE_id_copy_ex(bmain, (ID *)ntree, (ID **)&ntree_copy, do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT, false); + return ntree_copy; } bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree) { @@ -1994,10 +1991,11 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree) adt->tmpact = NULL; } - /* Make full copy. + /* Make full copy outside of Main database. * Note: previews are not copied here. */ - ltree = ntreeCopyTree_internal(ntree, G.main, true, false, false, false); + BKE_id_copy_ex(G.main, (ID *)ntree, (ID **)<ree, + LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_COPY_NO_PREVIEW, false); ltree->flag |= NTREE_IS_LOCALIZED; for (node = ltree->nodes.first; node; node = node->next) { @@ -2237,7 +2235,7 @@ static void ntree_interface_type_create(bNodeTree *ntree) /* register a subtype of PropertyGroup */ srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_PropertyGroup); RNA_def_struct_ui_text(srna, name, description); - RNA_def_struct_duplicate_pointers(srna); + RNA_def_struct_duplicate_pointers(&BLENDER_RNA, srna); /* associate the RNA type with the node tree */ ntree->interface_type = srna; @@ -2276,10 +2274,10 @@ StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, int create) ntree_interface_identifier(ntree, base, identifier, sizeof(identifier), name, description); /* rename the RNA type */ - RNA_def_struct_free_pointers(srna); - RNA_def_struct_identifier(srna, identifier); + RNA_def_struct_free_pointers(&BLENDER_RNA, srna); + RNA_def_struct_identifier(&BLENDER_RNA, srna, identifier); RNA_def_struct_ui_text(srna, name, description); - RNA_def_struct_duplicate_pointers(srna); + RNA_def_struct_duplicate_pointers(&BLENDER_RNA, srna); } } else if (create) { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index f3086396c3a..44058c989ff 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -312,7 +312,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr modifier_unique_name(&ob_dst->modifiers, nmd); } - BKE_object_copy_particlesystems(ob_dst, ob_src); + BKE_object_copy_particlesystems(ob_dst, ob_src, 0); /* TODO: smoke?, cloth? */ } @@ -330,14 +330,14 @@ void BKE_object_free_derived_caches(Object *ob) Mesh *me = ob->data; if (me && me->bb) { - atomic_fetch_and_or_uint32((uint*)&me->bb->flag, BOUNDBOX_DIRTY); + atomic_fetch_and_or_uint32((uint *)&me->bb->flag, BOUNDBOX_DIRTY); } } else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { Curve *cu = ob->data; if (cu && cu->bb) { - atomic_fetch_and_or_uint32((uint*)&cu->bb->flag, BOUNDBOX_DIRTY); + atomic_fetch_and_or_uint32((uint *)&cu->bb->flag, BOUNDBOX_DIRTY); } } @@ -670,7 +670,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) if (!name) name = get_obdata_defname(type); - ob = BKE_libblock_alloc(bmain, ID_OB, name); + ob = BKE_libblock_alloc(bmain, ID_OB, name, 0); /* default object vars */ ob->type = type; @@ -837,7 +837,7 @@ struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene) #endif /* WITH_GAMEENGINE */ -SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches) +SoftBody *copy_softbody(const SoftBody *sb, const int flag) { SoftBody *sbn; @@ -845,7 +845,7 @@ SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches) sbn = MEM_dupallocN(sb); - if (copy_caches == false) { + if ((flag & LIB_ID_COPY_CACHES) == 0) { sbn->totspring = sbn->totpoint = 0; sbn->bpoint = NULL; sbn->bspring = NULL; @@ -874,7 +874,7 @@ SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches) sbn->scratch = NULL; - sbn->pointcache = BKE_ptcache_copy_list(&sbn->ptcaches, &sb->ptcaches, copy_caches); + sbn->pointcache = BKE_ptcache_copy_list(&sbn->ptcaches, &sb->ptcaches, flag); if (sb->effector_weights) sbn->effector_weights = MEM_dupallocN(sb->effector_weights); @@ -882,7 +882,7 @@ SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches) return sbn; } -BulletSoftBody *copy_bulletsoftbody(const BulletSoftBody *bsb) +BulletSoftBody *copy_bulletsoftbody(const BulletSoftBody *bsb, const int UNUSED(flag)) { BulletSoftBody *bsbn; @@ -893,7 +893,7 @@ BulletSoftBody *copy_bulletsoftbody(const BulletSoftBody *bsb) return bsbn; } -ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys) +ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int flag) { ParticleSystem *psysn; ParticleData *pa; @@ -930,7 +930,7 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys) if (psys->clmd) { psysn->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth); - modifier_copyData((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd); + modifier_copyData_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag); psys->hair_in_dm = psys->hair_out_dm = NULL; } @@ -948,7 +948,8 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys) BLI_listbase_clear(&psysn->childcachebufs); psysn->renderdata = NULL; - psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, false); + /* XXX Never copy caches here? */ + psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag & ~LIB_ID_COPY_CACHES); /* XXX - from reading existing code this seems correct but intended usage of * pointcache should /w cloth should be added in 'ParticleSystem' - campbell */ @@ -956,12 +957,14 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys) psysn->clmd->point_cache = psysn->pointcache; } - id_us_plus((ID *)psysn->part); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)psysn->part); + } return psysn; } -void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src) +void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src, const int flag) { ParticleSystem *psys, *npsys; ModifierData *md; @@ -973,7 +976,7 @@ void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src) BLI_listbase_clear(&ob_dst->particlesystem); for (psys = ob_src->particlesystem.first; psys; psys = psys->next) { - npsys = BKE_object_copy_particlesystem(psys); + npsys = BKE_object_copy_particlesystem(psys, flag); BLI_addtail(&ob_dst->particlesystem, npsys); @@ -1010,23 +1013,25 @@ void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src) { if (ob_src->soft) { ob_dst->softflag = ob_src->softflag; - ob_dst->soft = copy_softbody(ob_src->soft, false); + ob_dst->soft = copy_softbody(ob_src->soft, 0); } } -static void copy_object_pose(Object *obn, const Object *ob) +static void copy_object_pose(Object *obn, const Object *ob, const int flag) { bPoseChannel *chan; /* note: need to clear obn->pose pointer first, so that BKE_pose_copy_data works (otherwise there's a crash) */ obn->pose = NULL; - BKE_pose_copy_data(&obn->pose, ob->pose, 1); /* 1 = copy constraints */ + BKE_pose_copy_data_ex(&obn->pose, ob->pose, flag, true); /* true = copy constraints */ for (chan = obn->pose->chanbase.first; chan; chan = chan->next) { bConstraint *con; chan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE); + /* XXX Remapping object pointing onto itself should be handled by generic BKE_library_remap stuff, but... + * the flush_constraint_targets callback am not sure about, so will delay that for now. */ for (con = chan->constraints.first; con; con = con->next) { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; @@ -1047,13 +1052,10 @@ static void copy_object_pose(Object *obn, const Object *ob) } } -static void copy_object_lod(Object *obn, const Object *ob) +static void copy_object_lod(Object *obn, const Object *ob, const int UNUSED(flag)) { BLI_duplicatelist(&obn->lodlevels, &ob->lodlevels); - if (obn->lodlevels.first) - ((LodLevel *)obn->lodlevels.first)->source = obn; - obn->currentlod = (LodLevel *)obn->lodlevels.first; } @@ -1098,98 +1100,99 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src) copy_v3_v3(ob_tar->size, ob_src->size); } -Object *BKE_object_copy_ex(Main *bmain, const Object *ob, bool copy_caches) +/** + * Only copy internal data of Object ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_src, const int flag) { - Object *obn; ModifierData *md; - int a; - obn = BKE_libblock_copy(bmain, &ob->id); - - if (ob->totcol) { - obn->mat = MEM_dupallocN(ob->mat); - obn->matbits = MEM_dupallocN(ob->matbits); - obn->totcol = ob->totcol; + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; + + if (ob_src->totcol) { + ob_dst->mat = MEM_dupallocN(ob_src->mat); + ob_dst->matbits = MEM_dupallocN(ob_src->matbits); + ob_dst->totcol = ob_src->totcol; } - if (ob->iuser) obn->iuser = MEM_dupallocN(ob->iuser); + if (ob_src->iuser) ob_dst->iuser = MEM_dupallocN(ob_src->iuser); - if (ob->bb) obn->bb = MEM_dupallocN(ob->bb); - obn->flag &= ~OB_FROMGROUP; + if (ob_src->bb) ob_dst->bb = MEM_dupallocN(ob_src->bb); + ob_dst->flag &= ~OB_FROMGROUP; - BLI_listbase_clear(&obn->modifiers); + BLI_listbase_clear(&ob_dst->modifiers); - for (md = ob->modifiers.first; md; md = md->next) { + for (md = ob_src->modifiers.first; md; md = md->next) { ModifierData *nmd = modifier_new(md->type); BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); - modifier_copyData(md, nmd); - BLI_addtail(&obn->modifiers, nmd); + modifier_copyData_ex(md, nmd, flag_subdata); + BLI_addtail(&ob_dst->modifiers, nmd); } - BLI_listbase_clear(&obn->prop); - BKE_bproperty_copy_list(&obn->prop, &ob->prop); + BLI_listbase_clear(&ob_dst->prop); + BKE_bproperty_copy_list(&ob_dst->prop, &ob_src->prop); - BKE_sca_logic_copy(obn, ob); + BKE_sca_logic_copy(ob_dst, ob_src, flag_subdata); - if (ob->pose) { - copy_object_pose(obn, ob); + if (ob_src->pose) { + copy_object_pose(ob_dst, ob_src, flag_subdata); /* backwards compat... non-armatures can get poses in older files? */ - if (ob->type == OB_ARMATURE) - BKE_pose_rebuild(obn, obn->data); + if (ob_src->type == OB_ARMATURE) + BKE_pose_rebuild(ob_dst, ob_dst->data); } - defgroup_copy_list(&obn->defbase, &ob->defbase); - BKE_constraints_copy(&obn->constraints, &ob->constraints, true); - - obn->mode = OB_MODE_OBJECT; - obn->sculpt = NULL; + defgroup_copy_list(&ob_dst->defbase, &ob_src->defbase); + BKE_constraints_copy_ex(&ob_dst->constraints, &ob_src->constraints, flag_subdata, true); - /* increase user numbers */ - id_us_plus((ID *)obn->data); - id_us_plus((ID *)obn->poselib); - id_us_plus((ID *)obn->gpd); - id_us_plus((ID *)obn->dup_group); + ob_dst->mode = OB_MODE_OBJECT; + ob_dst->sculpt = NULL; - for (a = 0; a < obn->totcol; a++) id_us_plus((ID *)obn->mat[a]); - - if (ob->pd) { - obn->pd = MEM_dupallocN(ob->pd); - if (obn->pd->tex) - id_us_plus(&(obn->pd->tex->id)); - if (obn->pd->rng) - obn->pd->rng = MEM_dupallocN(ob->pd->rng); + if (ob_src->pd) { + ob_dst->pd = MEM_dupallocN(ob_src->pd); + if (ob_dst->pd->rng) { + ob_dst->pd->rng = MEM_dupallocN(ob_src->pd->rng); + } } - obn->soft = copy_softbody(ob->soft, copy_caches); - obn->bsoft = copy_bulletsoftbody(ob->bsoft); - obn->rigidbody_object = BKE_rigidbody_copy_object(ob); - obn->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob); + ob_dst->soft = copy_softbody(ob_src->soft, flag_subdata); + ob_dst->bsoft = copy_bulletsoftbody(ob_src->bsoft, flag_subdata); + ob_dst->rigidbody_object = BKE_rigidbody_copy_object(ob_src, flag_subdata); + ob_dst->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob_src, flag_subdata); - BKE_object_copy_particlesystems(obn, ob); + BKE_object_copy_particlesystems(ob_dst, ob_src, flag_subdata); - obn->derivedDeform = NULL; - obn->derivedFinal = NULL; + ob_dst->derivedDeform = NULL; + ob_dst->derivedFinal = NULL; - BLI_listbase_clear(&obn->gpulamp); - BLI_listbase_clear(&obn->pc_ids); + BLI_listbase_clear(&ob_dst->gpulamp); + BLI_listbase_clear(&ob_dst->pc_ids); - obn->mpath = NULL; + ob_dst->mpath = NULL; - copy_object_lod(obn, ob); + copy_object_lod(ob_dst, ob_src, flag_subdata); - /* Copy runtime surve data. */ - obn->curve_cache = NULL; - - BKE_id_copy_ensure_local(bmain, &ob->id, &obn->id); + /* Do not copy runtime curve data. */ + ob_dst->curve_cache = NULL; /* Do not copy object's preview (mostly due to the fact renderers create temp copy of objects). */ - obn->preview = NULL; - - return obn; + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */ + BKE_previewimg_id_copy(&ob_dst->id, &ob_src->id); + } + else { + ob_dst->preview = NULL; + } } /* copy objects, will re-initialize cached simulation data */ Object *BKE_object_copy(Main *bmain, const Object *ob) { - return BKE_object_copy_ex(bmain, ob, false); + Object *ob_copy; + BKE_id_copy_ex(bmain, &ob->id, (ID **)&ob_copy, 0, false); + return ob_copy; } void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, const bool clear_proxy) @@ -1387,7 +1390,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) /* type conversions */ if (target->type == OB_ARMATURE) { - copy_object_pose(ob, target); /* data copy, object pointers in constraints */ + copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */ BKE_pose_rest(ob->pose); /* clear all transforms in channels */ BKE_pose_rebuild(ob, ob->data); /* set all internal links */ @@ -2679,7 +2682,7 @@ void BKE_object_sculpt_modifiers_changed(Object *ob) { SculptSession *ss = ob->sculpt; - if (ss) { + if (ss && ss->building_vp_handle == false) { if (!ss->cache) { /* we free pbvh on changes, except during sculpt since it can't deal with * changing PVBH node organization, we hope topology does not change in @@ -2690,6 +2693,9 @@ void BKE_object_sculpt_modifiers_changed(Object *ob) } BKE_sculptsession_free_deformMats(ob->sculpt); + + /* In vertex/weight paint, force maps to be rebuilt. */ + BKE_sculptsession_free_vwpaint_data(ob->sculpt); } else { PBVHNode **nodes; diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index ccf2aec5c7a..d387e30050c 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -481,6 +481,8 @@ bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_t *dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw; return true; } + default: + break; } } diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 076bef71875..b49e481b068 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -343,7 +343,7 @@ static void make_duplis_group(const DupliContext *ctx) } } -const DupliGenerator gen_dupli_group = { +static const DupliGenerator gen_dupli_group = { OB_DUPLIGROUP, /* type */ make_duplis_group /* make_duplis */ }; @@ -421,7 +421,7 @@ static void make_duplis_frames(const DupliContext *ctx) *ob = copyob; } -const DupliGenerator gen_dupli_frames = { +static const DupliGenerator gen_dupli_frames = { OB_DUPLIFRAMES, /* type */ make_duplis_frames /* make_duplis */ }; @@ -571,7 +571,7 @@ static void make_duplis_verts(const DupliContext *ctx) vdd.dm->release(vdd.dm); } -const DupliGenerator gen_dupli_verts = { +static const DupliGenerator gen_dupli_verts = { OB_DUPLIVERTS, /* type */ make_duplis_verts /* make_duplis */ }; @@ -684,7 +684,7 @@ static void make_duplis_font(const DupliContext *ctx) MEM_freeN(chartransdata); } -const DupliGenerator gen_dupli_verts_font = { +static const DupliGenerator gen_dupli_verts_font = { OB_DUPLIVERTS, /* type */ make_duplis_font /* make_duplis */ }; @@ -847,7 +847,7 @@ static void make_duplis_faces(const DupliContext *ctx) fdd.dm->release(fdd.dm); } -const DupliGenerator gen_dupli_faces = { +static const DupliGenerator gen_dupli_faces = { OB_DUPLIFACES, /* type */ make_duplis_faces /* make_duplis */ }; @@ -1168,7 +1168,7 @@ static void make_duplis_particles(const DupliContext *ctx) } } -const DupliGenerator gen_dupli_particles = { +static const DupliGenerator gen_dupli_particles = { OB_DUPLIPARTS, /* type */ make_duplis_particles /* make_duplis */ }; diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 64f90ef5c52..89f25136caf 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -522,6 +522,8 @@ static void unpack_generate_paths( case ID_IM: BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname); break; + default: + break; } { @@ -712,6 +714,8 @@ bool BKE_pack_check(ID *id) Library *li = (Library *)id; return li->packedfile != NULL; } + default: + break; } return false; } @@ -750,5 +754,7 @@ void BKE_unpack_id(Main *bmain, ID *id, ReportList *reports, int how) BKE_reportf(reports, RPT_ERROR, "Cannot unpack individual Library file, '%s'", li->name); break; } + default: + break; } } diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index c7cfe55f659..849fb5c6b5a 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -309,24 +309,31 @@ PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name) { PaintCurve *pc; - pc = BKE_libblock_alloc(bmain, ID_PC, name); + pc = BKE_libblock_alloc(bmain, ID_PC, name, 0); return pc; } -PaintCurve *BKE_paint_curve_copy(Main *bmain, const PaintCurve *pc) +/** + * Only copy internal data of PaintCurve ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_paint_curve_copy_data(Main *UNUSED(bmain), PaintCurve *pc_dst, const PaintCurve *pc_src, const int UNUSED(flag)) { - PaintCurve *pc_new; - - pc_new = BKE_libblock_copy(bmain, &pc->id); - - if (pc->tot_points != 0) { - pc_new->points = MEM_dupallocN(pc->points); + if (pc_src->tot_points != 0) { + pc_dst->points = MEM_dupallocN(pc_src->points); } +} - BKE_id_copy_ensure_local(bmain, &pc->id, &pc_new->id); - - return pc_new; +PaintCurve *BKE_paint_curve_copy(Main *bmain, const PaintCurve *pc) +{ + PaintCurve *pc_copy; + BKE_id_copy_ex(bmain, &pc->id, (ID **)&pc_copy, 0, false); + return pc_copy; } void BKE_paint_curve_make_local(Main *bmain, PaintCurve *pc, const bool lib_local) @@ -388,7 +395,7 @@ Palette *BKE_palette_add(Main *bmain, const char *name) { Palette *palette; - palette = BKE_libblock_alloc(bmain, ID_PAL, name); + palette = BKE_libblock_alloc(bmain, ID_PAL, name, 0); /* enable fake user by default */ id_fake_user_set(&palette->id); @@ -396,17 +403,24 @@ Palette *BKE_palette_add(Main *bmain, const char *name) return palette; } -Palette *BKE_palette_copy(Main *bmain, const Palette *palette) +/** + * Only copy internal data of Palette ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_palette_copy_data(Main *UNUSED(bmain), Palette *palette_dst, const Palette *palette_src, const int UNUSED(flag)) { - Palette *palette_new; - - palette_new = BKE_libblock_copy(bmain, &palette->id); - - BLI_duplicatelist(&palette_new->colors, &palette->colors); - - BKE_id_copy_ensure_local(bmain, &palette->id, &palette_new->id); + BLI_duplicatelist(&palette_dst->colors, &palette_src->colors); +} - return palette_new; +Palette *BKE_palette_copy(Main *bmain, const Palette *palette) +{ + Palette *palette_copy; + BKE_id_copy_ex(bmain, &palette->id, (ID **)&palette_copy, 0, false); + return palette_copy; } void BKE_palette_make_local(Main *bmain, Palette *palette, const bool lib_local) @@ -452,7 +466,7 @@ bool BKE_paint_select_vert_test(Object *ob) (ob->type == OB_MESH) && (ob->data != NULL) && (((Mesh *)ob->data)->editflag & ME_EDIT_PAINT_VERT_SEL) && - (ob->mode & OB_MODE_WEIGHT_PAINT) + (ob->mode & OB_MODE_WEIGHT_PAINT || ob->mode & OB_MODE_VERTEX_PAINT) ); } @@ -537,12 +551,15 @@ void BKE_paint_free(Paint *paint) * still do a id_us_plus(), rather then if we were copying between 2 existing * scenes where a matching value should decrease the existing user count as * with paint_brush_set() */ -void BKE_paint_copy(Paint *src, Paint *tar) +void BKE_paint_copy(Paint *src, Paint *tar, const int flag) { tar->brush = src->brush; - id_us_plus((ID *)tar->brush); - id_us_plus((ID *)tar->palette); tar->cavity_curve = curvemapping_copy(src->cavity_curve); + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)tar->brush); + id_us_plus((ID *)tar->palette); + } } void BKE_paint_stroke_get_average(Scene *scene, Object *ob, float stroke[3]) @@ -656,6 +673,31 @@ void BKE_sculptsession_free_deformMats(SculptSession *ss) MEM_SAFE_FREE(ss->deform_imats); } +void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss) +{ + struct SculptVertexPaintGeomMap *gmap = NULL; + if (ss->mode_type == OB_MODE_VERTEX_PAINT) { + gmap = &ss->mode.vpaint.gmap; + + MEM_SAFE_FREE(ss->mode.vpaint.previous_color); + MEM_SAFE_FREE(ss->mode.vpaint.previous_accum); + } + else if (ss->mode_type == OB_MODE_WEIGHT_PAINT) { + gmap = &ss->mode.wpaint.gmap; + + MEM_SAFE_FREE(ss->mode.wpaint.alpha_weight); + MEM_SAFE_FREE(ss->mode.wpaint.previous_weight); + MEM_SAFE_FREE(ss->mode.wpaint.previous_accum); + } + else { + return; + } + MEM_SAFE_FREE(gmap->vert_to_loop); + MEM_SAFE_FREE(gmap->vert_map_mem); + MEM_SAFE_FREE(gmap->vert_to_poly); + MEM_SAFE_FREE(gmap->poly_map_mem); +} + /* Write out the sculpt dynamic-topology BMesh to the Mesh */ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder) { @@ -747,6 +789,8 @@ void BKE_sculptsession_free(Object *ob) if (ss->deform_imats) MEM_freeN(ss->deform_imats); + BKE_sculptsession_free_vwpaint_data(ob->sculpt); + MEM_freeN(ss); ob->sculpt = NULL; @@ -831,6 +875,8 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob); ss->show_diffuse_color = (sd->flags & SCULPT_SHOW_DIFFUSE) != 0; + ss->building_vp_handle = false; + if (need_mask) { if (mmd == NULL) { if (!CustomData_has_layer(&me->vdata, CD_PAINT_MASK)) { @@ -859,7 +905,8 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - if (mmd) { + /* VWPaint require mesh info for loop lookup, so require sculpt mode here */ + if (mmd && ob->mode & OB_MODE_SCULPT) { ss->multires = mmd; ss->totvert = dm->getNumVerts(dm); ss->totpoly = dm->getNumPolys(dm); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 416d63cfefb..8c94cdfe784 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3300,7 +3300,7 @@ ParticleSettings *psys_new_settings(const char *name, Main *main) if (main == NULL) main = G.main; - part = BKE_libblock_alloc(main, ID_PA, name); + part = BKE_libblock_alloc(main, ID_PA, name, 0); default_particle_settings(part); @@ -3331,38 +3331,45 @@ void BKE_particlesettings_rough_curve_init(ParticleSettings *part) part->roughcurve = cumap; } -ParticleSettings *BKE_particlesettings_copy(Main *bmain, const ParticleSettings *part) +/** + * Only copy internal data of ParticleSettings ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_particlesettings_copy_data( + Main *UNUSED(bmain), ParticleSettings *part_dst, const ParticleSettings *part_src, const int UNUSED(flag)) { - ParticleSettings *partn; - int a; + part_dst->pd = MEM_dupallocN(part_src->pd); + part_dst->pd2 = MEM_dupallocN(part_src->pd2); + part_dst->effector_weights = MEM_dupallocN(part_src->effector_weights); + part_dst->fluid = MEM_dupallocN(part_src->fluid); - partn = BKE_libblock_copy(bmain, &part->id); + if (part_src->clumpcurve) { + part_dst->clumpcurve = curvemapping_copy(part_src->clumpcurve); + } + if (part_src->roughcurve) { + part_dst->roughcurve = curvemapping_copy(part_src->roughcurve); + } - partn->pd = MEM_dupallocN(part->pd); - partn->pd2 = MEM_dupallocN(part->pd2); - partn->effector_weights = MEM_dupallocN(part->effector_weights); - partn->fluid = MEM_dupallocN(part->fluid); + part_dst->boids = boid_copy_settings(part_src->boids); - if (part->clumpcurve) - partn->clumpcurve = curvemapping_copy(part->clumpcurve); - if (part->roughcurve) - partn->roughcurve = curvemapping_copy(part->roughcurve); - - partn->boids = boid_copy_settings(part->boids); - - for (a = 0; a < MAX_MTEX; a++) { - if (part->mtex[a]) { - partn->mtex[a] = MEM_mallocN(sizeof(MTex), "psys_copy_tex"); - memcpy(partn->mtex[a], part->mtex[a], sizeof(MTex)); - id_us_plus((ID *)partn->mtex[a]->tex); + for (int a = 0; a < MAX_MTEX; a++) { + if (part_src->mtex[a]) { + part_dst->mtex[a] = MEM_dupallocN(part_src->mtex[a]); } } - BLI_duplicatelist(&partn->dupliweights, &part->dupliweights); - - BKE_id_copy_ensure_local(bmain, &part->id, &partn->id); + BLI_duplicatelist(&part_dst->dupliweights, &part_src->dupliweights); +} - return partn; +ParticleSettings *BKE_particlesettings_copy(Main *bmain, const ParticleSettings *part) +{ + ParticleSettings *part_copy; + BKE_id_copy_ex(bmain, &part->id, (ID **)&part_copy, 0, false); + return part_copy; } void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const bool lib_local) diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index 4f758bde7f9..9a7980827ad 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -39,6 +39,7 @@ #include "BLI_jitter.h" #include "BLI_kdtree.h" #include "BLI_math.h" +#include "BLI_math_geom.h" #include "BLI_rand.h" #include "BLI_sort.h" #include "BLI_task.h" @@ -213,14 +214,22 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys) copy_v3_v3(co2, co1); co2[a] += delta[a] + 0.001f*d; co1[a] -= 0.001f*d; - + + struct IsectRayPrecalc isect_precalc; + float ray_direction[3]; + sub_v3_v3v3(ray_direction, co2, co1); + isect_ray_tri_watertight_v3_precalc(&isect_precalc, ray_direction); + /* lets intersect the faces */ for (i=0; i<totface; i++,mface++) { copy_v3_v3(v1, mvert[mface->v1].co); copy_v3_v3(v2, mvert[mface->v2].co); copy_v3_v3(v3, mvert[mface->v3].co); - bool intersects_tri = isect_axial_line_segment_tri_v3(a, co1, co2, v2, v3, v1, &lambda); + bool intersects_tri = isect_ray_tri_watertight_v3(co1, + &isect_precalc, + v1, v2, v3, + &lambda, NULL); if (intersects_tri) { if (from==PART_FROM_FACE) (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST; @@ -231,7 +240,10 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys) if (mface->v4 && (!intersects_tri || from==PART_FROM_VOLUME)) { copy_v3_v3(v4, mvert[mface->v4].co); - if (isect_axial_line_segment_tri_v3(a, co1, co2, v4, v1, v3, &lambda)) { + if (isect_ray_tri_watertight_v3(co1, + &isect_precalc, + v1, v3, v4, + &lambda, NULL)) { if (from==PART_FROM_FACE) (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST; else @@ -429,7 +441,6 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i ParticleThreadContext *ctx= thread->ctx; MFace *mface; - DM_ensure_tessface(ctx->dm); mface = ctx->dm->getTessFaceDataArray(ctx->dm, CD_MFACE); int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */ @@ -899,10 +910,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti else dm= CDDM_from_mesh((Mesh*)ob->data); - /* BMESH ONLY, for verts we don't care about tessfaces */ - if (from != PART_FROM_VERT) { - DM_ensure_tessface(dm); - } + DM_ensure_tessface(dm); /* we need orco for consistent distributions */ if (!CustomData_has_layer(&dm->vertData, CD_ORCO)) @@ -1096,13 +1104,10 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti /* This is to address tricky issues with vertex-emitting when user tries (and expects) exact 1-1 vert/part * distribution (see T47983 and its two example files). It allows us to consider pos as * 'midpoint between v and v+1' (or 'p and p+1', depending whether we have more vertices than particles or not), - * and avoid stumbling over float imprecisions in element_sum. */ - if (from == PART_FROM_VERT) { - pos = (totpart < totmapped) ? 0.5 / (double)totmapped : step * 0.5; /* We choose the smaller step. */ - } - else { - pos = 0.0; - } + * and avoid stumbling over float imprecisions in element_sum. + * Note: moved face and volume distribution to this as well (instead of starting at zero), + * for the same reasons, see T52682. */ + pos = (totpart < totmapped) ? 0.5 / (double)totmapped : step * 0.5; /* We choose the smaller step. */ for (i = 0, p = 0; p < totpart; p++, pos += step) { for ( ; (i < totmapped - 1) && (pos > (double)element_sum[i]); i++); @@ -1141,7 +1146,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti if (jitlevel == 0) { jitlevel= totpart/totelem; - if (part->flag & PART_EDISTR) jitlevel*= 2; /* looks better in general, not very scietific */ + if (part->flag & PART_EDISTR) jitlevel*= 2; /* looks better in general, not very scientific */ if (jitlevel<3) jitlevel= 3; } diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 3f9a92a5577..38eb861599a 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -2319,21 +2319,21 @@ static void collision_point_on_surface(float p[3], ParticleCollisionElement *pce } case 3: { - float p0[3], e1[3], e2[3], nor[3]; + float p0[3], e1[3], e2[3], nor[3]; - sub_v3_v3v3(e1, pce->x1, pce->x0); - sub_v3_v3v3(e2, pce->x2, pce->x0); - sub_v3_v3v3(p0, p, pce->x0); + sub_v3_v3v3(e1, pce->x1, pce->x0); + sub_v3_v3v3(e2, pce->x2, pce->x0); + sub_v3_v3v3(p0, p, pce->x0); - cross_v3_v3v3(nor, e1, e2); - normalize_v3(nor); + cross_v3_v3v3(nor, e1, e2); + normalize_v3(nor); - if (pce->inv_nor == 1) - negate_v3(nor); + if (pce->inv_nor == 1) + negate_v3(nor); - madd_v3_v3v3fl(co, pce->x0, nor, col->radius); - madd_v3_v3fl(co, e1, pce->uv[0]); - madd_v3_v3fl(co, e2, pce->uv[1]); + madd_v3_v3v3fl(co, pce->x0, nor, col->radius); + madd_v3_v3fl(co, e1, pce->uv[0]); + madd_v3_v3fl(co, e2, pce->uv[1]); break; } } @@ -3042,10 +3042,12 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int /* calculate maximum segment length */ max_length = 0.0f; LOOP_PARTICLES { - for (k=1, key=pa->hair+1; k<pa->totkey; k++,key++) { - float length = len_v3v3(key->co, (key-1)->co); - if (max_length < length) - max_length = length; + if (!(pa->flag & PARS_UNEXIST)) { + for (k=1, key=pa->hair+1; k<pa->totkey; k++,key++) { + float length = len_v3v3(key->co, (key-1)->co); + if (max_length < length) + max_length = length; + } } } @@ -3057,76 +3059,78 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int /* make vgroup for pin roots etc.. */ hair_index = 1; LOOP_PARTICLES { - float root_mat[4][4]; - float bending_stiffness; - bool use_hair; - - pa->hair_index = hair_index; - use_hair = psys_hair_use_simulation(pa, max_length); - - psys_mat_hair_to_object(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat); - mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat); - normalize_m4(root_mat); - - bending_stiffness = CLAMPIS(1.0f - part->bending_random * psys_frand(psys, p + 666), 0.0f, 1.0f); - - for (k=0, key=pa->hair; k<pa->totkey; k++,key++) { - ClothHairData *hair; - float *co, *co_next; - - co = key->co; - co_next = (key+1)->co; - - /* create fake root before actual root to resist bending */ - if (k==0) { - hair = &psys->clmd->hairdata[pa->hair_index - 1]; + if (!(pa->flag & PARS_UNEXIST)) { + float root_mat[4][4]; + float bending_stiffness; + bool use_hair; + + pa->hair_index = hair_index; + use_hair = psys_hair_use_simulation(pa, max_length); + + psys_mat_hair_to_object(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat); + mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat); + normalize_m4(root_mat); + + bending_stiffness = CLAMPIS(1.0f - part->bending_random * psys_frand(psys, p + 666), 0.0f, 1.0f); + + for (k=0, key=pa->hair; k<pa->totkey; k++,key++) { + ClothHairData *hair; + float *co, *co_next; + + co = key->co; + co_next = (key+1)->co; + + /* create fake root before actual root to resist bending */ + if (k==0) { + hair = &psys->clmd->hairdata[pa->hair_index - 1]; + copy_v3_v3(hair->loc, root_mat[3]); + copy_m3_m4(hair->rot, root_mat); + + hair->radius = hair_radius; + hair->bending_stiffness = bending_stiffness; + + add_v3_v3v3(mvert->co, co, co); + sub_v3_v3(mvert->co, co_next); + mul_m4_v3(hairmat, mvert->co); + + medge->v1 = pa->hair_index - 1; + medge->v2 = pa->hair_index; + + dvert = hair_set_pinning(dvert, 1.0f); + + mvert++; + medge++; + } + + /* store root transform in cloth data */ + hair = &psys->clmd->hairdata[pa->hair_index + k]; copy_v3_v3(hair->loc, root_mat[3]); copy_m3_m4(hair->rot, root_mat); - + hair->radius = hair_radius; hair->bending_stiffness = bending_stiffness; - - add_v3_v3v3(mvert->co, co, co); - sub_v3_v3(mvert->co, co_next); + + copy_v3_v3(mvert->co, co); mul_m4_v3(hairmat, mvert->co); - - medge->v1 = pa->hair_index - 1; - medge->v2 = pa->hair_index; - - dvert = hair_set_pinning(dvert, 1.0f); - + + if (k) { + medge->v1 = pa->hair_index + k - 1; + medge->v2 = pa->hair_index + k; + } + + /* roots and disabled hairs should be 1.0, the rest can be anything from 0.0 to 1.0 */ + if (use_hair) + dvert = hair_set_pinning(dvert, key->weight); + else + dvert = hair_set_pinning(dvert, 1.0f); + mvert++; - medge++; + if (k) + medge++; } - - /* store root transform in cloth data */ - hair = &psys->clmd->hairdata[pa->hair_index + k]; - copy_v3_v3(hair->loc, root_mat[3]); - copy_m3_m4(hair->rot, root_mat); - - hair->radius = hair_radius; - hair->bending_stiffness = bending_stiffness; - - copy_v3_v3(mvert->co, co); - mul_m4_v3(hairmat, mvert->co); - - if (k) { - medge->v1 = pa->hair_index + k - 1; - medge->v2 = pa->hair_index + k; - } - - /* roots and disabled hairs should be 1.0, the rest can be anything from 0.0 to 1.0 */ - if (use_hair) - dvert = hair_set_pinning(dvert, key->weight); - else - dvert = hair_set_pinning(dvert, 1.0f); - - mvert++; - if (k) - medge++; + + hair_index += pa->totkey + 1; } - - hair_index += pa->totkey + 1; } } @@ -3152,9 +3156,11 @@ static void do_hair_dynamics(ParticleSimulationData *sim) totpoint = 0; totedge = 0; LOOP_PARTICLES { - /* "out" dm contains all hairs */ - totedge += pa->totkey; - totpoint += pa->totkey + 1; /* +1 for virtual root point */ + if (!(pa->flag & PARS_UNEXIST)) { + /* "out" dm contains all hairs */ + totedge += pa->totkey; + totpoint += pa->totkey + 1; /* +1 for virtual root point */ + } } realloc_roots = false; /* whether hair root info array has to be reallocated */ @@ -4350,13 +4356,12 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, /* **** Depsgraph evaluation **** */ -void BKE_particle_system_eval(EvaluationContext *UNUSED(eval_ctx), - Scene *scene, - Object *ob, - ParticleSystem *psys) +void BKE_particle_system_eval_init(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob) { if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s on %s:%s\n", __func__, ob->id.name, psys->name); + printf("%s on %s\n", __func__, ob->id.name); } BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH); } diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 53dfffe2b97..4b154d3301c 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -34,6 +34,7 @@ #include "BKE_pbvh.h" #include "BKE_ccg.h" +#include "BKE_subsurf.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_mesh.h" /* for BKE_mesh_calc_normals */ @@ -606,6 +607,10 @@ void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, MEM_freeN(prim_bbc); } +void BKE_pbvh_set_ccgdm(PBVH *bvh, CCGDerivedMesh *ccgdm) { + bvh->ccgdm = ccgdm; +} + PBVH *BKE_pbvh_new(void) { PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh"); @@ -1156,7 +1161,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) } } -static void pbvh_draw_BB(PBVH *bvh) +void BKE_pbvh_draw_BB(PBVH *bvh) { GPU_pbvh_BB_draw_init(); @@ -1329,6 +1334,11 @@ void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key) *key = bvh->gridkey; } +CCGDerivedMesh *BKE_pbvh_get_ccgdm(const PBVH *bvh) { + return bvh->ccgdm; +} + + BMesh *BKE_pbvh_get_bmesh(PBVH *bvh) { BLI_assert(bvh->type == PBVH_BMESH); @@ -1860,7 +1870,7 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3], } if (G.debug_value == 14) - pbvh_draw_BB(bvh); + BKE_pbvh_draw_BB(bvh); } void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces, diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index 19d3b31bd31..01057318568 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -149,6 +149,8 @@ struct PBVH { * objects in sculpt mode with different sizes at the same time, so now storing that common gpu buffer * in an opaque pointer per pbvh. See T47637. */ struct GridCommonGPUBuffer *grid_common_gpu_buffer; + /* The ccgdm is required for CD_ORIGINDEX lookup in vertex paint + multires */ + struct CCGDerivedMesh *ccgdm; /* Only used during BVH build and update, * don't need to remain valid after */ diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index a7e00a8103a..7a1b378b3c4 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -3449,7 +3449,7 @@ void BKE_ptcache_free_list(ListBase *ptcaches) } } -static PointCache *ptcache_copy(PointCache *cache, bool copy_data) +static PointCache *ptcache_copy(PointCache *cache, const bool copy_data) { PointCache *ncache; @@ -3492,14 +3492,15 @@ static PointCache *ptcache_copy(PointCache *cache, bool copy_data) } /* returns first point cache */ -PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcaches_old, bool copy_data) +PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcaches_old, const int flag) { PointCache *cache = ptcaches_old->first; BLI_listbase_clear(ptcaches_new); - for (; cache; cache=cache->next) - BLI_addtail(ptcaches_new, ptcache_copy(cache, copy_data)); + for (; cache; cache=cache->next) { + BLI_addtail(ptcaches_new, ptcache_copy(cache, (flag & LIB_ID_COPY_CACHES) != 0)); + } return ptcaches_new->first; } @@ -3618,7 +3619,13 @@ void BKE_ptcache_bake(PTCacheBaker *baker) psys_get_pointcache_start_end(scene, pid->calldata, &cache->startframe, &cache->endframe); } - if (((cache->flag & PTCACHE_BAKED) == 0) && (render || bake)) { + // XXX workaround for regression inroduced in ee3fadd, needs looking into + if (pid->type == PTCACHE_TYPE_RIGIDBODY) { + if ((cache->flag & PTCACHE_REDO_NEEDED || (cache->flag & PTCACHE_SIMULATION_VALID)==0) && (render || bake)) { + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); + } + } + else if (((cache->flag & PTCACHE_BAKED) == 0) && (render || bake)) { BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); } diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index e8c0cf53d0b..03eb83376e7 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -184,7 +184,7 @@ void BKE_rigidbody_free_constraint(Object *ob) * be added to relevant groups later... */ -RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob) +RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int UNUSED(flag)) { RigidBodyOb *rboN = NULL; @@ -204,7 +204,7 @@ RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob) return rboN; } -RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob) +RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int UNUSED(flag)) { RigidBodyCon *rbcN = NULL; @@ -291,8 +291,6 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob) if (dm == NULL) return NULL; - DM_ensure_looptri(dm); - mvert = dm->getVertArray(dm); totvert = dm->getNumVerts(dm); looptri = dm->getLoopTriArray(dm); @@ -524,8 +522,6 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) if (dm == NULL) return; - DM_ensure_looptri(dm); - mvert = dm->getVertArray(dm); totvert = dm->getNumVerts(dm); lt = dm->getLoopTriArray(dm); @@ -609,8 +605,6 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) if (dm == NULL) return; - DM_ensure_looptri(dm); - mvert = dm->getVertArray(dm); totvert = dm->getNumVerts(dm); looptri = dm->getLoopTriArray(dm); @@ -945,24 +939,26 @@ RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) return rbw; } -RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw) +RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag) { - RigidBodyWorld *rbwn = MEM_dupallocN(rbw); + RigidBodyWorld *rbw_copy = MEM_dupallocN(rbw); - if (rbw->effector_weights) - rbwn->effector_weights = MEM_dupallocN(rbw->effector_weights); - if (rbwn->group) - id_us_plus(&rbwn->group->id); - if (rbwn->constraints) - id_us_plus(&rbwn->constraints->id); + if (rbw->effector_weights) { + rbw_copy->effector_weights = MEM_dupallocN(rbw->effector_weights); + } + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)rbw_copy->group); + id_us_plus((ID *)rbw_copy->constraints); + } - rbwn->pointcache = BKE_ptcache_copy_list(&rbwn->ptcaches, &rbw->ptcaches, false); + /* XXX Never copy caches here? */ + rbw_copy->pointcache = BKE_ptcache_copy_list(&rbw_copy->ptcaches, &rbw->ptcaches, flag & ~LIB_ID_COPY_CACHES); - rbwn->objects = NULL; - rbwn->physics_world = NULL; - rbwn->numbodies = 0; + rbw_copy->objects = NULL; + rbw_copy->physics_world = NULL; + rbw_copy->numbodies = 0; - return rbwn; + return rbw_copy; } void BKE_rigidbody_world_groups_relink(RigidBodyWorld *rbw) @@ -1600,8 +1596,12 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL); cache = rbw->pointcache; + if (ctime <= startframe) { + rbw->ltime = startframe; + return; + } /* make sure we don't go out of cache frame range */ - if (ctime > endframe) { + else if (ctime > endframe) { ctime = endframe; } @@ -1615,12 +1615,9 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) // RB_TODO deal with interpolated, old and baked results bool can_simulate = (ctime == rbw->ltime + 1) && !(cache->flag & PTCACHE_BAKED); - if (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0) { - rbw->ltime = cache->startframe; - } - - if (BKE_ptcache_read(&pid, ctime, can_simulate)) { + if (BKE_ptcache_read(&pid, ctime, can_simulate) == PTCACHE_READ_EXACT) { BKE_ptcache_validate(cache, (int)ctime); + rbw->ltime = ctime; return; } @@ -1658,13 +1655,13 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) # pragma GCC diagnostic ignored "-Wunused-parameter" #endif -struct RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob) { return NULL; } -struct RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob) { return NULL; } +struct RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int flag) { return NULL; } +struct RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int flag) { return NULL; } void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild) {} void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) { if (r_vol) *r_vol = 0.0f; } void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) { zero_v3(r_center); } struct RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) { return NULL; } -struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw) { return NULL; } +struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag) { return NULL; } void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw) {} void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata) {} struct RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) { return NULL; } diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index 19d646daf9f..fb81ed4d47f 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -72,7 +72,7 @@ void free_sensors(ListBase *lb) } } -bSensor *copy_sensor(bSensor *sens) +bSensor *copy_sensor(bSensor *sens, const int UNUSED(flag)) { bSensor *sensn; @@ -87,14 +87,14 @@ bSensor *copy_sensor(bSensor *sens) return sensn; } -void copy_sensors(ListBase *lbn, const ListBase *lbo) +void copy_sensors(ListBase *lbn, const ListBase *lbo, const int flag) { bSensor *sens, *sensn; lbn->first= lbn->last= NULL; sens= lbo->first; while (sens) { - sensn= copy_sensor(sens); + sensn= copy_sensor(sens, flag); BLI_addtail(lbn, sensn); sens= sens->next; } @@ -234,7 +234,7 @@ void free_controllers(ListBase *lb) } } -bController *copy_controller(bController *cont) +bController *copy_controller(bController *cont, const int UNUSED(flag)) { bController *contn; @@ -251,14 +251,14 @@ bController *copy_controller(bController *cont) return contn; } -void copy_controllers(ListBase *lbn, const ListBase *lbo) +void copy_controllers(ListBase *lbn, const ListBase *lbo, const int flag) { bController *cont, *contn; lbn->first= lbn->last= NULL; cont= lbo->first; while (cont) { - contn= copy_controller(cont); + contn= copy_controller(cont, flag); BLI_addtail(lbn, contn); cont= cont->next; } @@ -359,7 +359,7 @@ void free_actuators(ListBase *lb) } } -bActuator *copy_actuator(bActuator *act) +bActuator *copy_actuator(bActuator *act, const int flag) { bActuator *actn; @@ -374,29 +374,31 @@ bActuator *copy_actuator(bActuator *act) case ACT_SHAPEACTION: { bActionActuator *aa = (bActionActuator *)act->data; - if (aa->act) + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { id_us_plus((ID *)aa->act); + } break; } case ACT_SOUND: { bSoundActuator *sa = (bSoundActuator *)act->data; - if (sa->sound) + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { id_us_plus((ID *)sa->sound); + } break; } } return actn; } -void copy_actuators(ListBase *lbn, const ListBase *lbo) +void copy_actuators(ListBase *lbn, const ListBase *lbo, const int flag) { bActuator *act, *actn; lbn->first= lbn->last= NULL; act= lbo->first; while (act) { - actn= copy_actuator(act); + actn= copy_actuator(act, flag); BLI_addtail(lbn, actn); act= act->next; } @@ -783,11 +785,11 @@ void BKE_sca_logic_links_remap(Main *bmain, Object *ob_old, Object *ob_new) * Handle the copying of logic data into a new object, including internal logic links update. * External links (links between logic bricks of different objects) must be handled separately. */ -void BKE_sca_logic_copy(Object *ob_new, const Object *ob) +void BKE_sca_logic_copy(Object *ob_new, const Object *ob, const int flag) { - copy_sensors(&ob_new->sensors, &ob->sensors); - copy_controllers(&ob_new->controllers, &ob->controllers); - copy_actuators(&ob_new->actuators, &ob->actuators); + copy_sensors(&ob_new->sensors, &ob->sensors, flag); + copy_controllers(&ob_new->controllers, &ob->controllers, flag); + copy_actuators(&ob_new->actuators, &ob->actuators, flag); for (bSensor *sens = ob_new->sensors.first; sens; sens = sens->next) { if (sens->flag & SENS_NEW) { diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index a15f270a3ee..c0dcac33656 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -125,17 +125,6 @@ void free_avicodecdata(AviCodecData *acd) } } -void free_qtcodecdata(QuicktimeCodecData *qcd) -{ - if (qcd) { - if (qcd->cdParms) { - MEM_freeN(qcd->cdParms); - qcd->cdParms = NULL; - qcd->cdSize = 0; - } - } -} - static void remove_sequencer_fcurves(Scene *sce) { AnimData *adt = BKE_animdata_from_id(&sce->id); @@ -154,223 +143,292 @@ static void remove_sequencer_fcurves(Scene *sce) } } -Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) -{ - Scene *scen; - SceneRenderLayer *srl, *new_srl; - FreestyleLineSet *lineset; - ToolSettings *ts; - Base *base, *obase; - - if (type == SCE_COPY_EMPTY) { - ListBase rl, rv; - scen = BKE_scene_add(bmain, sce->id.name + 2); - - rl = scen->r.layers; - rv = scen->r.views; - curvemapping_free_data(&scen->r.mblur_shutter_curve); - scen->r = sce->r; - scen->r.layers = rl; - scen->r.actlay = 0; - scen->r.views = rv; - scen->unit = sce->unit; - scen->physics_settings = sce->physics_settings; - scen->gm = sce->gm; - scen->audio = sce->audio; - - if (sce->id.properties) - scen->id.properties = IDP_CopyProperty(sce->id.properties); - - MEM_freeN(scen->toolsettings); - BKE_sound_destroy_scene(scen); - } - else { - scen = BKE_libblock_copy(bmain, &sce->id); - BLI_duplicatelist(&(scen->base), &(sce->base)); - - if (type != SCE_COPY_FULL) { - id_us_plus((ID *)scen->world); - } - id_us_plus((ID *)scen->set); - /* id_us_plus((ID *)scen->gm.dome.warptext); */ /* XXX Not refcounted? see readfile.c */ - - scen->ed = NULL; - scen->theDag = NULL; - scen->depsgraph = NULL; - scen->obedit = NULL; - scen->stats = NULL; - scen->fps_info = NULL; - - if (sce->rigidbody_world) - scen->rigidbody_world = BKE_rigidbody_world_copy(sce->rigidbody_world); - - BLI_duplicatelist(&(scen->markers), &(sce->markers)); - BLI_duplicatelist(&(scen->transform_spaces), &(sce->transform_spaces)); - BLI_duplicatelist(&(scen->r.layers), &(sce->r.layers)); - BLI_duplicatelist(&(scen->r.views), &(sce->r.views)); - BKE_keyingsets_copy(&(scen->keyingsets), &(sce->keyingsets)); - - if (sce->nodetree) { - /* ID's are managed on both copy and switch */ - scen->nodetree = ntreeCopyTree(bmain, sce->nodetree); - BKE_libblock_relink_ex(bmain, scen->nodetree, &sce->id, &scen->id, false); +/** + * Only copy internal data of Scene ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, const int flag) +{ + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; + + sce_dst->ed = NULL; + sce_dst->theDag = NULL; + sce_dst->depsgraph = NULL; + sce_dst->obedit = NULL; + sce_dst->stats = NULL; + sce_dst->fps_info = NULL; + + BLI_duplicatelist(&(sce_dst->base), &(sce_src->base)); + for (Base *base_dst = sce_dst->base.first, *base_src = sce_src->base.first; + base_dst; + base_dst = base_dst->next, base_src = base_src->next) + { + if (base_src == sce_src->basact) { + sce_dst->basact = base_dst; } + } - obase = sce->base.first; - base = scen->base.first; - while (base) { - id_us_plus(&base->object->id); - if (obase == sce->basact) scen->basact = base; - - obase = obase->next; - base = base->next; - } + BLI_duplicatelist(&(sce_dst->markers), &(sce_src->markers)); + BLI_duplicatelist(&(sce_dst->transform_spaces), &(sce_src->transform_spaces)); + BLI_duplicatelist(&(sce_dst->r.layers), &(sce_src->r.layers)); + BLI_duplicatelist(&(sce_dst->r.views), &(sce_src->r.views)); + BKE_keyingsets_copy(&(sce_dst->keyingsets), &(sce_src->keyingsets)); - /* copy action and remove animation used by sequencer */ - BKE_animdata_copy_id_action(&scen->id, false); + if (sce_src->nodetree) { + BKE_id_copy_ex(bmain, (ID *)sce_src->nodetree, (ID **)&sce_dst->nodetree, flag, false); + BKE_libblock_relink_ex(bmain, sce_dst->nodetree, (void *)(&sce_src->id), &sce_dst->id, false); + } - if (type != SCE_COPY_FULL) - remove_sequencer_fcurves(scen); + if (sce_src->rigidbody_world) { + sce_dst->rigidbody_world = BKE_rigidbody_world_copy(sce_src->rigidbody_world, flag_subdata); + } - /* copy Freestyle settings */ - new_srl = scen->r.layers.first; - for (srl = sce->r.layers.first; srl; srl = srl->next) { - if (new_srl->prop != NULL) { - new_srl->prop = IDP_CopyProperty(new_srl->prop); - } - BKE_freestyle_config_copy(&new_srl->freestyleConfig, &srl->freestyleConfig); - if (type == SCE_COPY_FULL) { - for (lineset = new_srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { - if (lineset->linestyle) { - /* Has been incremented by BKE_freestyle_config_copy(). */ - id_us_min(&lineset->linestyle->id); - lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle); - } - } - } - new_srl = new_srl->next; + /* copy Freestyle settings */ + for (SceneRenderLayer *srl_dst = sce_dst->r.layers.first, *srl_src = sce_src->r.layers.first; + srl_src; + srl_dst = srl_dst->next, srl_src = srl_src->next) + { + if (srl_dst->prop != NULL) { + srl_dst->prop = IDP_CopyProperty_ex(srl_dst->prop, flag_subdata); } + BKE_freestyle_config_copy(&srl_dst->freestyleConfig, &srl_src->freestyleConfig, flag_subdata); } /* copy color management settings */ - BKE_color_managed_display_settings_copy(&scen->display_settings, &sce->display_settings); - BKE_color_managed_view_settings_copy(&scen->view_settings, &sce->view_settings); - BKE_color_managed_colorspace_settings_copy(&scen->sequencer_colorspace_settings, &sce->sequencer_colorspace_settings); + BKE_color_managed_display_settings_copy(&sce_dst->display_settings, &sce_src->display_settings); + BKE_color_managed_view_settings_copy(&sce_dst->view_settings, &sce_src->view_settings); + BKE_color_managed_colorspace_settings_copy(&sce_dst->sequencer_colorspace_settings, &sce_src->sequencer_colorspace_settings); - BKE_color_managed_display_settings_copy(&scen->r.im_format.display_settings, &sce->r.im_format.display_settings); - BKE_color_managed_view_settings_copy(&scen->r.im_format.view_settings, &sce->r.im_format.view_settings); + BKE_color_managed_display_settings_copy(&sce_dst->r.im_format.display_settings, &sce_src->r.im_format.display_settings); + BKE_color_managed_view_settings_copy(&sce_dst->r.im_format.view_settings, &sce_src->r.im_format.view_settings); - BKE_color_managed_display_settings_copy(&scen->r.bake.im_format.display_settings, &sce->r.bake.im_format.display_settings); - BKE_color_managed_view_settings_copy(&scen->r.bake.im_format.view_settings, &sce->r.bake.im_format.view_settings); + BKE_color_managed_display_settings_copy(&sce_dst->r.bake.im_format.display_settings, &sce_src->r.bake.im_format.display_settings); + BKE_color_managed_view_settings_copy(&sce_dst->r.bake.im_format.view_settings, &sce_src->r.bake.im_format.view_settings); - curvemapping_copy_data(&scen->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve); + curvemapping_copy_data(&sce_dst->r.mblur_shutter_curve, &sce_src->r.mblur_shutter_curve); /* tool settings */ - scen->toolsettings = MEM_dupallocN(sce->toolsettings); - - ts = scen->toolsettings; - if (ts) { + if (sce_dst->toolsettings != NULL) { + ToolSettings *ts = sce_dst->toolsettings = MEM_dupallocN(sce_dst->toolsettings); if (ts->vpaint) { ts->vpaint = MEM_dupallocN(ts->vpaint); - ts->vpaint->paintcursor = NULL; - ts->vpaint->vpaint_prev = NULL; - ts->vpaint->wpaint_prev = NULL; - BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint); + BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, flag_subdata); } if (ts->wpaint) { ts->wpaint = MEM_dupallocN(ts->wpaint); - ts->wpaint->paintcursor = NULL; - ts->wpaint->vpaint_prev = NULL; - ts->wpaint->wpaint_prev = NULL; - BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint); + BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, flag_subdata); } if (ts->sculpt) { ts->sculpt = MEM_dupallocN(ts->sculpt); - BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint); + BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, flag_subdata); } if (ts->uvsculpt) { ts->uvsculpt = MEM_dupallocN(ts->uvsculpt); - BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint); + BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag_subdata); } - BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint); + BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag_subdata); ts->imapaint.paintcursor = NULL; - id_us_plus((ID *)ts->imapaint.stencil); - id_us_plus((ID *)ts->imapaint.clone); - id_us_plus((ID *)ts->imapaint.canvas); ts->particle.paintcursor = NULL; ts->particle.scene = NULL; ts->particle.object = NULL; - + /* duplicate Grease Pencil Drawing Brushes */ BLI_listbase_clear(&ts->gp_brushes); - for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) { + for (bGPDbrush *brush = sce_src->toolsettings->gp_brushes.first; brush; brush = brush->next) { bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush); BLI_addtail(&ts->gp_brushes, newbrush); } - + /* duplicate Grease Pencil interpolation curve */ ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo); } - + /* make a private copy of the avicodecdata */ - if (sce->r.avicodecdata) { - scen->r.avicodecdata = MEM_dupallocN(sce->r.avicodecdata); - scen->r.avicodecdata->lpFormat = MEM_dupallocN(scen->r.avicodecdata->lpFormat); - scen->r.avicodecdata->lpParms = MEM_dupallocN(scen->r.avicodecdata->lpParms); - } - - /* make a private copy of the qtcodecdata */ - if (sce->r.qtcodecdata) { - scen->r.qtcodecdata = MEM_dupallocN(sce->r.qtcodecdata); - scen->r.qtcodecdata->cdParms = MEM_dupallocN(scen->r.qtcodecdata->cdParms); + if (sce_src->r.avicodecdata) { + sce_dst->r.avicodecdata = MEM_dupallocN(sce_src->r.avicodecdata); + sce_dst->r.avicodecdata->lpFormat = MEM_dupallocN(sce_dst->r.avicodecdata->lpFormat); + sce_dst->r.avicodecdata->lpParms = MEM_dupallocN(sce_dst->r.avicodecdata->lpParms); } - - if (sce->r.ffcodecdata.properties) { /* intentionally check scen not sce. */ - scen->r.ffcodecdata.properties = IDP_CopyProperty(sce->r.ffcodecdata.properties); + + if (sce_src->r.ffcodecdata.properties) { /* intentionally check sce_dst not sce_src. */ /* XXX ??? comment outdated... */ + sce_dst->r.ffcodecdata.properties = IDP_CopyProperty_ex(sce_src->r.ffcodecdata.properties, flag_subdata); } - /* NOTE: part of SCE_COPY_LINK_DATA and SCE_COPY_FULL operations - * are done outside of blenkernel with ED_objects_single_users! */ + /* before scene copy */ + BKE_sound_create_scene(sce_dst); - /* camera */ - if (type == SCE_COPY_LINK_DATA || type == SCE_COPY_FULL) { - ID_NEW_REMAP(scen->camera); + /* Copy sequencer, this is local data! */ + if (sce_src->ed) { + sce_dst->ed = MEM_callocN(sizeof(*sce_dst->ed), __func__); + sce_dst->ed->seqbasep = &sce_dst->ed->seqbase; + BKE_sequence_base_dupli_recursive( + sce_src, sce_dst, &sce_dst->ed->seqbase, &sce_src->ed->seqbase, SEQ_DUPE_ALL, flag_subdata); } - - /* before scene copy */ - BKE_sound_create_scene(scen); - /* world */ - if (type == SCE_COPY_FULL) { - if (scen->world) { - scen->world = BKE_world_copy(bmain, scen->world); - BKE_animdata_copy_id_action((ID *)scen->world, false); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { + BKE_previewimg_id_copy(&sce_dst->id, &sce_src->id); + } + else { + sce_dst->preview = NULL; + } +} + +Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) +{ + Scene *sce_copy; + + /* TODO this should/could most likely be replaced by call to more generic code at some point... + * But for now, let's keep it well isolated here. */ + if (type == SCE_COPY_EMPTY) { + ToolSettings *ts; + ListBase rl, rv; + + sce_copy = BKE_scene_add(bmain, sce->id.name + 2); + + rl = sce_copy->r.layers; + rv = sce_copy->r.views; + curvemapping_free_data(&sce_copy->r.mblur_shutter_curve); + sce_copy->r = sce->r; + sce_copy->r.layers = rl; + sce_copy->r.actlay = 0; + sce_copy->r.views = rv; + sce_copy->unit = sce->unit; + sce_copy->physics_settings = sce->physics_settings; + sce_copy->gm = sce->gm; + sce_copy->audio = sce->audio; + + if (sce->id.properties) + sce_copy->id.properties = IDP_CopyProperty(sce->id.properties); + + MEM_freeN(sce_copy->toolsettings); + BKE_sound_destroy_scene(sce_copy); + + /* copy color management settings */ + BKE_color_managed_display_settings_copy(&sce_copy->display_settings, &sce->display_settings); + BKE_color_managed_view_settings_copy(&sce_copy->view_settings, &sce->view_settings); + BKE_color_managed_colorspace_settings_copy(&sce_copy->sequencer_colorspace_settings, &sce->sequencer_colorspace_settings); + + BKE_color_managed_display_settings_copy(&sce_copy->r.im_format.display_settings, &sce->r.im_format.display_settings); + BKE_color_managed_view_settings_copy(&sce_copy->r.im_format.view_settings, &sce->r.im_format.view_settings); + + BKE_color_managed_display_settings_copy(&sce_copy->r.bake.im_format.display_settings, &sce->r.bake.im_format.display_settings); + BKE_color_managed_view_settings_copy(&sce_copy->r.bake.im_format.view_settings, &sce->r.bake.im_format.view_settings); + + curvemapping_copy_data(&sce_copy->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve); + + /* tool settings */ + sce_copy->toolsettings = MEM_dupallocN(sce->toolsettings); + + ts = sce_copy->toolsettings; + if (ts) { + if (ts->vpaint) { + ts->vpaint = MEM_dupallocN(ts->vpaint); + BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, 0); + } + if (ts->wpaint) { + ts->wpaint = MEM_dupallocN(ts->wpaint); + BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, 0); + } + if (ts->sculpt) { + ts->sculpt = MEM_dupallocN(ts->sculpt); + BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, 0); + } + if (ts->uvsculpt) { + ts->uvsculpt = MEM_dupallocN(ts->uvsculpt); + BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, 0); + } + + BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, 0); + ts->imapaint.paintcursor = NULL; + id_us_plus((ID *)ts->imapaint.stencil); + id_us_plus((ID *)ts->imapaint.clone); + id_us_plus((ID *)ts->imapaint.canvas); + ts->particle.paintcursor = NULL; + ts->particle.scene = NULL; + ts->particle.object = NULL; + + /* duplicate Grease Pencil Drawing Brushes */ + BLI_listbase_clear(&ts->gp_brushes); + for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) { + bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush); + BLI_addtail(&ts->gp_brushes, newbrush); + } + + /* duplicate Grease Pencil interpolation curve */ + ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo); + } + + /* make a private copy of the avicodecdata */ + if (sce->r.avicodecdata) { + sce_copy->r.avicodecdata = MEM_dupallocN(sce->r.avicodecdata); + sce_copy->r.avicodecdata->lpFormat = MEM_dupallocN(sce_copy->r.avicodecdata->lpFormat); + sce_copy->r.avicodecdata->lpParms = MEM_dupallocN(sce_copy->r.avicodecdata->lpParms); } - if (sce->ed) { - scen->ed = MEM_callocN(sizeof(Editing), "addseq"); - scen->ed->seqbasep = &scen->ed->seqbase; - BKE_sequence_base_dupli_recursive(sce, scen, &scen->ed->seqbase, &sce->ed->seqbase, SEQ_DUPE_ALL); + if (sce->r.ffcodecdata.properties) { /* intentionally check scen not sce. */ + sce_copy->r.ffcodecdata.properties = IDP_CopyProperty(sce->r.ffcodecdata.properties); } + + /* before scene copy */ + BKE_sound_create_scene(sce_copy); + + /* grease pencil */ + sce_copy->gpd = NULL; + + sce_copy->preview = NULL; + + return sce_copy; } - - /* grease pencil */ - if (scen->gpd) { + else { + BKE_id_copy_ex(bmain, (ID *)sce, (ID **)&sce_copy, LIB_ID_COPY_ACTIONS, false); + + /* Extra actions, most notably SCE_FULL_COPY also duplicates several 'children' datablocks... */ + if (type == SCE_COPY_FULL) { - scen->gpd = BKE_gpencil_data_duplicate(bmain, scen->gpd, false); - } - else if (type == SCE_COPY_EMPTY) { - scen->gpd = NULL; + /* Copy Freestyle LineStyle datablocks. */ + for (SceneRenderLayer *srl_dst = sce_copy->r.layers.first; srl_dst; srl_dst = srl_dst->next) { + for (FreestyleLineSet *lineset = srl_dst->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { + if (lineset->linestyle) { + /* XXX Not copying anim/actions here? */ + BKE_id_copy_ex(bmain, (ID *)lineset->linestyle, (ID **)&lineset->linestyle, 0, false); + } + } + } + + /* Full copy of world (included animations) */ + if (sce_copy->world) { + BKE_id_copy_ex(bmain, (ID *)sce_copy->world, (ID **)&sce_copy->world, LIB_ID_COPY_ACTIONS, false); + } + + /* Full copy of GreasePencil. */ + /* XXX Not copying anim/actions here? */ + if (sce_copy->gpd) { + BKE_id_copy_ex(bmain, (ID *)sce_copy->gpd, (ID **)&sce_copy->gpd, 0, false); + } } else { - id_us_plus((ID *)scen->gpd); + /* Remove sequencer if not full copy */ + /* XXX Why in Hell? :/ */ + remove_sequencer_fcurves(sce_copy); + BKE_sequencer_editing_free(sce_copy); } - } - BKE_previewimg_id_copy(&scen->id, &sce->id); + /* NOTE: part of SCE_COPY_LINK_DATA and SCE_COPY_FULL operations + * are done outside of blenkernel with ED_objects_single_users! */ + + /* camera */ + if (ELEM(type, SCE_COPY_LINK_DATA, SCE_COPY_FULL)) { + ID_NEW_REMAP(sce_copy->camera); + } - return scen; + return sce_copy; + } } void BKE_scene_groups_relink(Scene *sce) @@ -419,11 +477,6 @@ void BKE_scene_free(Scene *sce) MEM_freeN(sce->r.avicodecdata); sce->r.avicodecdata = NULL; } - if (sce->r.qtcodecdata) { - free_qtcodecdata(sce->r.qtcodecdata); - MEM_freeN(sce->r.qtcodecdata); - sce->r.qtcodecdata = NULL; - } if (sce->r.ffcodecdata.properties) { IDP_FreeProperty(sce->r.ffcodecdata.properties); MEM_freeN(sce->r.ffcodecdata.properties); @@ -583,7 +636,7 @@ void BKE_scene_init(Scene *sce) sce->r.seq_prev_type = OB_SOLID; sce->r.seq_rend_type = OB_SOLID; - sce->r.seq_flag = R_SEQ_GL_PREV; + sce->r.seq_flag = 0; sce->r.threads = 1; @@ -843,7 +896,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name) { Scene *sce; - sce = BKE_libblock_alloc(bmain, ID_SCE, name); + sce = BKE_libblock_alloc(bmain, ID_SCE, name, 0); id_us_min(&sce->id); id_us_ensure_real(&sce->id); @@ -1847,8 +1900,6 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc #endif { DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene); - /* TODO(sergey): This is to beocme a node in new depsgraph. */ - BKE_mask_update_scene(bmain, scene); } /* update sound system animation (TODO, move to depsgraph) */ @@ -1965,11 +2016,10 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, /* Following 2 functions are recursive * so don't call within 'scene_update_tagged_recursive' */ DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still + BKE_mask_evaluate_all_masks(bmain, ctime, true); } #endif - BKE_mask_evaluate_all_masks(bmain, ctime, true); - /* Update animated cache files for modifiers. */ BKE_cachefile_update_frame(bmain, sce, ctime, (((double)sce->r.frs_sec) / (double)sce->r.frs_sec_base)); @@ -2318,6 +2368,14 @@ int BKE_scene_num_threads(const Scene *scene) return BKE_render_num_threads(&scene->r); } +int BKE_render_preview_pixel_size(const RenderData *r) +{ + if (r->preview_pixel_size == 0) { + return (U.pixelsize > 1.5f)? 2 : 1; + } + return r->preview_pixel_size; +} + /* Apply the needed correction factor to value, based on unit_type (only length-related are affected currently) * and unit->scale_length. */ diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 857bd5447c8..df47b89fadc 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -181,6 +181,7 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar) BLI_listbase_clear(&newar->ui_lists); newar->swinid = 0; newar->regiontimer = NULL; + newar->headerstr = NULL; /* use optional regiondata callback */ if (ar->regiondata) { diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 669f76cf90b..9b0db300e6d 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -377,6 +377,8 @@ static void seqclipboard_ptr_restore(Main *bmain, ID **id_pt) } break; } + default: + break; } } @@ -480,9 +482,12 @@ void BKE_sequencer_editing_free(Scene *scene) static void sequencer_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf) { +#if 0 + /* Bute buffer is supposed to be in sequencer working space already. */ if (ibuf->rect != NULL) { IMB_colormanagement_assign_rect_colorspace(ibuf, scene->sequencer_colorspace_settings.name); } +#endif if (ibuf->rect_float != NULL) { IMB_colormanagement_assign_float_colorspace(ibuf, scene->sequencer_colorspace_settings.name); } @@ -3233,7 +3238,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq const bool is_background = G.background; const bool do_seq_gl = is_rendering ? 0 /* (context->scene->r.seq_flag & R_SEQ_GL_REND) */ : - (context->scene->r.seq_flag & R_SEQ_GL_PREV) != 0; + (context->scene->r.seq_prev_type) != OB_RENDER; // bool have_seq = false; /* UNUSED */ bool have_comp = false; bool use_gpencil = true; @@ -3315,7 +3320,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq } } else { - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); const int totviews = BKE_scene_multiview_num_views_get(&scene->r); int i; ImBuf **ibufs_arr; @@ -3332,7 +3337,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq */ if (!is_thread_main || is_rendering == false || is_background || context->eval_ctx->mode == DAG_EVAL_RENDER) { if (re == NULL) - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay); RE_BlenderFrame(re, context->bmain, scene, NULL, camera, scene->lay, frame, false); @@ -5371,9 +5376,8 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad return seq; } -static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dupe_flag) +static Sequence *seq_dupli(const Scene *scene_src, Scene *scene_dst, Sequence *seq, int dupe_flag, const int flag) { - Scene *sce_audio = scene_to ? scene_to : scene; Sequence *seqn = MEM_dupallocN(seq); seq->tmp = seqn; @@ -5397,7 +5401,7 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup } if (seq->prop) { - seqn->prop = IDP_CopyProperty(seq->prop); + seqn->prop = IDP_CopyProperty_ex(seq->prop, flag); } if (seqn->modifiers.first) { @@ -5416,7 +5420,7 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup else if (seq->type == SEQ_TYPE_SCENE) { seqn->strip->stripdata = NULL; if (seq->scene_sound) - seqn->scene_sound = BKE_sound_scene_add_scene_sound_defaults(sce_audio, seqn); + seqn->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene_dst, seqn); } else if (seq->type == SEQ_TYPE_MOVIECLIP) { /* avoid assert */ @@ -5433,9 +5437,11 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata); if (seq->scene_sound) - seqn->scene_sound = BKE_sound_add_scene_sound_defaults(sce_audio, seqn); + seqn->scene_sound = BKE_sound_add_scene_sound_defaults(scene_dst, seqn); - id_us_plus((ID *)seqn->sound); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)seqn->sound); + } } else if (seq->type == SEQ_TYPE_IMAGE) { seqn->strip->stripdata = @@ -5455,11 +5461,15 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup BLI_assert(0); } - if (dupe_flag & SEQ_DUPE_UNIQUE_NAME) - BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seqn); + if (scene_src == scene_dst) { + if (dupe_flag & SEQ_DUPE_UNIQUE_NAME) { + BKE_sequence_base_unique_name_recursive(&scene_dst->ed->seqbase, seqn); + } - if (dupe_flag & SEQ_DUPE_ANIM) - BKE_sequencer_dupe_animdata(scene, seq->name + 2, seqn->name + 2); + if (dupe_flag & SEQ_DUPE_ANIM) { + BKE_sequencer_dupe_animdata(scene_dst, seq->name + 2, seqn->name + 2); + } + } return seqn; } @@ -5486,16 +5496,16 @@ static void seq_new_fix_links_recursive(Sequence *seq) } } -Sequence *BKE_sequence_dupli_recursive(Scene *scene, Scene *scene_to, Sequence *seq, int dupe_flag) +Sequence *BKE_sequence_dupli_recursive(const Scene *scene_src, Scene *scene_dst, Sequence *seq, int dupe_flag) { Sequence *seqn; seq->tmp = NULL; - seqn = seq_dupli(scene, scene_to, seq, dupe_flag); + seqn = seq_dupli(scene_src, scene_dst, seq, dupe_flag, 0); if (seq->type == SEQ_TYPE_META) { Sequence *s; for (s = seq->seqbase.first; s; s = s->next) { - Sequence *n = BKE_sequence_dupli_recursive(scene, scene_to, s, dupe_flag); + Sequence *n = BKE_sequence_dupli_recursive(scene_src, scene_dst, s, dupe_flag); if (n) { BLI_addtail(&seqn->seqbase, n); } @@ -5508,19 +5518,19 @@ Sequence *BKE_sequence_dupli_recursive(Scene *scene, Scene *scene_to, Sequence * } void BKE_sequence_base_dupli_recursive( - Scene *scene, Scene *scene_to, ListBase *nseqbase, ListBase *seqbase, - int dupe_flag) + const Scene *scene_src, Scene *scene_dst, ListBase *nseqbase, const ListBase *seqbase, + int dupe_flag, const int flag) { Sequence *seq; Sequence *seqn = NULL; - Sequence *last_seq = BKE_sequencer_active_get(scene); + Sequence *last_seq = BKE_sequencer_active_get((Scene *)scene_src); /* always include meta's strips */ int dupe_flag_recursive = dupe_flag | SEQ_DUPE_ALL; for (seq = seqbase->first; seq; seq = seq->next) { seq->tmp = NULL; if ((seq->flag & SELECT) || (dupe_flag & SEQ_DUPE_ALL)) { - seqn = seq_dupli(scene, scene_to, seq, dupe_flag); + seqn = seq_dupli(scene_src, scene_dst, seq, dupe_flag, flag); if (seqn) { /*should never fail */ if (dupe_flag & SEQ_DUPE_CONTEXT) { seq->flag &= ~SEQ_ALLSEL; @@ -5530,13 +5540,13 @@ void BKE_sequence_base_dupli_recursive( BLI_addtail(nseqbase, seqn); if (seq->type == SEQ_TYPE_META) { BKE_sequence_base_dupli_recursive( - scene, scene_to, &seqn->seqbase, &seq->seqbase, - dupe_flag_recursive); + scene_src, scene_dst, &seqn->seqbase, &seq->seqbase, + dupe_flag_recursive, flag); } if (dupe_flag & SEQ_DUPE_CONTEXT) { if (seq == last_seq) { - BKE_sequencer_active_set(scene, seqn); + BKE_sequencer_active_set(scene_dst, seqn); } } } diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 7094d5a3547..f9d1793d7cb 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -152,6 +152,9 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; BVHTreeNearest nearest = NULL_BVHTreeNearest; + if (calc->target != NULL && calc->target->getNumVerts(calc->target) == 0) { + return; + } TIMEIT_BENCH(bvhtree_from_mesh_verts(&treeData, calc->target, 0.0, 2, 6), bvhtree_verts); if (treeData.tree == NULL) { @@ -376,6 +379,9 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for if ((calc->smd->shrinkOpts & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0) return; + if (calc->target != NULL && calc->target->getNumPolys(calc->target) == 0) { + return; + } /* Prepare data to retrieve the direction in which we should project each vertex */ if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) { @@ -432,7 +438,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for if (targ_tree) { BVHTree *aux_tree = NULL; void *aux_callback = NULL; - if (auxMesh != NULL) { + if (auxMesh != NULL && auxMesh->getNumPolys(auxMesh) != 0) { /* use editmesh to avoid array allocation */ if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) { emaux = BKE_editmesh_from_object(calc->smd->auxTarget); @@ -560,6 +566,10 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; BVHTreeNearest nearest = NULL_BVHTreeNearest; + if (calc->target->getNumPolys(calc->target) == 0) { + return; + } + /* Create a bvh-tree of the given target */ bvhtree_from_mesh_looptri(&treeData, calc->target, 0.0, 2, 6); if (treeData.tree == NULL) { diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index d0ef5cfc092..adecea7080c 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -2692,7 +2692,6 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object * if (smd->flow->dm) smd->flow->dm->release(smd->flow->dm); smd->flow->dm = CDDM_copy(dm); - DM_ensure_looptri(smd->flow->dm); if (scene->r.cfra > smd->time) { @@ -2715,7 +2714,6 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object * smd->coll->dm->release(smd->coll->dm); smd->coll->dm = CDDM_copy(dm); - DM_ensure_looptri(smd->coll->dm); } smd->time = scene->r.cfra; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 8469351c54a..45d1f969d64 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -83,7 +83,7 @@ bSound *BKE_sound_new_file(struct Main *bmain, const char *filepath) BLI_path_abs(str, path); - sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath)); + sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath), 0); BLI_strncpy(sound->name, filepath, FILE_MAX); /* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */ @@ -155,6 +155,34 @@ void BKE_sound_free(bSound *sound) } } +/** + * Only copy internal data of Sound ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_sound_copy_data(Main *bmain, bSound *sound_dst, const bSound *UNUSED(sound_src), const int UNUSED(flag)) +{ + sound_dst->handle = NULL; + sound_dst->cache = NULL; + sound_dst->waveform = NULL; + sound_dst->playback_handle = NULL; + sound_dst->spinlock = NULL; /* Think this is OK? Otherwise, easy to create new spinlock here... */ + + /* Just to be sure, should not have any value actually after reading time. */ + sound_dst->ipo = NULL; + sound_dst->newpackedfile = NULL; + + if (sound_dst->packedfile) { + sound_dst->packedfile = dupPackedFile(sound_dst->packedfile); + } + + /* Initialize whole runtime (audaspace) stuff. */ + BKE_sound_load(bmain, sound_dst); +} + void BKE_sound_make_local(Main *bmain, bSound *sound, const bool lib_local) { BKE_id_make_local_generic(bmain, &sound->id, true, lib_local); diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index d00e4b1a0d2..9d604a9382a 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -61,25 +61,31 @@ void *BKE_speaker_add(Main *bmain, const char *name) { Speaker *spk; - spk = BKE_libblock_alloc(bmain, ID_SPK, name); + spk = BKE_libblock_alloc(bmain, ID_SPK, name, 0); BKE_speaker_init(spk); return spk; } -Speaker *BKE_speaker_copy(Main *bmain, const Speaker *spk) +/** + * Only copy internal data of Speaker ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_speaker_copy_data(Main *UNUSED(bmain), Speaker *UNUSED(spk_dst), const Speaker *UNUSED(spk_src), const int UNUSED(flag)) { - Speaker *spkn; - - spkn = BKE_libblock_copy(bmain, &spk->id); - - if (spkn->sound) - id_us_plus(&spkn->sound->id); - - BKE_id_copy_ensure_local(bmain, &spk->id, &spkn->id); + /* Nothing to do! */ +} - return spkn; +Speaker *BKE_speaker_copy(Main *bmain, const Speaker *spk) +{ + Speaker *spk_copy; + BKE_id_copy_ex(bmain, &spk->id, (ID **)&spk_copy, 0, false); + return spk_copy; } void BKE_speaker_make_local(Main *bmain, Speaker *spk, const bool lib_local) diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index c4665c40ec4..7c5ee42b7bc 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -42,6 +42,8 @@ #include <math.h> #include <float.h> +#include "atomic_ops.h" + #include "MEM_guardedalloc.h" #include "DNA_mesh_types.h" @@ -3681,6 +3683,11 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int gridFaces = gridSize - 1, totface; int prev_mat_nr = -1; + if (ccgdm->pbvh) { + if (G.debug_value == 14) + BKE_pbvh_draw_BB(ccgdm->pbvh); + } + #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { int new_matnr; @@ -4414,7 +4421,8 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) if (!ob->sculpt) return NULL; - grid_pbvh = ccgDM_use_grid_pbvh(ccgdm); + /* In vwpaint, we always use a grid_pbvh for multires/subsurf */ + grid_pbvh = (!(ob->mode & OB_MODE_SCULPT) || ccgDM_use_grid_pbvh(ccgdm)); if (ob->sculpt->pbvh) { if (grid_pbvh) { @@ -4430,12 +4438,18 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) ccgdm->pbvh = ob->sculpt->pbvh; } - if (ccgdm->pbvh) + if (ccgdm->pbvh) { + /* For vertex paint, keep track of ccgdm */ + if (!(ob->mode & OB_MODE_SCULPT)) { + BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm); + } return ccgdm->pbvh; + } /* no pbvh exists yet, we need to create one. only in case of multires * we build a pbvh over the modified mesh, in other cases the base mesh * is being sculpted, so we build a pbvh from that. */ + /* Note: vwpaint always builds a pbvh over the modified mesh. */ if (grid_pbvh) { ccgdm_create_grids(dm); @@ -4466,6 +4480,10 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) if (ccgdm->pbvh) pbvh_show_diffuse_color_set(ccgdm->pbvh, ob->sculpt->show_diffuse_color); + /* For vertex paint, keep track of ccgdm */ + if (!(ob->mode & OB_MODE_SCULPT) && ccgdm->pbvh) { + BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm); + } return ccgdm->pbvh; } @@ -4474,16 +4492,17 @@ static void ccgDM_recalcTessellation(DerivedMesh *UNUSED(dm)) /* Nothing to do: CCG handles creating its own tessfaces */ } +/* WARNING! *MUST* be called in an 'loops_cache_rwlock' protected thread context! */ static void ccgDM_recalcLoopTri(DerivedMesh *dm) { - BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_WRITE); - MLoopTri *mlooptri; + MLoopTri *mlooptri = dm->looptris.array; const int tottri = dm->numPolyData * 2; int i, poly_index; DM_ensure_looptri_data(dm); - mlooptri = dm->looptris.array; + mlooptri = dm->looptris.array_wip; + BLI_assert(tottri == 0 || mlooptri != NULL); BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); BLI_assert(tottri == dm->looptris.num); @@ -4502,19 +4521,10 @@ static void ccgDM_recalcLoopTri(DerivedMesh *dm) lt->tri[2] = (poly_index * 4) + 2; lt->poly = poly_index; } - BLI_rw_mutex_unlock(&loops_cache_rwlock); -} -static const MLoopTri *ccgDM_getLoopTriArray(DerivedMesh *dm) -{ - if (dm->looptris.array) { - BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); - } - else { - dm->recalcLoopTri(dm); - } - - return dm->looptris.array; + BLI_assert(dm->looptris.array == NULL); + atomic_cas_ptr((void **)&dm->looptris.array, dm->looptris.array, dm->looptris.array_wip); + dm->looptris.array_wip = NULL; } static void ccgDM_calcNormals(DerivedMesh *dm) @@ -4533,8 +4543,6 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm) ccgdm->dm.getNumPolys = ccgDM_getNumPolys; ccgdm->dm.getNumTessFaces = ccgDM_getNumTessFaces; - ccgdm->dm.getLoopTriArray = ccgDM_getLoopTriArray; - ccgdm->dm.getVert = ccgDM_getFinalVert; ccgdm->dm.getEdge = ccgDM_getFinalEdge; ccgdm->dm.getTessFace = ccgDM_getFinalFace; diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 466bef7ff36..7c4aa81ee46 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -224,7 +224,7 @@ Text *BKE_text_add(Main *bmain, const char *name) { Text *ta; - ta = BKE_libblock_alloc(bmain, ID_TXT, name); + ta = BKE_libblock_alloc(bmain, ID_TXT, name, 0); BKE_text_init(ta); @@ -410,7 +410,7 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const return false; } - ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs)); + ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs), 0); ta->id.us = 0; BLI_listbase_clear(&ta->lines); @@ -449,53 +449,49 @@ Text *BKE_text_load(Main *bmain, const char *file, const char *relpath) return BKE_text_load_ex(bmain, file, relpath, false); } -Text *BKE_text_copy(Main *bmain, const Text *ta) +/** + * Only copy internal data of Text ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_text_copy_data(Main *UNUSED(bmain), Text *ta_dst, const Text *ta_src, const int UNUSED(flag)) { - Text *tan; - TextLine *line, *tmp; - - tan = BKE_libblock_copy(bmain, &ta->id); - /* file name can be NULL */ - if (ta->name) { - tan->name = BLI_strdup(ta->name); - } - else { - tan->name = NULL; + if (ta_src->name) { + ta_dst->name = BLI_strdup(ta_src->name); } - tan->flags = ta->flags | TXT_ISDIRTY; - - BLI_listbase_clear(&tan->lines); - tan->curl = tan->sell = NULL; - tan->compiled = NULL; - - tan->nlines = ta->nlines; + ta_dst->flags |= TXT_ISDIRTY; + + BLI_listbase_clear(&ta_dst->lines); + ta_dst->curl = ta_dst->sell = NULL; + ta_dst->compiled = NULL; - line = ta->lines.first; /* Walk down, reconstructing */ - while (line) { - tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline"); - tmp->line = MEM_mallocN(line->len + 1, "textline_string"); - tmp->format = NULL; - - strcpy(tmp->line, line->line); + for (TextLine *line_src = ta_src->lines.first; line_src; line_src = line_src->next) { + TextLine *line_dst = MEM_mallocN(sizeof(*line_dst), __func__); - tmp->len = line->len; - - BLI_addtail(&tan->lines, tmp); - - line = line->next; - } + line_dst->line = BLI_strdup(line_src->line); + line_dst->format = NULL; + line_dst->len = line_src->len; - tan->curl = tan->sell = tan->lines.first; - tan->curc = tan->selc = 0; + BLI_addtail(&ta_dst->lines, line_dst); + } - init_undo_text(tan); + ta_dst->curl = ta_dst->sell = ta_dst->lines.first; + ta_dst->curc = ta_dst->selc = 0; - BKE_id_copy_ensure_local(bmain, &ta->id, &tan->id); + init_undo_text(ta_dst); +} - return tan; +Text *BKE_text_copy(Main *bmain, const Text *ta) +{ + Text *ta_copy; + BKE_id_copy_ex(bmain, &ta->id, (ID **)&ta_copy, 0, false); + return ta_copy; } void BKE_text_make_local(Main *bmain, Text *text, const bool lib_local) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 1e0659d3d67..8f0334a4752 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -707,7 +707,7 @@ Tex *BKE_texture_add(Main *bmain, const char *name) { Tex *tex; - tex = BKE_libblock_alloc(bmain, ID_TE, name); + tex = BKE_libblock_alloc(bmain, ID_TE, name, 0); BKE_texture_default(tex); @@ -846,41 +846,71 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot) /* ------------------------------------------------------------------------- */ -Tex *BKE_texture_copy(Main *bmain, const Tex *tex) +/** + * Only copy internal data of Texture ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const int flag) { - Tex *texn; - - texn = BKE_libblock_copy(bmain, &tex->id); - if (BKE_texture_is_image_user(tex)) { - id_us_plus((ID *)texn->ima); + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; + + if (!BKE_texture_is_image_user(tex_src)) { + tex_dst->ima = NULL; } - else { - texn->ima = NULL; + + if (tex_dst->coba) { + tex_dst->coba = MEM_dupallocN(tex_dst->coba); + } + if (tex_dst->env) { + tex_dst->env = BKE_texture_envmap_copy(tex_dst->env, flag_subdata); + } + if (tex_dst->pd) { + tex_dst->pd = BKE_texture_pointdensity_copy(tex_dst->pd, flag_subdata); + } + if (tex_dst->vd) { + tex_dst->vd = MEM_dupallocN(tex_dst->vd); + } + if (tex_dst->ot) { + tex_dst->ot = BKE_texture_ocean_copy(tex_dst->ot, flag_subdata); } - - if (texn->coba) texn->coba = MEM_dupallocN(texn->coba); - if (texn->env) texn->env = BKE_texture_envmap_copy(texn->env); - if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd); - if (texn->vd) texn->vd = MEM_dupallocN(texn->vd); - if (texn->ot) texn->ot = BKE_texture_ocean_copy(texn->ot); - if (tex->nodetree) { - if (tex->nodetree->execdata) { - ntreeTexEndExecTree(tex->nodetree->execdata); + if (tex_src->nodetree) { + if (tex_src->nodetree->execdata) { + ntreeTexEndExecTree(tex_src->nodetree->execdata); } - texn->nodetree = ntreeCopyTree(bmain, tex->nodetree); + BKE_id_copy_ex(bmain, (ID *)tex_src->nodetree, (ID **)&tex_dst->nodetree, flag, false); } - BKE_previewimg_id_copy(&texn->id, &tex->id); - - BKE_id_copy_ensure_local(bmain, &tex->id, &texn->id); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { + BKE_previewimg_id_copy(&tex_dst->id, &tex_src->id); + } + else { + tex_dst->preview = NULL; + } +} - return texn; +Tex *BKE_texture_copy(Main *bmain, const Tex *tex) +{ + Tex *tex_copy; + BKE_id_copy_ex(bmain, &tex->id, (ID **)&tex_copy, 0, false); + return tex_copy; } /* texture copy without adding to main dbase */ Tex *BKE_texture_localize(Tex *tex) { + /* TODO replace with something like + * Tex *tex_copy; + * BKE_id_copy_ex(bmain, &tex->id, (ID **)&tex_copy, LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT, false); + * return tex_copy; + * + * ... Once f*** nodes are fully converted to that too :( */ + Tex *texn; texn = BKE_libblock_copy_nolib(&tex->id, false); @@ -889,17 +919,17 @@ Tex *BKE_texture_localize(Tex *tex) if (texn->coba) texn->coba = MEM_dupallocN(texn->coba); if (texn->env) { - texn->env = BKE_texture_envmap_copy(texn->env); + texn->env = BKE_texture_envmap_copy(texn->env, LIB_ID_CREATE_NO_USER_REFCOUNT); id_us_min(&texn->env->ima->id); } - if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd); + if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd, LIB_ID_CREATE_NO_USER_REFCOUNT); if (texn->vd) { texn->vd = MEM_dupallocN(texn->vd); if (texn->vd->dataset) texn->vd->dataset = MEM_dupallocN(texn->vd->dataset); } if (texn->ot) { - texn->ot = BKE_texture_ocean_copy(tex->ot); + texn->ot = BKE_texture_ocean_copy(tex->ot, LIB_ID_CREATE_NO_USER_REFCOUNT); } texn->preview = NULL; @@ -1099,6 +1129,8 @@ void set_active_mtex(ID *id, short act) case ID_PA: ((ParticleSettings *)id)->texact = act; break; + default: + break; } } @@ -1263,16 +1295,20 @@ EnvMap *BKE_texture_envmap_add(void) /* ------------------------------------------------------------------------- */ -EnvMap *BKE_texture_envmap_copy(const EnvMap *env) +EnvMap *BKE_texture_envmap_copy(const EnvMap *env, const int flag) { EnvMap *envn; int a; envn = MEM_dupallocN(env); envn->ok = 0; - for (a = 0; a < 6; a++) envn->cube[a] = NULL; - if (envn->ima) id_us_plus((ID *)envn->ima); - + for (a = 0; a < 6; a++) { + envn->cube[a] = NULL; + } + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)envn->ima); + } + return envn; } @@ -1336,14 +1372,16 @@ PointDensity *BKE_texture_pointdensity_add(void) return pd; } -PointDensity *BKE_texture_pointdensity_copy(const PointDensity *pd) +PointDensity *BKE_texture_pointdensity_copy(const PointDensity *pd, const int UNUSED(flag)) { PointDensity *pdn; pdn = MEM_dupallocN(pd); pdn->point_tree = NULL; pdn->point_data = NULL; - if (pdn->coba) pdn->coba = MEM_dupallocN(pdn->coba); + if (pdn->coba) { + pdn->coba = MEM_dupallocN(pdn->coba); + } pdn->falloff_curve = curvemapping_copy(pdn->falloff_curve); /* can be NULL */ return pdn; } @@ -1430,7 +1468,7 @@ OceanTex *BKE_texture_ocean_add(void) return ot; } -OceanTex *BKE_texture_ocean_copy(const OceanTex *ot) +OceanTex *BKE_texture_ocean_copy(const OceanTex *ot, const int UNUSED(flag)) { OceanTex *otn = MEM_dupallocN(ot); diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 9120d384a16..b4ef381534f 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -190,7 +190,7 @@ void BKE_tracking_free(MovieTracking *tracking) } /* Copy the whole list of tracks. */ -static void tracking_tracks_copy(ListBase *tracks_dst, const ListBase *tracks_src, GHash *tracks_mapping) +static void tracking_tracks_copy(ListBase *tracks_dst, const ListBase *tracks_src, GHash *tracks_mapping, const int flag) { MovieTrackingTrack *track_dst, *track_src; @@ -202,7 +202,9 @@ static void tracking_tracks_copy(ListBase *tracks_dst, const ListBase *tracks_sr if (track_src->markers) { track_dst->markers = MEM_dupallocN(track_src->markers); } - id_us_plus(&track_dst->gpd->id); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus(&track_dst->gpd->id); + } BLI_addtail(tracks_dst, track_dst); BLI_ghash_insert(tracks_mapping, track_src, track_dst); } @@ -210,7 +212,8 @@ static void tracking_tracks_copy(ListBase *tracks_dst, const ListBase *tracks_sr /* copy the whole list of plane tracks (need whole MovieTracking structures due to embedded pointers to tracks). * WARNING: implies tracking_[dst/src] and their tracks have already been copied. */ -static void tracking_plane_tracks_copy(ListBase *plane_tracks_dst, const ListBase *plane_tracks_src, GHash *tracks_mapping) +static void tracking_plane_tracks_copy( + ListBase *plane_tracks_dst, const ListBase *plane_tracks_src, GHash *tracks_mapping, const int flag) { MovieTrackingPlaneTrack *plane_track_dst, *plane_track_src; @@ -225,14 +228,17 @@ static void tracking_plane_tracks_copy(ListBase *plane_tracks_dst, const ListBas for (int i = 0; i < plane_track_dst->point_tracksnr; i++) { plane_track_dst->point_tracks[i] = BLI_ghash_lookup(tracks_mapping, plane_track_src->point_tracks[i]); } - id_us_plus(&plane_track_dst->image->id); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus(&plane_track_dst->image->id); + } BLI_addtail(plane_tracks_dst, plane_track_dst); } } /* Copy reconstruction structure. */ static void tracking_reconstruction_copy( - MovieTrackingReconstruction *reconstruction_dst, const MovieTrackingReconstruction *reconstruction_src) + MovieTrackingReconstruction *reconstruction_dst, const MovieTrackingReconstruction *reconstruction_src, + const int UNUSED(flag)) { *reconstruction_dst = *reconstruction_src; if (reconstruction_src->cameras) { @@ -242,23 +248,25 @@ static void tracking_reconstruction_copy( /* Copy stabilization structure. */ static void tracking_stabilization_copy( - MovieTrackingStabilization *stabilization_dst, const MovieTrackingStabilization *stabilization_src) + MovieTrackingStabilization *stabilization_dst, const MovieTrackingStabilization *stabilization_src, + const int UNUSED(flag)) { *stabilization_dst = *stabilization_src; } /* Copy tracking object. */ static void tracking_object_copy( - MovieTrackingObject *object_dst, const MovieTrackingObject *object_src, GHash *tracks_mapping) + MovieTrackingObject *object_dst, const MovieTrackingObject *object_src, GHash *tracks_mapping, const int flag) { *object_dst = *object_src; - tracking_tracks_copy(&object_dst->tracks, &object_src->tracks, tracks_mapping); - tracking_plane_tracks_copy(&object_dst->plane_tracks, &object_src->plane_tracks, tracks_mapping); - tracking_reconstruction_copy(&object_dst->reconstruction, &object_src->reconstruction); + tracking_tracks_copy(&object_dst->tracks, &object_src->tracks, tracks_mapping, flag); + tracking_plane_tracks_copy(&object_dst->plane_tracks, &object_src->plane_tracks, tracks_mapping, flag); + tracking_reconstruction_copy(&object_dst->reconstruction, &object_src->reconstruction, flag); } /* Copy list of tracking objects. */ -static void tracking_objects_copy(ListBase *objects_dst, const ListBase *objects_src, GHash *tracks_mapping) +static void tracking_objects_copy( + ListBase *objects_dst, const ListBase *objects_src, GHash *tracks_mapping, const int flag) { MovieTrackingObject *object_dst, *object_src; @@ -266,22 +274,22 @@ static void tracking_objects_copy(ListBase *objects_dst, const ListBase *objects for (object_src = objects_src->first; object_src != NULL; object_src = object_src->next) { object_dst = MEM_mallocN(sizeof(*object_dst), __func__); - tracking_object_copy(object_dst, object_src, tracks_mapping); + tracking_object_copy(object_dst, object_src, tracks_mapping, flag); BLI_addtail(objects_dst, object_dst); } } /* Copy tracking structure content. */ -void BKE_tracking_copy(MovieTracking *tracking_dst, const MovieTracking *tracking_src) +void BKE_tracking_copy(MovieTracking *tracking_dst, const MovieTracking *tracking_src, const int flag) { GHash *tracks_mapping = BLI_ghash_ptr_new(__func__); *tracking_dst = *tracking_src; - tracking_tracks_copy(&tracking_dst->tracks, &tracking_src->tracks, tracks_mapping); - tracking_plane_tracks_copy(&tracking_dst->plane_tracks, &tracking_src->plane_tracks, tracks_mapping); - tracking_reconstruction_copy(&tracking_dst->reconstruction, &tracking_src->reconstruction); - tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization); + tracking_tracks_copy(&tracking_dst->tracks, &tracking_src->tracks, tracks_mapping, flag); + tracking_plane_tracks_copy(&tracking_dst->plane_tracks, &tracking_src->plane_tracks, tracks_mapping, flag); + tracking_reconstruction_copy(&tracking_dst->reconstruction, &tracking_src->reconstruction, flag); + tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization, flag); if (tracking_src->act_track) { tracking_dst->act_track = BLI_ghash_lookup(tracks_mapping, tracking_src->act_track); } @@ -299,7 +307,7 @@ void BKE_tracking_copy(MovieTracking *tracking_dst, const MovieTracking *trackin } /* Warning! Will override tracks_mapping. */ - tracking_objects_copy(&tracking_dst->objects, &tracking_src->objects, tracks_mapping); + tracking_objects_copy(&tracking_dst->objects, &tracking_src->objects, tracks_mapping, flag); /* Those remaining are runtime data, they will be reconstructed as needed, do not bother copying them. */ tracking_dst->dopesheet.ok = false; diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c index 9475925cdda..30981ed8f23 100644 --- a/source/blender/blenkernel/intern/tracking_auto.c +++ b/source/blender/blenkernel/intern/tracking_auto.c @@ -312,7 +312,7 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip, int num_total_tracks = BLI_listbase_count(tracksbase); context->tracks = - MEM_callocN(sizeof(MovieTrackingTrack*) * num_total_tracks, + MEM_callocN(sizeof(MovieTrackingTrack *) * num_total_tracks, "auto track pointers"); context->image_accessor = @@ -381,7 +381,7 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip, bool BKE_autotrack_context_step(AutoTrackContext *context) { - int frame_delta = context->backwards ? -1 : 1; + const int frame_delta = context->backwards ? -1 : 1; bool ok = false; int track; @@ -395,67 +395,64 @@ bool BKE_autotrack_context_step(AutoTrackContext *context) libmv_reference_marker, libmv_tracked_marker; libmv_TrackRegionResult libmv_result; - int frame = BKE_movieclip_remap_scene_to_clip_frame( - context->clips[options->clip_index], - context->user.framenr); - bool has_marker; - + const int frame = BKE_movieclip_remap_scene_to_clip_frame( + context->clips[options->clip_index], + context->user.framenr); BLI_spin_lock(&context->spin_lock); - has_marker = libmv_autoTrackGetMarker(context->autotrack, - options->clip_index, - frame, - options->track_index, - &libmv_current_marker); + const bool has_marker = libmv_autoTrackGetMarker(context->autotrack, + options->clip_index, + frame, + options->track_index, + &libmv_current_marker); BLI_spin_unlock(&context->spin_lock); - - if (has_marker) { - if (!tracking_check_marker_margin(&libmv_current_marker, - options->track->margin, - context->frame_width, - context->frame_height)) - { - continue; - } - - libmv_tracked_marker = libmv_current_marker; - libmv_tracked_marker.frame = frame + frame_delta; - - if (options->use_keyframe_match) { - libmv_tracked_marker.reference_frame = - libmv_current_marker.reference_frame; - libmv_autoTrackGetMarker(context->autotrack, - options->clip_index, - libmv_tracked_marker.reference_frame, - options->track_index, - &libmv_reference_marker); - } - else { - libmv_tracked_marker.reference_frame = frame; - libmv_reference_marker = libmv_current_marker; - } - - if (libmv_autoTrackMarker(context->autotrack, - &options->track_region_options, - &libmv_tracked_marker, - &libmv_result)) - { - BLI_spin_lock(&context->spin_lock); - libmv_autoTrackAddMarker(context->autotrack, - &libmv_tracked_marker); - BLI_spin_unlock(&context->spin_lock); - } - else { - options->is_failed = true; - options->failed_frame = frame + frame_delta; - } - ok = true; + /* Check whether we've got marker to sync with. */ + if (!has_marker) { + continue; + } + /* Check whether marker is going outside of allowed frame margin. */ + if (!tracking_check_marker_margin(&libmv_current_marker, + options->track->margin, + context->frame_width, + context->frame_height)) + { + continue; + } + libmv_tracked_marker = libmv_current_marker; + libmv_tracked_marker.frame = frame + frame_delta; + /* Update reference frame. */ + if (options->use_keyframe_match) { + libmv_tracked_marker.reference_frame = + libmv_current_marker.reference_frame; + libmv_autoTrackGetMarker(context->autotrack, + options->clip_index, + libmv_tracked_marker.reference_frame, + options->track_index, + &libmv_reference_marker); } + else { + libmv_tracked_marker.reference_frame = frame; + libmv_reference_marker = libmv_current_marker; + } + /* Perform actual tracking. */ + if (libmv_autoTrackMarker(context->autotrack, + &options->track_region_options, + &libmv_tracked_marker, + &libmv_result)) + { + BLI_spin_lock(&context->spin_lock); + libmv_autoTrackAddMarker(context->autotrack, &libmv_tracked_marker); + BLI_spin_unlock(&context->spin_lock); + } + else { + options->is_failed = true; + options->failed_frame = frame + frame_delta; + } + ok = true; } - + /* Advance the frame. */ BLI_spin_lock(&context->spin_lock); context->user.framenr += frame_delta; BLI_spin_unlock(&context->spin_lock); - return ok; } diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index a95399562d5..d8e98291117 100644 --- a/source/blender/blenkernel/intern/tracking_util.c +++ b/source/blender/blenkernel/intern/tracking_util.c @@ -58,6 +58,15 @@ #include "libmv-capi.h" +/* Uncomment this to have caching-specific debug prints. */ +// #define DEBUG_CACHE + +#ifdef DEBUG_CACHE +# define CACHE_PRINTF(...) printf(__VA_ARGS__) +#else +# define CACHE_PRINTF(...) +#endif + /*********************** Tracks map *************************/ TracksMap *tracks_map_new(const char *object_name, bool is_camera, int num_tracks, int customdata_size) @@ -523,6 +532,8 @@ typedef struct AccessCacheKey { int frame; int downscale; libmv_InputMode input_mode; + bool has_region; + float region_min[2], region_max[2]; int64_t transform_key; } AccessCacheKey; @@ -537,23 +548,44 @@ static bool accesscache_hashcmp(const void *a_v, const void *b_v) { const AccessCacheKey *a = (const AccessCacheKey *) a_v; const AccessCacheKey *b = (const AccessCacheKey *) b_v; - -#define COMPARE_FIELD(field) - { \ - if (a->clip_index != b->clip_index) { \ - return false; \ - } \ - } (void) 0 - - COMPARE_FIELD(clip_index); - COMPARE_FIELD(frame); - COMPARE_FIELD(downscale); - COMPARE_FIELD(input_mode); - COMPARE_FIELD(transform_key); - -#undef COMPARE_FIELD - - return true; + if (a->clip_index != b->clip_index || + a->frame != b->frame || + a->downscale != b->downscale || + a->input_mode != b->input_mode || + a->has_region != b->has_region || + a->transform_key != b->transform_key) + { + return true; + } + /* If there is region applied, compare it. */ + if (a->has_region) { + if (!equals_v2v2(a->region_min, b->region_min) || + !equals_v2v2(a->region_max, b->region_max)) + { + return true; + } + } + return false; +} + +static void accesscache_construct_key(AccessCacheKey *key, + int clip_index, + int frame, + libmv_InputMode input_mode, + int downscale, + const libmv_Region *region, + int64_t transform_key) +{ + key->clip_index = clip_index; + key->frame = frame; + key->input_mode = input_mode; + key->downscale = downscale; + key->has_region = (region != NULL); + if (key->has_region) { + copy_v2_v2(key->region_min, region->min); + copy_v2_v2(key->region_max, region->max); + } + key->transform_key = transform_key; } static void accesscache_put(TrackingImageAccessor *accessor, @@ -561,15 +593,13 @@ static void accesscache_put(TrackingImageAccessor *accessor, int frame, libmv_InputMode input_mode, int downscale, + const libmv_Region *region, int64_t transform_key, ImBuf *ibuf) { AccessCacheKey key; - key.clip_index = clip_index; - key.frame = frame; - key.input_mode = input_mode; - key.downscale = downscale; - key.transform_key = transform_key; + accesscache_construct_key(&key, clip_index, frame, input_mode, downscale, + region, transform_key); IMB_moviecache_put(accessor->cache, &key, ibuf); } @@ -578,14 +608,12 @@ static ImBuf *accesscache_get(TrackingImageAccessor *accessor, int frame, libmv_InputMode input_mode, int downscale, + const libmv_Region *region, int64_t transform_key) { AccessCacheKey key; - key.clip_index = clip_index; - key.frame = frame; - key.input_mode = input_mode; - key.downscale = downscale; - key.transform_key = transform_key; + accesscache_construct_key(&key, clip_index, frame, input_mode, downscale, + region, transform_key); return IMB_moviecache_get(accessor->cache, &key); } @@ -674,29 +702,37 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, { ImBuf *ibuf, *orig_ibuf, *final_ibuf; int64_t transform_key = 0; - if (transform != NULL) { transform_key = libmv_frameAccessorgetTransformKey(transform); } - /* First try to get fully processed image from the cache. */ + BLI_spin_lock(&accessor->cache_lock); ibuf = accesscache_get(accessor, clip_index, frame, input_mode, downscale, + region, transform_key); + BLI_spin_unlock(&accessor->cache_lock); if (ibuf != NULL) { + CACHE_PRINTF("Used cached buffer for frame %d\n", frame); + /* This is a little heuristic here: if we re-used image once, this is + * a high probability of the image to be related to a keyframe matched + * reference image. Those images we don't want to be thrown away because + * if we toss them out we'll be re-calculating them at the next + * iteration. + */ + ibuf->userflags |= IB_PERSISTENT; return ibuf; } - + CACHE_PRINTF("Calculate new buffer for frame %d\n", frame); /* And now we do postprocessing of the original frame. */ orig_ibuf = accessor_get_preprocessed_ibuf(accessor, clip_index, frame); - if (orig_ibuf == NULL) { return NULL; } - + /* Cut a region if requested. */ if (region != NULL) { int width = region->max[0] - region->min[0], height = region->max[1] - region->min[1]; @@ -756,7 +792,7 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, BLI_unlock_thread(LOCK_MOVIECLIP); final_ibuf = orig_ibuf; } - + /* Downscale if needed. */ if (downscale > 0) { if (final_ibuf == orig_ibuf) { final_ibuf = IMB_dupImBuf(orig_ibuf); @@ -765,7 +801,7 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, orig_ibuf->x / (1 << downscale), orig_ibuf->y / (1 << downscale)); } - + /* Apply possible transformation. */ if (transform != NULL) { libmv_FloatImage input_image, output_image; ibuf_to_float_image(final_ibuf, &input_image); @@ -778,12 +814,13 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, final_ibuf = float_image_to_ibuf(&output_image); libmv_floatImageDestroy(&output_image); } - + /* Transform number of channels. */ if (input_mode == LIBMV_IMAGE_MODE_RGBA) { BLI_assert(orig_ibuf->channels == 3 || orig_ibuf->channels == 4); /* pass */ } else /* if (input_mode == LIBMV_IMAGE_MODE_MONO) */ { + BLI_assert(input_mode == LIBMV_IMAGE_MODE_MONO); if (final_ibuf->channels != 1) { ImBuf *grayscale_ibuf = make_grayscale_ibuf_copy(final_ibuf); if (final_ibuf != orig_ibuf) { @@ -793,37 +830,25 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, final_ibuf = grayscale_ibuf; } } - - /* it's possible processing still didn't happen at this point, + /* It's possible processing still didn't happen at this point, * but we really need a copy of the buffer to be transformed * and to be put to the cache. */ if (final_ibuf == orig_ibuf) { final_ibuf = IMB_dupImBuf(orig_ibuf); } - IMB_freeImBuf(orig_ibuf); - - /* We put postprocessed frame to the cache always for now, - * not the smartest thing in the world, but who cares at this point. - */ - - /* TODO(sergey): Disable cache for now, because we don't store region - * in the cache key and can't check whether cached version is usable for - * us or not. - * - * Need to think better about what to cache and when. - */ - if (false) { - accesscache_put(accessor, - clip_index, - frame, - input_mode, - downscale, - transform_key, - final_ibuf); - } - + BLI_spin_lock(&accessor->cache_lock); + /* Put final buffer to cache. */ + accesscache_put(accessor, + clip_index, + frame, + input_mode, + downscale, + region, + transform_key, + final_ibuf); + BLI_spin_unlock(&accessor->cache_lock); return final_ibuf; } @@ -876,7 +901,7 @@ static void accessor_release_image_callback(libmv_CacheKey cache_key) } static libmv_CacheKey accessor_get_mask_for_track_callback( - libmv_FrameAccessorUserData* user_data, + libmv_FrameAccessorUserData *user_data, int clip_index, int frame, int track_index, @@ -958,6 +983,8 @@ TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR accessor_get_mask_for_track_callback, accessor_release_mask_callback); + BLI_spin_init(&accessor->cache_lock); + return accessor; } @@ -965,5 +992,6 @@ void tracking_image_accessor_destroy(TrackingImageAccessor *accessor) { IMB_moviecache_free(accessor->cache); libmv_FrameAccessorDestroy(accessor->libmv_accessor); + BLI_spin_end(&accessor->cache_lock); MEM_freeN(accessor); } diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index c0a373395dc..8606da0743b 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -372,6 +372,12 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, con value_conv = value / unit->scalar; + /* Adjust precision to expected number of significant digits. + * Note that here, we shall not have to worry about very big/small numbers, units are expected to replace + * 'scientific notation' in those cases. */ + prec -= integer_digits_d(value_conv); + CLAMP(prec, 0, 6); + /* Convert to a string */ len = BLI_snprintf_rlen(str, len_max, "%.*f", prec, value_conv); @@ -442,12 +448,15 @@ size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system size_t i; i = unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0'); + prec -= integer_digits_d(value_a / unit_b->scalar) - integer_digits_d(value_b / unit_b->scalar); + prec = max_ii(prec, 0); + /* is there enough space for at least 1 char of the next unit? */ if (i + 2 < len_max) { str[i++] = ' '; /* use low precision since this is a smaller unit */ - i += unit_as_string(str + i, len_max - i, value_b, prec ? 1 : 0, usys, unit_b, '\0'); + i += unit_as_string(str + i, len_max - i, value_b, prec, usys, unit_b, '\0'); } return i; } diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 363c36e644d..e79b06a44fe 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -112,43 +112,59 @@ World *add_world(Main *bmain, const char *name) { World *wrld; - wrld = BKE_libblock_alloc(bmain, ID_WO, name); + wrld = BKE_libblock_alloc(bmain, ID_WO, name, 0); BKE_world_init(wrld); return wrld; } -World *BKE_world_copy(Main *bmain, const World *wrld) +/** + * Only copy internal data of World ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_world_copy_data(Main *bmain, World *wrld_dst, const World *wrld_src, const int flag) { - World *wrldn; - int a; - - wrldn = BKE_libblock_copy(bmain, &wrld->id); - - for (a = 0; a < MAX_MTEX; a++) { - if (wrld->mtex[a]) { - wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), "BKE_world_copy"); - memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex)); - id_us_plus((ID *)wrldn->mtex[a]->tex); + for (int a = 0; a < MAX_MTEX; a++) { + if (wrld_src->mtex[a]) { + wrld_dst->mtex[a] = MEM_dupallocN(wrld_src->mtex[a]); } } - if (wrld->nodetree) { - wrldn->nodetree = ntreeCopyTree(bmain, wrld->nodetree); + if (wrld_src->nodetree) { + BKE_id_copy_ex(bmain, (ID *)wrld_src->nodetree, (ID **)&wrld_dst->nodetree, flag, false); } - - BKE_previewimg_id_copy(&wrldn->id, &wrld->id); - BLI_listbase_clear(&wrldn->gpumaterial); + BLI_listbase_clear(&wrld_dst->gpumaterial); - BKE_id_copy_ensure_local(bmain, &wrld->id, &wrldn->id); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { + BKE_previewimg_id_copy(&wrld_dst->id, &wrld_src->id); + } + else { + wrld_dst->preview = NULL; + } +} - return wrldn; +World *BKE_world_copy(Main *bmain, const World *wrld) +{ + World *wrld_copy; + BKE_id_copy_ex(bmain, &wrld->id, (ID **)&wrld_copy, 0, false); + return wrld_copy; } World *localize_world(World *wrld) { + /* TODO replace with something like + * World *wrld_copy; + * BKE_id_copy_ex(bmain, &wrld->id, (ID **)&wrld_copy, LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT, false); + * return wrld_copy; + * + * ... Once f*** nodes are fully converted to that too :( */ + World *wrldn; int a; diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index 89b2caa5ac7..2fb4ed03603 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -80,10 +80,6 @@ static void *context_create_avi(void); static void context_free_avi(void *context_v); #endif /* WITH_AVI */ -#ifdef WITH_QUICKTIME -# include "quicktime_export.h" -#endif - #ifdef WITH_FFMPEG # include "BKE_writeffmpeg.h" #endif @@ -115,16 +111,6 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) #endif /* do the platform specific handles */ -#ifdef WITH_QUICKTIME - if (imtype == R_IMF_IMTYPE_QUICKTIME) { - mh.start_movie = start_qt; - mh.append_movie = append_qt; - mh.end_movie = end_qt; - mh.get_movie_path = filepath_qt; - mh.context_create = context_create_qt; - mh.context_free = context_free_qt; - } -#endif #ifdef WITH_FFMPEG if (ELEM(imtype, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_XVID, R_IMF_IMTYPE_THEORA)) { mh.start_movie = BKE_ffmpeg_start; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 156b74f5c3d..a19e4142894 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -681,6 +681,7 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int /* xasp & yasp got float lately... */ st->sample_aspect_ratio = c->sample_aspect_ratio = av_d2q(((double) rd->xasp / (double) rd->yasp), 255); + st->avg_frame_rate = av_inv_q(c->time_base); set_ffmpeg_properties(rd, c, "video", &opts); diff --git a/source/blender/blenkernel/tracking_private.h b/source/blender/blenkernel/tracking_private.h index 1a68a1cac6a..07236fb2096 100644 --- a/source/blender/blenkernel/tracking_private.h +++ b/source/blender/blenkernel/tracking_private.h @@ -125,6 +125,7 @@ typedef struct TrackingImageAccessor { int num_tracks; int start_frame; struct libmv_FrameAccessor *libmv_accessor; + SpinLock cache_lock; } TrackingImageAccessor; TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR_CLIP], diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h index 74f24c808ff..3ffca818c0d 100644 --- a/source/blender/blenlib/BLI_array.h +++ b/source/blender/blenlib/BLI_array.h @@ -135,11 +135,12 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, #define BLI_array_append_ret(arr) \ (BLI_array_reserve(arr, 1), &arr[(_##arr##_count++)]) -#define BLI_array_free(arr) \ +#define BLI_array_free(arr) { \ if (arr && (char *)arr != _##arr##_static) { \ BLI_array_fake_user(arr); \ MEM_freeN(arr); \ - } (void)0 + } \ +} ((void)0) #define BLI_array_pop(arr) ( \ (arr && _##arr##_count) ? \ diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h index 01fc9d70207..0726e3bb343 100644 --- a/source/blender/blenlib/BLI_compiler_compat.h +++ b/source/blender/blenlib/BLI_compiler_compat.h @@ -48,12 +48,7 @@ extern "C++" { #if defined(_MSC_VER) # define BLI_INLINE static __forceinline #else -# if (defined(__APPLE__) && defined(__ppc__)) -/* static inline __attribute__ here breaks osx ppc gcc42 build */ -# define BLI_INLINE static __attribute__((always_inline)) __attribute__((__unused__)) -# else -# define BLI_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__)) -# endif +# define BLI_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__)) #endif #endif /* __BLI_COMPILER_COMPAT_H__ */ diff --git a/source/blender/blenlib/BLI_dial.h b/source/blender/blenlib/BLI_dial.h index ad7680fe03e..71ab57bb61a 100644 --- a/source/blender/blenlib/BLI_dial.h +++ b/source/blender/blenlib/BLI_dial.h @@ -52,8 +52,8 @@ typedef struct Dial Dial; -Dial *BLI_dial_initialize(float start_position[2], float threshold); +Dial *BLI_dial_initialize(const float start_position[2], float threshold); -float BLI_dial_angle(Dial *dial, float current_position[2]); +float BLI_dial_angle(Dial *dial, const float current_position[2]); #endif /* __BLI_DIAL_H__ */ diff --git a/source/blender/blenlib/BLI_fnmatch.h b/source/blender/blenlib/BLI_fnmatch.h index f69f5b39869..06fa5048622 100644 --- a/source/blender/blenlib/BLI_fnmatch.h +++ b/source/blender/blenlib/BLI_fnmatch.h @@ -28,7 +28,7 @@ extern "C" { #endif -#if defined WIN32 && !defined _LIBC || defined __sun +#if defined WIN32 && !defined _LIBC #if defined(__cplusplus) || (defined(__STDC__) && __STDC__) #undef __P @@ -53,7 +53,7 @@ extern "C" { #define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ #define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ -#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined(_GNU_SOURCE) || defined(__SUNPRO_C) +#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined(_GNU_SOURCE) #define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ #define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ #define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ @@ -72,7 +72,7 @@ extern int fnmatch __P((const char *__pattern, const char *__string, # define _GNU_SOURCE # endif # include <fnmatch.h> -#endif /* defined WIN32 && !defined _LIBC || defined __sun */ +#endif /* defined WIN32 && !defined _LIBC */ #ifdef __cplusplus } diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index 7cf3e97bdc9..b42a36a3567 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -43,7 +43,7 @@ extern "C" { #ifndef GHASH_INTERNAL_API # ifdef __GNUC__ # undef _GHASH_INTERNAL_ATTR -# define _GHASH_INTERNAL_ATTR __attribute__ ((deprecated)) +# define _GHASH_INTERNAL_ATTR __attribute__ ((deprecated)) /* not deprecated, just private. */ # endif #endif @@ -90,6 +90,7 @@ void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfre void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve); void BLI_ghash_insert(GHash *gh, void *key, void *val); bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); +void *BLI_ghash_replace_key(GHash *gh, void *key); void *BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT; void *BLI_ghash_lookup_default(GHash *gh, const void *key, void *val_default) ATTR_WARN_UNUSED_RESULT; void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT; @@ -248,6 +249,7 @@ void BLI_gset_insert(GSet *gh, void *key); bool BLI_gset_add(GSet *gs, void *key); bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key); bool BLI_gset_reinsert(GSet *gh, void *key, GSetKeyFreeFP keyfreefp); +void *BLI_gset_replace_key(GSet *gs, void *key); bool BLI_gset_haskey(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT; bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp); diff --git a/source/blender/blenlib/BLI_kdtree.h b/source/blender/blenlib/BLI_kdtree.h index aa54e1c823c..18908f8c551 100644 --- a/source/blender/blenlib/BLI_kdtree.h +++ b/source/blender/blenlib/BLI_kdtree.h @@ -66,6 +66,10 @@ void BLI_kdtree_range_search_cb( const KDTree *tree, const float co[3], float range, bool (*search_cb)(void *user_data, int index, const float co[3], float dist_sq), void *user_data); +int BLI_kdtree_calc_duplicates_fast( + const KDTree *tree, const float range, bool use_index_order, + int *doubles); + /* Normal use is deprecated */ /* remove __normal functions when last users drop */ int BLI_kdtree_find_nearest_n__normal( diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h index 0126e30d900..e6a72298ae7 100644 --- a/source/blender/blenlib/BLI_math_base.h +++ b/source/blender/blenlib/BLI_math_base.h @@ -138,6 +138,9 @@ MINLINE int signum_i(float a); MINLINE float power_of_2(float f); +MINLINE int integer_digits_f(const float f); +MINLINE int integer_digits_d(const double d); + /* these don't really fit anywhere but were being copied about a lot */ MINLINE int is_power_of_2_i(int n); MINLINE int power_of_2_max_i(int n); @@ -146,10 +149,37 @@ MINLINE int power_of_2_min_i(int n); MINLINE unsigned int power_of_2_max_u(unsigned int x); MINLINE unsigned int power_of_2_min_u(unsigned int x); -MINLINE int iroundf(float a); MINLINE int divide_round_i(int a, int b); MINLINE int mod_i(int i, int n); +MINLINE signed char round_fl_to_char(float a); +MINLINE unsigned char round_fl_to_uchar(float a); +MINLINE short round_fl_to_short(float a); +MINLINE unsigned short round_fl_to_ushort(float a); +MINLINE int round_fl_to_int(float a); +MINLINE unsigned int round_fl_to_uint(float a); + +MINLINE signed char round_db_to_char(double a); +MINLINE unsigned char round_db_to_uchar(double a); +MINLINE short round_db_to_short(double a); +MINLINE unsigned short round_db_to_ushort(double a); +MINLINE int round_db_to_int(double a); +MINLINE unsigned int round_db_to_uint(double a); + +MINLINE signed char round_fl_to_char_clamp(float a); +MINLINE unsigned char round_fl_to_uchar_clamp(float a); +MINLINE short round_fl_to_short_clamp(float a); +MINLINE unsigned short round_fl_to_ushort_clamp(float a); +MINLINE int round_fl_to_int_clamp(float a); +MINLINE unsigned int round_fl_to_uint_clamp(float a); + +MINLINE signed char round_db_to_char_clamp(double a); +MINLINE unsigned char round_db_to_uchar_clamp(double a); +MINLINE short round_db_to_short_clamp(double a); +MINLINE unsigned short round_db_to_ushort_clamp(double a); +MINLINE int round_db_to_int_clamp(double a); +MINLINE unsigned int round_db_to_uint_clamp(double a); + int pow_i(int base, int exp); double double_round(double x, int ndigits); diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 18bba33cdfa..2893da9bce8 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -166,8 +166,14 @@ void limit_dist_v3(float v1[3], float v2[3], const float dist); int isect_seg_seg_v2(const float a1[2], const float a2[2], const float b1[2], const float b2[2]); int isect_seg_seg_v2_int(const int a1[2], const int a2[2], const int b1[2], const int b2[2]); -int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float vi[2]); -bool isect_seg_seg_v2_simple(const float v1[2], const float v2[2], const float v3[2], const float v4[2]); +int isect_seg_seg_v2_point_ex( + const float v0[2], const float v1[2], const float v2[2], const float v3[2], const float endpoint_bias, + float vi[2]); +int isect_seg_seg_v2_point( + const float v0[2], const float v1[2], const float v2[2], const float v3[2], + float vi[2]); +bool isect_seg_seg_v2_simple( + const float v1[2], const float v2[2], const float v3[2], const float v4[2]); int isect_line_sphere_v3(const float l1[3], const float l2[3], const float sp[3], const float r, float r_p1[3], float r_p2[3]); int isect_line_sphere_v2(const float l1[2], const float l2[2], const float sp[2], const float r, float r_p1[2], float r_p2[2]); diff --git a/source/blender/blenlib/BLI_math_inline.h b/source/blender/blenlib/BLI_math_inline.h index 840cf24f8cf..383abda5b2f 100644 --- a/source/blender/blenlib/BLI_math_inline.h +++ b/source/blender/blenlib/BLI_math_inline.h @@ -44,12 +44,7 @@ extern "C" { # define MALWAYS_INLINE MINLINE # else # define MINLINE static inline -# if (defined(__APPLE__) && defined(__ppc__)) - /* static inline __attribute__ here breaks osx ppc gcc42 build */ -# define MALWAYS_INLINE static __attribute__((always_inline)) __attribute__((unused)) -# else -# define MALWAYS_INLINE static inline __attribute__((always_inline)) __attribute__((unused)) -# endif +# define MALWAYS_INLINE static inline __attribute__((always_inline)) __attribute__((unused)) # endif #else # define MINLINE diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 43f414f376a..4fdb33926a2 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -299,6 +299,8 @@ void angle_poly_v3(float *angles, const float *verts[3], int len); void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2]); void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3]); +void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2]); +void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3]); void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3]); void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2]); void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3]); diff --git a/source/blender/blenlib/BLI_polyfill2d_beautify.h b/source/blender/blenlib/BLI_polyfill2d_beautify.h index 20e53b080fe..29a900200bb 100644 --- a/source/blender/blenlib/BLI_polyfill2d_beautify.h +++ b/source/blender/blenlib/BLI_polyfill2d_beautify.h @@ -33,8 +33,12 @@ void BLI_polyfill_beautify( /* structs for reuse */ struct MemArena *arena, struct Heap *eheap, struct EdgeHash *eh); -float BLI_polyfill_beautify_quad_rotate_calc( - const float v1[2], const float v2[2], const float v3[2], const float v4[2]); +float BLI_polyfill_beautify_quad_rotate_calc_ex( + const float v1[2], const float v2[2], const float v3[2], const float v4[2], + const bool lock_degenerate); +#define BLI_polyfill_beautify_quad_rotate_calc(v1, v2, v3, v4) \ + BLI_polyfill_beautify_quad_rotate_calc_ex(v1, v2, v3, v4, false) + /* avoid realloc's when creating new structures for polyfill ngons */ #define BLI_POLYFILL_ALLOC_NGON_RESERVE 64 diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h index 21b9c75ac35..471d875c9af 100644 --- a/source/blender/blenlib/BLI_rect.h +++ b/source/blender/blenlib/BLI_rect.h @@ -55,6 +55,8 @@ void BLI_rcti_do_minmax_v(struct rcti *rect, const int xy[2]); void BLI_rctf_do_minmax_v(struct rctf *rect, const float xy[2]); void BLI_rctf_transform_pt_v(const rctf *dst, const rctf *src, float xy_dst[2], const float xy_src[2]); +void BLI_rctf_transform_calc_m4_pivot_min_ex(const rctf *dst, const rctf *src, float matrix[4][4], uint x, uint y); +void BLI_rctf_transform_calc_m4_pivot_min(const rctf *dst, const rctf *src, float matrix[4][4]); void BLI_rctf_translate(struct rctf *rect, float x, float y); void BLI_rcti_translate(struct rcti *rect, int x, int y); diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h index bb19ed574bb..5701bce51ea 100644 --- a/source/blender/blenlib/BLI_string_utils.h +++ b/source/blender/blenlib/BLI_string_utils.h @@ -39,6 +39,7 @@ extern "C" { #endif #include "BLI_compiler_attrs.h" +#include "BLI_utildefines_variadic.h" struct ListBase; @@ -49,6 +50,24 @@ size_t BLI_split_name_num(char *left, int *nr, const char *name, const char deli void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len); void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len); +/* Join strings, return newly allocated string. */ +char *BLI_string_join_arrayN( + const char *strings[], uint strings_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +char *BLI_string_join_array_by_sep_charN( + char sep, const char *strings[], uint strings_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +char *BLI_string_join_array_by_sep_char_with_tableN( + char sep, char *table[], const char *strings[], uint strings_len) ATTR_NONNULL(); +/* Take multiple arguments, pass as (array, length). */ +#define BLI_string_joinN(...) \ + BLI_string_join_arrayN( \ + ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) +#define BLI_string_join_by_sep_charN(sep, ...) \ + BLI_string_join_array_by_sep_charN( \ + sep, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) +#define BLI_string_join_by_sep_char_with_tableN(sep, table, ...) \ + BLI_string_join_array_by_sep_char_with_tableN( \ + sep, table, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) + void BLI_string_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len); bool BLI_uniquename_cb( diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index 746eb922c65..66c7f247f61 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -39,35 +39,12 @@ extern "C" { /* avoid many includes for now */ #include "BLI_sys_types.h" #include "BLI_compiler_compat.h" +#include "BLI_utildefines_variadic.h" #ifndef NDEBUG /* for BLI_assert */ #include <stdio.h> #endif - -/* varargs macros (keep first so others can use) */ -/* --- internal helpers --- */ -#define _VA_NARGS_GLUE(x, y) x y -#define _VA_NARGS_RETURN_COUNT(\ - _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, \ - _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, \ - _33_, _34_, _35_, _36_, _37_, _38_, _39_, _40_, _41_, _42_, _43_, _44_, _45_, _46_, _47_, _48_, \ - _49_, _50_, _51_, _52_, _53_, _54_, _55_, _56_, _57_, _58_, _59_, _60_, _61_, _62_, _63_, _64_, \ - count, ...) count -#define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args -/* 64 args max */ -#define _VA_NARGS_COUNT(...) _VA_NARGS_EXPAND((__VA_ARGS__, \ - 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, \ - 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, \ - 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \ - 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) -#define _VA_NARGS_OVERLOAD_MACRO2(name, count) name##count -#define _VA_NARGS_OVERLOAD_MACRO1(name, count) _VA_NARGS_OVERLOAD_MACRO2(name, count) -#define _VA_NARGS_OVERLOAD_MACRO(name, count) _VA_NARGS_OVERLOAD_MACRO1(name, count) -/* --- expose for re-use --- */ -#define VA_NARGS_CALL_OVERLOAD(name, ...) \ - _VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, _VA_NARGS_COUNT(__VA_ARGS__)), (__VA_ARGS__)) - /* useful for finding bad use of min/max */ #if 0 /* gcc only */ diff --git a/source/blender/blenlib/BLI_utildefines_iter.h b/source/blender/blenlib/BLI_utildefines_iter.h new file mode 100644 index 00000000000..094c1a4b3dc --- /dev/null +++ b/source/blender/blenlib/BLI_utildefines_iter.h @@ -0,0 +1,52 @@ +/* + * ***** 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_UTILDEFINES_ITER_H__ +#define __BLI_UTILDEFINES_ITER_H__ + +/** \file BLI_utildefines_iter.h + * \ingroup bli + * + * General looping helpers, use `BLI_FOREACH` prefix. + */ + +/** + * Even value distribution. + * + * \a src must be larger than \a dst, + * \a dst defines the number of iterations, their values are evenly spaced. + * + * The following pairs represent (src, dst) arguments and the values they loop over. + * <pre> + * (19, 4) -> [2, 7, 11. 16] + * (100, 5) -> [9, 29, 49, 69, 89] + * (100, 3) -> [16, 49, 83] + * (100, 100) -> [0..99] + * </pre> + * \note this is mainly useful for numbers that might not divide evenly into eachother. + */ +#define BLI_FOREACH_SPARSE_RANGE(src, dst, i) \ +for (int _src = (src), _src2 = _src * 2, _dst2 = (dst) * 2, _error = _dst2 - _src, i = 0, _delta; \ + ((void)(_delta = divide_floor_i(_error, _dst2)), \ + (void)(i -= _delta), \ + (i < _src)); \ + _error -= (_delta * _dst2) + _src2) + +#endif /* __BLI_UTILDEFINES_ITER_H__ */ diff --git a/source/blender/blenlib/BLI_stackdefines.h b/source/blender/blenlib/BLI_utildefines_stack.h index 42b11eb9a2b..15b0029e727 100644 --- a/source/blender/blenlib/BLI_stackdefines.h +++ b/source/blender/blenlib/BLI_utildefines_stack.h @@ -18,10 +18,10 @@ * ***** END GPL LICENSE BLOCK ***** */ -#ifndef __BLI_STACKDEFINES_H__ -#define __BLI_STACKDEFINES_H__ +#ifndef __BLI_UTILDEFINES_STACK_H__ +#define __BLI_UTILDEFINES_STACK_H__ -/** \file BLI_stackdefines.h +/** \file BLI_utildefines_stack.h * \ingroup bli * * Macro's for a simple array based stack @@ -86,4 +86,4 @@ } ((void)0) #endif -#endif /* __BLI_STACKDEFINES_H__ */ +#endif /* __BLI_UTILDEFINES_STACK_H__ */ diff --git a/source/blender/blenlib/BLI_utildefines_variadic.h b/source/blender/blenlib/BLI_utildefines_variadic.h new file mode 100644 index 00000000000..7c15754fd83 --- /dev/null +++ b/source/blender/blenlib/BLI_utildefines_variadic.h @@ -0,0 +1,50 @@ +/* + * ***** 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_UTILDEFINES_VARIADIC_H__ +#define __BLI_UTILDEFINES_VARIADIC_H__ + +/** \file BLI_utildefines_variadic.h + * \ingroup bli + */ + +/* --- internal helpers --- */ +#define _VA_NARGS_GLUE(x, y) x y +#define _VA_NARGS_RETURN_COUNT(\ + _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, \ + _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, \ + _33_, _34_, _35_, _36_, _37_, _38_, _39_, _40_, _41_, _42_, _43_, _44_, _45_, _46_, _47_, _48_, \ + _49_, _50_, _51_, _52_, _53_, _54_, _55_, _56_, _57_, _58_, _59_, _60_, _61_, _62_, _63_, _64_, \ + count, ...) count +#define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args +#define _VA_NARGS_OVERLOAD_MACRO2(name, count) name##count +#define _VA_NARGS_OVERLOAD_MACRO1(name, count) _VA_NARGS_OVERLOAD_MACRO2(name, count) +#define _VA_NARGS_OVERLOAD_MACRO(name, count) _VA_NARGS_OVERLOAD_MACRO1(name, count) +/* --- expose for re-use --- */ +/* 64 args max */ +#define VA_NARGS_COUNT(...) _VA_NARGS_EXPAND((__VA_ARGS__, \ + 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, \ + 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, \ + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \ + 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) +#define VA_NARGS_CALL_OVERLOAD(name, ...) \ + _VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, VA_NARGS_COUNT(__VA_ARGS__)), (__VA_ARGS__)) + +#endif /* __BLI_UTILDEFINES_VARIADIC_H__ */ diff --git a/source/blender/blenlib/BLI_vfontdata.h b/source/blender/blenlib/BLI_vfontdata.h index 8a7079b6c5f..0cd50319a33 100644 --- a/source/blender/blenlib/BLI_vfontdata.h +++ b/source/blender/blenlib/BLI_vfontdata.h @@ -52,8 +52,10 @@ typedef struct VChar { } VChar; VFontData *BLI_vfontdata_from_freetypefont(struct PackedFile *pf); +VFontData *BLI_vfontdata_copy(const VFontData *vfont_src, const int flag); VChar *BLI_vfontchar_from_freetypefont(struct VFont *vfont, unsigned long character); +VChar *BLI_vfontchar_copy(const VChar *vchar_src, const int flag); #endif diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index fcb02a86a84..61a1241cd8f 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -192,7 +192,6 @@ set(SRC BLI_sort.h BLI_sort_utils.h BLI_stack.h - BLI_stackdefines.h BLI_strict_flags.h BLI_string.h BLI_string_cursor_utf8.h @@ -204,6 +203,9 @@ set(SRC BLI_threads.h BLI_timecode.h BLI_utildefines.h + BLI_utildefines_iter.h + BLI_utildefines_stack.h + BLI_utildefines_variadic.h BLI_uvproject.h BLI_vfontdata.h BLI_voronoi.h diff --git a/source/blender/blenlib/intern/BLI_dial.c b/source/blender/blenlib/intern/BLI_dial.c index cfbb52847fd..89f18fa10b4 100644 --- a/source/blender/blenlib/intern/BLI_dial.c +++ b/source/blender/blenlib/intern/BLI_dial.c @@ -46,7 +46,7 @@ struct Dial { }; -Dial *BLI_dial_initialize(float start_position[2], float threshold) +Dial *BLI_dial_initialize(const float start_position[2], float threshold) { Dial *dial = MEM_callocN(sizeof(Dial), "dial"); @@ -56,7 +56,7 @@ Dial *BLI_dial_initialize(float start_position[2], float threshold) return dial; } -float BLI_dial_angle(Dial *dial, float current_position[2]) +float BLI_dial_angle(Dial *dial, const float current_position[2]) { float current_direction[2]; diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index 69dee12c713..1b2a27e33d8 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -763,6 +763,28 @@ bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreef } /** + * Replaces the key of an item in the \a gh. + * + * Use when a key is re-allocated or it's memory location is changed. + * + * \returns The previous key or NULL if not found, the caller may free if it's needed. + */ +void *BLI_ghash_replace_key(GHash *gh, void *key) +{ + const unsigned int hash = ghash_keyhash(gh, key); + const unsigned int bucket_index = ghash_bucket_index(gh, hash); + GHashEntry *e = (GHashEntry *)ghash_lookup_entry_ex(gh, key, bucket_index); + if (e != NULL) { + void *key_prev = e->e.key; + e->e.key = key; + return key_prev; + } + else { + return NULL; + } +} + +/** * Lookup the value of \a key in \a gh. * * \param key The key to lookup. @@ -1434,6 +1456,18 @@ bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp) return ghash_insert_safe_keyonly((GHash *)gs, key, true, keyfreefp); } +/** + * Replaces the key to the set if it's found. + * Matching #BLI_ghash_replace_key + * + * \returns The old key or NULL if not found. + */ +void *BLI_gset_replace_key(GSet *gs, void *key) +{ + return BLI_ghash_replace_key((GHash *)gs, key); +} + + bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp) { return BLI_ghash_remove((GHash *)gs, key, keyfreefp, NULL); diff --git a/source/blender/blenlib/intern/BLI_kdtree.c b/source/blender/blenlib/intern/BLI_kdtree.c index a81f9b28b83..84ac339cc4d 100644 --- a/source/blender/blenlib/intern/BLI_kdtree.c +++ b/source/blender/blenlib/intern/BLI_kdtree.c @@ -674,3 +674,123 @@ finally: if (stack != defaultstack) MEM_freeN(stack); } + +/** + * Use when we want to loop over nodes ordered by index. + * Requires indices to be aligned with nodes. + */ +static uint *kdtree_order(const KDTree *tree) +{ + const KDTreeNode *nodes = tree->nodes; + uint *order = MEM_mallocN(sizeof(uint) * tree->totnode, __func__); + for (uint i = 0; i < tree->totnode; i++) { + order[nodes[i].index] = i; + } + return order; +} + +/* -------------------------------------------------------------------- */ +/** \name BLI_kdtree_calc_duplicates_fast + * \{ */ + +struct DeDuplicateParams { + /* Static */ + const KDTreeNode *nodes; + float range; + float range_sq; + int *duplicates; + int *duplicates_found; + + /* Per Search */ + float search_co[3]; + int search; +}; + +static void deduplicate_recursive(const struct DeDuplicateParams *p, uint i) +{ + const KDTreeNode *node = &p->nodes[i]; + if (p->search_co[node->d] + p->range <= node->co[node->d]) { + if (node->left != KD_NODE_UNSET) { + deduplicate_recursive(p, node->left); + } + } + else if (p->search_co[node->d] - p->range >= node->co[node->d]) { + if (node->right != KD_NODE_UNSET) { + deduplicate_recursive(p, node->right); + } + } + else { + if ((p->search != node->index) && (p->duplicates[node->index] == -1)) { + if (compare_len_squared_v3v3(node->co, p->search_co, p->range_sq)) { + p->duplicates[node->index] = (int)p->search; + *p->duplicates_found += 1; + } + } + if (node->left != KD_NODE_UNSET) { + deduplicate_recursive(p, node->left); + } + if (node->right != KD_NODE_UNSET) { + deduplicate_recursive(p, node->right); + } + } +} + +/** + * Find duplicate points in \a range. + * Favors speed over quality since it doesn't find the best target vertex for merging. + * Nodes are looped over, duplicates are added when found. + * Nevertheless results are predictable. + * + * \param range: Coordinates in this range are candidates to be merged. + * \param use_index_order: Loop over the coordinates ordered by #KDTreeNode.index + * At the expense of some performance, this ensures the layout of the tree doesn't influence + * the iteration order. + * \param duplicates: An array of int's the length of #KDTree.totnode + * Values initialized to -1 are candidates to me merged. + * Setting the index to it's own position in the array prevents it from being touched, + * although it can still be used as a target. + * \returns The numebr of merges found (includes any merges already in the \a duplicates array). + * + * \note Merging is always a single step (target indices wont be marked for merging). + */ +int BLI_kdtree_calc_duplicates_fast( + const KDTree *tree, const float range, bool use_index_order, + int *duplicates) +{ + int found = 0; + struct DeDuplicateParams p = { + .nodes = tree->nodes, + .range = range, + .range_sq = range * range, + .duplicates = duplicates, + .duplicates_found = &found, + }; + + if (use_index_order) { + uint *order = kdtree_order(tree); + for (uint i = 0; i < tree->totnode; i++) { + const uint node_index = order[i]; + const int index = (int)i; + if (ELEM(duplicates[index], -1, index)) { + p.search = index; + copy_v3_v3(p.search_co, tree->nodes[node_index].co); + deduplicate_recursive(&p, tree->root); + } + } + MEM_freeN(order); + } + else { + for (uint i = 0; i < tree->totnode; i++) { + const uint node_index = i; + const int index = p.nodes[node_index].index; + if (ELEM(duplicates[index], -1, index)) { + p.search = index; + copy_v3_v3(p.search_co, tree->nodes[node_index].co); + deduplicate_recursive(&p, tree->root); + } + } + } + return found; +} + +/** \} */ diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c index 8719c92a2a6..e990f0b663c 100644 --- a/source/blender/blenlib/intern/freetypefont.c +++ b/source/blender/blenlib/intern/freetypefont.c @@ -481,6 +481,22 @@ VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf) return vfd; } +static void *vfontdata_copy_characters_value_cb(const void *src) +{ + return BLI_vfontchar_copy(src, 0); +} + +VFontData *BLI_vfontdata_copy(const VFontData *vfont_src, const int UNUSED(flag)) +{ + VFontData *vfont_dst = MEM_dupallocN(vfont_src); + + if (vfont_src->characters != NULL) { + vfont_dst->characters = BLI_ghash_copy(vfont_src->characters, NULL, vfontdata_copy_characters_value_cb); + } + + return vfont_dst; +} + VChar *BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character) { VChar *che = NULL; @@ -503,6 +519,20 @@ VChar *BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character) return che; } +/* Yeah, this is very bad... But why is this in BLI in the first place, since it uses Nurb data? + * Anyway, do not feel like duplicating whole Nurb copy code here, so unless someone has a better idea... */ +#include "../../blenkernel/BKE_curve.h" + +VChar *BLI_vfontchar_copy(const VChar *vchar_src, const int UNUSED(flag)) +{ + VChar *vchar_dst = MEM_dupallocN(vchar_src); + + BLI_listbase_clear(&vchar_dst->nurbsbase); + BKE_nurbList_duplicate(&vchar_dst->nurbsbase, &vchar_src->nurbsbase); + + return vchar_dst; +} + #if 0 /* Freetype2 Outline struct */ diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index 8d2d80c2a35..749c18fc0ce 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -33,6 +33,7 @@ #include <float.h> #include <stdio.h> #include <stdlib.h> +#include <limits.h> #ifdef __SSE2__ # include <emmintrin.h> @@ -181,11 +182,59 @@ MINLINE unsigned power_of_2_min_u(unsigned x) return x - (x >> 1); } -MINLINE int iroundf(float a) -{ - return (int)floorf(a + 0.5f); +/* rounding and clamping */ + +#define _round_clamp_fl_impl(arg, ty, min, max) { \ + float r = floorf(arg + 0.5f); \ + if (UNLIKELY(r <= (float)min)) return (ty)min; \ + else if (UNLIKELY(r >= (float)max)) return (ty)max; \ + else return (ty)r; \ +} + +#define _round_clamp_db_impl(arg, ty, min, max) { \ + double r = floor(arg + 0.5); \ + if (UNLIKELY(r <= (double)min)) return (ty)min; \ + else if (UNLIKELY(r >= (double)max)) return (ty)max; \ + else return (ty)r; \ } +#define _round_fl_impl(arg, ty) { return (ty)floorf(arg + 0.5f); } +#define _round_db_impl(arg, ty) { return (ty)floor(arg + 0.5); } + +MINLINE signed char round_fl_to_char(float a) { _round_fl_impl(a, signed char) } +MINLINE unsigned char round_fl_to_uchar(float a) { _round_fl_impl(a, unsigned char) } +MINLINE short round_fl_to_short(float a) { _round_fl_impl(a, short) } +MINLINE unsigned short round_fl_to_ushort(float a) { _round_fl_impl(a, unsigned short) } +MINLINE int round_fl_to_int(float a) { _round_fl_impl(a, int) } +MINLINE unsigned int round_fl_to_uint(float a) { _round_fl_impl(a, unsigned int) } + +MINLINE signed char round_db_to_char(double a) { _round_db_impl(a, signed char) } +MINLINE unsigned char round_db_to_uchar(double a) { _round_db_impl(a, unsigned char) } +MINLINE short round_db_to_short(double a) { _round_db_impl(a, short) } +MINLINE unsigned short round_db_to_ushort(double a) { _round_db_impl(a, unsigned short) } +MINLINE int round_db_to_int(double a) { _round_db_impl(a, int) } +MINLINE unsigned int round_db_to_uint(double a) { _round_db_impl(a, unsigned int) } + +#undef _round_fl_impl +#undef _round_db_impl + +MINLINE signed char round_fl_to_char_clamp(float a) { _round_clamp_fl_impl(a, signed char, SCHAR_MIN, SCHAR_MAX) } +MINLINE unsigned char round_fl_to_uchar_clamp(float a) { _round_clamp_fl_impl(a, unsigned char, 0, UCHAR_MAX) } +MINLINE short round_fl_to_short_clamp(float a) { _round_clamp_fl_impl(a, short, SHRT_MIN, SHRT_MAX) } +MINLINE unsigned short round_fl_to_ushort_clamp(float a) { _round_clamp_fl_impl(a, unsigned short, 0, USHRT_MAX) } +MINLINE int round_fl_to_int_clamp(float a) { _round_clamp_fl_impl(a, int, INT_MIN, INT_MAX) } +MINLINE unsigned int round_fl_to_uint_clamp(float a) { _round_clamp_fl_impl(a, unsigned int, 0, UINT_MAX) } + +MINLINE signed char round_db_to_char_clamp(double a) { _round_clamp_db_impl(a, signed char, SCHAR_MIN, SCHAR_MAX) } +MINLINE unsigned char round_db_to_uchar_clamp(double a) { _round_clamp_db_impl(a, unsigned char, 0, UCHAR_MAX) } +MINLINE short round_db_to_short_clamp(double a) { _round_clamp_db_impl(a, short, SHRT_MIN, SHRT_MAX) } +MINLINE unsigned short round_db_to_ushort_clamp(double a) { _round_clamp_db_impl(a, unsigned short, 0, USHRT_MAX) } +MINLINE int round_db_to_int_clamp(double a) { _round_clamp_db_impl(a, int, INT_MIN, INT_MAX) } +MINLINE unsigned int round_db_to_uint_clamp(double a) { _round_clamp_db_impl(a, unsigned int, 0, UINT_MAX) } + +#undef _round_clamp_fl_impl +#undef _round_clamp_db_impl + /* integer division that rounds 0.5 up, particularly useful for color blending * with integers, to avoid gradual darkening when rounding down */ MINLINE int divide_round_i(int a, int b) @@ -194,6 +243,17 @@ MINLINE int divide_round_i(int a, int b) } /** + * Integer division that floors negative result. + * \note This works like Python's int division. + */ +MINLINE int divide_floor_i(int a, int b) +{ + int d = a / b; + int r = a % b; /* Optimizes into a single division. */ + return r ? d - ((a < 0) ^ (b < 0)) : d; +} + +/** * modulo that handles negative numbers, works the same as Python's. */ MINLINE int mod_i(int i, int n) @@ -314,6 +374,21 @@ MINLINE int signum_i(float a) else return 0; } +/** Returns number of (base ten) *significant* digits of integer part of given float + * (negative in case of decimal-only floats, 0.01 returns -1 e.g.). */ +MINLINE int integer_digits_f(const float f) +{ + return (f == 0.0f) ? 0 : (int)floor(log10(fabs(f))) + 1; +} + +/** Returns number of (base ten) *significant* digits of integer part of given double + * (negative in case of decimal-only floats, 0.01 returns -1 e.g.). */ +MINLINE int integer_digits_d(const double d) +{ + return (d == 0.0) ? 0 : (int)floor(log10(fabs(d))) + 1; +} + + /* Internal helpers for SSE2 implementation. * * NOTE: Are to be called ONLY from inside `#ifdef __SSE2__` !!! diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 630eaed05db..30164ff9f6a 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -765,18 +765,29 @@ int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], co return ISECT_LINE_LINE_NONE; } -/* get intersection point of two 2D segments and return intersection type: - * -1: collinear - * 1: intersection +/** + * Get intersection point of two 2D segments. + * + * \param endpoint_bias: Bias to use when testing for end-point overlap. + * A positive value considers intersections that extend past the endpoints, + * negative values contract the endpoints. + * Note the bias is applied to a 0-1 factor, not scaled to the length of segments. + * + * \returns intersection type: + * - -1: collinear. + * - 1: intersection. + * - 0: no intersection. */ -int isect_seg_seg_v2_point( +int isect_seg_seg_v2_point_ex( const float v0[2], const float v1[2], const float v2[2], const float v3[2], + const float endpoint_bias, float r_vi[2]) { float s10[2], s32[2], s30[2], d; const float eps = 1e-6f; - const float eps_sq = eps * eps; + const float endpoint_min = -endpoint_bias; + const float endpoint_max = endpoint_bias + 1.0f; sub_v2_v2v2(s10, v1, v0); sub_v2_v2v2(s32, v3, v2); @@ -790,8 +801,8 @@ int isect_seg_seg_v2_point( u = cross_v2v2(s30, s32) / d; v = cross_v2v2(s10, s30) / d; - if ((u >= -eps && u <= 1.0f + eps) && - (v >= -eps && v <= 1.0f + eps)) + if ((u >= endpoint_min && u <= endpoint_max) && + (v >= endpoint_min && v <= endpoint_max)) { /* intersection */ float vi_test[2]; @@ -810,7 +821,7 @@ int isect_seg_seg_v2_point( sub_v2_v2v2(s_vi_v2, vi_test, v2); v = (dot_v2v2(s32, s_vi_v2) / dot_v2v2(s32, s32)); #endif - if (v >= -eps && v <= 1.0f + eps) { + if (v >= endpoint_min && v <= endpoint_max) { copy_v2_v2(r_vi, vi_test); return 1; } @@ -828,7 +839,7 @@ int isect_seg_seg_v2_point( float u_a, u_b; if (equals_v2v2(v0, v1)) { - if (len_squared_v2v2(v2, v3) > eps_sq) { + if (len_squared_v2v2(v2, v3) > SQUARE(eps)) { /* use non-point segment as basis */ SWAP(const float *, v0, v2); SWAP(const float *, v1, v3); @@ -855,7 +866,7 @@ int isect_seg_seg_v2_point( if (u_a > u_b) SWAP(float, u_a, u_b); - if (u_a > 1.0f + eps || u_b < -eps) { + if (u_a > endpoint_max || u_b < endpoint_min) { /* non-overlapping segments */ return -1; } @@ -871,6 +882,15 @@ int isect_seg_seg_v2_point( } } +int isect_seg_seg_v2_point( + const float v0[2], const float v1[2], + const float v2[2], const float v3[2], + float r_vi[2]) +{ + const float endpoint_bias = 1e-6f; + return isect_seg_seg_v2_point_ex(v0, v1, v2, v3, endpoint_bias, r_vi); +} + bool isect_seg_seg_v2_simple(const float v1[2], const float v2[2], const float v3[2], const float v4[2]) { #define CCW(A, B, C) \ diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index f47f9ad76e6..d1a219c196a 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -1663,6 +1663,9 @@ void rotate_m4(float mat[4][4], const char axis, const float angle) mat[0][col] = temp; } break; + default: + BLI_assert(0); + break; } } diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index c6e9b8229ba..5f44c93e169 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -652,6 +652,31 @@ void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3]) } /** + * Project \a p onto a unit length \a v_proj + */ +void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2]) +{ + BLI_ASSERT_UNIT_V2(v_proj); + const float mul = dot_v2v2(p, v_proj); + + out[0] = mul * v_proj[0]; + out[1] = mul * v_proj[1]; +} + +/** + * Project \a p onto a unit length \a v_proj + */ +void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3]) +{ + BLI_ASSERT_UNIT_V3(v_proj); + const float mul = dot_v3v3(p, v_proj); + + out[0] = mul * v_proj[0]; + out[1] = mul * v_proj[1]; + out[2] = mul * v_proj[2]; +} + +/** * In this case plane is a 3D vector only (no 4th component). * * Projecting will make \a c a copy of \a v orthogonal to \a v_plane. diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c index 347640aae0d..86c24307ae2 100644 --- a/source/blender/blenlib/intern/noise.c +++ b/source/blender/blenlib/intern/noise.c @@ -1395,9 +1395,9 @@ static float voronoi_CrS(float x, float y, float z) static float cellNoiseU(float x, float y, float z) { /* avoid precision issues on unit coordinates */ - x = (x + 0.000001f)*0.999999f; - y = (y + 0.000001f)*0.999999f; - z = (z + 0.000001f)*0.999999f; + x = (x + 0.000001f)*1.00001f; + y = (y + 0.000001f)*1.00001f; + z = (z + 0.000001f)*1.00001f; int xi = (int)(floor(x)); int yi = (int)(floor(y)); @@ -1417,9 +1417,9 @@ float cellNoise(float x, float y, float z) void cellNoiseV(float x, float y, float z, float ca[3]) { /* avoid precision issues on unit coordinates */ - x = (x + 0.000001f)*0.999999f; - y = (y + 0.000001f)*0.999999f; - z = (z + 0.000001f)*0.999999f; + x = (x + 0.000001f)*1.00001f; + y = (y + 0.000001f)*1.00001f; + z = (z + 0.000001f)*1.00001f; int xi = (int)(floor(x)); int yi = (int)(floor(y)); diff --git a/source/blender/blenlib/intern/polyfill2d.c b/source/blender/blenlib/intern/polyfill2d.c index 5f9b92198a5..018e2f9be5a 100644 --- a/source/blender/blenlib/intern/polyfill2d.c +++ b/source/blender/blenlib/intern/polyfill2d.c @@ -411,11 +411,11 @@ static bool kdtree2d_isect_tri_recursive( } #define KDTREE2D_ISECT_TRI_RECURSE_NEG \ - (((node->neg != KDNODE_UNSET) && (co[node->axis] > bounds[node->axis].min)) && \ + (((node->neg != KDNODE_UNSET) && (co[node->axis] >= bounds[node->axis].min)) && \ (kdtree2d_isect_tri_recursive(tree, tri_index, tri_coords, tri_center, bounds, \ &tree->nodes[node->neg]))) #define KDTREE2D_ISECT_TRI_RECURSE_POS \ - (((node->pos != KDNODE_UNSET) && (co[node->axis] < bounds[node->axis].max)) && \ + (((node->pos != KDNODE_UNSET) && (co[node->axis] <= bounds[node->axis].max)) && \ (kdtree2d_isect_tri_recursive(tree, tri_index, tri_coords, tri_center, bounds, \ &tree->nodes[node->pos]))) @@ -698,12 +698,12 @@ static bool pf_ear_tip_check(PolyFill *pf, PolyIndex *pi_ear_tip) /* check if counting is wrong */ { uint coords_tot_concave_test = 0; - uint i = pf->coords_tot; - while (i--) { - if (coords_sign[indices[i]] != CONVEX) { + PolyIndex *pi_iter = pi_ear_tip; + do { + if (pi_iter->sign != CONVEX) { coords_tot_concave_test += 1; } - } + } while ((pi_iter = pi_iter->next) != pi_ear_tip); BLI_assert(coords_tot_concave_test == pf->coords_tot_concave); } #endif diff --git a/source/blender/blenlib/intern/polyfill2d_beautify.c b/source/blender/blenlib/intern/polyfill2d_beautify.c index 896177f436c..5f6fb8e6cd4 100644 --- a/source/blender/blenlib/intern/polyfill2d_beautify.c +++ b/source/blender/blenlib/intern/polyfill2d_beautify.c @@ -121,45 +121,53 @@ BLI_INLINE bool is_boundary_edge(unsigned int i_a, unsigned int i_b, const unsig * Assuming we have 2 triangles sharing an edge (2 - 4), * check if the edge running from (1 - 3) gives better results. * + * \param lock_degenerate: Use to avoid rotating out of a degenerate state. + * - When true, an existing zero area face on either side of the (2 - 4) split will return a positive value. + * - When false, the check must be non-biased towards either split direction. + * * \return (negative number means the edge can be rotated, lager == better). */ -float BLI_polyfill_beautify_quad_rotate_calc( - const float v1[2], const float v2[2], const float v3[2], const float v4[2]) +float BLI_polyfill_beautify_quad_rotate_calc_ex( + const float v1[2], const float v2[2], const float v3[2], const float v4[2], + const bool lock_degenerate) { /* not a loop (only to be able to break out) */ do { - bool is_zero_a, is_zero_b; - + /* Allow very small faces to be considered non-zero. */ + const float eps_zero_area = 1e-12f; const float area_2x_234 = cross_tri_v2(v2, v3, v4); const float area_2x_241 = cross_tri_v2(v2, v4, v1); const float area_2x_123 = cross_tri_v2(v1, v2, v3); const float area_2x_134 = cross_tri_v2(v1, v3, v4); - { - BLI_assert((ELEM(v1, v2, v3, v4) == false) && - (ELEM(v2, v1, v3, v4) == false) && - (ELEM(v3, v1, v2, v4) == false) && - (ELEM(v4, v1, v2, v3) == false)); - - is_zero_a = (fabsf(area_2x_234) <= FLT_EPSILON); - is_zero_b = (fabsf(area_2x_241) <= FLT_EPSILON); - - if (is_zero_a && is_zero_b) { - break; - } + BLI_assert((ELEM(v1, v2, v3, v4) == false) && + (ELEM(v2, v1, v3, v4) == false) && + (ELEM(v3, v1, v2, v4) == false) && + (ELEM(v4, v1, v2, v3) == false)); + /* + * Test for unusable (1-3) state. + * - Area sign flipping to check faces aren't going to point in opposite directions. + * - Area epsilon check that the one of the faces won't be zero area. + */ + if ((area_2x_123 >= 0.0f) != (area_2x_134 >= 0.0f)) { + break; } - - /* one of the tri's was degenerate, check we're not rotating - * into a different degenerate shape or flipping the face */ - if ((fabsf(area_2x_123) <= FLT_EPSILON) || (fabsf(area_2x_134) <= FLT_EPSILON)) { - /* one of the new rotations is degenerate */ + else if ((fabsf(area_2x_123) <= eps_zero_area) || (fabsf(area_2x_134) <= eps_zero_area)) { break; } - if ((area_2x_123 >= 0.0f) != (area_2x_134 >= 0.0f)) { - /* rotation would cause flipping */ - break; + /* Test for unusable (2-4) state (same as above). */ + if ((area_2x_234 >= 0.0f) != (area_2x_241 >= 0.0f)) { + if (lock_degenerate) { + break; + } + else { + return -FLT_MAX; /* always rotate */ + } + } + else if ((fabsf(area_2x_234) <= eps_zero_area) || (fabsf(area_2x_241) <= eps_zero_area)) { + return -FLT_MAX; /* always rotate */ } { diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c index e0c4cbe9990..3adc6b30f6e 100644 --- a/source/blender/blenlib/intern/rct.c +++ b/source/blender/blenlib/intern/rct.c @@ -32,6 +32,7 @@ * A minimalist lib for functions doing stuff with rectangle structs. */ +#include <stdlib.h> #include <stdio.h> #include <math.h> @@ -41,6 +42,9 @@ #include "DNA_vec_types.h" #include "BLI_rect.h" +/* avoid including BLI_math */ +static void unit_m4(float m[4][4]); + /** * Determine if a rect is empty. An empty * rect is one with a zero (or negative) @@ -405,6 +409,31 @@ void BLI_rctf_transform_pt_v(const rctf *dst, const rctf *src, float xy_dst[2], xy_dst[1] = dst->ymin + ((dst->ymax - dst->ymin) * xy_dst[1]); } +/** + * Calculate a 4x4 matrix representing the transformation between two rectangles. + * + * \note Multiplying a vector by this matrix does *not* give the same value as #BLI_rctf_transform_pt_v. + */ +void BLI_rctf_transform_calc_m4_pivot_min_ex( + const rctf *dst, const rctf *src, float matrix[4][4], + uint x, uint y) +{ + BLI_assert(x < 3 && y < 3); + + unit_m4(matrix); + + matrix[x][x] = BLI_rctf_size_x(src) / BLI_rctf_size_x(dst); + matrix[y][y] = BLI_rctf_size_y(src) / BLI_rctf_size_y(dst); + matrix[3][x] = (src->xmin - dst->xmin) * matrix[x][x]; + matrix[3][y] = (src->ymin - dst->ymin) * matrix[y][y]; +} + +void BLI_rctf_transform_calc_m4_pivot_min( + const rctf *dst, const rctf *src, float matrix[4][4]) +{ + BLI_rctf_transform_calc_m4_pivot_min_ex(dst, src, matrix, 0, 1); +} + void BLI_rcti_translate(rcti *rect, int x, int y) { rect->xmin += x; @@ -763,3 +792,12 @@ void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle) #undef ROTATE_SINCOS /** \} */ + +static void unit_m4(float m[4][4]) +{ + m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f; + m[0][1] = m[0][2] = m[0][3] = 0.0f; + m[1][0] = m[1][2] = m[1][3] = 0.0f; + m[2][0] = m[2][1] = m[2][3] = 0.0f; + m[3][0] = m[3][1] = m[3][2] = 0.0f; +} diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index b819c513fbd..a48c8b074dd 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -37,14 +37,10 @@ #include <sys/stat.h> -#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun__) || defined(__sun) +#if defined(__NetBSD__) || defined(__DragonFly__) /* Other modern unix os's should probably use this also */ # include <sys/statvfs.h> # define USE_STATFS_STATVFS -#elif (defined(__sparc) || defined(__sparc__)) && !defined(__FreeBSD__) && !defined(__linux__) -# include <sys/statfs.h> - /* 4 argument version (not common) */ -# define USE_STATFS_4ARGS #endif #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c index 8d91a55a5ad..a693463a302 100644 --- a/source/blender/blenlib/intern/string_utils.c +++ b/source/blender/blenlib/intern/string_utils.c @@ -383,3 +383,91 @@ bool BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim return BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len); } + +/* ------------------------------------------------------------------------- */ +/** \name Join Strings + * + * For non array versions of these functions, use the macros: + * - #BLI_string_joinN + * - #BLI_string_join_by_sep_charN + * - #BLI_string_join_by_sep_char_with_tableN + * + * \{ */ + +/** + * Join an array of strings into a newly allocated, null terminated string. + */ +char *BLI_string_join_arrayN( + const char *strings[], uint strings_len) +{ + uint total_len = 1; + for (uint i = 0; i < strings_len; i++) { + total_len += strlen(strings[i]); + } + char *result = MEM_mallocN(sizeof(char) * total_len, __func__); + char *c = result; + for (uint i = 0; i < strings_len; i++) { + c += BLI_strcpy_rlen(c, strings[i]); + } + return result; +} + +/** + * A version of #BLI_string_joinN that takes a separator which can be any character including '\0'. + */ +char *BLI_string_join_array_by_sep_charN( + char sep, const char *strings[], uint strings_len) +{ + uint total_len = 0; + for (uint i = 0; i < strings_len; i++) { + total_len += strlen(strings[i]) + 1; + } + if (total_len == 0) { + total_len = 1; + } + + char *result = MEM_mallocN(sizeof(char) * total_len, __func__); + char *c = result; + if (strings_len != 0) { + for (uint i = 0; i < strings_len; i++) { + c += BLI_strcpy_rlen(c, strings[i]); + *c = sep; + c++; + } + c--; + } + *c = '\0'; + return result; +} + +/** + * A version of #BLI_string_join_array_by_sep_charN that takes a table array. + * The new location of each string is written into this array. + */ +char *BLI_string_join_array_by_sep_char_with_tableN( + char sep, char *table[], const char *strings[], uint strings_len) +{ + uint total_len = 0; + for (uint i = 0; i < strings_len; i++) { + total_len += strlen(strings[i]) + 1; + } + if (total_len == 0) { + total_len = 1; + } + + char *result = MEM_mallocN(sizeof(char) * total_len, __func__); + char *c = result; + if (strings_len != 0) { + for (uint i = 0; i < strings_len; i++) { + table[i] = c; /* <-- only difference to BLI_string_join_array_by_sep_charN. */ + c += BLI_strcpy_rlen(c, strings[i]); + *c = sep; + c++; + } + c--; + } + *c = '\0'; + return result; +} + +/** \} */ diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c index e755a7ae52c..7856bad4d99 100644 --- a/source/blender/blenlib/intern/timecode.c +++ b/source/blender/blenlib/intern/timecode.c @@ -94,11 +94,11 @@ size_t BLI_timecode_string_from_time( * to cope with 'half' frames, etc., which should be fine in most cases */ seconds = (int)time; - frames = iroundf((float)(((double)time - (double)seconds) * fps)); + frames = round_fl_to_int((float)(((double)time - (double)seconds) * fps)); } else { /* seconds (with pixel offset rounding) */ - seconds = iroundf(time); + seconds = round_fl_to_int(time); } switch (timecode_style) { @@ -169,7 +169,7 @@ size_t BLI_timecode_string_from_time( /* precision of decimal part */ const int ms_dp = (power <= 0) ? (1 - power) : 1; - const int ms = iroundf((time - (float)seconds) * 1000.0f); + const int ms = round_fl_to_int((time - (float)seconds) * 1000.0f); rlen = BLI_snprintf_rlen( str, maxncpy, "%s%02d:%02d:%02d,%0*d", neg, hours, minutes, seconds, ms_dp, ms); @@ -183,7 +183,7 @@ size_t BLI_timecode_string_from_time( rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds); } else { - rlen = BLI_snprintf_rlen(str, maxncpy, "%d", iroundf(time_seconds)); + rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds)); } break; } @@ -250,7 +250,7 @@ size_t BLI_timecode_string_from_time_seconds( rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds); } else { - rlen = BLI_snprintf_rlen(str, maxncpy, "%d", iroundf(time_seconds)); + rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds)); } return rlen; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f224f0b5633..3b7662be2b2 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -638,7 +638,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab /* Add library datablock itself to 'main' Main, since libraries are **never** linked data. * Fixes bug where you could end with all ID_LI datablocks having the same name... */ - lib = BKE_libblock_alloc(mainlist->first, ID_LI, "Lib"); + lib = BKE_libblock_alloc(mainlist->first, ID_LI, "Lib", 0); lib->id.us = ID_FAKE_USERS(lib); /* Important, consistency with main ID reading code from read_libblock(). */ BLI_strncpy(lib->name, filepath, sizeof(lib->name)); BLI_strncpy(lib->filepath, name1, sizeof(lib->filepath)); @@ -6003,16 +6003,6 @@ static void direct_link_scene(FileData *fd, Scene *sce) sce->toolsettings->particle.scene = NULL; sce->toolsettings->particle.object = NULL; sce->toolsettings->gp_sculpt.paintcursor = NULL; - - /* in rare cases this is needed, see [#33806] */ - if (sce->toolsettings->vpaint) { - sce->toolsettings->vpaint->vpaint_prev = NULL; - sce->toolsettings->vpaint->tot = 0; - } - if (sce->toolsettings->wpaint) { - sce->toolsettings->wpaint->wpaint_prev = NULL; - sce->toolsettings->wpaint->tot = 0; - } /* relink grease pencil drawing brushes */ link_list(fd, &sce->toolsettings->gp_brushes); @@ -6162,11 +6152,6 @@ static void direct_link_scene(FileData *fd, Scene *sce) sce->r.avicodecdata->lpFormat = newdataadr(fd, sce->r.avicodecdata->lpFormat); sce->r.avicodecdata->lpParms = newdataadr(fd, sce->r.avicodecdata->lpParms); } - - sce->r.qtcodecdata = newdataadr(fd, sce->r.qtcodecdata); - if (sce->r.qtcodecdata) { - sce->r.qtcodecdata->cdParms = newdataadr(fd, sce->r.qtcodecdata->cdParms); - } if (sce->r.ffcodecdata.properties) { sce->r.ffcodecdata.properties = newdataadr(fd, sce->r.ffcodecdata.properties); IDP_DirectLinkGroup_OrFree(&sce->r.ffcodecdata.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); @@ -9912,6 +9897,8 @@ void BLO_expand_main(void *fdhandle, Main *mainvar) case ID_CF: expand_cachefile(fd, mainvar, (CacheFile *)id); break; + default: + break; } do_it = true; diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 94d335870ca..8459e080f99 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -60,6 +60,7 @@ #include "DNA_genfile.h" #include "BKE_animsys.h" +#include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_library.h" #include "BKE_main.h" @@ -1652,6 +1653,23 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } + { + Brush *br; + br = (Brush *)BKE_libblock_find_name_ex(main, ID_BR, "Average"); + if (!br) { + br = BKE_brush_add(main, "Average", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT); + br->vertexpaint_tool = PAINT_BLEND_AVERAGE; + br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT; + } + + br = (Brush *)BKE_libblock_find_name_ex(main, ID_BR, "Smear"); + if (!br) { + br = BKE_brush_add(main, "Smear", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT); + br->vertexpaint_tool = PAINT_BLEND_SMEAR; + br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT; + } + } + FOREACH_NODETREE(main, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { do_versions_compositor_render_passes(ntree); @@ -1659,7 +1677,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } FOREACH_NODETREE_END } - { + if (!MAIN_VERSION_ATLEAST(main, 279, 0)) { for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { if (scene->r.im_format.exr_codec == R_IMF_EXR_CODEC_DWAB) { scene->r.im_format.exr_codec = R_IMF_EXR_CODEC_DWAA; @@ -1671,12 +1689,23 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) CustomData_set_layer_name(&me->vdata, CD_MDEFORMVERT, 0, ""); } } + + { + /* Fix for invalid state of screen due to bug in older versions. */ + for (bScreen *sc = main->screen.first; sc; sc = sc->id.next) { + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { + if(sa->full && sc->state == SCREENNORMAL) { + sa->full = NULL; + } + } + } + } } void do_versions_after_linking_270(Main *main) { /* To be added to next subversion bump! */ - { + if (!MAIN_VERSION_ATLEAST(main, 279, 0)) { FOREACH_NODETREE(main, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { ntreeSetTypes(NULL, ntree); diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index e7e0054e7a1..3d3e73eb470 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -58,6 +58,9 @@ void BLO_update_defaults_userpref_blend(void) U.uiflag |= USER_QUIT_PROMPT; U.uiflag |= USER_CONTINUOUS_MOUSE; + /* See T45301 */ + U.uiflag |= USER_LOCK_CURSOR_ADJUST; + U.versions = 1; U.savetime = 2; @@ -106,6 +109,16 @@ void BLO_update_defaults_startup_blend(Main *bmain) sculpt->detail_size = 12; } + if (ts->vpaint) { + VPaint *vp = ts->vpaint; + vp->radial_symm[0] = vp->radial_symm[1] = vp->radial_symm[2] = 1; + } + + if (ts->wpaint) { + VPaint *wp = ts->wpaint; + wp->radial_symm[0] = wp->radial_symm[1] = wp->radial_symm[2] = 1; + } + if (ts->gp_sculpt.brush[0].size == 0) { GP_BrushEdit_Settings *gset = &ts->gp_sculpt; GP_EditBrush_Data *brush; @@ -233,6 +246,20 @@ void BLO_update_defaults_startup_blend(Main *bmain) br->ob_mode = OB_MODE_TEXTURE_PAINT; } + /* Vertex/Weight Paint */ + br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Average"); + if (!br) { + br = BKE_brush_add(bmain, "Average", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT); + br->vertexpaint_tool = PAINT_BLEND_AVERAGE; + br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT; + } + br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Smear"); + if (!br) { + br = BKE_brush_add(bmain, "Smear", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT); + br->vertexpaint_tool = PAINT_BLEND_SMEAR; + br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT; + } + br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Mask"); if (br) { br->imagepaint_tool = PAINT_TOOL_MASK; diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index c29ffbb76f2..ad37679800b 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -2911,12 +2911,12 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) Scene *sce; for (sce = main->scene.first; sce; sce = sce->id.next) { if (sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[1] || - sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[2] || - sce->toolsettings->skgen_subdivisions[1] == sce->toolsettings->skgen_subdivisions[2]) + sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[2] || + sce->toolsettings->skgen_subdivisions[1] == sce->toolsettings->skgen_subdivisions[2]) { - sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION; - sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH; - sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE; + sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION; + sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH; + sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE; } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ee9665dc834..2648ebdc395 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -2688,13 +2688,6 @@ static void write_scene(WriteData *wd, Scene *sce) writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms); } } - - if (sce->r.qtcodecdata) { - writestruct(wd, DATA, QuicktimeCodecData, 1, sce->r.qtcodecdata); - if (sce->r.qtcodecdata->cdParms) { - writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms); - } - } if (sce->r.ffcodecdata.properties) { IDP_WriteProperty(sce->r.ffcodecdata.properties, wd); } @@ -3841,6 +3834,9 @@ static bool write_file_handle( } for (; id; id = id->next) { + /* We should never attempt to write non-regular IDs (i.e. all kind of temp/runtime ones). */ + BLI_assert((id->tag & (LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT | LIB_TAG_NOT_ALLOCATED)) == 0); + switch ((ID_Type)GS(id->name)) { case ID_WM: write_windowmanager(wd, (wmWindowManager *)id); diff --git a/source/blender/blentranslation/CMakeLists.txt b/source/blender/blentranslation/CMakeLists.txt index c0dce5b4f0d..320a784ea25 100644 --- a/source/blender/blentranslation/CMakeLists.txt +++ b/source/blender/blentranslation/CMakeLists.txt @@ -61,4 +61,6 @@ endif() blender_add_lib(bf_blentranslation "${SRC}" "${INC}" "${INC_SYS}") -add_subdirectory(msgfmt) +if(WITH_INTERNATIONAL) + add_subdirectory(msgfmt) +endif() diff --git a/source/blender/blentranslation/msgfmt/msgfmt.c b/source/blender/blentranslation/msgfmt/msgfmt.c index 487d9fee7b4..3abce7b1d3f 100644 --- a/source/blender/blentranslation/msgfmt/msgfmt.c +++ b/source/blender/blentranslation/msgfmt/msgfmt.c @@ -160,7 +160,8 @@ static char **get_keys_sorted(GHash *messages, const uint32_t num_keys) return keys; } -BLI_INLINE size_t uint32_to_bytes(const int value, char *bytes) { +BLI_INLINE size_t uint32_to_bytes(const int value, char *bytes) +{ size_t i; for (i = 0; i < sizeof(value); i++) { bytes[i] = (char) ((value >> ((int)i * 8)) & 0xff); @@ -168,7 +169,8 @@ BLI_INLINE size_t uint32_to_bytes(const int value, char *bytes) { return i; } -BLI_INLINE size_t msg_to_bytes(char *msg, char *bytes, uint32_t size) { +BLI_INLINE size_t msg_to_bytes(char *msg, char *bytes, uint32_t size) +{ /* Note that we also perform replacing of our NULLSEP placeholder by real NULL char... */ size_t i; for (i = 0; i < size; i++, msg++, bytes++) { @@ -452,7 +454,8 @@ static int make(const char *input_file_name, const char *output_file_name) return EXIT_SUCCESS; } -int main(int argc, char **argv) { +int main(int argc, char **argv) +{ if (argc != 3) { printf("Usage: %s <input.po> <output.mo>\n", argv[0]); return EXIT_FAILURE; diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 4fe14fdf5c9..c7ff93cf504 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -32,7 +32,7 @@ #include "BLI_array.h" #include "BLI_alloca.h" #include "BLI_linklist_stack.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLT_translation.h" @@ -2415,7 +2415,8 @@ static void bmesh_kernel_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separ /* don't visit again */ n_prev->next = n_step->next; } - } while ((n_prev = n_step), + } while ((void) + (n_prev = n_step), (n_step = n_step->next)); } while ((n_orig = n_orig->next) && n_orig->next); diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c index 5780dc57d78..b3b23933d2f 100644 --- a/source/blender/bmesh/intern/bmesh_edgeloop.c +++ b/source/blender/bmesh/intern/bmesh_edgeloop.c @@ -32,6 +32,7 @@ #include "BLI_math_vector.h" #include "BLI_listbase.h" #include "BLI_mempool.h" +#include "BLI_utildefines_iter.h" #include "bmesh.h" @@ -708,21 +709,16 @@ void BM_edgeloop_expand( } if (el_store->len < el_store_len) { - const int step = max_ii(1, el_store->len / (el_store->len % el_store_len)); - LinkData *node_first = el_store->verts.first; - LinkData *node_curr = node_first; + LinkData *node_curr = el_store->verts.first; - do { - LinkData *node_curr_init = node_curr; - LinkData *node_curr_copy; - int i = 0; - BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (&el_store->verts, node_curr, node_curr_init) { - if (i++ < step) { - break; - } + int iter_prev = 0; + BLI_FOREACH_SPARSE_RANGE(el_store->len, (el_store_len - el_store->len), iter) { + while (iter_prev < iter) { + node_curr = node_curr->next; + iter_prev += 1; } - BLI_LISTBASE_CIRCULAR_FORWARD_END (&el_store->verts, node_curr, node_curr_init); + LinkData *node_curr_copy; node_curr_copy = MEM_dupallocN(node_curr); if (split == false) { BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy); @@ -730,7 +726,8 @@ void BM_edgeloop_expand( } else { if (node_curr->next || (el_store->flag & BM_EDGELOOP_IS_CLOSED)) { - EDGE_SPLIT(node_curr_copy, node_curr->next ? node_curr->next : (LinkData *)el_store->verts.first); + EDGE_SPLIT(node_curr_copy, + node_curr->next ? node_curr->next : (LinkData *)el_store->verts.first); BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy); node_curr = node_curr_copy->next; } @@ -742,9 +739,11 @@ void BM_edgeloop_expand( split_swap = !split_swap; } el_store->len++; - } while (el_store->len < el_store_len); + iter_prev += 1; + } } +#undef BKE_FOREACH_SUBSET_OF_RANGE #undef EDGE_SPLIT BLI_assert(el_store->len == el_store_len); diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c index 59ce91a3e70..7787d704b59 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_conv.c +++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c @@ -219,6 +219,11 @@ static BMFace *bm_face_create_from_mpoly( /** * \brief Mesh -> BMesh + * \param bm: The mesh to write into, while this is typically a newly created BMesh, + * merging into existing data is supported. + * Note the custom-data layout isn't used. + * If more comprehensive merging is needed we should move this into a separate function + * since this should be kept fast for edit-mode switching and storing undo steps. * * \warning This function doesn't calculate face normals. */ @@ -226,6 +231,9 @@ void BM_mesh_bm_from_me( BMesh *bm, Mesh *me, const struct BMeshFromMeshParams *params) { + const bool is_new = + !(bm->totvert || + (bm->vdata.totlayer || bm->edata.totlayer || bm->pdata.totlayer || bm->ldata.totlayer)); MVert *mvert; MEdge *medge; MLoop *mloop; @@ -233,19 +241,12 @@ void BM_mesh_bm_from_me( KeyBlock *actkey, *block; BMVert *v, **vtable = NULL; BMEdge *e, **etable = NULL; - BMFace *f; + BMFace *f, **ftable = NULL; float (*keyco)[3] = NULL; - int totuv, totloops, i, j; - - /* free custom data */ - /* this isnt needed in most cases but do just incase */ - CustomData_free(&bm->vdata, bm->totvert); - CustomData_free(&bm->edata, bm->totedge); - CustomData_free(&bm->ldata, bm->totloop); - CustomData_free(&bm->pdata, bm->totface); + int totuv, totloops, i; if (!me || !me->totvert) { - if (me) { /*no verts? still copy customdata layout*/ + if (me && is_new) { /*no verts? still copy customdata layout*/ CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_ASSIGN, 0); CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_ASSIGN, 0); CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_ASSIGN, 0); @@ -259,19 +260,27 @@ void BM_mesh_bm_from_me( return; /* sanity check */ } - vtable = MEM_mallocN(sizeof(void **) * me->totvert, "mesh to bmesh vtable"); + if (is_new) { + CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0); + /* make sure uv layer names are consisten */ + totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); + for (i = 0; i < totuv; i++) { + int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i); + CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name); + } + } - /* make sure uv layer names are consisten */ - totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); - for (i = 0; i < totuv; i++) { - int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i); - CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name); + /* -------------------------------------------------------------------- */ + /* Shape Key */ + int tot_shape_keys = me->key ? BLI_listbase_count(&me->key->block) : 0; + if (is_new == false) { + tot_shape_keys = min_ii(tot_shape_keys, CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY)); } + const float (**shape_key_table)[3] = tot_shape_keys ? BLI_array_alloca(shape_key_table, tot_shape_keys) : NULL; if ((params->active_shapekey != 0) && (me->key != NULL)) { actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1); @@ -280,63 +289,68 @@ void BM_mesh_bm_from_me( actkey = NULL; } - const int tot_shape_keys = me->key ? BLI_listbase_count(&me->key->block) : 0; - const float (**shape_key_table)[3] = tot_shape_keys ? BLI_array_alloca(shape_key_table, tot_shape_keys) : NULL; - - if (tot_shape_keys || params->add_key_index) { - CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0); + if (is_new) { + if (tot_shape_keys || params->add_key_index) { + CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0); + } } if (tot_shape_keys) { - /* check if we need to generate unique ids for the shapekeys. - * this also exists in the file reading code, but is here for - * a sanity check */ - if (!me->key->uidgen) { - fprintf(stderr, - "%s had to generate shape key uid's in a situation we shouldn't need to! " - "(bmesh internal error)\n", - __func__); - - me->key->uidgen = 1; - for (block = me->key->block.first; block; block = block->next) { - block->uid = me->key->uidgen++; + if (is_new) { + /* check if we need to generate unique ids for the shapekeys. + * this also exists in the file reading code, but is here for + * a sanity check */ + if (!me->key->uidgen) { + fprintf(stderr, + "%s had to generate shape key uid's in a situation we shouldn't need to! " + "(bmesh internal error)\n", + __func__); + + me->key->uidgen = 1; + for (block = me->key->block.first; block; block = block->next) { + block->uid = me->key->uidgen++; + } } } if (actkey && actkey->totelem == me->totvert) { - keyco = actkey->data; - bm->shapenr = params->active_shapekey; + keyco = params->use_shapekey ? actkey->data : NULL; + if (is_new) { + bm->shapenr = params->active_shapekey; + } } - for (i = 0, block = me->key->block.first; block; block = block->next, i++) { - CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, - CD_ASSIGN, NULL, 0, block->name); - - j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i); - bm->vdata.layers[j].uid = block->uid; - + for (i = 0, block = me->key->block.first; i < tot_shape_keys; block = block->next, i++) { + if (is_new) { + CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, + CD_ASSIGN, NULL, 0, block->name); + int j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i); + bm->vdata.layers[j].uid = block->uid; + } shape_key_table[i] = (const float (*)[3])block->data; } } - CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT); - CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE); - CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP); - CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE); + if (is_new) { + CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT); + CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE); + CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP); + CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE); - BM_mesh_cd_flag_apply(bm, me->cd_flag); + BM_mesh_cd_flag_apply(bm, me->cd_flag); + } const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); const int cd_shape_key_offset = me->key ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) : -1; - const int cd_shape_keyindex_offset = (tot_shape_keys || params->add_key_index) ? + const int cd_shape_keyindex_offset = is_new && (tot_shape_keys || params->add_key_index) ? CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) : -1; + vtable = MEM_mallocN(sizeof(BMVert **) * me->totvert, __func__); + for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) { - v = vtable[i] = BM_vert_create( - bm, keyco && params->use_shapekey ? keyco[i] : mvert->co, NULL, - BM_CREATE_SKIP_CD); + v = vtable[i] = BM_vert_create(bm, keyco ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD); BM_elem_index_set(v, i); /* set_ok */ /* transfer flag */ @@ -360,20 +374,16 @@ void BM_mesh_bm_from_me( /* set shapekey data */ if (tot_shape_keys) { float (*co_dst)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset); - for (j = 0; j < tot_shape_keys; j++, co_dst++) { + for (int j = 0; j < tot_shape_keys; j++, co_dst++) { copy_v3_v3(*co_dst, shape_key_table[j][i]); } } } - - bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */ - - if (!me->totedge) { - MEM_freeN(vtable); - return; + if (is_new) { + bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */ } - etable = MEM_mallocN(sizeof(void **) * me->totedge, "mesh to bmesh etable"); + etable = MEM_mallocN(sizeof(BMEdge **) * me->totedge, __func__); medge = me->medge; for (i = 0; i < me->totedge; i++, medge++) { @@ -395,8 +405,14 @@ void BM_mesh_bm_from_me( if (cd_edge_crease_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)medge->crease / 255.0f); } + if (is_new) { + bm->elem_index_dirty &= ~BM_EDGE; /* added in order, clear dirty flag */ + } - bm->elem_index_dirty &= ~BM_EDGE; /* added in order, clear dirty flag */ + /* only needed for selection. */ + if (me->mselect && me->totselect != 0) { + ftable = MEM_mallocN(sizeof(BMFace **) * me->totpoly, __func__); + } mloop = me->mloop; mp = me->mpoly; @@ -406,6 +422,9 @@ void BM_mesh_bm_from_me( f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart, bm, vtable, etable); + if (ftable != NULL) { + ftable[i] = f; + } if (UNLIKELY(f == NULL)) { printf("%s: Warning! Bad face in mesh" @@ -428,7 +447,7 @@ void BM_mesh_bm_from_me( f->mat_nr = mp->mat_nr; if (i == me->act_face) bm->act_face = f; - j = mp->loopstart; + int j = mp->loopstart; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { /* don't use 'j' since we may have skipped some faces, hence some loops. */ @@ -445,54 +464,49 @@ void BM_mesh_bm_from_me( BM_face_normal_update(f); } } + if (is_new) { + bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* added in order, clear dirty flag */ + } - bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* added in order, clear dirty flag */ + /* -------------------------------------------------------------------- */ + /* MSelect clears the array elements (avoid adding multiple times). + * + * Take care to keep this last and not use (v/e/ftable) after this. + */ if (me->mselect && me->totselect != 0) { - - BMVert **vert_array = MEM_mallocN(sizeof(BMVert *) * bm->totvert, "VSelConv"); - BMEdge **edge_array = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, "ESelConv"); - BMFace **face_array = MEM_mallocN(sizeof(BMFace *) * bm->totface, "FSelConv"); MSelect *msel; - -#pragma omp parallel sections if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT) - { -#pragma omp section - { BM_iter_as_array(bm, BM_VERTS_OF_MESH, NULL, (void **)vert_array, bm->totvert); } -#pragma omp section - { BM_iter_as_array(bm, BM_EDGES_OF_MESH, NULL, (void **)edge_array, bm->totedge); } -#pragma omp section - { BM_iter_as_array(bm, BM_FACES_OF_MESH, NULL, (void **)face_array, bm->totface); } - } - for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) { + BMElem **ele_p; switch (msel->type) { case ME_VSEL: - BM_select_history_store(bm, (BMElem *)vert_array[msel->index]); + ele_p = (BMElem **)&vtable[msel->index]; break; case ME_ESEL: - BM_select_history_store(bm, (BMElem *)edge_array[msel->index]); + ele_p = (BMElem **)&etable[msel->index]; break; case ME_FSEL: - BM_select_history_store(bm, (BMElem *)face_array[msel->index]); + ele_p = (BMElem **)&ftable[msel->index]; break; + default: + continue; } - } - MEM_freeN(vert_array); - MEM_freeN(edge_array); - MEM_freeN(face_array); + if (*ele_p != NULL) { + BM_select_history_store_notest(bm, *ele_p); + *ele_p = NULL; + } + } } else { - me->totselect = 0; - if (me->mselect) { - MEM_freeN(me->mselect); - me->mselect = NULL; - } + BM_select_history_clear(bm); } MEM_freeN(vtable); MEM_freeN(etable); + if (ftable) { + MEM_freeN(ftable); + } } diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.c b/source/blender/bmesh/intern/bmesh_mesh_validate.c index 7c9ebc800a3..3a6a3543bc8 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_validate.c +++ b/source/blender/bmesh/intern/bmesh_mesh_validate.c @@ -41,7 +41,7 @@ /* macro which inserts the function name */ -#if defined __GNUC__ || defined __sun +#if defined __GNUC__ # define ERRMSG(format, args...) { fprintf(stderr, "%s: " format ", " AT "\n", __func__, ##args); errtot++; } (void)0 #else # define ERRMSG(format, ...) { fprintf(stderr, "%s: " format ", " AT "\n", __func__, __VA_ARGS__); errtot++; } (void)0 diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index a4621b45fe6..7b9d17b27b5 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -39,6 +39,8 @@ #include "BLI_polyfill2d.h" #include "BLI_polyfill2d_beautify.h" #include "BLI_linklist.h" +#include "BLI_edgehash.h" +#include "BLI_heap.h" #include "bmesh.h" #include "bmesh_tools.h" @@ -1474,3 +1476,147 @@ void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptri #undef USE_TESSFACE_SPEEDUP } + + +/** + * A version of #BM_mesh_calc_tessellation that avoids degenerate triangles. + */ +void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot) +{ + /* this assumes all faces can be scan-filled, which isn't always true, + * worst case we over alloc a little which is acceptable */ +#ifndef NDEBUG + const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop); +#endif + + BMIter iter; + BMFace *efa; + int i = 0; + + MemArena *pf_arena = NULL; + + /* use_beauty */ + Heap *pf_heap = NULL; + EdgeHash *pf_ehash = NULL; + + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + /* don't consider two-edged faces */ + if (UNLIKELY(efa->len < 3)) { + /* do nothing */ + } + else if (efa->len == 3) { + BMLoop *l; + BMLoop **l_ptr = looptris[i++]; + l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa); + l_ptr[1] = l = l->next; + l_ptr[2] = l->next; + } + else if (efa->len == 4) { + BMLoop *l_v1 = BM_FACE_FIRST_LOOP(efa); + BMLoop *l_v2 = l_v1->next; + BMLoop *l_v3 = l_v2->next; + BMLoop *l_v4 = l_v1->prev; + + /* #BM_verts_calc_rotate_beauty performs excessive checks we don't need! + * It's meant for rotating edges, it also calculates a new normal. + * + * Use #BLI_polyfill_beautify_quad_rotate_calc since we have the normal. + */ +#if 0 + const bool split_13 = (BM_verts_calc_rotate_beauty( + l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) < 0.0f); +#else + float axis_mat[3][3], v_quad[4][2]; + axis_dominant_v3_to_m3(axis_mat, efa->no); + mul_v2_m3v3(v_quad[0], axis_mat, l_v1->v->co); + mul_v2_m3v3(v_quad[1], axis_mat, l_v2->v->co); + mul_v2_m3v3(v_quad[2], axis_mat, l_v3->v->co); + mul_v2_m3v3(v_quad[3], axis_mat, l_v4->v->co); + + const bool split_13 = BLI_polyfill_beautify_quad_rotate_calc( + v_quad[0], v_quad[1], v_quad[2], v_quad[3]) < 0.0f; +#endif + + BMLoop **l_ptr_a = looptris[i++]; + BMLoop **l_ptr_b = looptris[i++]; + if (split_13) { + l_ptr_a[0] = l_v1; + l_ptr_a[1] = l_v2; + l_ptr_a[2] = l_v3; + + l_ptr_b[0] = l_v1; + l_ptr_b[1] = l_v3; + l_ptr_b[2] = l_v4; + } + else { + l_ptr_a[0] = l_v1; + l_ptr_a[1] = l_v2; + l_ptr_a[2] = l_v4; + + l_ptr_b[0] = l_v2; + l_ptr_b[1] = l_v3; + l_ptr_b[2] = l_v4; + } + } + else { + int j; + + BMLoop *l_iter; + BMLoop *l_first; + BMLoop **l_arr; + + float axis_mat[3][3]; + float (*projverts)[2]; + unsigned int (*tris)[3]; + + const int totfilltri = efa->len - 2; + + if (UNLIKELY(pf_arena == NULL)) { + pf_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE); + pf_ehash = BLI_edgehash_new_ex(__func__, BLI_POLYFILL_ALLOC_NGON_RESERVE); + } + + tris = BLI_memarena_alloc(pf_arena, sizeof(*tris) * totfilltri); + l_arr = BLI_memarena_alloc(pf_arena, sizeof(*l_arr) * efa->len); + projverts = BLI_memarena_alloc(pf_arena, sizeof(*projverts) * efa->len); + + axis_dominant_v3_to_m3_negate(axis_mat, efa->no); + + j = 0; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + l_arr[j] = l_iter; + mul_v2_m3v3(projverts[j], axis_mat, l_iter->v->co); + j++; + } while ((l_iter = l_iter->next) != l_first); + + BLI_polyfill_calc_arena((const float (*)[2])projverts, efa->len, 1, tris, pf_arena); + + BLI_polyfill_beautify((const float (*)[2])projverts, efa->len, tris, pf_arena, pf_heap, pf_ehash); + + for (j = 0; j < totfilltri; j++) { + BMLoop **l_ptr = looptris[i++]; + unsigned int *tri = tris[j]; + + l_ptr[0] = l_arr[tri[0]]; + l_ptr[1] = l_arr[tri[1]]; + l_ptr[2] = l_arr[tri[2]]; + } + + BLI_memarena_clear(pf_arena); + } + } + + if (pf_arena) { + BLI_memarena_free(pf_arena); + + BLI_heap_free(pf_heap, NULL); + BLI_edgehash_free(pf_ehash, NULL); + } + + *r_looptris_tot = i; + + BLI_assert(i <= looptris_tot); + +} diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h index d944f3a8bc5..313caac1243 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.h +++ b/source/blender/bmesh/intern/bmesh_polygon.h @@ -33,6 +33,7 @@ struct Heap; #include "BLI_compiler_attrs.h" void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot); +void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot); void BM_face_calc_tessellation( const BMFace *f, const bool use_fixed_quad, diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c index e515f9af63f..8a3cb329610 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -32,7 +32,7 @@ #include "BLI_memarena.h" #include "BLI_array.h" #include "BLI_alloca.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_linklist_stack.h" #include "BLI_sort.h" #include "BLI_sort_utils.h" @@ -725,10 +725,30 @@ BLI_INLINE bool edge_isect_verts_point_2d( const BMEdge *e, const BMVert *v_a, const BMVert *v_b, float r_isect[2]) { - return ((isect_seg_seg_v2_point(v_a->co, v_b->co, e->v1->co, e->v2->co, r_isect) == 1) && + /* This bias seems like it could be too large, + * mostly its not needed, see T52329 for example where it is. */ + const float endpoint_bias = 1e-4f; + return ((isect_seg_seg_v2_point_ex(v_a->co, v_b->co, e->v1->co, e->v2->co, endpoint_bias, r_isect) == 1) && ((e->v1 != v_a) && (e->v2 != v_a) && (e->v1 != v_b) && (e->v2 != v_b))); } +BLI_INLINE int axis_pt_cmp(const float pt_a[2], const float pt_b[2]) +{ + if (pt_a[0] < pt_b[0]) { + return -1; + } + if (pt_a[0] > pt_b[0]) { + return 1; + } + if (pt_a[1] < pt_b[1]) { + return -1; + } + if (pt_a[1] > pt_b[1]) { + return 1; + } + return 0; +} + /** * Represents isolated edge-links, * each island owns contiguous slices of the vert array. @@ -749,7 +769,8 @@ struct EdgeGroupIsland { struct { BMVert *min, *max; /* used for sorting only */ - float min_axis; + float min_axis[2]; + float max_axis[2]; } vert_span; }; @@ -758,12 +779,11 @@ static int group_min_cmp_fn(const void *p1, const void *p2) const struct EdgeGroupIsland *g1 = *(struct EdgeGroupIsland **)p1; const struct EdgeGroupIsland *g2 = *(struct EdgeGroupIsland **)p2; /* min->co[SORT_AXIS] hasn't been applied yet */ - const float f1 = g1->vert_span.min_axis; - const float f2 = g2->vert_span.min_axis; - - if (f1 < f2) return -1; - if (f1 > f2) return 1; - else return 0; + int test = axis_pt_cmp(g1->vert_span.min_axis, g2->vert_span.min_axis); + if (UNLIKELY(test == 0)) { + test = axis_pt_cmp(g1->vert_span.max_axis, g2->vert_span.max_axis); + } + return test; } struct Edges_VertVert_BVHTreeTest { @@ -993,8 +1013,8 @@ static int bm_face_split_edgenet_find_connection( for (int j = 0; j < 2; j++) { BMVert *v_iter = v_pair[j]; if (BM_elem_flag_test(v_iter, VERT_IS_VALID)) { - if (direction_sign ? (v_iter->co[SORT_AXIS] >= v_origin->co[SORT_AXIS]) : - (v_iter->co[SORT_AXIS] <= v_origin->co[SORT_AXIS])) + if (direction_sign ? (v_iter->co[SORT_AXIS] > v_origin->co[SORT_AXIS]) : + (v_iter->co[SORT_AXIS] < v_origin->co[SORT_AXIS])) { BLI_SMALLSTACK_PUSH(vert_search, v_iter); BLI_SMALLSTACK_PUSH(vert_blacklist, v_iter); @@ -1360,8 +1380,8 @@ bool BM_face_split_edgenet_connect_islands( /* init with *any* different verts */ g->vert_span.min = ((BMEdge *)edge_links->link)->v1; g->vert_span.max = ((BMEdge *)edge_links->link)->v2; - float min_axis = FLT_MAX; - float max_axis = -FLT_MAX; + float min_axis[2] = {FLT_MAX, FLT_MAX}; + float max_axis[2] = {-FLT_MAX, -FLT_MAX}; do { BMEdge *e = edge_links->link; @@ -1372,24 +1392,29 @@ bool BM_face_split_edgenet_connect_islands( BLI_assert(v_iter->head.htype == BM_VERT); /* ideally we could use 'v_iter->co[SORT_AXIS]' here, * but we need to sort the groups before setting the vertex array order */ + const float axis_value[2] = { #if SORT_AXIS == 0 - const float axis_value = dot_m3_v3_row_x(axis_mat, v_iter->co); + dot_m3_v3_row_x(axis_mat, v_iter->co), + dot_m3_v3_row_y(axis_mat, v_iter->co), #else - const float axis_value = dot_m3_v3_row_y(axis_mat, v_iter->co); + dot_m3_v3_row_y(axis_mat, v_iter->co), + dot_m3_v3_row_x(axis_mat, v_iter->co), #endif + }; - if (axis_value < min_axis) { + if (axis_pt_cmp(axis_value, min_axis) == -1) { g->vert_span.min = v_iter; - min_axis = axis_value; + copy_v2_v2(min_axis, axis_value); } - if (axis_value > max_axis ) { + if (axis_pt_cmp(axis_value, max_axis) == 1) { g->vert_span.max = v_iter; - max_axis = axis_value; + copy_v2_v2(max_axis, axis_value); } } } while ((edge_links = edge_links->next)); - g->vert_span.min_axis = min_axis; + copy_v2_v2(g->vert_span.min_axis, min_axis); + copy_v2_v2(g->vert_span.max_axis, max_axis); g->has_prev_edge = false; @@ -1449,8 +1474,10 @@ bool BM_face_split_edgenet_connect_islands( bm->elem_index_dirty |= BM_VERT; - /* Now create bvh tree*/ - BVHTree *bvhtree = BLI_bvhtree_new(edge_arr_len, 0.0f, 8, 8); + /* Now create bvh tree + * + * Note that a large epsilon is used because meshes with dimensions of around 100+ need it. see T52329. */ + BVHTree *bvhtree = BLI_bvhtree_new(edge_arr_len, 1e-4f, 8, 8); for (uint i = 0; i < edge_arr_len; i++) { const float e_cos[2][3] = { {UNPACK2(edge_arr[i]->v1->co), 0.0f}, diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h index 4161fbe90fb..4dcf97e3f35 100644 --- a/source/blender/bmesh/intern/bmesh_private.h +++ b/source/blender/bmesh/intern/bmesh_private.h @@ -44,13 +44,14 @@ # define BM_CHECK_ELEMENT(el) (void)(el) #else int bmesh_elem_check(void *element, const char htype); -# define BM_CHECK_ELEMENT(el) \ +# define BM_CHECK_ELEMENT(el) { \ if (bmesh_elem_check(el, ((BMHeader *)el)->htype)) { \ printf("check_element failure, with code %i on line %i in file\n" \ " \"%s\"\n\n", \ bmesh_elem_check(el, ((BMHeader *)el)->htype), \ __LINE__, __FILE__); \ - } (void)0 + } \ +} ((void)0) #endif int bmesh_radial_length(const BMLoop *l); diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 668fb998254..5bdc3927e16 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -36,7 +36,7 @@ #include "BLI_math.h" #include "BLI_alloca.h" #include "BLI_linklist.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BKE_customdata.h" @@ -754,6 +754,22 @@ bool BM_vert_is_edge_pair(const BMVert *v) } /** + * Fast alternative to ``(BM_vert_edge_count(v) == 2)`` + * that checks both edges connect to the same faces. + */ +bool BM_vert_is_edge_pair_manifold(const BMVert *v) +{ + const BMEdge *e = v->e; + if (e) { + BMEdge *e_other = BM_DISK_EDGE_NEXT(e, v); + if (((e_other != e) && (BM_DISK_EDGE_NEXT(e_other, v) == e))) { + return BM_edge_is_manifold(e) && BM_edge_is_manifold(e_other); + } + } + return false; +} + +/** * Access a verts 2 connected edges. * * \return true when only 2 verts are found. diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 83977fa8be0..c9fce96c798 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -85,6 +85,7 @@ int BM_vert_face_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_vert_is_edge_pair_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b); bool BM_vert_face_check(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/bmesh/operators/bmo_bisect_plane.c b/source/blender/bmesh/operators/bmo_bisect_plane.c index 2c80ff651b8..ed232e81b82 100644 --- a/source/blender/bmesh/operators/bmo_bisect_plane.c +++ b/source/blender/bmesh/operators/bmo_bisect_plane.c @@ -29,7 +29,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_math.h" #include "bmesh.h" diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c index c5c4ac959a9..0b5f1bb9ca1 100644 --- a/source/blender/bmesh/operators/bmo_connect.c +++ b/source/blender/bmesh/operators/bmo_connect.c @@ -27,7 +27,7 @@ */ #include "BLI_utildefines.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_alloca.h" #include "BLI_linklist_stack.h" diff --git a/source/blender/bmesh/operators/bmo_offset_edgeloops.c b/source/blender/bmesh/operators/bmo_offset_edgeloops.c index a9840a72fc9..269f933f27f 100644 --- a/source/blender/bmesh/operators/bmo_offset_edgeloops.c +++ b/source/blender/bmesh/operators/bmo_offset_edgeloops.c @@ -33,7 +33,7 @@ #include "BLI_math.h" #include "BLI_alloca.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BKE_customdata.h" diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index cca0f7387cd..d8f83d786b4 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -839,7 +839,7 @@ void BM_mesh_calc_uvs_grid( const float dx = 1.0f / (float)(x_segments - 1); const float dy = 1.0f / (float)(y_segments - 1); float x = 0.0f; - float y = 0.0f; + float y = dy; int loop_index; @@ -854,16 +854,16 @@ void BM_mesh_calc_uvs_grid( switch (loop_index) { case 0: - x += dx; + y -= dy; break; case 1: - y += dy; + x += dx; break; case 2: - x -= dx; + y += dy; break; case 3: - y -= dy; + x -= dx; break; default: break; diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index 7d19d90807a..e85751531ae 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -30,7 +30,8 @@ #include "BLI_math.h" #include "BLI_alloca.h" -#include "BLI_stackdefines.h" +#include "BLI_kdtree.h" +#include "BLI_utildefines_stack.h" #include "BLI_stack.h" #include "BKE_customdata.h" @@ -277,22 +278,7 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) BMO_mesh_delete_oflag_context(bm, ELE_DEL, DEL_ONLYTAGGED); } -static int vergaverco(const void *e1, const void *e2) -{ - const BMVert *v1 = *(const void **)e1, *v2 = *(const void **)e2; - float x1 = v1->co[0] + v1->co[1] + v1->co[2]; - float x2 = v2->co[0] + v2->co[1] + v2->co[2]; - - if (x1 > x2) return 1; - else if (x1 < x2) return -1; - else return 0; -} - -// #define VERT_TESTED 1 // UNUSED -#define VERT_DOUBLE 2 -#define VERT_TARGET 4 #define VERT_KEEP 8 -// #define VERT_MARK 16 // UNUSED #define VERT_IN 32 #define EDGE_MARK 1 @@ -584,77 +570,62 @@ static void bmesh_find_doubles_common( BMesh *bm, BMOperator *op, BMOperator *optarget, BMOpSlot *optarget_slot) { - BMVert **verts; - int verts_len; + const BMOpSlot *slot_verts = BMO_slot_get(op->slots_in, "verts"); + BMVert * const *verts = (BMVert **)slot_verts->data.buf; + const int verts_len = slot_verts->len; - int i, j, keepvert = 0; + bool has_keep_vert = false; + bool found_duplicates = false; const float dist = BMO_slot_float_get(op->slots_in, "dist"); - const float dist_sq = dist * dist; - const float dist3 = ((float)M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */ /* Test whether keep_verts arg exists and is non-empty */ if (BMO_slot_exists(op->slots_in, "keep_verts")) { BMOIter oiter; - keepvert = BMO_iter_new(&oiter, op->slots_in, "keep_verts", BM_VERT) != NULL; + has_keep_vert = BMO_iter_new(&oiter, op->slots_in, "keep_verts", BM_VERT) != NULL; } - /* get the verts as an array we can sort */ - verts = BMO_slot_as_arrayN(op->slots_in, "verts", &verts_len); - - /* sort by vertex coordinates added together */ - qsort(verts, verts_len, sizeof(BMVert *), vergaverco); - /* Flag keep_verts */ - if (keepvert) { + if (has_keep_vert) { BMO_slot_buffer_flag_enable(bm, op->slots_in, "keep_verts", BM_VERT, VERT_KEEP); } - for (i = 0; i < verts_len; i++) { - BMVert *v_check = verts[i]; - - if (BMO_vert_flag_test(bm, v_check, VERT_DOUBLE | VERT_TARGET)) { - continue; + int *duplicates = MEM_mallocN(sizeof(int) * verts_len, __func__); + { + KDTree *tree = BLI_kdtree_new(verts_len); + for (int i = 0; i < verts_len; i++) { + BLI_kdtree_insert(tree, i, verts[i]->co); + if (has_keep_vert && BMO_vert_flag_test(bm, verts[i], VERT_KEEP)) { + duplicates[i] = i; + } + else { + duplicates[i] = -1; + } } - for (j = i + 1; j < verts_len; j++) { - BMVert *v_other = verts[j]; - - /* a match has already been found, (we could check which is best, for now don't) */ - if (BMO_vert_flag_test(bm, v_other, VERT_DOUBLE | VERT_TARGET)) { - continue; - } + BLI_kdtree_balance(tree); + found_duplicates = BLI_kdtree_calc_duplicates_fast(tree, dist, false, duplicates) != 0; + BLI_kdtree_free(tree); + } - /* Compare sort values of the verts using 3x tolerance (allowing for the tolerance - * on each of the three axes). This avoids the more expensive length comparison - * for most vertex pairs. */ - if ((v_other->co[0] + v_other->co[1] + v_other->co[2]) - - (v_check->co[0] + v_check->co[1] + v_check->co[2]) > dist3) - { - break; + if (found_duplicates) { + for (int i = 0; i < verts_len; i++) { + BMVert *v_check = verts[i]; + if (duplicates[i] == -1) { + /* nop (others can use as target) */ } - - if (keepvert) { - if (BMO_vert_flag_test(bm, v_other, VERT_KEEP) == BMO_vert_flag_test(bm, v_check, VERT_KEEP)) - continue; + else if (duplicates[i] == i) { + /* keep (others can use as target) */ } - - if (compare_len_squared_v3v3(v_check->co, v_other->co, dist_sq)) { - - /* If one vert is marked as keep, make sure it will be the target */ - if (BMO_vert_flag_test(bm, v_other, VERT_KEEP)) { - SWAP(BMVert *, v_check, v_other); - } - - BMO_vert_flag_enable(bm, v_other, VERT_DOUBLE); - BMO_vert_flag_enable(bm, v_check, VERT_TARGET); - - BMO_slot_map_elem_insert(optarget, optarget_slot, v_other, v_check); + else { + BMVert *v_other = verts[duplicates[i]]; + BLI_assert(ELEM(duplicates[duplicates[i]], -1, duplicates[i])); + BMO_slot_map_elem_insert(optarget, optarget_slot, v_check, v_other); } } } - MEM_freeN(verts); + MEM_freeN(duplicates); } void bmo_remove_doubles_exec(BMesh *bm, BMOperator *op) diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c index 94b60a51f68..adcc0c71629 100644 --- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c +++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c @@ -40,7 +40,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_alloca.h" #include "BLI_math.h" #include "BLI_listbase.h" diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c index f08f21a2c88..6e6242fc9f9 100644 --- a/source/blender/bmesh/tools/bmesh_beautify.c +++ b/source/blender/bmesh/tools/bmesh_beautify.c @@ -150,7 +150,7 @@ static float bm_edge_calc_rotate_beauty__area( (ELEM(v4, v1, v2, v3) == false)); add_v3_v3v3(no, no_a, no_b); - if (UNLIKELY((no_scale = normalize_v3(no)) <= FLT_EPSILON)) { + if (UNLIKELY((no_scale = normalize_v3(no)) == 0.0f)) { break; } @@ -182,7 +182,12 @@ static float bm_edge_calc_rotate_beauty__area( } } - return BLI_polyfill_beautify_quad_rotate_calc(v1_xy, v2_xy, v3_xy, v4_xy); + /** + * Important to lock degenerate here, + * since the triangle pars will be projected into different 2D spaces. + * Allowing to rotate out of a degenerate state can flip the faces (when performed iteratively). + */ + return BLI_polyfill_beautify_quad_rotate_calc_ex(v1_xy, v2_xy, v3_xy, v4_xy, true); } while (false); return FLT_MAX; diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 6673c5d25cf..51a0fa4b2cc 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -234,7 +234,7 @@ static bool nearly_parallel(const float d1[3], const float d2[3]) float ang; ang = angle_v3v3(d1, d2); - return (fabsf(ang) < BEVEL_EPSILON_ANG) || (fabsf(ang - M_PI) < BEVEL_EPSILON_ANG); + return (fabsf(ang) < BEVEL_EPSILON_ANG) || (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_ANG); } /* Make a new BoundVert of the given kind, insert it at the end of the circular linked @@ -4531,53 +4531,198 @@ static void set_profile_spacing(BevelParams *bp) } /* - * Calculate and return an offset that is the lesser of the current + * Assume we have a situation like: + * + * a d + * \ / + * A \ / C + * \ th1 th2/ + * b---------c + * B + * + * where edges are A, B, and C, + * following a face around vertices a, b, c, d; + * th1 is angle abc and th2 is angle bcd; + * and the argument EdgeHalf eb is B, going from b to c. + * In general case, edge offset specs for A, B, C have + * the form ka*t, kb*t, kc*t where ka, kb, kc are some factors + * (may be 0) and t is the current bp->offset. + * We want to calculate t at which the clone of B parallel + * to it collapses. This can be calculated using trig. + * Another case of geometry collision that can happen is + * When B slides along A because A is unbeveled. + * Then it might collide with a. Similarly for B sliding along C. + */ +static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb) +{ + EdgeHalf *ea, *ec, *ebother; + BevVert *bvc; + BMLoop *lb; + BMVert *va, *vb, *vc, *vd; + float ka, kb, kc, g, h, t, den, no_collide_offset, th1, th2, sin1, sin2, tan1, tan2, limit; + + limit = no_collide_offset = bp->offset + 1e6; + if (bp->offset == 0.0f) + return no_collide_offset; + kb = eb->offset_l_spec; + ea = eb->next; /* note: this is in direction b --> a */ + ka = ea->offset_r_spec; + if (eb->is_rev) { + vc = eb->e->v1; + vb = eb->e->v2; + } + else { + vb = eb->e->v1; + vc = eb->e->v2; + } + va = ea->is_rev ? ea->e->v1 : ea->e->v2; + bvc = NULL; + ebother = find_other_end_edge_half(bp, eb, &bvc); + if (ebother != NULL) { + ec = ebother->prev; /* note: this is in direction c --> d*/ + vc = bvc->v; + kc = ec->offset_l_spec; + vd = ec->is_rev ? ec->e->v1 : ec->e->v2; + } + else { + /* No bevvert for w, so C can't be beveled */ + kc = 0.0f; + ec = NULL; + /* Find an edge from c that has same face */ + lb = BM_face_edge_share_loop(eb->fnext, eb->e); + if (!lb) { + return no_collide_offset; + } + if (lb->next->v == vc) + vd = lb->next->next->v; + else if (lb->v == vc) + vd = lb->prev->v; + else { + return no_collide_offset; + } + } + if (ea->e == eb->e || (ec && ec->e == eb->e)) + return no_collide_offset; + ka = ka / bp->offset; + kb = kb / bp->offset; + kc = kc / bp->offset; + th1 = angle_v3v3v3(va->co, vb->co, vc->co); + th2 = angle_v3v3v3(vb->co, vc->co, vd->co); + + /* First calculate offset at which edge B collapses, which happens + * when advancing clones of A, B, C all meet at a point. + * This only happens if at least two of those three edges have non-zero k's */ + sin1 = sinf(th1); + sin2 = sinf(th2); + if ((ka > 0.0f) + (kb > 0.0f) + (kc > 0.0f) >= 2) { + tan1 = tanf(th1); + tan2 = tanf(th2); + g = tan1 * tan2; + h = sin1 * sin2; + den = g * (ka * sin2 + kc * sin1) + kb * h * (tan1 + tan2); + if (den != 0.0f) { + t = BM_edge_calc_length(eb->e); + t *= g * h / den; + if (t >= 0.0f) + limit = t; + } + } + + /* Now check edge slide cases */ + if (kb > 0.0f && ka == 0.0f /*&& bvb->selcount == 1 && bvb->edgecount > 2*/) { + t = BM_edge_calc_length(ea->e); + t *= sin1 / kb; + if (t >= 0.0f && t < limit) + limit = t; + } + if (kb > 0.0f && kc == 0.0f /* && bvc && ec && bvc->selcount == 1 && bvc->edgecount > 2 */) { + t = BM_edge_calc_length(ec->e); + t *= sin2 / kb; + if (t >= 0.0f && t < limit) + limit = t; + } + return limit; +} + +/* + * We have an edge A between vertices a and b, + * where EdgeHalf ea is the half of A that starts at a. + * For vertex-only bevels, the new vertices slide from a at a rate ka*t + * and from b at a rate kb*t. + * We want to calculate the t at which the two meet. + */ +static float vertex_collide_offset(BevelParams *bp, EdgeHalf *ea) +{ + float limit, ka, kb, no_collide_offset, la, kab; + EdgeHalf *eb; + + limit = no_collide_offset = bp->offset + 1e6; + if (bp->offset == 0.0f) + return no_collide_offset; + ka = ea->offset_l_spec / bp->offset; + eb = find_other_end_edge_half(bp, ea, NULL); + kb = eb ? eb->offset_l_spec / bp->offset : 0.0f; + kab = ka + kb; + la = BM_edge_calc_length(ea->e); + if (kab <= 0.0f) + return no_collide_offset; + limit = la / kab; + return limit; +} + +/* + * Calculate an offset that is the lesser of the current * bp.offset and the maximum possible offset before geometry * collisions happen. - * Currently this is a quick and dirty estimate of the max - * possible: half the minimum edge length of any vertex involved - * in a bevel. This is usually conservative. - * The correct calculation is quite complicated. - * TODO: implement this correctly. + * If the offset changes as a result of this, adjust the + * current edge offset specs to reflect this clamping, + * and store the new offset in bp.offset. */ -static float bevel_limit_offset(BMesh *bm, BevelParams *bp) +static void bevel_limit_offset(BevelParams *bp) { - BMVert *v; - BMEdge *e; - BMIter v_iter, e_iter; - float limited_offset, half_elen; - bool vbeveled; + BevVert *bv; + EdgeHalf *eh; + GHashIterator giter; + float limited_offset, offset_factor, collision_offset; + int i; limited_offset = bp->offset; - if (bp->offset_type == BEVEL_AMT_PERCENT) { - if (limited_offset > 50.0f) - limited_offset = 50.0f; - return limited_offset; - } - BM_ITER_MESH (v, &v_iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + GHASH_ITER(giter, bp->vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + for (i = 0; i < bv->edgecount; i++) { + eh = &bv->edges[i]; if (bp->vertex_only) { - vbeveled = true; + collision_offset = vertex_collide_offset(bp, eh); + if (collision_offset < limited_offset) + limited_offset = collision_offset; } else { - vbeveled = false; - BM_ITER_ELEM (e, &e_iter, v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(BM_edge_other_vert(e, v), BM_ELEM_TAG)) { - vbeveled = true; - break; - } - } + collision_offset = geometry_collide_offset(bp, eh); + if (collision_offset < limited_offset) + limited_offset = collision_offset; } - if (vbeveled) { - BM_ITER_ELEM (e, &e_iter, v, BM_EDGES_OF_VERT) { - half_elen = 0.5f * BM_edge_calc_length(e); - if (half_elen < limited_offset) - limited_offset = half_elen; - } + } + } + + if (limited_offset < bp->offset) { + /* All current offset specs have some number times bp->offset, + * so we can just multiply them all by the reduction factor + * of the offset to have the effect of recalculating the specs + * with the new limited_offset. + */ + offset_factor = limited_offset / bp->offset; + GHASH_ITER(giter, bp->vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + for (i = 0; i < bv->edgecount; i++) { + eh = &bv->edges[i]; + eh->offset_l_spec *= offset_factor; + eh->offset_r_spec *= offset_factor; + eh->offset_l *= offset_factor; + eh->offset_r *= offset_factor; } } + bp->offset = limited_offset; } - return limited_offset; } /** @@ -4604,6 +4749,7 @@ void BM_mesh_bevel( BMEdge *e; BevVert *bv; BevelParams bp = {NULL}; + GHashIterator giter; bp.offset = offset; bp.offset_type = offset_type; @@ -4627,24 +4773,33 @@ void BM_mesh_bevel( BLI_memarena_use_calloc(bp.mem_arena); set_profile_spacing(&bp); - if (limit_offset) - bp.offset = bevel_limit_offset(bm, &bp); - /* Analyze input vertices, sorting edges and assigning initial new vertex positions */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { bv = bevel_vert_construct(bm, &bp, v); - if (bv) + if (!limit_offset && bv) build_boundary(&bp, bv, true); } } + /* Perhaps clamp offset to avoid geometry colliisions */ + if (limit_offset) { + bevel_limit_offset(&bp); + + /* Assign initial new vertex positions */ + GHASH_ITER(giter, bp.vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + build_boundary(&bp, bv, true); + } + } + /* Perhaps do a pass to try to even out widths */ if (!bp.vertex_only) { adjust_offsets(&bp); } /* Build the meshes around vertices, now that positions are final */ + /* Note: could use GHASH_ITER over bp.vert_hash when backward compatibility no longer matters */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { bv = find_bevvert(&bp, v); diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c index 676a8de94c8..f3927a3ff67 100644 --- a/source/blender/bmesh/tools/bmesh_bisect_plane.c +++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c @@ -38,7 +38,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_alloca.h" #include "BLI_linklist.h" #include "BLI_linklist_stack.h" diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c index c417131d588..36ae7231f94 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c +++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c @@ -40,7 +40,7 @@ #include "BLI_edgehash.h" #include "BLI_polyfill2d.h" #include "BLI_polyfill2d_beautify.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BKE_customdata.h" diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c index b9408492cc1..9d1b20cb4d2 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.c +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -44,7 +44,7 @@ #include "BLI_sort_utils.h" #include "BLI_linklist_stack.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #ifndef NDEBUG # include "BLI_array_utils.h" #endif diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c index 30b083cacda..85c591b6684 100644 --- a/source/blender/bmesh/tools/bmesh_path.c +++ b/source/blender/bmesh/tools/bmesh_path.c @@ -38,24 +38,34 @@ /* -------------------------------------------------------------------- */ /* Generic Helpers */ -static float step_cost_3_v3(const float v1[3], const float v2[3], const float v3[3]) +/** + * Use skip options when we want to start measuring from a boundary. + */ +static float step_cost_3_v3_ex( + const float v1[3], const float v2[3], const float v3[3], + bool skip_12, bool skip_23) { - float cost, d1[3], d2[3]; - + float d1[3], d2[3]; /* The cost is based on the simple sum of the length of the two edgees... */ sub_v3_v3v3(d1, v2, v1); sub_v3_v3v3(d2, v3, v2); - cost = normalize_v3(d1) + normalize_v3(d2); + const float cost_12 = normalize_v3(d1); + const float cost_23 = normalize_v3(d2); + const float cost = ((skip_12 ? 0.0f : cost_12) + + (skip_23 ? 0.0f : cost_23)); /* but is biased to give higher values to sharp turns, so that it will take * paths with fewer "turns" when selecting between equal-weighted paths between * the two edges */ - cost = cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v3v3(d1, d2))))); - - return cost; + return cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v3v3(d1, d2))))); } +static float step_cost_3_v3( + const float v1[3], const float v2[3], const float v3[3]) +{ + return step_cost_3_v3_ex(v1, v2, v3, false, false); +} /* -------------------------------------------------------------------- */ @@ -364,7 +374,7 @@ LinkNode *BM_mesh_calc_path_edge( /* -------------------------------------------------------------------- */ /* BM_mesh_calc_path_face */ -static float facetag_cut_cost_edge(BMFace *f_a, BMFace *f_b, BMEdge *e) +static float facetag_cut_cost_edge(BMFace *f_a, BMFace *f_b, BMEdge *e, const void * const f_endpoints[2]) { float f_a_cent[3]; float f_b_cent[3]; @@ -392,10 +402,12 @@ static float facetag_cut_cost_edge(BMFace *f_a, BMFace *f_b, BMEdge *e) } #endif - return step_cost_3_v3(f_a_cent, e_cent, f_b_cent); + return step_cost_3_v3_ex( + f_a_cent, e_cent, f_b_cent, + (f_a == f_endpoints[0]), (f_b == f_endpoints[1])); } -static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v) +static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v, const void * const f_endpoints[2]) { float f_a_cent[3]; float f_b_cent[3]; @@ -403,12 +415,14 @@ static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v) BM_face_calc_center_mean_weighted(f_a, f_a_cent); BM_face_calc_center_mean_weighted(f_b, f_b_cent); - return step_cost_3_v3(f_a_cent, v->co, f_b_cent); + return step_cost_3_v3_ex( + f_a_cent, v->co, f_b_cent, + (f_a == f_endpoints[0]), (f_b == f_endpoints[1])); } static void facetag_add_adjacent( Heap *heap, BMFace *f_a, BMFace **faces_prev, float *cost, - const struct BMCalcPathParams *params) + const void * const f_endpoints[2], const struct BMCalcPathParams *params) { const int f_a_index = BM_elem_index_get(f_a); @@ -427,7 +441,7 @@ static void facetag_add_adjacent( /* we know 'f_b' is not visited, check it out! */ const int f_b_index = BM_elem_index_get(f_b); const float cost_cut = params->use_topology_distance ? - 1.0f : facetag_cut_cost_edge(f_a, f_b, l_iter->e); + 1.0f : facetag_cut_cost_edge(f_a, f_b, l_iter->e, f_endpoints); const float cost_new = cost[f_a_index] + cost_cut; if (cost[f_b_index] > cost_new) { @@ -454,7 +468,7 @@ static void facetag_add_adjacent( /* we know 'f_b' is not visited, check it out! */ const int f_b_index = BM_elem_index_get(f_b); const float cost_cut = params->use_topology_distance ? - 1.0f : facetag_cut_cost_vert(f_a, f_b, l_a->v); + 1.0f : facetag_cut_cost_vert(f_a, f_b, l_a->v, f_endpoints); const float cost_new = cost[f_a_index] + cost_cut; if (cost[f_b_index] > cost_new) { @@ -482,6 +496,9 @@ LinkNode *BM_mesh_calc_path_face( BMFace **faces_prev; int i, totface; + /* Start measuring face path at the face edges, ignoring their centers. */ + const void * const f_endpoints[2] = {f_src, f_dst}; + /* note, would pass BM_EDGE except we are looping over all faces anyway */ // BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG @@ -522,7 +539,7 @@ LinkNode *BM_mesh_calc_path_face( if (!BM_elem_flag_test(f, BM_ELEM_TAG)) { BM_elem_flag_enable(f, BM_ELEM_TAG); - facetag_add_adjacent(heap, f, faces_prev, cost, params); + facetag_add_adjacent(heap, f, faces_prev, cost, f_endpoints, params); } } diff --git a/source/blender/bmesh/tools/bmesh_path_region.c b/source/blender/bmesh/tools/bmesh_path_region.c index aad1f9c5a49..d23ea537d82 100644 --- a/source/blender/bmesh/tools/bmesh_path_region.c +++ b/source/blender/bmesh/tools/bmesh_path_region.c @@ -29,22 +29,32 @@ #include "BLI_math.h" #include "BLI_linklist.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_alloca.h" #include "bmesh.h" #include "bmesh_path_region.h" /* own include */ -/* Special handling of vertices with 2 edges - * (act as if the edge-chain is a single edge). */ +/** + * Special handling of vertices with 2 edges + * (act as if the edge-chain is a single edge). + * + * \note Regarding manifold edge stepping: #BM_vert_is_edge_pair_manifold usage. + * Logic to skip a chain of vertices is not applied at boundaries because it gives + * strange behavior from a user perspective especially with boundary quads, see: T52701 + * + * Restrict walking over a vertex chain to cases where the edges share the same faces. + * This is more typical of what a user would consider a vertex chain. + */ #define USE_EDGE_CHAIN #ifdef USE_EDGE_CHAIN /** - * Takes a vertex with 2 edge users and fills in the vertices at each end-point, - * or nothing if if the edges loop back to its self. + * Takes a vertex with 2 edge users and assigns the vertices at each end-point, + * + * \return Success when \a v_end_pair values are set or false if the edges loop back on themselves. */ static bool bm_vert_pair_ends(BMVert *v_pivot, BMVert *v_end_pair[2]) { @@ -53,7 +63,7 @@ static bool bm_vert_pair_ends(BMVert *v_pivot, BMVert *v_end_pair[2]) do { BMEdge *e_chain = e; BMVert *v_other = BM_edge_other_vert(e_chain, v_pivot); - while (BM_vert_is_edge_pair(v_other)) { + while (BM_vert_is_edge_pair_manifold(v_other)) { BMEdge *e_chain_next = BM_DISK_EDGE_NEXT(e_chain, v_other); BLI_assert(BM_DISK_EDGE_NEXT(e_chain_next, v_other) == e_chain); v_other = BM_edge_other_vert(e_chain_next, v_other); @@ -88,7 +98,7 @@ static bool bm_vert_region_test_chain(BMVert *v, int * const depths[2], const in if (bm_vert_region_test(v, depths, pass)) { return true; } - else if (BM_vert_is_edge_pair(v) && + else if (BM_vert_is_edge_pair_manifold(v) && bm_vert_pair_ends(v, v_end_pair) && bm_vert_region_test(v_end_pair[0], depths, pass) && bm_vert_region_test(v_end_pair[1], depths, pass)) @@ -206,7 +216,7 @@ static LinkNode *mesh_calc_path_region_elem( for (int i = 0; i < ele_verts_len[side]; i++) { BMVert *v = ele_verts[side][i]; BMVert *v_end_pair[2]; - if (BM_vert_is_edge_pair(v) && bm_vert_pair_ends(v, v_end_pair)) { + if (BM_vert_is_edge_pair_manifold(v) && bm_vert_pair_ends(v, v_end_pair)) { for (int j = 0; j < 2; j++) { const int v_end_index = BM_elem_index_get(v_end_pair[j]); if (depths[side][v_end_index] == -1) { @@ -239,7 +249,7 @@ static LinkNode *mesh_calc_path_region_elem( /* Walk along the chain, fill in values until we reach a vertex with 3+ edges. */ { BMEdge *e_chain = e; - while (BM_vert_is_edge_pair(v_b) && + while (BM_vert_is_edge_pair_manifold(v_b) && ((depths[side][v_b_index] == -1))) { depths[side][v_b_index] = pass; @@ -256,7 +266,7 @@ static LinkNode *mesh_calc_path_region_elem( /* Add the other vertex to the stack, to be traversed in the next pass. */ if (depths[side][v_b_index] == -1) { #ifdef USE_EDGE_CHAIN - BLI_assert(!BM_vert_is_edge_pair(v_b)); + BLI_assert(!BM_vert_is_edge_pair_manifold(v_b)); #endif BLI_assert(pass == depths[side][BM_elem_index_get(v_a)] + 1); depths[side][v_b_index] = pass; diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp index 3bff20e846b..d4f434d56fd 100644 --- a/source/blender/collada/AnimationExporter.cpp +++ b/source/blender/collada/AnimationExporter.cpp @@ -312,12 +312,12 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa if (ob->type == OB_ARMATURE) { ob_name = getObjectBoneName(ob, fcu); BLI_snprintf( - anim_id, - sizeof(anim_id), - "%s_%s.%s", - (char *)translate_id(ob_name).c_str(), - (char *)translate_id(transformName).c_str(), - axis_name); + anim_id, + sizeof(anim_id), + "%s_%s.%s", + (char *)translate_id(ob_name).c_str(), + (char *)translate_id(transformName).c_str(), + axis_name); } else { if (ma) @@ -326,12 +326,12 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa ob_name = id_name(ob); BLI_snprintf( - anim_id, - sizeof(anim_id), - "%s_%s_%s", - (char *)translate_id(ob_name).c_str(), - (char *)getAnimationPathId(fcu).c_str(), - axis_name); + anim_id, + sizeof(anim_id), + "%s_%s_%s", + (char *)translate_id(ob_name).c_str(), + (char *)getAnimationPathId(fcu).c_str(), + axis_name); } openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); @@ -530,7 +530,7 @@ void AnimationExporter::dae_baked_animation(std::vector<float> &fra, Object *ob_ addSampler(sampler); - std::string target = translate_id(bone_name) + "/transform"; + std::string target = get_joint_id(bone, ob_arm) + "/transform"; addChannel(COLLADABU::URI(empty, sampler_id), target); closeAnimation(); diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index 634071bc90f..dcfd062470c 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -305,7 +305,10 @@ int DocumentExporter::exportCurrentScene(Scene *sce) // <library_visual_scenes> SceneExporter se(writer, &arm_exporter, this->export_settings); - +#if 0 + /* The following code seems to be an obsolete workaround + Comment out until it proofs correct that we no longer need it. + */ if (has_animations && this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX) { // channels adressing <matrix> objects is not (yet) supported // So we force usage of <location>, <translation> and <scale> @@ -317,7 +320,9 @@ int DocumentExporter::exportCurrentScene(Scene *sce) else { se.setExportTransformationType(this->export_settings->export_transformation_type); } - +#else + se.setExportTransformationType(this->export_settings->export_transformation_type); +#endif se.exportScene(sce); // <scene> diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 435eaa0208a..f7fdfb06a40 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -508,9 +508,9 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA std::vector<Object *> *root_objects = new std::vector<Object *>(); fprintf(stderr, - "Writing node id='%s', name='%s'\n", - id.c_str(), - name.c_str()); + "Writing node id='%s', name='%s'\n", + id.c_str(), + name.c_str()); if (is_joint) { if (parent_node == NULL && !is_library_node) { diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp index b8b1ff7fd95..8a9ccbbed51 100644 --- a/source/blender/collada/GeometryExporter.cpp +++ b/source/blender/collada/GeometryExporter.cpp @@ -396,7 +396,7 @@ void GeometryExporter::createPolylist(short material_index, ostr << translate_id(material_id); facelist->setMaterial(ostr.str()); } - + COLLADASW::InputList &til = facelist->getInputList(); // creates <input> in <polylist> for vertices @@ -718,12 +718,13 @@ void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me) source.setArrayId(layer_id + ARRAY_ID_SUFFIX); source.setAccessorCount(me->totloop); - source.setAccessorStride(3); + source.setAccessorStride(4); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); param.push_back("R"); param.push_back("G"); param.push_back("B"); + param.push_back("A"); source.prepareToAppendValues(); @@ -735,7 +736,8 @@ void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me) source.appendValues( mlc->r / 255.0f, mlc->g / 255.0f, - mlc->b / 255.0f + mlc->b / 255.0f, + mlc->a / 255.0f ); } } diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp index e3dfd69d8ec..40db5efda27 100644 --- a/source/blender/compositor/intern/COM_compositor.cpp +++ b/source/blender/compositor/intern/COM_compositor.cpp @@ -64,9 +64,21 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende /* Make sure node tree has previews. * Don't create previews in advance, this is done when adding preview operations. * Reserved preview size is determined by render output for now. + * + * We fit the aspect into COM_PREVIEW_SIZE x COM_PREVIEW_SIZE image to avoid + * insane preview resolution, which might even overflow preview dimensions. */ - float aspect = rd->xsch > 0 ? (float)rd->ysch / (float)rd->xsch : 1.0f; - BKE_node_preview_init_tree(editingtree, COM_PREVIEW_SIZE, (int)(COM_PREVIEW_SIZE * aspect), false); + const float aspect = rd->xsch > 0 ? (float)rd->ysch / (float)rd->xsch : 1.0f; + int preview_width, preview_height; + if (aspect < 1.0f) { + preview_width = COM_PREVIEW_SIZE; + preview_height = (int)(COM_PREVIEW_SIZE * aspect); + } + else { + preview_width = (int)(COM_PREVIEW_SIZE / aspect); + preview_height = COM_PREVIEW_SIZE; + } + BKE_node_preview_init_tree(editingtree, preview_width, preview_height, false); /* initialize workscheduler, will check if already done. TODO deinitialize somewhere */ bool use_opencl = (editingtree->flag & NTREE_COM_OPENCL) != 0; diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cpp b/source/blender/compositor/nodes/COM_CompositorNode.cpp index 9e8b40d8af4..4754f23a167 100644 --- a/source/blender/compositor/nodes/COM_CompositorNode.cpp +++ b/source/blender/compositor/nodes/COM_CompositorNode.cpp @@ -41,6 +41,7 @@ void CompositorNode::convertToOperations(NodeConverter &converter, const Composi NodeInput *depthSocket = this->getInputSocket(2); CompositorOperation *compositorOperation = new CompositorOperation(); + compositorOperation->setScene(context.getScene()); compositorOperation->setSceneName(context.getScene()->id.name); compositorOperation->setRenderData(context.getRenderData()); compositorOperation->setViewName(context.getViewName()); diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp index 75128de2d84..2286db81860 100644 --- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp +++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp @@ -15,8 +15,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Jeroen Bakker + * Contributor: + * Jeroen Bakker * Monique Dewanchand */ @@ -25,16 +25,22 @@ #include "COM_TranslateOperation.h" #include "COM_RotateOperation.h" #include "COM_ScaleOperation.h" +#include "COM_SetColorOperation.h" #include "COM_SetValueOperation.h" +#include "COM_SetVectorOperation.h" RenderLayersNode::RenderLayersNode(bNode *editorNode) : Node(editorNode) { /* pass */ } -void RenderLayersNode::testSocketLink(NodeConverter &converter, const CompositorContext &context, - NodeOutput *output, RenderLayersProg *operation, - Scene *scene, int layerId, bool is_preview) const +void RenderLayersNode::testSocketLink(NodeConverter &converter, + const CompositorContext &context, + NodeOutput *output, + RenderLayersProg *operation, + Scene *scene, + int layerId, + bool is_preview) const { operation->setScene(scene); operation->setLayerId(layerId); @@ -43,45 +49,140 @@ void RenderLayersNode::testSocketLink(NodeConverter &converter, const Compositor converter.mapOutputSocket(output, operation->getOutputSocket()); converter.addOperation(operation); - + if (is_preview) /* only for image socket */ converter.addPreview(operation->getOutputSocket()); } -void RenderLayersNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const +void RenderLayersNode::testRenderLink(NodeConverter &converter, + const CompositorContext &context, + Render *re) const { Scene *scene = (Scene *)this->getbNode()->id; - short layerId = this->getbNode()->custom1; - Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL; - int numberOfOutputs = this->getNumberOfOutputSockets(); - - if (re) { - RenderResult *rr = RE_AcquireResultRead(re); - if (rr) { - SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&scene->r.layers, layerId); - if (srl) { - RenderLayer *rl = RE_GetRenderLayer(rr, srl->name); - if (rl) { - for (int i = 0; i < numberOfOutputs; i++) { - NodeOutput *output = this->getOutputSocket(i); - NodeImageLayer *storage = (NodeImageLayer*) output->getbNodeSocket()->storage; - RenderPass *rpass = (RenderPass*) BLI_findstring(&rl->passes, storage->pass_name, offsetof(RenderPass, name)); - if (rpass) { - if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && STREQ(output->getbNodeSocket()->name, "Alpha")) { - testSocketLink(converter, context, output, new RenderLayersAlphaProg(rpass->name, COM_DT_VALUE, rpass->channels), scene, layerId, false); - } - else if (STREQ(rpass->name, RE_PASSNAME_Z)) { - testSocketLink(converter, context, output, new RenderLayersDepthProg(rpass->name, COM_DT_VALUE, rpass->channels), scene, layerId, false); - } - else { - DataType type = ((rpass->channels == 4)? COM_DT_COLOR : ((rpass->channels == 3)? COM_DT_VECTOR : COM_DT_VALUE)); - testSocketLink(converter, context, output, new RenderLayersProg(rpass->name, type, rpass->channels), scene, layerId, STREQ(output->getbNodeSocket()->name, "Image")); - } - } - } - } + const short layerId = this->getbNode()->custom1; + RenderResult *rr = RE_AcquireResultRead(re); + if (rr == NULL) { + missingRenderLink(converter); + return; + } + SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&scene->r.layers, layerId); + if (srl == NULL) { + missingRenderLink(converter); + return; + } + RenderLayer *rl = RE_GetRenderLayer(rr, srl->name); + if (rl == NULL) { + missingRenderLink(converter); + return; + } + const int num_outputs = this->getNumberOfOutputSockets(); + for (int i = 0; i < num_outputs; i++) { + NodeOutput *output = this->getOutputSocket(i); + NodeImageLayer *storage = (NodeImageLayer*) output->getbNodeSocket()->storage; + RenderPass *rpass = (RenderPass*) BLI_findstring( + &rl->passes, + storage->pass_name, + offsetof(RenderPass, name)); + if (rpass == NULL) { + missingSocketLink(converter, output); + continue; + } + RenderLayersProg *operation; + bool is_preview; + if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && + STREQ(output->getbNodeSocket()->name, "Alpha")) + { + operation = new RenderLayersAlphaProg(rpass->name, + COM_DT_VALUE, + rpass->channels); + is_preview = false; + } + else if (STREQ(rpass->name, RE_PASSNAME_Z)) { + operation = new RenderLayersDepthProg(rpass->name, + COM_DT_VALUE, + rpass->channels); + is_preview = false; + } + else { + DataType type; + switch (rpass->channels) { + case 4: type = COM_DT_COLOR; break; + case 3: type = COM_DT_VECTOR; break; + case 1: type = COM_DT_VALUE; break; + default: + BLI_assert(!"Unexpected number of channels for pass"); + type = COM_DT_VALUE; + break; } + operation = new RenderLayersProg(rpass->name, + type, + rpass->channels); + is_preview = STREQ(output->getbNodeSocket()->name, "Image"); + } + testSocketLink(converter, + context, + output, + operation, + scene, + layerId, + is_preview); + } +} + +void RenderLayersNode::missingSocketLink(NodeConverter &converter, + NodeOutput *output) const +{ + NodeOperation *operation; + switch (output->getDataType()) { + case COM_DT_COLOR: + { + const float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + SetColorOperation *color_operation = new SetColorOperation(); + color_operation->setChannels(color); + operation = color_operation; + break; + } + case COM_DT_VECTOR: + { + const float vector[3] = {0.0f, 0.0f, 0.0f}; + SetVectorOperation *vector_operation = new SetVectorOperation(); + vector_operation->setVector(vector); + operation = vector_operation; + break; + } + case COM_DT_VALUE: + { + SetValueOperation *value_operation = new SetValueOperation(); + value_operation->setValue(0.0f); + operation = value_operation; + break; } + } + + converter.mapOutputSocket(output, operation->getOutputSocket()); + converter.addOperation(operation); +} + +void RenderLayersNode::missingRenderLink(NodeConverter &converter) const +{ + const int num_outputs = this->getNumberOfOutputSockets(); + for (int i = 0; i < num_outputs; i++) { + NodeOutput *output = this->getOutputSocket(i); + missingSocketLink(converter, output); + } +} + +void RenderLayersNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + Scene *scene = (Scene *)this->getbNode()->id; + Render *re = (scene) ? RE_GetSceneRender(scene) : NULL; + + if (re != NULL) { + testRenderLink(converter, context, re); RE_ReleaseResult(re); } + else { + missingRenderLink(converter); + } } diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.h b/source/blender/compositor/nodes/COM_RenderLayersNode.h index 1f733a9f4bb..5c6c5e17d1f 100644 --- a/source/blender/compositor/nodes/COM_RenderLayersNode.h +++ b/source/blender/compositor/nodes/COM_RenderLayersNode.h @@ -24,6 +24,8 @@ #include "DNA_node_types.h" #include "COM_RenderLayersProg.h" +struct Render; + /** * @brief RenderLayersNode * @ingroup Node @@ -31,7 +33,8 @@ class RenderLayersNode : public Node { public: RenderLayersNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const; private: void testSocketLink(NodeConverter &converter, const CompositorContext &context, @@ -40,4 +43,11 @@ private: Scene *scene, int layerId, bool is_preview) const; + void testRenderLink(NodeConverter &converter, + const CompositorContext &context, + Render *re) const; + + void missingSocketLink(NodeConverter &converter, + NodeOutput *output) const; + void missingRenderLink(NodeConverter &converter) const; }; diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cpp index 76f74c144f6..15ffff2fc90 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.cpp +++ b/source/blender/compositor/operations/COM_CompositorOperation.cpp @@ -51,6 +51,7 @@ CompositorOperation::CompositorOperation() : NodeOperation() this->m_useAlphaInput = false; this->m_active = false; + this->m_scene = NULL; this->m_sceneName[0] = '\0'; this->m_viewName = NULL; } @@ -78,7 +79,7 @@ void CompositorOperation::deinitExecution() return; if (!isBreaked()) { - Render *re = RE_GetRender(this->m_sceneName); + Render *re = RE_GetSceneRender(this->m_scene); RenderResult *rr = RE_AcquireResultWrite(re); if (rr) { @@ -217,7 +218,7 @@ void CompositorOperation::determineResolution(unsigned int resolution[2], unsign // check actual render resolution with cropping it may differ with cropped border.rendering // FIX for: [31777] Border Crop gives black (easy) - Render *re = RE_GetRender(this->m_sceneName); + Render *re = RE_GetSceneRender(this->m_scene); if (re) { RenderResult *rr = RE_AcquireResultRead(re); if (rr) { diff --git a/source/blender/compositor/operations/COM_CompositorOperation.h b/source/blender/compositor/operations/COM_CompositorOperation.h index e81ba520695..269a065a793 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.h +++ b/source/blender/compositor/operations/COM_CompositorOperation.h @@ -26,11 +26,14 @@ #include "BLI_rect.h" #include "BLI_string.h" +struct Scene; + /** * @brief Compositor output operation */ class CompositorOperation : public NodeOperation { private: + const struct Scene *m_scene; /** * @brief Scene name, used for getting the render output, includes 'SC' prefix. */ @@ -84,6 +87,7 @@ public: CompositorOperation(); const bool isActiveCompositorOutput() const { return this->m_active; } void executeRegion(rcti *rect, unsigned int tileNumber); + void setScene(const struct Scene *scene) { m_scene = scene; } void setSceneName(const char *sceneName) { BLI_strncpy(this->m_sceneName, sceneName, sizeof(this->m_sceneName)); } void setViewName(const char *viewName) { this->m_viewName = viewName; } void setRenderData(const RenderData *rd) { this->m_rd = rd; } diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp index 57aa3a1bac2..94f407dad86 100644 --- a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp @@ -65,10 +65,10 @@ void GlareSimpleStarOperation::generateGlare(float *data, MemoryBuffer *inputTil } } // // B - for (y = tbuf1->getHeight() - 1 && (!breaked); y >= 0; y--) { + for (y = this->getHeight() - 1; y >= 0 && (!breaked); y--) { ym = y - i; yp = y + i; - for (x = tbuf1->getWidth() - 1; x >= 0; x--) { + for (x = this->getWidth() - 1; x >= 0; x--) { xm = x - i; xp = x + i; tbuf1->read(c, x, y); diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp index 41f7da7c49f..0c2da8415f8 100644 --- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp +++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp @@ -28,55 +28,58 @@ extern "C" { MovieClipAttributeOperation::MovieClipAttributeOperation() : NodeOperation() { this->addOutputSocket(COM_DT_VALUE); - this->m_valueSet = false; this->m_framenumber = 0; this->m_attribute = MCA_X; this->m_invert = false; } -void MovieClipAttributeOperation::executePixelSampled(float output[4], - float /*x*/, float /*y*/, - PixelSampler /*sampler*/) +void MovieClipAttributeOperation::initExecution() { - /* TODO(sergey): This code isn't really thread-safe. */ - if (!this->m_valueSet) { - float loc[2], scale, angle; - loc[0] = 0.0f; - loc[1] = 0.0f; - scale = 1.0f; - angle = 0.0f; - if (this->m_clip) { - int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_clip, this->m_framenumber); - BKE_tracking_stabilization_data_get(this->m_clip, clip_framenr, getWidth(), getHeight(), loc, &scale, &angle); - } - switch (this->m_attribute) { - case MCA_SCALE: - this->m_value = scale; - break; - case MCA_ANGLE: - this->m_value = angle; - break; - case MCA_X: - this->m_value = loc[0]; - break; - case MCA_Y: - this->m_value = loc[1]; - break; + float loc[2], scale, angle; + loc[0] = 0.0f; + loc[1] = 0.0f; + scale = 1.0f; + angle = 0.0f; + int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame( + this->m_clip, this->m_framenumber); + BKE_tracking_stabilization_data_get(this->m_clip, + clip_framenr, + getWidth(), getHeight(), + loc, &scale, &angle); + switch (this->m_attribute) { + case MCA_SCALE: + this->m_value = scale; + break; + case MCA_ANGLE: + this->m_value = angle; + break; + case MCA_X: + this->m_value = loc[0]; + break; + case MCA_Y: + this->m_value = loc[1]; + break; + } + if (this->m_invert) { + if (this->m_attribute != MCA_SCALE) { + this->m_value = -this->m_value; } - if (this->m_invert) { - if (this->m_attribute != MCA_SCALE) { - this->m_value = -this->m_value; - } - else { - this->m_value = 1.0f / this->m_value; - } + else { + this->m_value = 1.0f / this->m_value; } - this->m_valueSet = true; } +} + +void MovieClipAttributeOperation::executePixelSampled(float output[4], + float /*x*/, float /*y*/, + PixelSampler /*sampler*/) +{ output[0] = this->m_value; } -void MovieClipAttributeOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) +void MovieClipAttributeOperation::determineResolution( + unsigned int resolution[2], + unsigned int preferredResolution[2]) { resolution[0] = preferredResolution[0]; resolution[1] = preferredResolution[1]; diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h index 731b9debaf0..659f54c1ca2 100644 --- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h +++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h @@ -39,16 +39,18 @@ class MovieClipAttributeOperation : public NodeOperation { private: MovieClip *m_clip; float m_value; - bool m_valueSet; int m_framenumber; bool m_invert; MovieClipAttribute m_attribute; + public: /** * Default constructor */ MovieClipAttributeOperation(); - + + void initExecution(); + /** * the inner loop of this program */ diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp index f2f1b211a97..d1c654ddb6c 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp +++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp @@ -48,7 +48,7 @@ RenderLayersProg::RenderLayersProg(const char *passName, DataType type, int elem void RenderLayersProg::initExecution() { Scene *scene = this->getScene(); - Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL; + Render *re = (scene) ? RE_GetSceneRender(scene) : NULL; RenderResult *rr = NULL; if (re) @@ -179,7 +179,7 @@ void RenderLayersProg::deinitExecution() void RenderLayersProg::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2]) { Scene *sce = this->getScene(); - Render *re = (sce) ? RE_GetRender(sce->id.name) : NULL; + Render *re = (sce) ? RE_GetSceneRender(sce) : NULL; RenderResult *rr = NULL; resolution[0] = 0; @@ -246,4 +246,4 @@ void RenderLayersDepthProg::executePixelSampled(float output[4], float x, float unsigned int offset = (iy * this->getWidth() + ix); output[0] = inputBuffer[offset]; } -}
\ No newline at end of file +} diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cpp b/source/blender/compositor/operations/COM_ScaleOperation.cpp index 117ae743ee7..46e155e43b5 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.cpp +++ b/source/blender/compositor/operations/COM_ScaleOperation.cpp @@ -271,9 +271,9 @@ bool ScaleFixedSizeOperation::determineDependingAreaOfInterest(rcti *input, Read { rcti newInput; - newInput.xmax = (input->xmax - m_offsetX) * this->m_relX; + newInput.xmax = (input->xmax - m_offsetX) * this->m_relX + 1; newInput.xmin = (input->xmin - m_offsetX) * this->m_relX; - newInput.ymax = (input->ymax - m_offsetY) * this->m_relY; + newInput.ymax = (input->ymax - m_offsetY) * this->m_relY + 1; newInput.ymin = (input->ymin - m_offsetY) * this->m_relY; return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); diff --git a/source/blender/datatoc/datatoc.c b/source/blender/datatoc/datatoc.c index 4e49a9a7694..ffccca98f99 100644 --- a/source/blender/datatoc/datatoc.c +++ b/source/blender/datatoc/datatoc.c @@ -91,6 +91,11 @@ int main(int argc, char **argv) } fprintf(fpout, "/* DataToC output of file <%s> */\n\n", argv[1]); + + /* Quiet 'missing-variable-declarations' warning. */ + fprintf(fpout, "extern int datatoc_%s_size;\n", argv[1]); + fprintf(fpout, "extern char datatoc_%s[];\n\n", argv[1]); + fprintf(fpout, "int datatoc_%s_size = %d;\n", argv[1], (int)size); fprintf(fpout, "char datatoc_%s[] = {\n", argv[1]); while (size--) { diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index 945a4785b9c..59b10b95d49 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -134,6 +134,9 @@ void DEG_ids_clear_recalc(struct Main *bmain); /* Flush updates for all IDs */ void DEG_ids_flush_tagged(struct Main *bmain); +/* Flush updates for IDs in a single scene. */ +void DEG_scene_flush_update(struct Main *bmain, struct Scene *scene); + /* Check if something was changed in the database and inform * editors about this. */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 086fd0c1144..e3494e4756e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -69,7 +69,7 @@ static bool check_object_needs_evaluation(Object *object) void deg_graph_build_flush_layers(Depsgraph *graph) { - BLI_Stack *stack = BLI_stack_new(sizeof(OperationDepsNode*), + BLI_Stack *stack = BLI_stack_new(sizeof(OperationDepsNode *), "DEG flush layers stack"); foreach (OperationDepsNode *node, graph->operations) { IDDepsNode *id_node = node->owner->owner; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 55f1f93be6a..17f0c030bd0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -81,6 +81,7 @@ extern "C" { #include "BKE_lattice.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_mask.h" #include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_mball.h" @@ -320,8 +321,11 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) if (base != NULL) { id_node->layers |= base->lay; } - if (ob == scene->camera) { - /* Camera should always be updated, it used directly by viewport. */ + if (ob->type == OB_CAMERA) { + /* Camera should always be updated, it used directly by viewport. + * + * TODO(sergey): Make it only for active scene camera. + */ id_node->layers |= (unsigned int)(-1); } /* Skip rest of components if the ID node was already there. */ @@ -671,6 +675,13 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob) ComponentDepsNode *psys_comp = add_component_node(&ob->id, DEG_NODE_TYPE_EVAL_PARTICLES); + add_operation_node(psys_comp, + function_bind(BKE_particle_system_eval_init, + _1, + scene, + ob), + DEG_OPCODE_PSYS_EVAL_INIT); + /* particle systems */ LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) { ParticleSettings *part = psys->part; @@ -682,11 +693,7 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob) /* this particle system */ // TODO: for now, this will just be a placeholder "ubereval" node add_operation_node(psys_comp, - function_bind(BKE_particle_system_eval, - _1, - scene, - ob, - psys), + NULL, DEG_OPCODE_PSYS_EVAL, psys->name); } @@ -845,17 +852,6 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) "Geometry Eval"); op_node->set_as_entry(); - /* Calculate curve path - this is used by constraints, etc. */ - if (ELEM(ob->type, OB_CURVE, OB_FONT)) { - add_operation_node(obdata, - DEG_NODE_TYPE_GEOMETRY, - function_bind(BKE_curve_eval_path, - _1, - (Curve *)obdata), - DEG_OPCODE_GEOMETRY_PATH, - "Path"); - } - /* Make sure objects used for bevel.taper are in the graph. * NOTE: This objects might be not linked to the scene. */ @@ -965,7 +961,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) { ID *id = bnode->id; if (id != NULL) { - short id_type = GS(id->name); + ID_Type id_type = GS(id->name); if (id_type == ID_MA) { build_material((Material *)id); } @@ -1102,7 +1098,18 @@ void DepsgraphNodeBuilder::build_mask(Mask *mask) { ID *mask_id = &mask->id; add_id_node(mask_id); + /* F-Curve based animation/ */ build_animdata(mask_id); + /* Animation based on mask's shapes. */ + add_operation_node(mask_id, + DEG_NODE_TYPE_ANIMATION, + function_bind(BKE_mask_eval_animation, _1, mask), + DEG_OPCODE_MASK_ANIMATION); + /* Final mask evaluation. */ + add_operation_node(mask_id, + DEG_NODE_TYPE_PARAMETERS, + function_bind(BKE_mask_eval_update, _1, mask), + DEG_OPCODE_MASK_EVAL); } void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index fe7ccaa7fc0..ceb2fd25f94 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -182,6 +182,11 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob) op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_EVAL_POSE, + function_bind(BKE_pose_eval_init_ik, _1, scene, ob, ob->pose), + DEG_OPCODE_POSE_INIT_IK); + + op_node = add_operation_node(&ob->id, + DEG_NODE_TYPE_EVAL_POSE, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE); op_node->set_as_exit(); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc index 3249867e416..521276bc608 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc @@ -126,6 +126,13 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene) LINKLIST_FOREACH (MovieClip *, clip, &bmain->movieclip) { build_movieclip(clip); } + + /* Parameters evaluation for scene relations mainly. */ + add_operation_node(&scene->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_PLACEHOLDER, + "Scene Eval"); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 62a7d6c6ab7..d42c4047691 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -661,58 +661,74 @@ void DepsgraphRelationBuilder::build_object_parent(Object *ob) } } -void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode_Type component_type, const char *component_subdata, - ListBase *constraints, RootPChanMap *root_map) +void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, + eDepsNode_Type component_type, + const char *component_subdata, + ListBase *constraints, + RootPChanMap *root_map) { - OperationKey constraint_op_key(id, component_type, component_subdata, - (component_type == DEG_NODE_TYPE_BONE) ? DEG_OPCODE_BONE_CONSTRAINTS : DEG_OPCODE_TRANSFORM_CONSTRAINTS); - - /* add dependencies for each constraint in turn */ + OperationKey constraint_op_key( + id, + component_type, + component_subdata, + (component_type == DEG_NODE_TYPE_BONE) + ? DEG_OPCODE_BONE_CONSTRAINTS + : DEG_OPCODE_TRANSFORM_CONSTRAINTS); + /* Add dependencies for each constraint in turn. */ for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - - /* invalid constraint type... */ - if (cti == NULL) + /* Invalid constraint type. */ + if (cti == NULL) { continue; - - /* special case for camera tracking -- it doesn't use targets to define relations */ - // TODO: we can now represent dependencies in a much richer manner, so review how this is done... - if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { + } + /* Special case for camera tracking -- it doesn't use targets to + * define relations. + */ + /* TODO: we can now represent dependencies in a much richer manner, + * so review how this is done. + */ + if (ELEM(cti->type, + CONSTRAINT_TYPE_FOLLOWTRACK, + CONSTRAINT_TYPE_CAMERASOLVER, + CONSTRAINT_TYPE_OBJECTSOLVER)) + { bool depends_on_camera = false; - if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) { bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data; - - if (((data->clip) || (data->flag & FOLLOWTRACK_ACTIVECLIP)) && data->track[0]) + if (((data->clip) || + (data->flag & FOLLOWTRACK_ACTIVECLIP)) && data->track[0]) + { depends_on_camera = true; - + } if (data->depth_ob) { - // DAG_RL_DATA_OB | DAG_RL_OB_OB - ComponentKey depth_key(&data->depth_ob->id, DEG_NODE_TYPE_TRANSFORM); - add_relation(depth_key, constraint_op_key, cti->name); + ComponentKey depth_transform_key(&data->depth_ob->id, + DEG_NODE_TYPE_TRANSFORM); + ComponentKey depth_geometry_key(&data->depth_ob->id, + DEG_NODE_TYPE_GEOMETRY); + add_relation(depth_transform_key, constraint_op_key, cti->name); + add_relation(depth_geometry_key, constraint_op_key, cti->name); } } else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) { depends_on_camera = true; } - if (depends_on_camera && scene->camera) { - // DAG_RL_DATA_OB | DAG_RL_OB_OB ComponentKey camera_key(&scene->camera->id, DEG_NODE_TYPE_TRANSFORM); add_relation(camera_key, constraint_op_key, cti->name); } - - /* TODO(sergey): This is more a TimeSource -> MovieClip -> Constraint dependency chain. */ + /* TODO(sergey): This is more a TimeSource -> MovieClip -> + * Constraint dependency chain. + */ TimeSourceKey time_src_key; add_relation(time_src_key, constraint_op_key, "[TimeSrc -> Animation]"); } else if (cti->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) { - /* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint dependency chain. */ + /* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint + * dependency chain. + */ TimeSourceKey time_src_key; add_relation(time_src_key, constraint_op_key, "[TimeSrc -> Animation]"); - bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data; - if (data->cache_file) { ComponentKey cache_key(&data->cache_file->id, DEG_NODE_TYPE_CACHE); add_relation(cache_key, constraint_op_key, cti->name); @@ -721,52 +737,73 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode else if (cti->get_constraint_targets) { ListBase targets = {NULL, NULL}; cti->get_constraint_targets(con, &targets); - LINKLIST_FOREACH (bConstraintTarget *, ct, &targets) { if (ct->tar == NULL) { continue; } - - if (ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) { - /* ignore IK constraints - these are handled separately (on pose level) */ + if (ELEM(con->type, + CONSTRAINT_TYPE_KINEMATIC, + CONSTRAINT_TYPE_SPLINEIK)) + { + /* Ignore IK constraints - these are handled separately + * (on pose level). + */ } - else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) { - /* these constraints require path geometry data... */ + else if (ELEM(con->type, + CONSTRAINT_TYPE_FOLLOWPATH, + CONSTRAINT_TYPE_CLAMPTO)) + { + /* These constraints require path geometry data. */ ComponentKey target_key(&ct->tar->id, DEG_NODE_TYPE_GEOMETRY); - add_relation(target_key, constraint_op_key, cti->name); // XXX: type = geom_transform - // TODO: path dependency + add_relation(target_key, constraint_op_key, cti->name); + ComponentKey target_transform_key(&ct->tar->id, + DEG_NODE_TYPE_TRANSFORM); + add_relation(target_transform_key, constraint_op_key, cti->name); } else if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) { /* bone */ if (&ct->tar->id == id) { /* same armature */ eDepsOperation_Code target_key_opcode; - - /* Using "done" here breaks in-chain deps, while using "ready" here breaks most production rigs instead... - * So, we do a compromise here, and only do this when an IK chain conflict may occur + /* Using "done" here breaks in-chain deps, while using + * "ready" here breaks most production rigs instead. + * So, we do a compromise here, and only do this when an + * IK chain conflict may occur. */ - if (root_map->has_common_root(component_subdata, ct->subtarget)) { + if (root_map->has_common_root(component_subdata, + ct->subtarget)) + { target_key_opcode = DEG_OPCODE_BONE_READY; } else { target_key_opcode = DEG_OPCODE_BONE_DONE; } - - OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_BONE, ct->subtarget, target_key_opcode); + OperationKey target_key(&ct->tar->id, + DEG_NODE_TYPE_BONE, + ct->subtarget, + target_key_opcode); add_relation(target_key, constraint_op_key, cti->name); } else { - /* different armature - we can safely use the result of that */ - OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_BONE, ct->subtarget, DEG_OPCODE_BONE_DONE); + /* Different armature - we can safely use the result + * of that. + */ + OperationKey target_key(&ct->tar->id, + DEG_NODE_TYPE_BONE, + ct->subtarget, + DEG_OPCODE_BONE_DONE); add_relation(target_key, constraint_op_key, cti->name); } } - else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { - /* vertex group */ - /* NOTE: for now, we don't need to represent vertex groups separately... */ + else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && + (ct->subtarget[0])) + { + /* Vertex group. */ + /* NOTE: for now, we don't need to represent vertex groups + * separately. + */ ComponentKey target_key(&ct->tar->id, DEG_NODE_TYPE_GEOMETRY); add_relation(target_key, constraint_op_key, cti->name); - if (ct->tar->type == OB_MESH) { OperationDepsNode *node2 = find_operation_node(target_key); if (node2 != NULL) { @@ -778,37 +815,48 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode /* Constraints which requires the target object surface. */ ComponentKey target_key(&ct->tar->id, DEG_NODE_TYPE_GEOMETRY); add_relation(target_key, constraint_op_key, cti->name); - - /* NOTE: obdata eval now doesn't necessarily depend on the object's transform... */ - ComponentKey target_transform_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM); + /* NOTE: obdata eval now doesn't necessarily depend on the + * object's transform. + */ + ComponentKey target_transform_key(&ct->tar->id, + DEG_NODE_TYPE_TRANSFORM); add_relation(target_transform_key, constraint_op_key, cti->name); } else { - /* standard object relation */ + /* Standard object relation. */ // TODO: loc vs rot vs scale? if (&ct->tar->id == id) { /* Constraint targetting own object: - * - This case is fine IFF we're dealing with a bone constraint pointing to - * its own armature. In that case, it's just transform -> bone. - * - If however it is a real self targetting case, just make it depend on the - * previous constraint (or the pre-constraint state)... + * - This case is fine IFF we're dealing with a bone + * constraint pointing to its own armature. In that + * case, it's just transform -> bone. + * - If however it is a real self targetting case, just + * make it depend on the previous constraint (or the + * pre-constraint state). */ - if ((ct->tar->type == OB_ARMATURE) && (component_type == DEG_NODE_TYPE_BONE)) { - OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL); + if ((ct->tar->type == OB_ARMATURE) && + (component_type == DEG_NODE_TYPE_BONE)) + { + OperationKey target_key(&ct->tar->id, + DEG_NODE_TYPE_TRANSFORM, + DEG_OPCODE_TRANSFORM_FINAL); add_relation(target_key, constraint_op_key, cti->name); } else { - OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL); + OperationKey target_key(&ct->tar->id, + DEG_NODE_TYPE_TRANSFORM, + DEG_OPCODE_TRANSFORM_LOCAL); add_relation(target_key, constraint_op_key, cti->name); } } else { - /* normal object dependency */ - OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL); + /* Normal object dependency. */ + OperationKey target_key(&ct->tar->id, + DEG_NODE_TYPE_TRANSFORM, + DEG_OPCODE_TRANSFORM_FINAL); add_relation(target_key, constraint_op_key, cti->name); } } - /* Constraints which needs world's matrix for transform. * TODO(sergey): More constraints here? */ @@ -819,14 +867,14 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode CONSTRAINT_TYPE_TRANSLIKE)) { /* TODO(sergey): Add used space check. */ - ComponentKey target_transform_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM); + ComponentKey target_transform_key(&ct->tar->id, + DEG_NODE_TYPE_TRANSFORM); add_relation(target_transform_key, constraint_op_key, cti->name); } - } - - if (cti->flush_constraint_targets) + if (cti->flush_constraint_targets) { cti->flush_constraint_targets(con, &targets, 1); + } } } } @@ -927,16 +975,20 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; - /* create dependency between driver and data affected by it */ + /* Create dependency between driver and data affected by it. */ /* - direct property relationship... */ //RNAPathKey affected_key(id, fcu->rna_path); //add_relation(driver_key, affected_key, "[Driver -> Data] DepsRel"); - /* driver -> data components (for interleaved evaluation - bones/constraints/modifiers) */ - // XXX: this probably should probably be moved out into a separate function + /* Driver -> data components (for interleaved evaluation + * bones/constraints/modifiers). + */ + // XXX: this probably should probably be moved out into a separate function. if (strstr(rna_path, "pose.bones[") != NULL) { /* interleaved drivers during bone eval */ - // TODO: ideally, if this is for a constraint, it goes to said constraint + /* TODO: ideally, if this is for a constraint, it goes to said + * constraint. + */ Object *ob = (Object *)id; char *bone_name; @@ -949,7 +1001,10 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) } if (pchan) { - OperationKey bone_key(id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); + OperationKey bone_key(id, + DEG_NODE_TYPE_BONE, + pchan->name, + DEG_OPCODE_BONE_LOCAL); add_relation(driver_key, bone_key, "[Driver -> Bone]"); } else { @@ -959,30 +1014,36 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) } } else if (GS(id->name) == ID_AR && strstr(rna_path, "bones[")) { - /* drivers on armature-level bone settings (i.e. bbone stuff), - * which will affect the evaluation of corresponding pose bones + /* Drivers on armature-level bone settings (i.e. bbone stuff), + * which will affect the evaluation of corresponding pose bones. */ IDDepsNode *arm_node = m_graph->find_id_node(id); char *bone_name = BLI_str_quoted_substrN(rna_path, "bones["); if (arm_node && bone_name) { - /* find objects which use this, and make their eval callbacks depend on this */ + /* Find objects which use this, and make their eval callbacks + * depend on this. + */ foreach (DepsRelation *rel, arm_node->outlinks) { IDDepsNode *to_node = (IDDepsNode *)rel->to; - - /* we only care about objects with pose data which use this... */ + /* We only care about objects with pose data which use this. */ if (GS(to_node->id->name) == ID_OB) { Object *ob = (Object *)to_node->id; - bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name); // NOTE: ob->pose may be NULL - - if (pchan) { - OperationKey bone_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); - add_relation(driver_key, bone_key, "[Arm Bone -> Driver -> Bone]"); + /* NOTE: ob->pose may be NULL. */ + bPoseChannel *pchan = BKE_pose_channel_find_name( + ob->pose, bone_name); + if (pchan != NULL) { + OperationKey bone_key(&ob->id, + DEG_NODE_TYPE_BONE, + pchan->name, + DEG_OPCODE_BONE_LOCAL); + add_relation(driver_key, + bone_key, + "[Arm Bone -> Driver -> Bone]"); } } } - - /* free temp data */ + /* Free temp data. */ MEM_freeN(bone_name); bone_name = NULL; } @@ -993,7 +1054,9 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) } } else if (GS(id->name) == ID_OB && strstr(rna_path, "modifiers[")) { - OperationKey modifier_key(id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL); + OperationKey modifier_key(id, + DEG_NODE_TYPE_GEOMETRY, + DEG_OPCODE_GEOMETRY_UBEREVAL); if (has_node(modifier_key)) { add_relation(driver_key, modifier_key, "[Driver -> Modifier]"); } @@ -1002,7 +1065,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) } } else if (GS(id->name) == ID_KE && strstr(rna_path, "key_blocks[")) { - /* shape key driver - hook into the base geometry operation */ + /* Shape key driver - hook into the base geometry operation. */ // XXX: double check where this points Key *shape_key = (Key *)id; @@ -1016,33 +1079,44 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) else { if (GS(id->name) == ID_OB) { /* assume that driver affects a transform... */ - OperationKey local_transform_key(id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL); - add_relation(driver_key, local_transform_key, "[Driver -> Transform]"); + OperationKey local_transform_key(id, + DEG_NODE_TYPE_TRANSFORM, + DEG_OPCODE_TRANSFORM_LOCAL); + add_relation(driver_key, + local_transform_key, + "[Driver -> Transform]"); } else if (GS(id->name) == ID_KE) { ComponentKey geometry_key(id, DEG_NODE_TYPE_GEOMETRY); - add_relation(driver_key, geometry_key, "[Driver -> Shapekey Geometry]"); + add_relation(driver_key, + geometry_key, + "[Driver -> Shapekey Geometry]"); } } - - /* ensure that affected prop's update callbacks will be triggered once done */ - // TODO: implement this once the functionality to add these links exists in RNA - // XXX: the data itself could also set this, if it were to be truly initialised later? - - /* loop over variables to get the target relationships */ + /* Ensure that affected prop's update callbacks will be triggered once + * done. + */ + /* TODO: Implement this once the functionality to add these links exists + * RNA. + */ + /* XXX: the data itself could also set this, if it were to be truly + * initialised later? + */ + /* Loop over variables to get the target relationships. */ LINKLIST_FOREACH (DriverVar *, dvar, &driver->variables) { - /* only used targets */ + /* Only used targets. */ DRIVER_TARGETS_USED_LOOPER(dvar) { - if (dtar->id == NULL) + if (dtar->id == NULL) { continue; - - /* special handling for directly-named bones */ + } + /* Special handling for directly-named bones. */ if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) { Object *ob = (Object *)dtar->id; - bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); + bPoseChannel *target_pchan = + BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); if (target_pchan != NULL) { - /* get node associated with bone */ + /* Get node associated with bone. */ // XXX: watch the space! /* Some cases can't use final bone transform, for example: * - Driving the bone with itself (addressed here) @@ -1054,55 +1128,75 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) { continue; } - OperationKey target_key(dtar->id, DEG_NODE_TYPE_BONE, target_pchan->name, DEG_OPCODE_BONE_DONE); - add_relation(target_key, driver_key, "[Bone Target -> Driver]"); + OperationKey target_key(dtar->id, + DEG_NODE_TYPE_BONE, + target_pchan->name, + DEG_OPCODE_BONE_DONE); + add_relation(target_key, + driver_key, + "[Bone Target -> Driver]"); } } else if (dtar->flag & DTAR_FLAG_STRUCT_REF) { - /* get node associated with the object's transforms */ - OperationKey target_key(dtar->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL); + /* Get node associated with the object's transforms. */ + if (dtar->id == id) { + /* Ignore input dependency if we're driving properties of + * the same ID, otherwise we'll be ending up in a cyclic + * dependency here. + */ + continue; + } + OperationKey target_key(dtar->id, + DEG_NODE_TYPE_TRANSFORM, + DEG_OPCODE_TRANSFORM_FINAL); add_relation(target_key, driver_key, "[Target -> Driver]"); } else if (dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) { - /* workaround for ensuring that local bone transforms don't end up - * having to wait for pose eval to finish (to prevent cycles) + /* Workaround for ensuring that local bone transforms don't end + * up having to wait for pose eval to finish (to prevent cycles). */ Object *ob = (Object *)dtar->id; - char *bone_name = BLI_str_quoted_substrN(dtar->rna_path, "pose.bones["); - bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, bone_name); - if (bone_name) { + char *bone_name = BLI_str_quoted_substrN(dtar->rna_path, + "pose.bones["); + bPoseChannel *target_pchan = + BKE_pose_channel_find_name(ob->pose, bone_name); + if (bone_name != NULL) { MEM_freeN(bone_name); bone_name = NULL; } - if (target_pchan) { + if (target_pchan != NULL) { if (dtar->id == id && pchan != NULL && STREQ(pchan->name, target_pchan->name)) { continue; } - OperationKey bone_key(dtar->id, DEG_NODE_TYPE_BONE, target_pchan->name, DEG_OPCODE_BONE_LOCAL); + OperationKey bone_key(dtar->id, + DEG_NODE_TYPE_BONE, + target_pchan->name, + DEG_OPCODE_BONE_LOCAL); add_relation(bone_key, driver_key, "[RNA Bone -> Driver]"); } } else { if (dtar->id == id) { - /* Ignore input dependency if we're driving properties of the same ID, - * otherwise we'll be ending up in a cyclic dependency here. + /* Ignore input dependency if we're driving properties of + * the same ID, otherwise we'll be ending up in a cyclic + * dependency here. */ continue; } - /* resolve path to get node */ - RNAPathKey target_key(dtar->id, dtar->rna_path ? dtar->rna_path : ""); + /* Resolve path to get node. */ + RNAPathKey target_key(dtar->id, + dtar->rna_path ? dtar->rna_path : ""); add_relation(target_key, driver_key, "[RNA Target -> Driver]"); } } DRIVER_TARGETS_LOOPER_END } - - /* It's quite tricky to detect if the driver actually depends on time or not, - * so for now we'll be quite conservative here about optimization and consider - * all python drivers to be depending on time. + /* It's quite tricky to detect if the driver actually depends on time or + * not, so for now we'll be quite conservative here about optimization and + * consider all python drivers to be depending on time. */ if ((driver->type == DRIVER_TYPE_PYTHON) && python_driver_depends_on_time(driver)) @@ -1239,6 +1333,13 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) OperationKey obdata_ubereval_key(&ob->id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL); + OperationKey eval_init_key(&ob->id, + DEG_NODE_TYPE_EVAL_PARTICLES, + DEG_OPCODE_PSYS_EVAL_INIT); + /* TODO(sergey): Are all particle systems depends on time? + * Hair without dynamics i.e. + */ + add_relation(time_src_key, eval_init_key, "TimeSrc -> PSys"); /* particle systems */ LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) { @@ -1254,10 +1355,7 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) if (!psys_check_enabled(ob, psys, G.is_rendering)) continue; - /* TODO(sergey): Are all particle systems depends on time? - * Hair without dynamics i.e. - */ - add_relation(time_src_key, psys_key, "TimeSrc -> PSys"); + add_relation(eval_init_key, psys_key, "Init -> PSys"); /* TODO(sergey): Currently particle update is just a placeholder, * hook it to the ubereval node so particle system is getting updated @@ -1737,8 +1835,18 @@ void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) { void DepsgraphRelationBuilder::build_mask(Mask *mask) { - /* Animation. */ - build_animdata(&mask->id); + ID *mask_id = &mask->id; + /* F-Curve animation. */ + build_animdata(mask_id); + /* Own mask animation. */ + OperationKey mask_animation_key(mask_id, + DEG_NODE_TYPE_ANIMATION, + DEG_OPCODE_MASK_ANIMATION); + TimeSourceKey time_src_key; + add_relation(time_src_key, mask_animation_key, "TimeSrc -> Mask Animation"); + /* Final mask evaluation. */ + ComponentKey parameters_key(mask_id, DEG_NODE_TYPE_PARAMETERS); + add_relation(mask_animation_key, parameters_key, "Mask Animation -> Mask Eval"); } void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index be666165a0b..ca548ed33d0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -83,7 +83,15 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob, * - see notes on direction of rel below... */ bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); - OperationKey solver_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER); + OperationKey pchan_local_key(&ob->id, DEG_NODE_TYPE_BONE, + pchan->name, DEG_OPCODE_BONE_LOCAL); + OperationKey init_ik_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT_IK); + OperationKey solver_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, + rootchan->name, + DEG_OPCODE_POSE_IK_SOLVER); + + add_relation(pchan_local_key, init_ik_key, "IK Constraint -> Init IK Tree"); + add_relation(init_ik_key, solver_key, "Init IK -> IK Solver"); /* IK target */ // XXX: this should get handled as part of the constraint code @@ -300,9 +308,11 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob) /* attach links between pose operations */ OperationKey init_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); + OperationKey init_ik_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT_IK); OperationKey flush_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - add_relation(init_key, flush_key, "[Pose Init -> Pose Cleanup]"); + add_relation(init_key, init_ik_key, "Pose Init -> Pose Init IK"); + add_relation(init_ik_key, flush_key, "Pose Init IK -> Pose Cleanup"); /* Make sure pose is up-to-date with armature updates. */ OperationKey armature_key(&arm->id, diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 31b4bbc7950..5adcb3a11b3 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -109,7 +109,7 @@ void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag) * nodes for update after relations update and after layer * visibility changes. */ - short idtype = GS(id->name); + ID_Type idtype = GS(id->name); if (idtype == ID_OB) { Object *object = (Object *)id; object->recalc |= (flag & OB_RECALC_ALL); @@ -277,15 +277,20 @@ void DEG_ids_flush_tagged(Main *bmain) scene != NULL; scene = (Scene *)scene->id.next) { - /* TODO(sergey): Only visible scenes? */ - if (scene->depsgraph != NULL) { - DEG::deg_graph_flush_updates( - bmain, - reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph)); - } + DEG_scene_flush_update(bmain, scene); } } +void DEG_scene_flush_update(Main *bmain, Scene *scene) +{ + if (scene->depsgraph == NULL) { + return; + } + DEG::deg_graph_flush_updates( + bmain, + reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph)); +} + /* Update dependency graph when visible scenes/layers changes. */ void DEG_graph_on_visible_update(Main *bmain, Scene *scene) { @@ -347,6 +352,12 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene) GHASH_FOREACH_END(); } scene->lay_updated |= graph->layers; + /* If graph is tagged for update, we don't need to bother with updates here, + * nodes will be re-created. + */ + if (graph->need_update) { + return; + } /* Special trick to get local view to work. */ LINKLIST_FOREACH (Base *, base, &scene->base) { Object *object = base->object; diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc index 77454cd85ec..e177c8c8ec0 100644 --- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc +++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc @@ -108,8 +108,8 @@ static const char *stringify_opcode(eDepsOperation_Code opcode) STRINGIFY_OPCODE(TRANSFORM_FINAL); STRINGIFY_OPCODE(OBJECT_UBEREVAL); STRINGIFY_OPCODE(GEOMETRY_UBEREVAL); - STRINGIFY_OPCODE(GEOMETRY_PATH); STRINGIFY_OPCODE(POSE_INIT); + STRINGIFY_OPCODE(POSE_INIT_IK); STRINGIFY_OPCODE(POSE_DONE); STRINGIFY_OPCODE(POSE_IK_SOLVER); STRINGIFY_OPCODE(POSE_SPLINE_IK_SOLVER); @@ -119,6 +119,9 @@ static const char *stringify_opcode(eDepsOperation_Code opcode) STRINGIFY_OPCODE(BONE_READY); STRINGIFY_OPCODE(BONE_DONE); STRINGIFY_OPCODE(PSYS_EVAL); + STRINGIFY_OPCODE(PSYS_EVAL_INIT); + STRINGIFY_OPCODE(MASK_ANIMATION); + STRINGIFY_OPCODE(MASK_EVAL); case DEG_NUM_OPCODES: return "SpecialCase"; #undef STRINGIFY_OPCODE diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h index c1a42941a7d..ef7b32a8d83 100644 --- a/source/blender/depsgraph/intern/depsgraph_types.h +++ b/source/blender/depsgraph/intern/depsgraph_types.h @@ -176,14 +176,14 @@ typedef enum eDepsOperation_Code { /* XXX: Placeholder - UberEval */ DEG_OPCODE_GEOMETRY_UBEREVAL, - /* Curve Objects - Path Calculation (used for path-following tools, */ - DEG_OPCODE_GEOMETRY_PATH, - /* Pose -------------------------------------------- */ - /* Init IK Trees, etc. */ + /* Init pose, clear flags, etc. */ DEG_OPCODE_POSE_INIT, + /* Initialize IK solver related pose stuff. */ + DEG_OPCODE_POSE_INIT_IK, + /* Free IK Trees + Compute Deform Matrices */ DEG_OPCODE_POSE_DONE, @@ -219,8 +219,13 @@ typedef enum eDepsOperation_Code { /* Particles --------------------------------------- */ /* XXX: placeholder - Particle System eval */ + DEG_OPCODE_PSYS_EVAL_INIT, DEG_OPCODE_PSYS_EVAL, + /* Masks ------------------------------------------- */ + DEG_OPCODE_MASK_ANIMATION, + DEG_OPCODE_MASK_EVAL, + DEG_NUM_OPCODES, } eDepsOperation_Code; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index c230ab4c8fd..0adbadeebba 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -54,6 +54,12 @@ extern "C" { namespace DEG { +enum { + COMPONENT_STATE_NONE = 0, + COMPONENT_STATE_SCHEDULED = 1, + COMPONENT_STATE_DONE = 2, +}; + namespace { // TODO(sergey): De-duplicate with depsgraph_tag,cc @@ -83,7 +89,7 @@ static void flush_init_func(void *data_v, int i) ComponentDepsNode *comp_node = node->owner; IDDepsNode *id_node = comp_node->owner; id_node->done = 0; - comp_node->done = 0; + comp_node->done = COMPONENT_STATE_NONE; node->scheduled = false; } @@ -146,7 +152,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) lib_id_recalc_data_tag(bmain, id); } - if (comp_node->done == 0) { + if (comp_node->done != COMPONENT_STATE_DONE) { Object *object = NULL; if (GS(id->name) == ID_OB) { object = (Object *)id; @@ -190,10 +196,22 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) break; } } + /* When some target changes bone, we might need to re-run the + * whole IK solver, otherwise result might be unpredictable. + */ + if (comp_node->type == DEG_NODE_TYPE_BONE) { + ComponentDepsNode *pose_comp = + id_node->find_component(DEG_NODE_TYPE_EVAL_POSE); + BLI_assert(pose_comp != NULL); + if (pose_comp->done == COMPONENT_STATE_NONE) { + queue.push_front(pose_comp->get_entry_operation()); + pose_comp->done = COMPONENT_STATE_SCHEDULED; + } + } } id_node->done = 1; - comp_node->done = 1; + comp_node->done = COMPONENT_STATE_DONE; /* Flush to nodes along links... */ /* TODO(sergey): This is mainly giving speedup due ot less queue pushes, which diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 5852ee72b19..dba060bfb29 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -4458,8 +4458,8 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle * a callback available (e.g. broken F-Curve rename) */ if (acf->name_prop(ale, &ptr, &prop)) { - const short margin_x = 3 * iroundf(UI_DPI_FAC); - const short channel_height = iroundf(ymaxc - yminc); + const short margin_x = 3 * round_fl_to_int(UI_DPI_FAC); + const short channel_height = round_fl_to_int(ymaxc - yminc); const short width = ac->ar->winx - offset - (margin_x * 2); uiBut *but; diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 2f73eb6b71c..e18560b95af 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -2247,6 +2247,8 @@ static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin } /* TODO: images? */ + default: + break; } } diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index aafd7ebb1f9..efcc3e9477c 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -149,7 +149,7 @@ int ED_markers_post_apply_transform(ListBase *markers, Scene *scene, int mode, f (side == 'L' && marker->frame < cfra) || (side == 'R' && marker->frame >= cfra)) { - marker->frame += iroundf(value); + marker->frame += round_fl_to_int(value); changed_tot++; } break; @@ -157,7 +157,7 @@ int ED_markers_post_apply_transform(ListBase *markers, Scene *scene, int mode, f case TFM_TIME_SCALE: { /* rescale the distance between the marker and the current frame */ - marker->frame = cfra + iroundf((float)(marker->frame - cfra) * value); + marker->frame = cfra + round_fl_to_int((float)(marker->frame - cfra) * value); changed_tot++; break; } @@ -195,7 +195,7 @@ TimeMarker *ED_markers_find_nearest_marker(ListBase *markers, float x) int ED_markers_find_nearest_marker_time(ListBase *markers, float x) { TimeMarker *nearest = ED_markers_find_nearest_marker(markers, x); - return (nearest) ? (nearest->frame) : iroundf(x); + return (nearest) ? (nearest->frame) : round_fl_to_int(x); } @@ -895,7 +895,7 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *even case PADENTER: case LEFTMOUSE: case MIDDLEMOUSE: - if (WM_modal_tweak_exit(event, mm->event_type)) { + if (WM_event_is_modal_tweak_exit(event, mm->event_type)) { ed_marker_move_exit(C, op); WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL); WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 0eb6508f7b2..fcdd45d4ac3 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -108,7 +108,7 @@ static void change_frame_apply(bContext *C, wmOperator *op) SUBFRA = frame - (int)frame; } else { - CFRA = iroundf(frame); + CFRA = round_fl_to_int(frame); SUBFRA = 0.0f; } FRAMENUMBER_MIN_CLAMP(CFRA); @@ -301,8 +301,8 @@ static int previewrange_define_exec(bContext *C, wmOperator *op) if (efra < sfra) efra = sfra; scene->r.flag |= SCER_PRV_RANGE; - scene->r.psfra = iroundf(sfra); - scene->r.pefra = iroundf(efra); + scene->r.psfra = round_fl_to_int(sfra); + scene->r.pefra = round_fl_to_int(efra); /* send notifiers */ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 21c25f829b1..52b93edae15 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -40,6 +40,7 @@ #include "BLI_string.h" #include "DNA_anim_types.h" +#include "DNA_object_types.h" #include "DNA_texture_types.h" #include "BKE_animsys.h" @@ -1029,6 +1030,11 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op) UI_context_update_anim_flag(C); + DAG_relations_tag_update(CTX_data_main(C)); + DAG_id_tag_update(ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA); + + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); // XXX + MEM_freeN(path); } } diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index c1e82583521..071c5fab9d7 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -52,6 +52,7 @@ #include "BKE_deform.h" #include "RNA_access.h" +#include "RNA_enum_types.h" #include "ED_anim_api.h" #include "ED_keyframing.h" diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index f2a35bb1553..540886196fe 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1073,10 +1073,11 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou /* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor, * is determined by the array index for the F-Curve */ - if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { + PropertySubType prop_subtype = RNA_property_subtype(prop); + if (ELEM(prop_subtype, PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { fcu->color_mode = FCURVE_COLOR_AUTO_RGB; } - else if (RNA_property_subtype(prop), PROP_QUATERNION) { + else if (ELEM(prop_subtype, PROP_QUATERNION)) { fcu->color_mode = FCURVE_COLOR_AUTO_YRGB; } } @@ -1785,7 +1786,9 @@ static int insert_key_button_exec(bContext *C, wmOperator *op) NlaStrip *strip = (NlaStrip *)ptr.data; FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); - success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0); + if (fcu) { + success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0); + } } else if (UI_but_flag_is_set(but, UI_BUT_DRIVEN)) { /* Driven property - Find driver */ @@ -1890,27 +1893,27 @@ static int delete_key_button_exec(bContext *C, wmOperator *op) NlaStrip *strip = (NlaStrip *)ptr.data; FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0); - BLI_assert(fcu != NULL); /* NOTE: This should be true, or else we wouldn't be able to get here */ - - if (BKE_fcurve_is_protected(fcu)) { - BKE_reportf(op->reports, RPT_WARNING, - "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'", - strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2); - } - else { - /* remove the keyframe directly - * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve, - * and delete_keyframe() expects the FCurve to be part of an action - */ - bool found = false; - int i; - - /* try to find index of beztriple to get rid of */ - i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); - if (found) { - /* delete the key at the index (will sanity check + do recalc afterwards) */ - delete_fcurve_key(fcu, i, 1); - success = true; + if (fcu) { + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf(op->reports, RPT_WARNING, + "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'", + strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2); + } + else { + /* remove the keyframe directly + * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve, + * and delete_keyframe() expects the FCurve to be part of an action + */ + bool found = false; + int i; + + /* try to find index of beztriple to get rid of */ + i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); + if (found) { + /* delete the key at the index (will sanity check + do recalc afterwards) */ + delete_fcurve_key(fcu, i, 1); + success = true; + } } } } diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index 4408ec26b3f..0a27fe14de7 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -1052,6 +1052,8 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); break; } + default: + break; } /* send notifiers for updates (this doesn't require context to work!) */ diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 47e73f9b777..51b76563c72 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -66,7 +66,7 @@ /* ************************** Object Tools Exports ******************************* */ /* NOTE: these functions are exported to the Object module to be called from the tools there */ -void ED_armature_apply_transform(Object *ob, float mat[4][4]) +void ED_armature_apply_transform(Object *ob, float mat[4][4], const bool do_props) { bArmature *arm = ob->data; @@ -74,14 +74,14 @@ void ED_armature_apply_transform(Object *ob, float mat[4][4]) ED_armature_to_edit(arm); /* Transform the bones */ - ED_armature_transform_bones(arm, mat); + ED_armature_transform_bones(arm, mat, do_props); /* Turn the list into an armature */ ED_armature_from_edit(arm); ED_armature_edit_free(arm); } -void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4]) +void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props) { EditBone *ebone; float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */ @@ -106,27 +106,29 @@ void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4]) /* apply the transformed roll back */ mat3_to_vec_roll(tmat, NULL, &ebone->roll); - ebone->rad_head *= scale; - ebone->rad_tail *= scale; - ebone->dist *= scale; - - /* we could be smarter and scale by the matrix along the x & z axis */ - ebone->xwidth *= scale; - ebone->zwidth *= scale; + if (do_props) { + ebone->rad_head *= scale; + ebone->rad_tail *= scale; + ebone->dist *= scale; + + /* we could be smarter and scale by the matrix along the x & z axis */ + ebone->xwidth *= scale; + ebone->zwidth *= scale; + } } } -void ED_armature_transform(struct bArmature *arm, float mat[4][4]) +void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props) { if (arm->edbo) { - ED_armature_transform_bones(arm, mat); + ED_armature_transform_bones(arm, mat, do_props); } else { /* Put the armature into editmode */ ED_armature_to_edit(arm); /* Transform the bones */ - ED_armature_transform_bones(arm, mat); + ED_armature_transform_bones(arm, mat, do_props); /* Go back to object mode*/ ED_armature_from_edit(arm); @@ -220,7 +222,7 @@ float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const bool vec_roll_to_mat3_normalized(nor, 0.0f, mat); /* project the new_up_axis along the normal */ - project_v3_v3v3(vec, align_axis, nor); + project_v3_v3v3_normalized(vec, align_axis, nor); sub_v3_v3v3(align_axis_proj, align_axis, vec); if (axis_only) { diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 1c342657eec..417d7c8ba3b 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -380,7 +380,7 @@ int join_armature_exec(bContext *C, wmOperator *op) if (base->object->adt) { if (ob->adt == NULL) { /* no animdata, so just use a copy of the whole thing */ - ob->adt = BKE_animdata_copy(base->object->adt, false); + ob->adt = BKE_animdata_copy(bmain, base->object->adt, false); } else { /* merge in data - we'll fix the drivers manually */ @@ -391,7 +391,7 @@ int join_armature_exec(bContext *C, wmOperator *op) if (curarm->adt) { if (arm->adt == NULL) { /* no animdata, so just use a copy of the whole thing */ - arm->adt = BKE_animdata_copy(curarm->adt, false); + arm->adt = BKE_animdata_copy(bmain, curarm->adt, false); } else { /* merge in data - we'll fix the drivers manually */ diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 8dfcd5acab8..f62073d56ef 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -39,6 +39,7 @@ #include "DNA_scene_types.h" #include "BKE_fcurve.h" +#include "BKE_nla.h" #include "BKE_context.h" #include "BKE_object.h" @@ -94,9 +95,13 @@ typedef struct tPoseSlideOp { ListBase pfLinks; /* links between posechannels and f-curves */ DLRBT_Tree keys; /* binary tree for quicker searching for keyframes (when applicable) */ - int cframe; /* current frame number */ - int prevFrame; /* frame before current frame (blend-from) */ - int nextFrame; /* frame after current frame (blend-to) */ + int cframe; /* current frame number - global time */ + + int prevFrame; /* frame before current frame (blend-from) - global time */ + int nextFrame; /* frame after current frame (blend-to) - global time */ + + float prevFrameF; /* prevFrame, but in local action time (for F-Curve lookups to work) */ + float nextFrameF; /* nextFrame, but in local action time (for F-Curve lookups to work) */ short mode; /* sliding mode (ePoseSlide_Modes) */ short flag; /* unused for now, but can later get used for storing runtime settings.... */ @@ -189,11 +194,15 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode) pso->channels = RNA_enum_get(op->ptr, "channels"); pso->axislock = RNA_enum_get(op->ptr, "axis_lock"); - /* check the settings from the context */ + /* ensure validity of the settings from the context */ if (ELEM(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action)) return 0; - else - act = pso->ob->adt->action; + + act = pso->ob->adt->action; + + /* apply NLA mapping corrections so the frame lookups work */ + pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP); + pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP); /* for each Pose-Channel which gets affected, get the F-Curves for that channel * and set the relevant transform flags... @@ -259,9 +268,9 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val) /* get keyframe values for endpoint poses to blend with */ /* previous/start */ - sVal = evaluate_fcurve(fcu, (float)pso->prevFrame); + sVal = evaluate_fcurve(fcu, pso->prevFrameF); /* next/end */ - eVal = evaluate_fcurve(fcu, (float)pso->nextFrame); + eVal = evaluate_fcurve(fcu, pso->nextFrameF); /* if both values are equal, don't do anything */ if (IS_EQF(sVal, eVal)) { @@ -483,15 +492,15 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) float quat_prev[4], quat_next[4]; /* get 2 quats */ - quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrame); - quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrame); - quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrame); - quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrame); + quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrameF); + quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrameF); + quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrameF); + quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrameF); - quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrame); - quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrame); - quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrame); - quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrame); + quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrameF); + quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrameF); + quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrameF); + quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrameF); /* perform blending */ if (pso->mode == POSESLIDE_BREAKDOWN) { @@ -543,6 +552,10 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso) /* move out one step either side */ pso->prevFrame--; pso->nextFrame++; + + /* apply NLA mapping corrections so the frame lookups work */ + pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP); + pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP); } /* for each link, handle each set of transforms */ @@ -746,6 +759,10 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p pso->nextFrame = (ak->next) ? (ak->next->cfra) : (pso->cframe + 1); RNA_int_set(op->ptr, "next_frame", pso->nextFrame); } + + /* apply NLA mapping corrections so the frame lookups work */ + pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP); + pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP); } else { BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between"); @@ -1464,7 +1481,7 @@ static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu, /* stop on matching marker if there is one */ for (ce = modeData.sel_markers.first; ce; ce = ce->next) { - if (ce->cfra == iroundf(bezt->vec[1][0])) + if (ce->cfra == round_fl_to_int(bezt->vec[1][0])) break; } diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h index 856573ffab0..02c76a840f1 100644 --- a/source/blender/editors/curve/curve_intern.h +++ b/source/blender/editors/curve/curve_intern.h @@ -40,7 +40,7 @@ struct wmOperatorType; struct ViewContext; /* editfont.c */ -enum { DEL_ALL, DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL }; +enum { DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_NEXT_WORD, DEL_PREV_WORD, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL }; enum { CASE_LOWER, CASE_UPPER }; enum { LINE_BEGIN, LINE_END, PREV_CHAR, NEXT_CHAR, PREV_WORD, NEXT_WORD, PREV_LINE, NEXT_LINE, PREV_PAGE, NEXT_PAGE }; diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c index fce6425b9be..5d637b113d8 100644 --- a/source/blender/editors/curve/curve_ops.c +++ b/source/blender/editors/curve/curve_ops.c @@ -178,9 +178,10 @@ void ED_keymap_curve(wmKeyConfig *keyconf) RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_style_toggle", PKEY, KM_PRESS, KM_CTRL, 0)->ptr, "style", CU_CHINFO_SMALLCAPS); RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", DELKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_NEXT_SEL); + RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", DELKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_NEXT_WORD); RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_PREV_SEL); RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", DEL_PREV_SEL); /* same as above [#26623] */ - RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_ALL); + RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_PREV_WORD); RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", HOMEKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_BEGIN); RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", ENDKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_END); diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 34e026a3ef4..5c3a694929e 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -70,102 +70,6 @@ /* Distance between start/end points to consider cyclic */ #define STROKE_CYCLIC_DIST_PX 8 - -/* -------------------------------------------------------------------- */ - -/** \name Depth Utilities - * \{ */ - - -static float depth_read_zbuf(const ViewContext *vc, int x, int y) -{ - ViewDepths *vd = vc->rv3d->depths; - - if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) - return vd->depths[y * vd->w + x]; - else - return -1.0f; -} - -static bool depth_unproject( - const ARegion *ar, const bglMats *mats, - const int mval[2], const double depth, - float r_location_world[3]) -{ - double p[3]; - if (gluUnProject( - (double)ar->winrct.xmin + mval[0] + 0.5, - (double)ar->winrct.ymin + mval[1] + 0.5, - depth, mats->modelview, mats->projection, (const GLint *)mats->viewport, - &p[0], &p[1], &p[2])) - { - copy_v3fl_v3db(r_location_world, p); - return true; - } - return false; -} - -static bool depth_read_normal( - const ViewContext *vc, const bglMats *mats, const int mval[2], - float r_normal[3]) -{ - /* pixels surrounding */ - bool depths_valid[9] = {false}; - float coords[9][3] = {{0}}; - - ARegion *ar = vc->ar; - const ViewDepths *depths = vc->rv3d->depths; - - for (int x = 0, i = 0; x < 2; x++) { - for (int y = 0; y < 2; y++) { - const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)}; - - const double depth = (double)depth_read_zbuf(vc, mval_ofs[0], mval_ofs[1]); - if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { - if (depth_unproject(ar, mats, mval_ofs, depth, coords[i])) { - depths_valid[i] = true; - } - } - i++; - } - } - - const int edges[2][6][2] = { - /* x edges */ - {{0, 1}, {1, 2}, - {3, 4}, {4, 5}, - {6, 7}, {7, 8}}, - /* y edges */ - {{0, 3}, {3, 6}, - {1, 4}, {4, 7}, - {2, 5}, {5, 8}}, - }; - - float cross[2][3] = {{0.0f}}; - - for (int i = 0; i < 6; i++) { - for (int axis = 0; axis < 2; axis++) { - if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) { - float delta[3]; - sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]); - add_v3_v3(cross[axis], delta); - } - } - } - - cross_v3_v3v3(r_normal, cross[0], cross[1]); - - if (normalize_v3(r_normal) != 0.0f) { - return true; - } - else { - return false; - } -} - -/** \} */ - - /* -------------------------------------------------------------------- */ /** \name StrokeElem / #RNA_OperatorStrokeElement Conversion Functions @@ -308,9 +212,9 @@ static bool stroke_elem_project( ((unsigned int)mval_i[0] < depths->w) && ((unsigned int)mval_i[1] < depths->h)) { - const double depth = (double)depth_read_zbuf(&cdd->vc, mval_i[0], mval_i[1]); + const double depth = (double)ED_view3d_depth_read_cached(&cdd->vc, mval_i); if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { - if (depth_unproject(ar, &cdd->mats, mval_i, depth, r_location_world)) { + if (ED_view3d_depth_unproject(ar, &cdd->mats, mval_i, depth, r_location_world)) { is_location_world_set = true; if (r_normal_world) { zero_v3(r_normal_world); @@ -319,7 +223,7 @@ static bool stroke_elem_project( if (surface_offset != 0.0f) { const float offset = cdd->project.use_surface_offset_absolute ? 1.0f : radius; float normal[3]; - if (depth_read_normal(&cdd->vc, &cdd->mats, mval_i, normal)) { + if (ED_view3d_depth_read_cached_normal(&cdd->vc, &cdd->mats, mval_i, normal)) { madd_v3_v3fl(r_location_world, normal, offset * surface_offset); if (r_normal_world) { copy_v3_v3(r_normal_world, normal); @@ -627,7 +531,7 @@ static void curve_draw_event_add_first(wmOperator *op, const wmEvent *event) CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW, CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE)) { - if (depth_read_normal(&cdd->vc, &cdd->mats, event->mval, normal)) { + if (ED_view3d_depth_read_cached_normal(&cdd->vc, &cdd->mats, event->mval, normal)) { if (cps->surface_plane == CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW) { float cross_a[3], cross_b[3]; cross_v3_v3v3(cross_a, rv3d->viewinv[2], normal); diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 57e731874b4..535e5d7bd28 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -1170,9 +1170,10 @@ void FONT_OT_line_break(wmOperatorType *ot) /******************* delete operator **********************/ static EnumPropertyItem delete_type_items[] = { - {DEL_ALL, "ALL", 0, "All", ""}, {DEL_NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""}, {DEL_PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""}, + {DEL_NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""}, + {DEL_PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""}, {DEL_SELECTION, "SELECTION", 0, "Selection", ""}, {DEL_NEXT_SEL, "NEXT_OR_SELECTION", 0, "Next or Selection", ""}, {DEL_PREV_SEL, "PREVIOUS_OR_SELECTION", 0, "Previous or Selection", ""}, @@ -1183,7 +1184,9 @@ static int delete_exec(bContext *C, wmOperator *op) Object *obedit = CTX_data_edit_object(C); Curve *cu = obedit->data; EditFont *ef = cu->editfont; - int x, selstart, selend, type = RNA_enum_get(op->ptr, "type"); + int selstart, selend, type = RNA_enum_get(op->ptr, "type"); + int range[2] = {0, 0}; + bool has_select = false; if (ef->len == 0) return OPERATOR_CANCELLED; @@ -1191,6 +1194,7 @@ static int delete_exec(bContext *C, wmOperator *op) if (BKE_vfont_select_get(obedit, &selstart, &selend)) { if (type == DEL_NEXT_SEL) type = DEL_SELECTION; else if (type == DEL_PREV_SEL) type = DEL_SELECTION; + has_select = true; } else { if (type == DEL_NEXT_SEL) type = DEL_NEXT_CHAR; @@ -1198,10 +1202,6 @@ static int delete_exec(bContext *C, wmOperator *op) } switch (type) { - case DEL_ALL: - ef->len = ef->pos = 0; - ef->textbuf[0] = 0; - break; case DEL_SELECTION: if (!kill_selection(obedit, 0)) return OPERATOR_CANCELLED; @@ -1210,29 +1210,69 @@ static int delete_exec(bContext *C, wmOperator *op) if (ef->pos <= 0) return OPERATOR_CANCELLED; - for (x = ef->pos; x <= ef->len; x++) - ef->textbuf[x - 1] = ef->textbuf[x]; - for (x = ef->pos; x <= ef->len; x++) - ef->textbufinfo[x - 1] = ef->textbufinfo[x]; + range[0] = ef->pos - 1; + range[1] = ef->pos; ef->pos--; - ef->textbuf[--ef->len] = '\0'; break; case DEL_NEXT_CHAR: if (ef->pos >= ef->len) return OPERATOR_CANCELLED; - for (x = ef->pos; x < ef->len; x++) - ef->textbuf[x] = ef->textbuf[x + 1]; - for (x = ef->pos; x < ef->len; x++) - ef->textbufinfo[x] = ef->textbufinfo[x + 1]; + range[0] = ef->pos; + range[1] = ef->pos + 1; + break; + case DEL_NEXT_WORD: + { + int pos = ef->pos; + BLI_str_cursor_step_wchar(ef->textbuf, ef->len, &pos, STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, true); + range[0] = ef->pos; + range[1] = pos; + break; + } - ef->textbuf[--ef->len] = '\0'; + case DEL_PREV_WORD: + { + int pos = ef->pos; + BLI_str_cursor_step_wchar(ef->textbuf, ef->len, &pos, STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, true); + range[0] = pos; + range[1] = ef->pos; + ef->pos = pos; break; + } default: return OPERATOR_CANCELLED; } + if (range[0] != range[1]) { + BLI_assert(range[0] < range[1]); + int len_remove = range[1] - range[0]; + int len_tail = ef->len - range[1]; + if (has_select) { + for (int i = 0; i < 2; i++) { + int *sel = i ? &ef->selend : &ef->selstart; + if (*sel <= range[0]) { + /* pass */ + } + else if (*sel >= range[1]) { + *sel -= len_remove; + } + else if (*sel < range[1]) { + /* pass */ + *sel = range[0]; + } + } + } + + memmove(&ef->textbuf[range[0]], &ef->textbuf[range[1]], sizeof(*ef->textbuf) * len_tail); + memmove(&ef->textbufinfo[range[0]], &ef->textbufinfo[range[1]], sizeof(*ef->textbufinfo) * len_tail); + + ef->len -= len_remove; + ef->textbuf[ef->len] = '\0'; + + BKE_vfont_select_clamp(obedit); + } + text_update_edited(C, obedit, FO_EDIT); return OPERATOR_FINISHED; @@ -1253,7 +1293,7 @@ void FONT_OT_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_enum(ot->srna, "type", delete_type_items, DEL_ALL, "Type", "Which part of the text to delete"); + RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PREV_CHAR, "Type", "Which part of the text to delete"); } /*********************** insert text operator *************************/ diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index ecab37c729f..c08ed0db400 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -1732,10 +1732,10 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, AReg rctf rectf; ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */ - offsx = iroundf(rectf.xmin); - offsy = iroundf(rectf.ymin); - winx = iroundf(rectf.xmax - rectf.xmin); - winy = iroundf(rectf.ymax - rectf.ymin); + offsx = round_fl_to_int(rectf.xmin); + offsy = round_fl_to_int(rectf.ymin); + winx = round_fl_to_int(rectf.xmax - rectf.xmin); + winy = round_fl_to_int(rectf.ymax - rectf.ymin); } else { offsx = 0; diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index bd4856f1b93..90d44503013 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -252,8 +252,10 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl) for (gpf = gpl->frames.first; gpf; gpf = gpfn) { gpfn = gpf->next; - if (gpf->flag & GP_FRAME_SELECT) - changed |= BKE_gpencil_layer_delframe(gpl, gpf); + if (gpf->flag & GP_FRAME_SELECT) { + BKE_gpencil_layer_delframe(gpl, gpf); + changed = true; + } } return changed; @@ -314,7 +316,7 @@ void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type) */ /* globals for copy/paste data (like for other copy/paste buffers) */ -ListBase gp_anim_copybuf = {NULL, NULL}; +static ListBase gp_anim_copybuf = {NULL, NULL}; static int gp_anim_copy_firstframe = 999999999; static int gp_anim_copy_lastframe = -999999999; static int gp_anim_copy_cfra = 0; diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index 5332bec0c64..e5fb162a96c 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -710,7 +710,7 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in } else { /* ERROR */ - BLI_assert("3D stroke being sculpted in non-3D view"); + BLI_assert(!"3D stroke being sculpted in non-3D view"); } } else { diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index fc6df49cf6c..55a3fc09f2e 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -343,7 +343,7 @@ ListBase gp_strokes_copypastebuf = {NULL, NULL}; * This is needed to prevent dangling and unsafe pointers when pasting across datablocks, * or after a color used by a stroke in the buffer gets deleted (via user action or undo). */ -GHash *gp_strokes_copypastebuf_colors = NULL; +static GHash *gp_strokes_copypastebuf_colors = NULL; /* Free copy/paste buffer data */ void ED_gpencil_strokes_copybuf_free(void) diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 59b5b41f114..83e2a85db49 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -117,8 +117,8 @@ static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_t /* Interpolate all values */ interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor); - pt->pressure = interpf(prev->pressure, next->pressure, factor); - pt->strength = interpf(prev->strength, next->strength, factor); + pt->pressure = interpf(prev->pressure, next->pressure, 1.0f - factor); + pt->strength = interpf(prev->strength, next->strength, 1.0f - factor); CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); } } @@ -284,7 +284,9 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) new_stroke = MEM_dupallocN(gps_from); new_stroke->points = MEM_dupallocN(gps_from->points); new_stroke->triangles = MEM_dupallocN(gps_from->triangles); - + new_stroke->tot_triangles = 0; + new_stroke->flag |= GP_STROKE_RECALC_CACHES; + if (valid) { /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { @@ -302,6 +304,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points)); new_stroke->tot_triangles = 0; new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles)); + new_stroke->flag |= GP_STROKE_RECALC_CACHES; } /* add to strokes */ @@ -986,7 +989,9 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) new_stroke = MEM_dupallocN(gps_from); new_stroke->points = MEM_dupallocN(gps_from->points); new_stroke->triangles = MEM_dupallocN(gps_from->triangles); - + new_stroke->tot_triangles = 0; + new_stroke->flag |= GP_STROKE_RECALC_CACHES; + /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 78e1a0dda36..3a2169798e5 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -99,8 +99,8 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, DKEY); /* Pie Menu - For standard tools */ - WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_tool_palette", QKEY, KM_PRESS, 0, DKEY); - WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_settings_palette", WKEY, KM_PRESS, 0, DKEY); + WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_tool_palette", QKEY, KM_PRESS, 0, DKEY); + WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_settings_palette", WKEY, KM_PRESS, 0, DKEY); /* Add Blank Frame */ /* XXX: BKEY or NKEY? BKEY is easier to reach from DKEY, so we'll use that for now */ @@ -135,7 +135,7 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, 0); /* Pie Menu - For settings/tools easy access */ - WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_sculpt", EKEY, KM_PRESS, 0, DKEY); + WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_sculpt", EKEY, KM_PRESS, 0, DKEY); /* Brush Settings */ /* NOTE: We cannot expose these in the standard keymap, as they will interfere with regular hotkeys diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 4a4ab832b28..68a5dd8a94e 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -124,6 +124,15 @@ typedef struct bAnimListElem { void *key_data; /* motion data - mostly F-Curves, but can be other types too */ + /* NOTE: id here is the "IdAdtTemplate"-style datablock (e.g. Object, Material, Texture, NodeTree) + * from which evaluation of the RNA-paths takes place. It's used to figure out how deep + * channels should be nested (e.g. for Textures/NodeTrees) in the tree, and allows property + * lookups (e.g. for sliders and for inserting keyframes) to work. If we had instead used + * bAction or something similar, none of this would be possible: although it's trivial + * to use an IdAdtTemplate type to find the source action a channel (e.g. F-Curve) comes from + * (i.e. in the AnimEditors, it *must* be the active action, as only that can be edited), + * it's impossible to go the other way (i.e. one action may be used in multiple places). + */ struct ID *id; /* ID block that channel is attached to */ struct AnimData *adt; /* source of the animation data attached to ID block (for convenience) */ @@ -256,7 +265,7 @@ typedef enum eAnimFilter_Flags { ANIMFILTER_TMP_PEEK = (1 << 30), /* ignore ONLYSEL flag from filterflag, (internal use only!) */ - ANIMFILTER_TMP_IGNORE_ONLYSEL = (1 << 31) + ANIMFILTER_TMP_IGNORE_ONLYSEL = (1u << 31) } eAnimFilter_Flags; /* ---------- Flag Checking Macros ------------ */ diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 6b8943421bd..9130336228d 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -158,9 +158,9 @@ void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4]); void transform_armature_mirror_update(struct Object *obedit); void ED_armature_origin_set(struct Scene *scene, struct Object *ob, float cursor[3], int centermode, int around); -void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4]); -void ED_armature_apply_transform(struct Object *ob, float mat[4][4]); -void ED_armature_transform(struct bArmature *arm, float mat[4][4]); +void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props); +void ED_armature_apply_transform(struct Object *ob, float mat[4][4], const bool do_props); +void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props); #define ARM_GROUPS_NAME 1 #define ARM_GROUPS_ENVELOPE 2 diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 6b1e3051d2b..b5e54a56996 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -285,6 +285,7 @@ bool ED_mesh_uv_texture_remove_active(struct Mesh *me); bool ED_mesh_uv_texture_remove_named(struct Mesh *me, const char *name); void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me); void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum); +bool ED_mesh_color_ensure(struct Mesh *me, const char *name); int ED_mesh_color_add(struct Mesh *me, const char *name, const bool active_set); bool ED_mesh_color_remove_index(struct Mesh *me, const int n); bool ED_mesh_color_remove_active(struct Mesh *me); diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index ebd2a3dcb7a..9a0a7f8f1bb 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -148,7 +148,8 @@ int BIF_countTransformOrientation(const struct bContext *C); #define P_CORRECT_UV (1 << 8) #define P_NO_DEFAULTS (1 << 10) #define P_NO_TEXSPACE (1 << 11) -#define P_GPENCIL_EDIT (1 << 12) +#define P_CENTER (1 << 12) +#define P_GPENCIL_EDIT (1 << 13) void Transform_Properties(struct wmOperatorType *ot, int flags); @@ -159,12 +160,6 @@ void BIF_draw_manipulator(const struct bContext *C); /* Snapping */ -typedef enum SnapSelect { - SNAP_ALL = 0, - SNAP_NOT_SELECTED = 1, - SNAP_NOT_ACTIVE = 2, -} SnapSelect; - #define SNAP_MIN_DISTANCE 30 bool peelObjectsTransform( @@ -187,11 +182,7 @@ bool snapObjectsTransform( /* return args */ float r_loc[3], float r_no[3]); bool snapNodesTransform( - struct TransInfo *t, const int mval[2], SnapSelect snap_select, - /* return args */ - float r_loc[2], float *r_dist_px, char *r_node_border); -bool snapNodesContext( - struct bContext *C, const int mval[2], SnapSelect snap_select, + struct TransInfo *t, const int mval[2], /* return args */ float r_loc[2], float *r_dist_px, char *r_node_border); diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index 8066adf55ce..e440e8c8389 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -40,6 +40,12 @@ struct View3D; /* ED_transform_snap_object_*** API */ +typedef enum SnapSelect { + SNAP_ALL = 0, + SNAP_NOT_SELECTED = 1, + SNAP_NOT_ACTIVE = 2, +} SnapSelect; + /** used for storing multiple hits */ struct SnapObjectHitDepth { struct SnapObjectHitDepth *next, *prev; diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index d5c301d98d6..85fb0ee4447 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -106,7 +106,14 @@ void ED_view3d_lastview_store(struct RegionView3D *rv3d); /* Depth buffer */ void ED_view3d_depth_update(struct ARegion *ar); -float ED_view3d_depth_read_cached(const struct ViewContext *vc, int x, int y); +float ED_view3d_depth_read_cached(const struct ViewContext *vc, const int mval[2]); +bool ED_view3d_depth_read_cached_normal( + const ViewContext *vc, const struct bglMats *mats, const int mval[2], + float r_normal[3]); +bool ED_view3d_depth_unproject( + const struct ARegion *ar, const struct bglMats *mats, + const int mval[2], const double depth, + float r_location_world[3]); void ED_view3d_depth_tag_update(struct RegionView3D *rv3d); /* Projection */ diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 252c199d46c..e14a3a3ff0a 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -212,6 +212,8 @@ enum { UI_BUT_ALIGN_STITCH_TOP = (1 << 18), UI_BUT_ALIGN_STITCH_LEFT = (1 << 19), UI_BUT_ALIGN_ALL = (UI_BUT_ALIGN | UI_BUT_ALIGN_STITCH_TOP | UI_BUT_ALIGN_STITCH_LEFT), + + UI_BUT_BOX_ITEM = (1 << 20), /* This but is "inside" a box item (currently used to change theme colors). */ }; /* scale fixed button widths by this to account for DPI */ @@ -994,7 +996,7 @@ void uiItemsFullEnumO( struct IDProperty *properties, int context, int flag); void uiItemsFullEnumO_items( uiLayout *layout, struct wmOperatorType *ot, PointerRNA ptr, PropertyRNA *prop, - IDProperty *properties, int context, int flag, + struct IDProperty *properties, int context, int flag, const EnumPropertyItem *item_array, int totitem); void uiItemL(uiLayout *layout, const char *name, int icon); /* label */ @@ -1082,7 +1084,7 @@ void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p); /* Float precision helpers */ -#define UI_PRECISION_FLOAT_MAX 7 +#define UI_PRECISION_FLOAT_MAX 6 /* For float buttons the 'step' (or a1), is scaled */ #define UI_PRECISION_FLOAT_SCALE 0.01f diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index f8a5f30a596..a0efd586af5 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -303,7 +303,6 @@ enum { TH_EDGE_BEVEL, TH_VERTEX_BEVEL }; -/* XXX WARNING: previous is saved in file, so do not change order! */ /* specific defines per space should have higher define values */ diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 4caacb65f5f..4c0493a881c 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -203,6 +203,7 @@ bool UI_view2d_view_to_region_clip(struct View2D *v2d, float x, float y, int *r void UI_view2d_view_to_region(struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL(); void UI_view2d_view_to_region_fl(struct View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) ATTR_NONNULL(); +void UI_view2d_view_to_region_m4(struct View2D *v2d, float matrix[4][4]) ATTR_NONNULL(); void UI_view2d_view_to_region_rcti(struct View2D *v2d, const struct rctf *rect_src, struct rcti *rect_dst) ATTR_NONNULL(); bool UI_view2d_view_to_region_rcti_clip(struct View2D *v2d, const struct rctf *rect_src, struct rcti *rect_dst) ATTR_NONNULL(); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index bcb1e3e648a..5c05fc8c530 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -488,6 +488,9 @@ static int ui_but_calc_float_precision(uiBut *but, double value) else if (prec == -1) { prec = (but->hardmax < 10.001f) ? 3 : 2; } + else { + CLAMP(prec, 0, UI_PRECISION_FLOAT_MAX); + } return UI_calc_float_precision(prec, value); } @@ -684,7 +687,7 @@ static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBu if (oldbut->active) { /* flags from the buttons we want to refresh, may want to add more here... */ - const int flag_copy = UI_BUT_REDALERT; + const int flag_copy = UI_BUT_REDALERT | UI_HAS_ICON; found_active = true; @@ -1165,6 +1168,8 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) uiBut *but; char buf[128]; + BLI_assert(block->flag & UI_BLOCK_LOOP); + /* only do it before bounding */ if (block->rect.xmin != block->rect.xmax) return; @@ -1179,6 +1184,9 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) } else { for (but = block->buttons.first; but; but = but->next) { + if (but->dt != UI_EMBOSS_PULLDOWN) { + continue; + } if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) { ui_but_add_shortcut(but, buf, false); @@ -1932,13 +1940,14 @@ void ui_but_value_set(uiBut *but, double value) else { /* first do rounding */ if (but->pointype == UI_BUT_POIN_CHAR) { - value = (char)floor(value + 0.5); + value = round_db_to_uchar_clamp(value); } else if (but->pointype == UI_BUT_POIN_SHORT) { - value = (short)floor(value + 0.5); + value = round_db_to_short_clamp(value); + } + else if (but->pointype == UI_BUT_POIN_INT) { + value = round_db_to_int_clamp(value); } - else if (but->pointype == UI_BUT_POIN_INT) - value = (int)floor(value + 0.5); else if (but->pointype == UI_BUT_POIN_FLOAT) { float fval = (float)value; if (fval >= -0.00001f && fval <= 0.00001f) fval = 0.0f; /* prevent negative zero */ @@ -2146,9 +2155,14 @@ static float ui_get_but_step_unit(uiBut *but, float step_default) /** * \param float_precision For number buttons the precision to use or -1 to fallback to the button default. + * \param use_exp_float Use exponent representation of floats when out of reasonable range (outside of 1e3/1e-3). */ -void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision) +void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision, const bool use_exp_float, bool *r_use_exp_float) { + if (r_use_exp_float) { + *r_use_exp_float = false; + } + if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) { PropertyType type; const char *buf = NULL; @@ -2216,17 +2230,38 @@ void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int ui_get_but_string_unit(but, str, maxlen, value, false, float_precision); } else { - const int prec = (float_precision == -1) ? ui_but_calc_float_precision(but, value) : float_precision; - BLI_snprintf(str, maxlen, "%.*f", prec, value); + int prec = (float_precision == -1) ? ui_but_calc_float_precision(but, value) : float_precision; + if (use_exp_float) { + const int int_digits_num = integer_digits_f(value); + if (int_digits_num < -6 || int_digits_num > 12) { + BLI_snprintf(str, maxlen, "%.*g", prec, value); + if (r_use_exp_float) { + *r_use_exp_float = true; + } + } + else { + prec -= int_digits_num; + CLAMP(prec, 0, UI_PRECISION_FLOAT_MAX); + BLI_snprintf(str, maxlen, "%.*f", prec, value); + } + } + else { +#if 0 /* TODO, but will likely break some stuff, so better after 2.79 release. */ + prec -= int_digits_num; + CLAMP(prec, 0, UI_PRECISION_FLOAT_MAX); +#endif + BLI_snprintf(str, maxlen, "%.*f", prec, value); + } } } - else + else { BLI_snprintf(str, maxlen, "%d", (int)value); + } } } void ui_but_string_get(uiBut *but, char *str, const size_t maxlen) { - ui_but_string_get_ex(but, str, maxlen, -1); + ui_but_string_get_ex(but, str, maxlen, -1, false, NULL); } /** @@ -2448,7 +2483,9 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str) return false; } - if (!ui_but_is_float(but)) value = (int)floor(value + 0.5); + if (!ui_but_is_float(but)) { + value = floor(value + 0.5); + } /* not that we use hard limits here */ if (value < (double)but->hardmin) value = but->hardmin; diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index a3f0e29065d..5349744af6c 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1440,87 +1440,82 @@ static bool ui_selectcontext_begin( const bool is_array = RNA_property_array_check(prop); const int rna_type = RNA_property_type(prop); - if (!UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) { - goto finally; - } - - selctx_data->elems_len = BLI_listbase_count(&lb); - if (selctx_data->elems_len == 0) { - goto finally; - } - - selctx_data->elems = MEM_mallocN(sizeof(uiSelectContextElem) * selctx_data->elems_len, __func__); + if (UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path) && + !BLI_listbase_is_empty(&lb)) + { + selctx_data->elems_len = BLI_listbase_count(&lb); + selctx_data->elems = MEM_mallocN(sizeof(uiSelectContextElem) * selctx_data->elems_len, __func__); - for (i = 0, link = lb.first; i < selctx_data->elems_len; i++, link = link->next) { - uiSelectContextElem *other = &selctx_data->elems[i]; - /* TODO,. de-duplicate copy_to_selected_button */ - if (link->ptr.data != ptr.data) { - if (use_path_from_id) { - /* Path relative to ID. */ - lprop = NULL; - RNA_id_pointer_create(link->ptr.id.data, &idptr); - RNA_path_resolve_property(&idptr, path, &lptr, &lprop); - } - else if (path) { - /* Path relative to elements from list. */ - lprop = NULL; - RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop); - } - else { - lptr = link->ptr; - lprop = prop; - } + for (i = 0, link = lb.first; i < selctx_data->elems_len; i++, link = link->next) { + uiSelectContextElem *other = &selctx_data->elems[i]; + /* TODO,. de-duplicate copy_to_selected_button */ + if (link->ptr.data != ptr.data) { + if (use_path_from_id) { + /* Path relative to ID. */ + lprop = NULL; + RNA_id_pointer_create(link->ptr.id.data, &idptr); + RNA_path_resolve_property(&idptr, path, &lptr, &lprop); + } + else if (path) { + /* Path relative to elements from list. */ + lprop = NULL; + RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop); + } + else { + lptr = link->ptr; + lprop = prop; + } - /* lptr might not be the same as link->ptr! */ - if ((lptr.data != ptr.data) && - (lprop == prop) && - RNA_property_editable(&lptr, lprop)) - { - other->ptr = lptr; - if (is_array) { - if (rna_type == PROP_FLOAT) { - other->val_f = RNA_property_float_get_index(&lptr, lprop, index); - } - else if (rna_type == PROP_INT) { - other->val_i = RNA_property_int_get_index(&lptr, lprop, index); - } - /* ignored for now */ + /* lptr might not be the same as link->ptr! */ + if ((lptr.data != ptr.data) && + (lprop == prop) && + RNA_property_editable(&lptr, lprop)) + { + other->ptr = lptr; + if (is_array) { + if (rna_type == PROP_FLOAT) { + other->val_f = RNA_property_float_get_index(&lptr, lprop, index); + } + else if (rna_type == PROP_INT) { + other->val_i = RNA_property_int_get_index(&lptr, lprop, index); + } + /* ignored for now */ #if 0 - else if (rna_type == PROP_BOOLEAN) { - other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index); - } + else if (rna_type == PROP_BOOLEAN) { + other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index); + } #endif - } - else { - if (rna_type == PROP_FLOAT) { - other->val_f = RNA_property_float_get(&lptr, lprop); } - else if (rna_type == PROP_INT) { - other->val_i = RNA_property_int_get(&lptr, lprop); - } - /* ignored for now */ + else { + if (rna_type == PROP_FLOAT) { + other->val_f = RNA_property_float_get(&lptr, lprop); + } + else if (rna_type == PROP_INT) { + other->val_i = RNA_property_int_get(&lptr, lprop); + } + /* ignored for now */ #if 0 - else if (rna_type == PROP_BOOLEAN) { - other->val_b = RNA_property_boolean_get(&lptr, lprop); - } - else if (rna_type == PROP_ENUM) { - other->val_i = RNA_property_enum_get(&lptr, lprop); - } + else if (rna_type == PROP_BOOLEAN) { + other->val_b = RNA_property_boolean_get(&lptr, lprop); + } + else if (rna_type == PROP_ENUM) { + other->val_i = RNA_property_enum_get(&lptr, lprop); + } #endif - } + } - continue; + continue; + } } + + selctx_data->elems_len -= 1; + i -= 1; } - selctx_data->elems_len -= 1; - i -= 1; + success = (selctx_data->elems_len != 0); } } - success = (selctx_data->elems_len != 0); - -finally: if (selctx_data->elems_len == 0) { MEM_SAFE_FREE(selctx_data->elems); } @@ -2319,7 +2314,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, /* Get many decimal places, then strip trailing zeros. * note: too high values start to give strange results */ char buf_copy[UI_MAX_DRAW_STR]; - ui_but_string_get_ex(but, buf_copy, sizeof(buf_copy), UI_PRECISION_FLOAT_MAX); + ui_but_string_get_ex(but, buf_copy, sizeof(buf_copy), UI_PRECISION_FLOAT_MAX, false, NULL); BLI_str_rstrip_float_zero(buf_copy, '\0'); WM_clipboard_text_set(buf_copy, 0); @@ -3060,6 +3055,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) wmWindow *win = CTX_wm_window(C); int len; const bool is_num_but = ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER); + bool no_zero_strip = false; if (data->str) { MEM_freeN(data->str); @@ -3092,14 +3088,16 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) data->maxlen = ui_but_string_get_max_length(but); if (data->maxlen != 0) { data->str = MEM_callocN(sizeof(char) * data->maxlen, "textedit str"); - ui_but_string_get(but, data->str, data->maxlen); + /* We do not want to truncate precision to default here, it's nice to show value, + * not to edit it - way too much precision is lost then. */ + ui_but_string_get_ex(but, data->str, data->maxlen, UI_PRECISION_FLOAT_MAX, true, &no_zero_strip); } else { data->is_str_dynamic = true; data->str = ui_but_string_get_dynamic(but, &data->maxlen); } - if (ui_but_is_float(but) && !ui_but_is_unit(but) && !ui_but_anim_expression_get(but, NULL, 0)) { + if (ui_but_is_float(but) && !ui_but_is_unit(but) && !ui_but_anim_expression_get(but, NULL, 0) && !no_zero_strip) { BLI_str_rstrip_float_zero(data->str, '\0'); } @@ -4297,7 +4295,7 @@ static bool ui_numedit_but_NUM( if (!is_float) { - temp = iroundf(tempf); + temp = round_fl_to_int(tempf); temp = ui_numedit_apply_snap(temp, softmin, softmax, snap); @@ -4582,7 +4580,7 @@ static bool ui_numedit_but_SLI( tempf = softmin + f * softrange; - temp = iroundf(tempf); + temp = round_fl_to_int(tempf); if (snap) { if (tempf == softmin || tempf == softmax) { @@ -6792,8 +6790,8 @@ static bool ui_but_menu(bContext *C, uiBut *but) /* set the prop and pointer data for python access to the hovered ui element; TODO, index could be supported as well*/ PointerRNA temp_ptr; RNA_pointer_create(NULL, &RNA_Property, but->rnaprop, &temp_ptr); - uiLayoutSetContextPointer(layout,"button_prop", &temp_ptr); - uiLayoutSetContextPointer(layout,"button_pointer", ptr); + uiLayoutSetContextPointer(layout, "button_prop", &temp_ptr); + uiLayoutSetContextPointer(layout, "button_pointer", ptr); /* second slower test, saved people finding keyframe items in menus when its not possible */ if (is_anim) @@ -7012,8 +7010,9 @@ static bool ui_but_menu(bContext *C, uiBut *but) } /* Set the operator pointer for python access */ - if (but->opptr) - uiLayoutSetContextPointer(layout,"button_operator", but->opptr); + if (but->opptr) { + uiLayoutSetContextPointer(layout, "button_operator", but->opptr); + } uiItemS(layout); } @@ -7061,7 +7060,7 @@ static bool ui_but_menu(bContext *C, uiBut *but) } uiItemFullO(layout, "UI_OT_edittranslation_init", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, 0); - mt = WM_menutype_find("WM_MT_button_context", false); + mt = WM_menutype_find("WM_MT_button_context", true); if (mt) { Menu menu = {NULL}; menu.layout = uiLayoutColumn(layout, false); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 067279777ba..ab760c40451 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -473,7 +473,9 @@ extern void ui_hsvcircle_pos_from_vals(struct uiBut *but, const rcti *rect, floa extern void ui_hsvcube_pos_from_vals(struct uiBut *but, const rcti *rect, float *hsv, float *xp, float *yp); bool ui_but_is_colorpicker_display_space(struct uiBut *but); -extern void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision) ATTR_NONNULL(); +extern void ui_but_string_get_ex( + uiBut *but, char *str, const size_t maxlen, + const int float_precision, const bool use_exp_float, bool *r_use_exp_float) ATTR_NONNULL(1, 2); extern void ui_but_string_get(uiBut *but, char *str, const size_t maxlen) ATTR_NONNULL(); extern char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size); extern void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen) ATTR_NONNULL(); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index da43a58bc74..c21a76918e8 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -128,6 +128,8 @@ typedef struct uiItem { enum { UI_ITEM_FIXED = 1 << 0, UI_ITEM_MIN = 1 << 1, + + UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */ }; typedef struct uiButtonItem { @@ -192,8 +194,9 @@ static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_ static int ui_item_fit(int item, int pos, int all, int available, bool is_last, int alignment, float *extra_pixel) { /* available == 0 is unlimited */ - if (available == 0) + if (ELEM(0, available, all)) { return item; + } if (all > available) { /* contents is bigger than available space */ @@ -216,8 +219,9 @@ static int ui_item_fit(int item, int pos, int all, int available, bool is_last, return (int)width; } } - else + else { return item; + } } } @@ -243,7 +247,9 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool variable = (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X); if (variable) { - layout->item.flag |= UI_ITEM_MIN; + if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) { + layout->item.flag |= UI_ITEM_MIN; + } const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; /* it may seem odd that the icon only adds (UI_UNIT_X / 4) * but taking margins into account its fine */ @@ -700,7 +706,7 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *n WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, NULL); } else if (flag & UI_ITEM_R_EVENT) { - uiDefButR_prop(block, UI_BTYPE_KEY_EVENT, 0, name, x, y, w, h, ptr, prop, index, 0, 0, -1, -1, NULL); + but = uiDefButR_prop(block, UI_BTYPE_KEY_EVENT, 0, name, x, y, w, h, ptr, prop, index, 0, 0, -1, -1, NULL); } else if (flag & UI_ITEM_R_FULL_EVENT) { if (RNA_struct_is_a(ptr->type, &RNA_KeyMapItem)) { @@ -1720,6 +1726,10 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN UI_but_func_search_set(but, ui_searchbox_create_generic, rna_search_cb, but, NULL, NULL); } + else if (but->type == UI_BTYPE_SEARCH_MENU) { + /* In case we fail to find proper searchprop, so other code might have already set but->type to search menu... */ + but->type = UI_BTYPE_LABEL; + } } void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon) @@ -2306,6 +2316,10 @@ static void ui_litem_layout_column(uiLayout *litem, bool is_box) if (item->next && (!is_box || item != litem->items.first)) y -= litem->space; + + if (is_box) { + item->flag |= UI_ITEM_BOX_ITEM; + } } litem->h = litem->y - y; @@ -2457,7 +2471,6 @@ static void ui_litem_estimate_box(uiLayout *litem) uiStyle *style = litem->root->style; ui_litem_estimate_column(litem, true); - litem->item.flag &= ~UI_ITEM_MIN; litem->w += 2 * style->boxspace; litem->h += 2 * style->boxspace; } @@ -3129,8 +3142,11 @@ static void ui_item_estimate(uiItem *item) for (subitem = litem->items.first; subitem; subitem = subitem->next) ui_item_estimate(subitem); - if (BLI_listbase_is_empty(&litem->items)) + if (BLI_listbase_is_empty(&litem->items)) { + litem->w = 0; + litem->h = 0; return; + } if (litem->scale[0] != 0.0f || litem->scale[1] != 0.0f) ui_item_scale(litem, litem->scale); @@ -3266,8 +3282,18 @@ static void ui_item_layout(uiItem *item) break; } - for (subitem = litem->items.first; subitem; subitem = subitem->next) + for (subitem = litem->items.first; subitem; subitem = subitem->next) { + if (item->flag & UI_ITEM_BOX_ITEM) { + subitem->flag |= UI_ITEM_BOX_ITEM; + } ui_item_layout(subitem); + } + } + else { + if (item->flag & UI_ITEM_BOX_ITEM) { + uiButtonItem *bitem = (uiButtonItem *)item; + bitem->but->drawflag |= UI_BUT_BOX_ITEM; + } } } @@ -3384,8 +3410,9 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but) ui_item_size((uiItem *)bitem, &w, &h); /* XXX uiBut hasn't scaled yet * we can flag the button as not expandable, depending on its size */ - if (w <= 2 * UI_UNIT_X) + if (w <= 2 * UI_UNIT_X && (!but->str || but->str[0] == '\0')) { bitem->item.flag |= UI_ITEM_MIN; + } BLI_addtail(&layout->items, bitem); diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index fb95cdf389b..d0c110d1db5 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -360,6 +360,9 @@ bool UI_context_copy_to_selected_list( else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) { *r_lb = CTX_data_collection_get(C, "selected_editable_sequences"); } + else if (RNA_struct_is_a(ptr->type, &RNA_FCurve)) { + *r_lb = CTX_data_collection_get(C, "selected_editable_fcurves"); + } else if (RNA_struct_is_a(ptr->type, &RNA_Node) || RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) { @@ -494,51 +497,51 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll) char *path = NULL; bool use_path_from_id; CollectionPointerLink *link; - ListBase lb; - - if (!UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) - return success; + ListBase lb = {NULL}; - for (link = lb.first; link; link = link->next) { - if (link->ptr.data != ptr.data) { - if (use_path_from_id) { - /* Path relative to ID. */ - lprop = NULL; - RNA_id_pointer_create(link->ptr.id.data, &idptr); - RNA_path_resolve_property(&idptr, path, &lptr, &lprop); - } - else if (path) { - /* Path relative to elements from list. */ - lprop = NULL; - RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop); - } - else { - lptr = link->ptr; - lprop = prop; - } + if (UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path) && + !BLI_listbase_is_empty(&lb)) + { + for (link = lb.first; link; link = link->next) { + if (link->ptr.data != ptr.data) { + if (use_path_from_id) { + /* Path relative to ID. */ + lprop = NULL; + RNA_id_pointer_create(link->ptr.id.data, &idptr); + RNA_path_resolve_property(&idptr, path, &lptr, &lprop); + } + else if (path) { + /* Path relative to elements from list. */ + lprop = NULL; + RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop); + } + else { + lptr = link->ptr; + lprop = prop; + } - if (lptr.data == ptr.data) { - /* lptr might not be the same as link->ptr! */ - continue; - } + if (lptr.data == ptr.data) { + /* lptr might not be the same as link->ptr! */ + continue; + } - if (lprop == prop) { - if (RNA_property_editable(&lptr, lprop)) { - if (poll) { - success = true; - break; - } - else { - if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) { - RNA_property_update(C, &lptr, prop); + if (lprop == prop) { + if (RNA_property_editable(&lptr, lprop)) { + if (poll) { success = true; + break; + } + else { + if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) { + RNA_property_update(C, &lptr, prop); + success = true; + } } } } } } } - MEM_SAFE_FREE(path); BLI_freelistN(&lb); } diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index c131bcb8e14..d53cdddb26f 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -496,14 +496,14 @@ static void ui_draw_panel_dragwidget(const rctf *rect) const int col_tint = 84; const int px = (int)U.pixelsize; - const int px_zoom = max_ii(iroundf(BLI_rctf_size_y(rect) / 22.0f), 1); + const int px_zoom = max_ii(round_fl_to_int(BLI_rctf_size_y(rect) / 22.0f), 1); - const int box_margin = max_ii(iroundf((float)(px_zoom * 2.0f)), px); - const int box_size = max_ii(iroundf((BLI_rctf_size_y(rect) / 8.0f) - px), px); + const int box_margin = max_ii(round_fl_to_int((float)(px_zoom * 2.0f)), px); + const int box_size = max_ii(round_fl_to_int((BLI_rctf_size_y(rect) / 8.0f) - px), px); const int x_min = rect->xmin; const int y_min = rect->ymin; - const int y_ofs = max_ii(iroundf(BLI_rctf_size_y(rect) / 3.0f), px); + const int y_ofs = max_ii(round_fl_to_int(BLI_rctf_size_y(rect) / 3.0f), px); const int x_ofs = y_ofs; int i_x, i_y; @@ -877,8 +877,8 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo for (a = 0; a < tot; a++, ps++) { if ((ps->pa->flag & PNL_SELECT) == 0) { if ((ps->orig->ofsx != ps->pa->ofsx) || (ps->orig->ofsy != ps->pa->ofsy)) { - ps->orig->ofsx = iroundf(fac * (float)ps->pa->ofsx + (1.0f - fac) * (float)ps->orig->ofsx); - ps->orig->ofsy = iroundf(fac * (float)ps->pa->ofsy + (1.0f - fac) * (float)ps->orig->ofsy); + ps->orig->ofsx = round_fl_to_int(fac * (float)ps->pa->ofsx + (1.0f - fac) * (float)ps->orig->ofsx); + ps->orig->ofsy = round_fl_to_int(fac * (float)ps->pa->ofsy + (1.0f - fac) * (float)ps->orig->ofsy); done = true; } } @@ -1615,11 +1615,11 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) PanelCategoryDyn *pc_dyn; const float aspect = ((uiBlock *)ar->uiblocks.first)->aspect; const float zoom = 1.0f / aspect; - const int px = max_ii(1, iroundf(U.pixelsize)); - const int category_tabs_width = iroundf(UI_PANEL_CATEGORY_MARGIN_WIDTH * zoom); + const int px = max_ii(1, round_fl_to_int(U.pixelsize)); + const int category_tabs_width = round_fl_to_int(UI_PANEL_CATEGORY_MARGIN_WIDTH * zoom); const float dpi_fac = UI_DPI_FAC; - const int tab_v_pad_text = iroundf((2 + ((px * 3) * dpi_fac)) * zoom); /* pading of tabs around text */ - const int tab_v_pad = iroundf((4 + (2 * px * dpi_fac)) * zoom); /* padding between tabs */ + const int tab_v_pad_text = round_fl_to_int((2 + ((px * 3) * dpi_fac)) * zoom); /* pading of tabs around text */ + const int tab_v_pad = round_fl_to_int((4 + (2 * px * dpi_fac)) * zoom); /* padding between tabs */ const float tab_curve_radius = ((px * 3) * dpi_fac) * zoom; const int roundboxtype = UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT; bool is_alpha; diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 5ed94474726..1dffce43a39 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -342,11 +342,13 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) /* Tip */ if (but_tip.strinfo) { - BLI_strncpy(data->header, but_tip.strinfo, sizeof(data->lines[0])); if (enum_label.strinfo) { BLI_snprintf(data->header, sizeof(data->header), "%s: ", but_tip.strinfo); BLI_strncpy(data->active_info, enum_label.strinfo, sizeof(data->lines[0])); } + else { + BLI_snprintf(data->header, sizeof(data->header), "%s.", but_tip.strinfo); + } data->format[data->totline].style = UI_TIP_STYLE_HEADER; data->totline++; @@ -2440,7 +2442,7 @@ static void ui_block_colorpicker(uiBlock *block, float rgba[4], PointerRNA *ptr, BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, )); yco = -3.0f * UI_UNIT_Y; - bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 7, 0, 0, TIP_("Hex triplet for color (#RRGGBB)")); + bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)")); UI_but_func_set(bt, ui_colorpicker_hex_rna_cb, bt, hexcol); bt->custom_data = cpicker; uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("(Gamma Corrected)"), 0, yco - UI_UNIT_Y, butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); @@ -2952,8 +2954,8 @@ uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, co pie->block_radial->puphash = ui_popup_menu_hash(title); pie->block_radial->flag |= UI_BLOCK_RADIAL; - /* if pie is spawned by a left click, it is always assumed to be click style */ - if (event->type == LEFTMOUSE) { + /* if pie is spawned by a left click, release or click event, it is always assumed to be click style */ + if (event->type == LEFTMOUSE || ELEM(event->val, KM_RELEASE, KM_CLICK)) { pie->block_radial->pie_data.flags |= UI_PIE_CLICK_STYLE; pie->block_radial->pie_data.event = EVENT_NONE; win->lock_pie_event = EVENT_NONE; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 131584dd405..3cc16f37736 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2841,7 +2841,7 @@ static void uilist_resize_update_cb(bContext *C, void *arg1, void *UNUSED(arg2)) uiListDyn *dyn_data = ui_list->dyn_data; /* This way we get diff in number of additional items to show (positive) or hide (negative). */ - const int diff = iroundf((float)(dyn_data->resize - dyn_data->resize_prev) / (float)UI_UNIT_Y); + const int diff = round_fl_to_int((float)(dyn_data->resize - dyn_data->resize_prev) / (float)UI_UNIT_Y); if (diff != 0) { ui_list->list_grip += diff; diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index cf16cc9f50d..1927d7280f3 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -265,7 +265,7 @@ int UI_icon_from_report_type(int type) */ int UI_calc_float_precision(int prec, double value) { - static const double pow10_neg[UI_PRECISION_FLOAT_MAX + 1] = {1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7}; + static const double pow10_neg[UI_PRECISION_FLOAT_MAX + 1] = {1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6}; static const double max_pow = 10000000.0; /* pow(10, UI_PRECISION_FLOAT_MAX) */ BLI_assert(prec <= UI_PRECISION_FLOAT_MAX); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index f7f2b422724..51bf09125ba 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -3655,11 +3655,15 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct switch (but->type) { case UI_BTYPE_LABEL: - if (but->block->flag & UI_BLOCK_LOOP) - widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect); - else { - wt = widget_type(UI_WTYPE_LABEL); - fstyle = &style->widgetlabel; + wt = widget_type(UI_WTYPE_LABEL); + fstyle = &style->widgetlabel; + if (but->drawflag & UI_BUT_BOX_ITEM) { + wt->wcol_theme = &tui->wcol_box; + wt->state = widget_state; + } + else if (but->block->flag & UI_BLOCK_LOOP) { + wt->wcol_theme = &tui->wcol_menu_back; + wt->state = widget_state; } break; diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 539284030c2..4b47d0da13e 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -2758,6 +2758,24 @@ void init_userdef_do_versions(void) } } + if (!USER_VERSION_ATLEAST(278, 6)) { + /* Clear preference flags for re-use. */ + U.flag &= ~( + USER_FLAG_DEPRECATED_1 | USER_FLAG_DEPRECATED_2 | USER_FLAG_DEPRECATED_3 | + USER_FLAG_DEPRECATED_6 | USER_FLAG_DEPRECATED_7 | + USER_FLAG_DEPRECATED_9 | USER_FLAG_DEPRECATED_10); + U.uiflag &= ~( + USER_UIFLAG_DEPRECATED_7); + U.transopts &= ~( + USER_TR_DEPRECATED_2 | USER_TR_DEPRECATED_3 | USER_TR_DEPRECATED_4 | + USER_TR_DEPRECATED_6 | USER_TR_DEPRECATED_7); + U.gameflags &= ~( + USER_GL_RENDER_DEPRECATED_0 | USER_GL_RENDER_DEPRECATED_1 | + USER_GL_RENDER_DEPRECATED_3 | USER_GL_RENDER_DEPRECATED_4); + + U.uiflag |= USER_LOCK_CURSOR_ADJUST; + } + /** * Include next version bump. * diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index c78d97ef86f..c704c4ae126 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -2138,6 +2138,14 @@ void UI_view2d_view_to_region_rcti(View2D *v2d, const rctf *rect_src, rcti *rect clamp_rctf_to_rcti(rect_dst, &rect_tmp); } +void UI_view2d_view_to_region_m4(View2D *v2d, float matrix[4][4]) +{ + rctf mask; + unit_m4(matrix); + BLI_rctf_rcti_copy(&mask, &v2d->mask); + BLI_rctf_transform_calc_m4_pivot_min(&v2d->cur, &mask, matrix); +} + bool UI_view2d_view_to_region_rcti_clip(View2D *v2d, const rctf *rect_src, rcti *rect_dst) { const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)}; diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index a5e90ebbe7a..975bbddd893 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -93,7 +93,7 @@ static int cachefile_open_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); - CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filename)); + CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filename), 0); BLI_strncpy(cache_file->filepath, filename, FILE_MAX); BKE_cachefile_reload(bmain, cache_file); diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index 35de390274c..196285cf02a 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -999,7 +999,7 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event) if (weight) { sub_v2_v2v2(c, offco, p); - project_v2_v2v2(vec, c, no); + project_v2_v2v2_normalized(vec, c, no); w = len_v2(vec); diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index a478526dee0..6c6c106b19a 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -797,25 +797,47 @@ void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTop qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort); - /* Since the loop starts at 2, we must define the last index where the hash's differ */ - last = ((totvert >= 2) && (topo_pairs[0].hash == topo_pairs[1].hash)) ? 0 : 1; + last = 0; /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2, * but you cant ever access the last 'a' index of MirrTopoPairs */ - for (a = 2; a <= totvert; a++) { - /* printf("I %d %ld %d\n", (a-last), MirrTopoPairs[a ].hash, MirrTopoPairs[a ].v_index ); */ - if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { - if (a - last == 2) { - if (em) { - index_lookup[topo_pairs[a - 1].v_index] = (intptr_t)BM_vert_at_index(em->bm, topo_pairs[a - 2].v_index); - index_lookup[topo_pairs[a - 2].v_index] = (intptr_t)BM_vert_at_index(em->bm, topo_pairs[a - 1].v_index); + if (em) { + BMVert **vtable = em->bm->vtable; + for (a = 1; a <= totvert; a++) { + /* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */ + if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { + const int match_count = a - last; + if (match_count == 2) { + const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; + index_lookup[j] = (intptr_t)vtable[k]; + index_lookup[k] = (intptr_t)vtable[j]; + } + else if (match_count == 1) { + /* Center vertex. */ + const int j = topo_pairs[a - 1].v_index; + index_lookup[j] = (intptr_t)vtable[j]; + } + last = a; + } + } + } + else { + /* same as above, for mesh */ + for (a = 1; a <= totvert; a++) { + if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { + const int match_count = a - last; + if (match_count == 2) { + const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; + index_lookup[j] = k; + index_lookup[k] = j; } - else { - index_lookup[topo_pairs[a - 1].v_index] = topo_pairs[a - 2].v_index; - index_lookup[topo_pairs[a - 2].v_index] = topo_pairs[a - 1].v_index; + else if (match_count == 1) { + /* Center vertex. */ + const int j = topo_pairs[a - 1].v_index; + index_lookup[j] = j; } + last = a; } - last = a; } } diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index a81add7a86e..6b4f3516338 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -150,6 +150,7 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) for (i = 0; i < NUM_VALUE_KINDS; i++) { opdata->shift_value[i] = -1.0f; + opdata->initial_length[i] = -1.0f; /* note: scale for OFFSET_VALUE will get overwritten in edbm_bevel_invoke */ opdata->scale[i] = value_scale_per_inch[i] / pixels_per_inch; @@ -300,7 +301,7 @@ static void edbm_bevel_calc_initial_length(wmOperator *op, const wmEvent *event, mlen[1] = opdata->mcenter[1] - event->mval[1]; len = len_v2(mlen); vmode = opdata->value_mode; - if (mode_changed) { + if (mode_changed || opdata->initial_length[vmode] == -1.0f) { /* If current value is not default start value, adjust len so that * the scaling and offset in edbm_bevel_mouse_set_value will * start at current value */ @@ -506,6 +507,8 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) else if (opdata->value_mode == OFFSET_VALUE_PERCENT && type != BEVEL_AMT_PERCENT) opdata->value_mode = OFFSET_VALUE; RNA_property_enum_set(op->ptr, prop, type); + if (opdata->initial_length[opdata->value_mode] == -1.0f) + edbm_bevel_calc_initial_length(op, event, true); } /* Update offset accordingly to new offset_type. */ if (!has_numinput && diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 5e44509e10a..69e8fa03d72 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1206,6 +1206,7 @@ static bool knife_ray_intersect_face( for (; tri_i < tottri; tri_i++) { const float *lv1, *lv2, *lv3; + float ray_tri_uv[2]; tri = kcd->em->looptris[tri_i]; if (tri[0]->f != f) @@ -1217,7 +1218,7 @@ static bool knife_ray_intersect_face( * tesselation edge and might not hit either tesselation tri with * an exact test; * we will exclude hits near real edges by a later test */ - if (isect_ray_tri_epsilon_v3(v1, raydir, lv1, lv2, lv3, &lambda, NULL, KNIFE_FLT_EPS)) { + if (isect_ray_tri_epsilon_v3(v1, raydir, lv1, lv2, lv3, &lambda, ray_tri_uv, KNIFE_FLT_EPS)) { /* check if line coplanar with tri */ normal_tri_v3(tri_norm, lv1, lv2, lv3); plane_from_point_normal_v3(tri_plane, lv1, tri_norm); @@ -1226,8 +1227,7 @@ static bool knife_ray_intersect_face( { return false; } - copy_v3_v3(hit_cageco, v1); - madd_v3_v3fl(hit_cageco, raydir, lambda); + interp_v3_v3v3v3_uv(hit_cageco, lv1, lv2, lv3, ray_tri_uv); /* Now check that far enough away from verts and edges */ lst = knife_get_face_kedges(kcd, f); for (ref = lst->first; ref; ref = ref->next) { @@ -1239,11 +1239,7 @@ static bool knife_ray_intersect_face( return false; } } - - transform_point_by_tri_v3( - hit_co, hit_cageco, - tri[0]->v->co, tri[1]->v->co, tri[2]->v->co, - lv1, lv2, lv3); + interp_v3_v3v3v3_uv(hit_co, tri[0]->v->co, tri[1]->v->co, tri[2]->v->co, ray_tri_uv); return true; } } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 1f90b60a1f5..c513c49aa8e 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -169,7 +169,7 @@ struct EdgeRingOpSubdProps { }; -static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_default) +static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_min, const int cuts_default) { /* Note, these values must match delete_mesh() event values */ static EnumPropertyItem prop_subd_edgering_types[] = { @@ -181,7 +181,7 @@ static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_defa PropertyRNA *prop; - prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, 1000, "Number of Cuts", "", 0, 64); + prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, 1000, "Number of Cuts", "", cuts_min, 64); RNA_def_property_flag(prop, PROP_SKIP_SAVE); RNA_def_enum(ot->srna, "interpolation", prop_subd_edgering_types, SUBD_RING_INTERP_PATH, @@ -248,7 +248,7 @@ void MESH_OT_subdivide_edgering(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - mesh_operator_edgering_props(ot, 10); + mesh_operator_edgering_props(ot, 1, 10); } @@ -5447,7 +5447,7 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot) RNA_def_float(ot->srna, "merge_factor", 0.5f, 0.0f, 1.0f, "Merge Factor", "", 0.0f, 1.0f); RNA_def_int(ot->srna, "twist_offset", 0, -1000, 1000, "Twist", "Twist offset for closed loops", -1000, 1000); - mesh_operator_edgering_props(ot, 0); + mesh_operator_edgering_props(ot, 0, 0); } static int edbm_wireframe_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 772bb1bd308..737c8ac665d 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -252,7 +252,7 @@ void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me) { /* could be ldata or pdata */ CustomData *pdata = GET_CD_DATA(me, pdata); - const int layernum = CustomData_get_active_layer_index(pdata, CD_MTEXPOLY); + const int layernum = CustomData_get_active_layer(pdata, CD_MTEXPOLY); ED_mesh_uv_loop_reset_ex(me, layernum); WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); @@ -464,6 +464,20 @@ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set) return layernum; } +bool ED_mesh_color_ensure(struct Mesh *me, const char *name) +{ + BLI_assert(me->edit_btmesh == NULL); + + if (!me->mloopcol && me->totloop) { + CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop, name); + BKE_mesh_update_customdata_pointers(me, true); + } + + DAG_id_tag_update(&me->id, 0); + + return (me->mloopcol != NULL); +} + bool ED_mesh_color_remove_index(Mesh *me, const int n) { CustomData *ldata = GET_CD_DATA(me, ldata); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index b5a9c4e9e5b..74da6817185 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1344,89 +1344,87 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, const bool use_hierarchy) { Main *bmain = CTX_data_main(C); - ListBase *lb; + ListBase *lb_duplis; DupliObject *dob; - GHash *dupli_gh = NULL, *parent_gh = NULL; - Object *object; + GHash *dupli_gh, *parent_gh = NULL; - if (!(base->object->transflag & OB_DUPLI)) + if (!(base->object->transflag & OB_DUPLI)) { return; + } - lb = object_duplilist(bmain->eval_ctx, scene, base->object); + lb_duplis = object_duplilist(bmain->eval_ctx, scene, base->object); - if (use_hierarchy || use_base_parent) { - dupli_gh = BLI_ghash_ptr_new(__func__); - if (use_hierarchy) { - if (base->object->transflag & OB_DUPLIGROUP) { - parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__); - } - else { - parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); - } + dupli_gh = BLI_ghash_ptr_new(__func__); + if (use_hierarchy) { + if (base->object->transflag & OB_DUPLIGROUP) { + parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__); + } + else { + parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); } } - for (dob = lb->first; dob; dob = dob->next) { - Base *basen; - Object *ob = ID_NEW_SET(dob->ob, BKE_object_copy(bmain, dob->ob)); + for (dob = lb_duplis->first; dob; dob = dob->next) { + Object *ob_src = dob->ob; + Object *ob_dst = ID_NEW_SET(dob->ob, BKE_object_copy(bmain, ob_src)); + Base *base_dst; /* font duplis can have a totcol without material, we get them from parent * should be implemented better... */ - if (ob->mat == NULL) ob->totcol = 0; + if (ob_dst->mat == NULL) { + ob_dst->totcol = 0; + } - basen = MEM_dupallocN(base); - basen->flag &= ~(OB_FROMDUPLI | OB_FROMGROUP); - ob->flag = basen->flag; - basen->lay = base->lay; - BLI_addhead(&scene->base, basen); /* addhead: othwise eternal loop */ - basen->object = ob; + base_dst = MEM_dupallocN(base); + base_dst->flag &= ~(OB_FROMDUPLI | OB_FROMGROUP); + ob_dst->flag = base_dst->flag; + base_dst->lay = base->lay; + BLI_addhead(&scene->base, base_dst); /* addhead: othwise eternal loop */ + base_dst->object = ob_dst; /* make sure apply works */ - BKE_animdata_free(&ob->id, true); - ob->adt = NULL; + BKE_animdata_free(&ob_dst->id, true); + ob_dst->adt = NULL; /* Proxies are not to be copied. */ - ob->proxy_from = NULL; - ob->proxy_group = NULL; - ob->proxy = NULL; + ob_dst->proxy_from = NULL; + ob_dst->proxy_group = NULL; + ob_dst->proxy = NULL; - ob->parent = NULL; - BKE_constraints_free(&ob->constraints); - ob->curve_cache = NULL; - ob->transflag &= ~OB_DUPLI; - ob->lay = base->lay; + ob_dst->parent = NULL; + BKE_constraints_free(&ob_dst->constraints); + ob_dst->curve_cache = NULL; + ob_dst->transflag &= ~OB_DUPLI; + ob_dst->lay = base->lay; - copy_m4_m4(ob->obmat, dob->mat); - BKE_object_apply_mat4(ob, ob->obmat, false, false); + copy_m4_m4(ob_dst->obmat, dob->mat); + BKE_object_apply_mat4(ob_dst, ob_dst->obmat, false, false); - if (dupli_gh) { - BLI_ghash_insert(dupli_gh, dob, ob); - } + BLI_ghash_insert(dupli_gh, dob, ob_dst); if (parent_gh) { void **val; /* Due to nature of hash/comparison of this ghash, a lot of duplis may be considered as 'the same', * this avoids trying to insert same key several time and raise asserts in debug builds... */ if (!BLI_ghash_ensure_p(parent_gh, dob, &val)) { - *val = ob; + *val = ob_dst; } } + } + + for (dob = lb_duplis->first; dob; dob = dob->next) { + Object *ob_src = dob->ob; + Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob); /* Remap new object to itself, and clear again newid pointer of orig object. */ - BKE_libblock_relink_to_newid(&ob->id); - set_sca_new_poins_ob(ob); - BKE_id_clear_newpoin(&dob->ob->id); + BKE_libblock_relink_to_newid(&ob_dst->id); + set_sca_new_poins_ob(ob_dst); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - } + DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); - if (use_hierarchy) { - for (dob = lb->first; dob; dob = dob->next) { + if (use_hierarchy) { /* original parents */ - Object *ob_src = dob->ob; Object *ob_src_par = ob_src->parent; - - Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob); Object *ob_dst_par = NULL; /* find parent that was also made real */ @@ -1437,8 +1435,8 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, dob_key.ob = ob_src_par; if (base->object->transflag & OB_DUPLIGROUP) { memcpy(&dob_key.persistent_id[1], - &dob->persistent_id[1], - sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); + &dob->persistent_id[1], + sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); } else { dob_key.persistent_id[0] = dob->persistent_id[0]; @@ -1462,49 +1460,42 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, ob_dst->parent = base->object; ob_dst->partype = PAROBJECT; } - - if (ob_dst->parent) { - /* note, this may be the parent of other objects, but it should - * still work out ok */ - BKE_object_apply_mat4(ob_dst, dob->mat, false, true); - - /* to set ob_dst->orig and in case theres any other discrepicies */ - DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB); - } } - } - else if (use_base_parent) { - /* since we are ignoring the internal hierarchy - parent all to the - * base object */ - for (dob = lb->first; dob; dob = dob->next) { - /* original parents */ - Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob); - + else if (use_base_parent) { + /* since we are ignoring the internal hierarchy - parent all to the + * base object */ ob_dst->parent = base->object; ob_dst->partype = PAROBJECT; + } - /* similer to the code above, see comments */ + if (ob_dst->parent) { + /* note, this may be the parent of other objects, but it should + * still work out ok */ BKE_object_apply_mat4(ob_dst, dob->mat, false, true); + + /* to set ob_dst->orig and in case theres any other discrepicies */ DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB); } } if (base->object->transflag & OB_DUPLIGROUP && base->object->dup_group) { - for (object = bmain->object.first; object; object = object->id.next) { - if (object->proxy_group == base->object) { - object->proxy = NULL; - object->proxy_from = NULL; - DAG_id_tag_update(&object->id, OB_RECALC_OB); + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + if (ob->proxy_group == base->object) { + ob->proxy = NULL; + ob->proxy_from = NULL; + DAG_id_tag_update(&ob->id, OB_RECALC_OB); } } } - if (dupli_gh) - BLI_ghash_free(dupli_gh, NULL, NULL); - if (parent_gh) + BLI_ghash_free(dupli_gh, NULL, NULL); + if (parent_gh) { BLI_ghash_free(parent_gh, NULL, NULL); + } - free_object_duplilist(lb); + free_object_duplilist(lb_duplis); + + BKE_main_id_clear_newpoins(bmain); base->object->transflag &= ~OB_DUPLI; } @@ -1682,7 +1673,7 @@ static int convert_exec(bContext *C, wmOperator *op) * However, changing this is more design than bugfix, not to mention convoluted code below, * so that will be for later. * But at the very least, do not do that with linked IDs! */ - if ((ID_IS_LINKED_DATABLOCK(ob) || ID_IS_LINKED_DATABLOCK(ob->data)) && !keep_original) { + if ((ID_IS_LINKED_DATABLOCK(ob) || (ob->data && ID_IS_LINKED_DATABLOCK(ob->data))) && !keep_original) { keep_original = true; BKE_reportf(op->reports, RPT_INFO, "Converting some linked object/object data, enforcing 'Keep Original' option to True"); @@ -2198,6 +2189,11 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (didit) { Key *key = BKE_key_from_object(obn); + Key *oldkey = BKE_key_from_object(ob); + if (oldkey != NULL) { + ID_NEW_SET(oldkey, key); + } + if (dupflag & USER_DUP_ACT) { bActuator *act; diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index ad43c48f0b9..122330f7ede 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -625,7 +625,9 @@ static Mesh *bake_mesh_new_from_object(Main *bmain, Scene *scene, Object *ob) ED_object_editmode_load(ob); Mesh *me = BKE_mesh_new_from_object(bmain, scene, ob, 1, 2, 0, 0); - BKE_mesh_split_faces(me, true); + if (me->flag & ME_AUTOSMOOTH) { + BKE_mesh_split_faces(me, true); + } return me; } @@ -1029,7 +1031,7 @@ cage_cleanup: } else { /* if everything else fails, use the material index */ - char tmp[4]; + char tmp[5]; sprintf(tmp, "%d", i % 1000); BLI_path_suffix(name, FILE_MAX, tmp, "_"); } @@ -1159,7 +1161,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr) bkr->result = OPERATOR_CANCELLED; - bkr->render = RE_NewRender(bkr->scene->id.name); + bkr->render = RE_NewSceneRender(bkr->scene); /* XXX hack to force saving to always be internal. Whether (and how) to support * external saving will be addressed later */ diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index edd7b5dd1be..4a96a2e2200 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -773,9 +773,9 @@ static void copymenu_logicbricks(Scene *scene, View3D *v3d, Object *ob) /* now copy it, this also works without logicbricks! */ clear_sca_new_poins_ob(ob); - copy_sensors(&base->object->sensors, &ob->sensors); - copy_controllers(&base->object->controllers, &ob->controllers); - copy_actuators(&base->object->actuators, &ob->actuators); + copy_sensors(&base->object->sensors, &ob->sensors, 0); + copy_controllers(&base->object->controllers, &ob->controllers, 0); + copy_actuators(&base->object->actuators, &ob->actuators, 0); set_sca_new_poins_ob(base->object); /* some menu settings */ @@ -934,7 +934,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) base->object->collision_boundtype = ob->collision_boundtype; } base->object->margin = ob->margin; - base->object->bsoft = copy_bulletsoftbody(ob->bsoft); + base->object->bsoft = copy_bulletsoftbody(ob->bsoft, 0); } else if (event == 17) { /* tex space */ @@ -1042,7 +1042,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) base->object->softflag = ob->softflag; if (base->object->soft) sbFree(base->object->soft); - base->object->soft = copy_softbody(ob->soft, false); + base->object->soft = copy_softbody(ob->soft, 0); if (!modifiers_findByType(base->object, eModifierType_Softbody)) { BLI_addhead(&base->object->modifiers, modifier_new(eModifierType_Softbody)); @@ -1158,13 +1158,16 @@ void ED_object_check_force_modifiers(Main *bmain, Scene *scene, Object *object) /* add/remove modifier as needed */ if (!md) { - if (pd && (pd->shape == PFIELD_SHAPE_SURFACE) && ELEM(pd->forcefield, PFIELD_GUIDE, PFIELD_TEXTURE) == 0) - if (ELEM(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE)) + if (pd && (pd->shape == PFIELD_SHAPE_SURFACE) && !ELEM(pd->forcefield, 0, PFIELD_GUIDE, PFIELD_TEXTURE)) { + if (ELEM(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE)) { ED_object_modifier_add(NULL, bmain, scene, object, NULL, eModifierType_Surface); + } + } } else { - if (!pd || pd->shape != PFIELD_SHAPE_SURFACE || pd->forcefield != PFIELD_FORCE) + if (!pd || (pd->shape != PFIELD_SHAPE_SURFACE) || ELEM(pd->forcefield, 0, PFIELD_GUIDE, PFIELD_TEXTURE)) { ED_object_modifier_remove(NULL, bmain, object, md); + } } } @@ -2106,9 +2109,9 @@ static int logicbricks_copy_exec(bContext *C, wmOperator *UNUSED(op)) /* now copy it, this also works without logicbricks! */ clear_sca_new_poins_ob(ob); - copy_sensors(&ob_iter->sensors, &ob->sensors); - copy_controllers(&ob_iter->controllers, &ob->controllers); - copy_actuators(&ob_iter->actuators, &ob->actuators); + copy_sensors(&ob_iter->sensors, &ob->sensors, 0); + copy_controllers(&ob_iter->controllers, &ob->controllers, 0); + copy_actuators(&ob_iter->actuators, &ob->actuators, 0); set_sca_new_poins_ob(ob_iter); /* some menu settings */ @@ -2169,7 +2172,7 @@ static int game_physics_copy_exec(bContext *C, wmOperator *UNUSED(op)) copy_v3_v3(ob_iter->anisotropicFriction, ob->anisotropicFriction); ob_iter->collision_boundtype = ob->collision_boundtype; ob_iter->margin = ob->margin; - ob_iter->bsoft = copy_bulletsoftbody(ob->bsoft); + ob_iter->bsoft = copy_bulletsoftbody(ob->bsoft, 0); if (ob->restrictflag & OB_RESTRICT_RENDER) ob_iter->restrictflag |= OB_RESTRICT_RENDER; else diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 3284af2df69..d5b516257a1 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1581,13 +1581,13 @@ static int make_links_data_exec(bContext *C, wmOperator *op) DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); break; case MAKE_LINKS_ANIMDATA: - BKE_animdata_copy_id((ID *)ob_dst, (ID *)ob_src, false); + BKE_animdata_copy_id(bmain, (ID *)ob_dst, (ID *)ob_src, false); if (ob_dst->data && ob_src->data) { if (ID_IS_LINKED_DATABLOCK(obdata_id)) { is_lib = true; break; } - BKE_animdata_copy_id((ID *)ob_dst->data, (ID *)ob_src->data, false); + BKE_animdata_copy_id(bmain, (ID *)ob_dst->data, (ID *)ob_src->data, false); } DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); break; @@ -2137,7 +2137,9 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo IDP_RelinkProperty(scene->gpd->id.properties); } - IDP_RelinkProperty(scene->world->id.properties); + if (scene->world) { + IDP_RelinkProperty(scene->world->id.properties); + } if (scene->clip) { IDP_RelinkProperty(scene->clip->id.properties); diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 4d7d7df0d2f..6491da4c23c 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -414,7 +414,10 @@ static void ignore_parent_tx(Main *bmain, Scene *scene, Object *ob) } } -static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_loc, bool apply_rot, bool apply_scale) +static int apply_objects_internal( + bContext *C, ReportList *reports, + bool apply_loc, bool apply_rot, bool apply_scale, + bool do_props) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -531,7 +534,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l BKE_mesh_calc_normals(me); } else if (ob->type == OB_ARMATURE) { - ED_armature_apply_transform(ob, mat); + ED_armature_apply_transform(ob, mat, do_props); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; @@ -540,12 +543,12 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l } else if (ob->type == OB_MBALL) { MetaBall *mb = ob->data; - BKE_mball_transform(mb, mat); + BKE_mball_transform(mb, mat, do_props); } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; scale = mat3_to_scale(rsmat); - BKE_curve_transform_ex(cu, mat, true, scale); + BKE_curve_transform_ex(cu, mat, true, do_props, scale); } else if (ob->type == OB_FONT) { Curve *cu = ob->data; @@ -561,7 +564,9 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l tb->h *= scale; } - cu->fsize *= scale; + if (do_props) { + cu->fsize *= scale; + } } else if (ob->type == OB_CAMERA) { MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); @@ -677,9 +682,10 @@ static int object_transform_apply_exec(bContext *C, wmOperator *op) const bool loc = RNA_boolean_get(op->ptr, "location"); const bool rot = RNA_boolean_get(op->ptr, "rotation"); const bool sca = RNA_boolean_get(op->ptr, "scale"); + const bool do_props = RNA_boolean_get(op->ptr, "properties"); if (loc || rot || sca) { - return apply_objects_internal(C, op->reports, loc, rot, sca); + return apply_objects_internal(C, op->reports, loc, rot, sca, do_props); } else { /* allow for redo */ @@ -704,6 +710,8 @@ void OBJECT_OT_transform_apply(wmOperatorType *ot) RNA_def_boolean(ot->srna, "location", 0, "Location", ""); RNA_def_boolean(ot->srna, "rotation", 0, "Rotation", ""); RNA_def_boolean(ot->srna, "scale", 0, "Scale", ""); + RNA_def_boolean(ot->srna, "properties", true, "Apply Properties", + "Modify properties such as curve vertex radius, font size and bone envelope"); } /********************* Set Object Center ************************/ @@ -712,7 +720,8 @@ enum { GEOMETRY_TO_ORIGIN = 0, ORIGIN_TO_GEOMETRY, ORIGIN_TO_CURSOR, - ORIGIN_TO_CENTER_OF_MASS + ORIGIN_TO_CENTER_OF_MASS_SURFACE, + ORIGIN_TO_CENTER_OF_MASS_VOLUME, }; static int object_origin_set_exec(bContext *C, wmOperator *op) @@ -866,10 +875,21 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (obedit == NULL && ob->type == OB_MESH) { Mesh *me = ob->data; - if (centermode == ORIGIN_TO_CURSOR) { /* done */ } - else if (centermode == ORIGIN_TO_CENTER_OF_MASS) { BKE_mesh_center_centroid(me, cent); } - else if (around == V3D_AROUND_CENTER_MEAN) { BKE_mesh_center_median(me, cent); } - else { BKE_mesh_center_bounds(me, cent); } + if (centermode == ORIGIN_TO_CURSOR) { + /* done */ + } + else if (centermode == ORIGIN_TO_CENTER_OF_MASS_SURFACE) { + BKE_mesh_center_of_surface(me, cent); + } + else if (centermode == ORIGIN_TO_CENTER_OF_MASS_VOLUME) { + BKE_mesh_center_of_volume(me, cent); + } + else if (around == V3D_AROUND_CENTER_MEAN) { + BKE_mesh_center_median(me, cent); + } + else { + BKE_mesh_center_bounds(me, cent); + } negate_v3_v3(cent_neg, cent); BKE_mesh_translate(me, cent_neg, 1); @@ -923,8 +943,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) cent[2] = 0.0f; - cu->xof = cu->xof - (cent[0] / cu->fsize); - cu->yof = cu->yof - (cent[1] / cu->fsize); + cu->xof = cu->xof - cent[0]; + cu->yof = cu->yof - cent[1]; tot_change++; cu->id.tag |= LIB_TAG_DOIT; @@ -1077,11 +1097,14 @@ void OBJECT_OT_origin_set(wmOperatorType *ot) static EnumPropertyItem prop_set_center_types[] = { {GEOMETRY_TO_ORIGIN, "GEOMETRY_ORIGIN", 0, "Geometry to Origin", "Move object geometry to object origin"}, {ORIGIN_TO_GEOMETRY, "ORIGIN_GEOMETRY", 0, "Origin to Geometry", - "Move object origin to center of object geometry"}, + "Calculate the center of geometry based on the current pivot point (median, otherwise bounding-box)"}, {ORIGIN_TO_CURSOR, "ORIGIN_CURSOR", 0, "Origin to 3D Cursor", - "Move object origin to position of the 3D cursor"}, - {ORIGIN_TO_CENTER_OF_MASS, "ORIGIN_CENTER_OF_MASS", 0, "Origin to Center of Mass", - "Move object origin to the object center of mass (assuming uniform density)"}, + "Move object origin to position of the 3D cursor"}, + /* Intentional naming mismatch since some scripts refer to this. */ + {ORIGIN_TO_CENTER_OF_MASS_SURFACE, "ORIGIN_CENTER_OF_MASS", 0, "Origin to Center of Mass (Surface)", + "Calculate the center of mass from the surface area"}, + {ORIGIN_TO_CENTER_OF_MASS_VOLUME, "ORIGIN_CENTER_OF_VOLUME", 0, "Origin to Center of Mass (Volume)", + "Calculate the center of mass from the volume (must be manifold geometry with consistent normals)"}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 3c406764157..584176e4b5d 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -50,7 +50,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_linklist_stack.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BKE_context.h" @@ -238,6 +238,9 @@ bool ED_vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, co } return false; } + + default: + break; } } @@ -1712,17 +1715,11 @@ static void vgroup_invert_subset(Object *ob, } } -enum { - WEIGHT_SMOOTH_ALL = -1, - WEIGHT_SMOOTH_DESELECT = false, - WEIGHT_SMOOTH_SELECT = true, -}; - static void vgroup_smooth_subset( Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int subset_count, const float fac, const int repeat, - const float fac_expand, const int source) + const float fac_expand) { const float ifac = 1.0f - fac; MDeformVert **dvert_array = NULL; @@ -1730,6 +1727,8 @@ static void vgroup_smooth_subset( int *vgroup_subset_map = BLI_array_alloca(vgroup_subset_map, subset_count); float *vgroup_subset_weights = BLI_array_alloca(vgroup_subset_weights, subset_count); const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : false; + const bool use_select = vertex_group_use_vert_sel(ob); + const bool use_hide = use_select; const int expand_sign = signum_i(fac_expand); const float expand = fabsf(fac_expand); @@ -1773,19 +1772,26 @@ static void vgroup_smooth_subset( verts_used = MEM_mallocN(sizeof(*verts_used) * dvert_tot, __func__); STACK_INIT(verts_used, dvert_tot); +#define IS_BM_VERT_READ(v) \ + (use_hide ? (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == 0) : true) +#define IS_BM_VERT_WRITE(v) \ + (use_select ? (BM_elem_flag_test(v, BM_ELEM_SELECT) != 0) : true) + +#define IS_ME_VERT_READ(v) \ + (use_hide ? (((v)->flag & ME_HIDE) == 0) : true) +#define IS_ME_VERT_WRITE(v) \ + (use_select ? (((v)->flag & SELECT) != 0) : true) /* initialize used verts */ if (bm) { for (int i = 0; i < dvert_tot; i++) { BMVert *v = BM_vert_at_index(bm, i); - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + if (IS_BM_VERT_WRITE(v)) { BMIter eiter; BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { BMVert *v_other = BM_edge_other_vert(e, v); - if ((source == WEIGHT_SMOOTH_ALL) || - (source == (BM_elem_flag_test(v_other, BM_ELEM_SELECT) != 0))) - { + if (IS_BM_VERT_READ(v_other)) { STACK_PUSH(verts_used, i); break; } @@ -1795,13 +1801,12 @@ static void vgroup_smooth_subset( } else { for (int i = 0; i < dvert_tot; i++) { - MVert *v = &me->mvert[i]; - if (v->flag & SELECT) { + const MVert *v = &me->mvert[i]; + if (IS_ME_VERT_WRITE(v)) { for (int j = 0; j < emap[i].count; j++) { - MVert *v_other = &me->mvert[emap[i].indices[j]]; - if ((source == WEIGHT_SMOOTH_ALL) || - (source == ((v_other->flag & SELECT) != 0))) - { + const MEdge *e = &me->medge[emap[i].indices[j]]; + const MVert *v_other = &me->mvert[(e->v1 == i) ? e->v2 : e->v1]; + if (IS_ME_VERT_READ(v_other)) { STACK_PUSH(verts_used, i); break; } @@ -1854,13 +1859,11 @@ static void vgroup_smooth_subset( BMEdge *e; /* checked already */ - BLI_assert(BM_elem_flag_test(v, BM_ELEM_SELECT)); + BLI_assert(IS_BM_VERT_WRITE(v)); BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { BMVert *v_other = BM_edge_other_vert(e, v); - if ((source == WEIGHT_SMOOTH_ALL) || - (source == (BM_elem_flag_test(v_other, BM_ELEM_SELECT) != 0))) - { + if (IS_BM_VERT_READ(v_other)) { const int i_other = BM_elem_index_get(v_other); WEIGHT_ACCUMULATE; @@ -1871,16 +1874,14 @@ static void vgroup_smooth_subset( int j; /* checked already */ - BLI_assert(me->mvert[i].flag & SELECT); + BLI_assert(IS_ME_VERT_WRITE(&me->mvert[i])); for (j = 0; j < emap[i].count; j++) { MEdge *e = &me->medge[emap[i].indices[j]]; const int i_other = (e->v1 == i ? e->v2 : e->v1); MVert *v_other = &me->mvert[i_other]; - if ((source == WEIGHT_SMOOTH_ALL) || - (source == ((v_other->flag & SELECT) != 0))) - { + if (IS_ME_VERT_READ(v_other)) { WEIGHT_ACCUMULATE; } } @@ -1904,6 +1905,11 @@ static void vgroup_smooth_subset( ED_vgroup_parray_from_weight_array(dvert_array, dvert_tot, weight_accum_prev, def_nr, true); } +#undef IS_BM_VERT_READ +#undef IS_BM_VERT_WRITE +#undef IS_ME_VERT_READ +#undef IS_ME_VERT_WRITE + MEM_freeN(weight_accum_curr); MEM_freeN(weight_accum_prev); MEM_freeN(verts_used); @@ -2497,7 +2503,7 @@ static int UNUSED_FUNCTION(vertex_group_poll_edit) (bContext *C) } /* editmode _or_ weight paint vertex sel */ -static int vertex_group_vert_select_poll_ex(bContext *C, const short ob_type_flag) +static int vertex_group_vert_poll_ex(bContext *C, const bool needs_select, const short ob_type_flag) { Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; @@ -2513,12 +2519,17 @@ static int vertex_group_vert_select_poll_ex(bContext *C, const short ob_type_fla return true; } else if (ob->mode & OB_MODE_WEIGHT_PAINT) { - if (BKE_object_is_in_wpaint_select_vert(ob)) { - return true; + if (needs_select) { + if (BKE_object_is_in_wpaint_select_vert(ob)) { + return true; + } + else { + CTX_wm_operator_poll_msg_set(C, "Vertex select needs to be enabled in weight paint mode"); + return false; + } } else { - CTX_wm_operator_poll_msg_set(C, "Vertex select needs to be enabled in weight paint mode"); - return false; + return true; } } else { @@ -2526,15 +2537,31 @@ static int vertex_group_vert_select_poll_ex(bContext *C, const short ob_type_fla } } +#if 0 +static int vertex_group_vert_poll(bContext *C) +{ + return vertex_group_vert_poll_ex(C, false, 0); +} +#endif + + +static int vertex_group_mesh_vert_poll(bContext *C) +{ + return vertex_group_vert_poll_ex(C, false, (1 << OB_MESH)); +} + static int vertex_group_vert_select_poll(bContext *C) { - return vertex_group_vert_select_poll_ex(C, 0); + return vertex_group_vert_poll_ex(C, true, 0); } +#if 0 static int vertex_group_mesh_vert_select_poll(bContext *C) { - return vertex_group_vert_select_poll_ex(C, (1 << OB_MESH)); + return vertex_group_vert_poll_ex(C, true, (1 << OB_MESH)); } +#endif + /* editmode _or_ weight paint vertex sel and active group unlocked */ static int vertex_group_vert_select_unlocked_poll(bContext *C) @@ -3081,13 +3108,12 @@ static int vertex_group_smooth_exec(bContext *C, wmOperator *op) const float fac = RNA_float_get(op->ptr, "factor"); const int repeat = RNA_int_get(op->ptr, "repeat"); eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); - const int source = RNA_enum_get(op->ptr, "source"); const float fac_expand = RNA_float_get(op->ptr, "expand"); int subset_count, vgroup_tot; const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); - vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand, source); + vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand); MEM_freeN((void *)vgroup_validmap); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); @@ -3099,20 +3125,13 @@ static int vertex_group_smooth_exec(bContext *C, wmOperator *op) void OBJECT_OT_vertex_group_smooth(wmOperatorType *ot) { - static EnumPropertyItem smooth_source_item[] = { - {WEIGHT_SMOOTH_ALL, "ALL", 0, "All", ""}, - {WEIGHT_SMOOTH_SELECT, "SELECT", 0, "Only Selected", ""}, - {WEIGHT_SMOOTH_DESELECT, "DESELECT", 0, "Only Deselected", ""}, - {0, NULL, 0, NULL, NULL} - }; - /* identifiers */ ot->name = "Smooth Vertex Weights"; ot->idname = "OBJECT_OT_vertex_group_smooth"; ot->description = "Smooth weights for selected vertices"; /* api callbacks */ - ot->poll = vertex_group_mesh_vert_select_poll; + ot->poll = vertex_group_mesh_vert_poll; ot->exec = vertex_group_smooth_exec; /* flags */ @@ -3123,7 +3142,6 @@ void OBJECT_OT_vertex_group_smooth(wmOperatorType *ot) RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200); RNA_def_float(ot->srna, "expand", 0.0f, -1.0f, 1.0, "Expand/Contract", "Expand/contract weights", -1.0f, 1.0f); - RNA_def_enum(ot->srna, "source", smooth_source_item, -1, "Source", "Vertices to mix with"); } static int vertex_group_clean_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 2541aaa4b11..72c5a74aee9 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -424,7 +424,6 @@ static bool PE_create_shape_tree(PEData *data, Object *shapeob) return false; } - DM_ensure_looptri(dm); return (bvhtree_from_mesh_looptri(&data->shape_bvh, dm, 0.0f, 4, 8) != NULL); } diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 4a4474868a2..29b652e1326 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -1035,7 +1035,7 @@ static bool copy_particle_systems_to_object(Main *bmain, psys_from; psys_from = PSYS_FROM_NEXT(psys_from), ++i) { - psys = BKE_object_copy_particlesystem(psys_from); + psys = BKE_object_copy_particlesystem(psys_from, 0); tmp_psys[i] = psys; if (psys_start == NULL) diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt index 971ab9f3458..ec8bf3e955d 100644 --- a/source/blender/editors/render/CMakeLists.txt +++ b/source/blender/editors/render/CMakeLists.txt @@ -51,16 +51,6 @@ set(SRC render_intern.h ) -if(WITH_CODEC_QUICKTIME) - list(APPEND INC - ../../quicktime - ) - list(APPEND INC_SYS - ${QUICKTIME_INCLUDE_DIRS} - ) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_HEADLESS) add_definitions(-DWITH_HEADLESS) endif() diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 43b1d033d23..26c863d8514 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -305,7 +305,7 @@ static int screen_render_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); lay_override = (v3d && v3d->lay != scene->lay) ? v3d->lay : 0; G.is_break = false; @@ -964,7 +964,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even rj->image = ima; /* setup new render */ - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); RE_test_break_cb(re, rj, render_breakjob); RE_draw_lock_cb(re, rj, render_drawlock); RE_display_update_cb(re, rj, image_rect_update); @@ -1171,7 +1171,7 @@ static void render_update_resolution(Render *re, const RenderPreview *rp, } if (rp->has_freestyle) { - if (rp->resolution_divider == 1) { + if (rp->resolution_divider == BKE_render_preview_pixel_size(&rp->scene->r)) { RE_ChangeModeFlag(re, R_EDGE_FRS, false); } else { @@ -1237,7 +1237,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda use_border = render_view3d_disprect(rp->scene, rp->ar, rp->v3d, rp->rv3d, &cliprct); - if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE)) || rstats->convertdone == 0) { + if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE | PR_UPDATE_VIEW)) || rstats->convertdone == 0) { RenderData rdata; /* no osa, blur, seq, layers, savebuffer etc for preview render */ @@ -1312,11 +1312,12 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda RE_updateRenderInstances(re, ob_inst_update_flag); for (;;) { + int pixel_size = BKE_render_preview_pixel_size(&rp->scene->r); if (first_time == false) { if (restore) RE_DataBase_IncrementalView(re, rp->viewmat, 1); - rp->resolution_divider /= 2; + rp->resolution_divider = MAX2(rp->resolution_divider/2, pixel_size); *do_update = 1; render_update_resolution(re, rp, use_border, &cliprct); @@ -1333,7 +1334,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda first_time = false; - if (*stop || rp->resolution_divider == 1) { + if (*stop || rp->resolution_divider == pixel_size) { break; } } @@ -1435,7 +1436,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C) Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); int width = ar->winx, height = ar->winy; - int divider = 1; + int divider = BKE_render_preview_pixel_size(&scene->r); int resolution_threshold = scene->r.preview_start_resolution * scene->r.preview_start_resolution; diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 01050eda70b..a27026878e1 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -681,7 +681,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) } /* create render */ - oglrender->re = RE_NewRender(scene->id.name); + oglrender->re = RE_NewSceneRender(scene); /* create image and image user */ oglrender->ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 0878636d0fa..d252d764b42 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -1298,16 +1298,16 @@ static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op) switch (freestyle_get_modifier_type(&ptr)) { case LS_MODIFIER_TYPE_COLOR: - BKE_linestyle_color_modifier_copy(lineset->linestyle, modifier); + BKE_linestyle_color_modifier_copy(lineset->linestyle, modifier, 0); break; case LS_MODIFIER_TYPE_ALPHA: - BKE_linestyle_alpha_modifier_copy(lineset->linestyle, modifier); + BKE_linestyle_alpha_modifier_copy(lineset->linestyle, modifier, 0); break; case LS_MODIFIER_TYPE_THICKNESS: - BKE_linestyle_thickness_modifier_copy(lineset->linestyle, modifier); + BKE_linestyle_thickness_modifier_copy(lineset->linestyle, modifier, 0); break; case LS_MODIFIER_TYPE_GEOMETRY: - BKE_linestyle_geometry_modifier_copy(lineset->linestyle, modifier); + BKE_linestyle_geometry_modifier_copy(lineset->linestyle, modifier, 0); break; default: BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier"); @@ -1781,6 +1781,8 @@ static void copy_mtex_copybuf(ID *id) case ID_LS: mtex = &(((FreestyleLineStyle *)id)->mtex[(int)((FreestyleLineStyle *)id)->texact]); break; + default: + break; } if (mtex && *mtex) { @@ -1818,7 +1820,7 @@ static void paste_mtex_copybuf(ID *id) mtex = &(((FreestyleLineStyle *)id)->mtex[(int)((FreestyleLineStyle *)id)->texact]); break; default: - BLI_assert("invalid id type"); + BLI_assert(!"invalid id type"); return; } diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index c165bbfd301..293e507c2b3 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -54,6 +54,7 @@ #include "ED_armature.h" #include "ED_gpencil.h" +#include "ED_anim_api.h" #include "WM_api.h" #include "UI_interface.h" @@ -87,7 +88,7 @@ const char *screen_context_dir[] = { "visible_gpencil_layers", "editable_gpencil_layers", "editable_gpencil_strokes", "active_gpencil_layer", "active_gpencil_frame", "active_gpencil_palette", "active_gpencil_palettecolor", "active_gpencil_brush", - "active_operator", + "active_operator", "selected_editable_fcurves", NULL}; int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result) @@ -608,6 +609,30 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult return 1; } } + else if (CTX_data_equals(member, "selected_editable_fcurves")) + { + bAnimContext ac; + + if (ANIM_animdata_get_context(C, &ac) && ELEM(ac.spacetype, SPACE_ACTION, SPACE_IPO)) { + bAnimListElem *ale; + ListBase anim_data = {NULL, NULL}; + + int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS | ANIMFILTER_SEL) | + (ac.spacetype == SPACE_IPO ? ANIMFILTER_CURVE_VISIBLE : ANIMFILTER_LIST_VISIBLE); + + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + for (ale = anim_data.first; ale; ale = ale->next) { + if (ale->type == ANIMTYPE_FCURVE) + CTX_data_list_add(result, ale->id, &RNA_FCurve, ale->data); + } + + ANIM_animdata_freelist(&anim_data); + + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + } else { return 0; /* not found */ } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index f469686b0b2..71b00a0a7c6 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -467,7 +467,7 @@ bScreen *ED_screen_add(wmWindow *win, Scene *scene, const char *name) bScreen *sc; ScrVert *sv1, *sv2, *sv3, *sv4; - sc = BKE_libblock_alloc(G.main, ID_SCR, name); + sc = BKE_libblock_alloc(G.main, ID_SCR, name, 0); sc->scene = scene; sc->do_refresh = true; sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN; @@ -1894,17 +1894,28 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s if (sa && sa->full) { /* restoring back to SCREENNORMAL */ - ScrArea *old; - sc = sa->full; /* the old screen to restore */ oldscreen = win->screen; /* the one disappearing */ sc->state = SCREENNORMAL; - /* find old area */ - for (old = sc->areabase.first; old; old = old->next) - if (old->full) break; - if (old == NULL) { + /* find old area to restore from */ + ScrArea *fullsa = NULL; + for (ScrArea *old = sc->areabase.first; old; old = old->next) { + /* area to restore from is always first */ + if (old->full && !fullsa) { + fullsa = old; + } + + /* clear full screen state */ + old->full = NULL; + old->flag &= ~AREA_TEMP_INFO; + } + + sa->flag &= ~AREA_TEMP_INFO; + sa->full = NULL; + + if (fullsa == NULL) { if (G.debug & G_DEBUG) printf("%s: something wrong in areafullscreen\n", __func__); return NULL; @@ -1917,9 +1928,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s } } - ED_area_data_swap(old, sa); - if (sa->flag & AREA_TEMP_INFO) sa->flag &= ~AREA_TEMP_INFO; - old->full = NULL; + ED_area_data_swap(fullsa, sa); /* animtimer back */ sc->animtimer = oldscreen->animtimer; diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index c99d9add432..27e19ca1fc3 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -2260,25 +2260,28 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op) BLI_dlrbTree_linkedlist_sync(&keys); /* find matching keyframe in the right direction */ - do { - if (next) - ak = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfra); - else - ak = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfra); - - if (ak) { - if (CFRA != (int)ak->cfra) { - /* this changes the frame, so set the frame and we're done */ - CFRA = (int)ak->cfra; - done = true; + if (next) + ak = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfra); + else + ak = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfra); + + while ((ak != NULL) && (done == false)) { + if (CFRA != (int)ak->cfra) { + /* this changes the frame, so set the frame and we're done */ + CFRA = (int)ak->cfra; + done = true; + } + else { + /* take another step... */ + if (next) { + ak = ak->next; } else { - /* make this the new starting point for the search */ - cfra = ak->cfra; + ak = ak->prev; } } - } while ((ak != NULL) && (done == false)); - + } + /* free temp stuff */ BLI_dlrbTree_free(&keys); diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 46753df4e13..69f14c950bb 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -52,6 +52,10 @@ set(SRC paint_undo.c paint_utils.c paint_vertex.c + paint_vertex_color_ops.c + paint_vertex_color_utils.c + paint_vertex_weight_ops.c + paint_vertex_weight_utils.c paint_vertex_proj.c sculpt.c sculpt_undo.c diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index bf344e1f721..79ce440251d 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -1448,7 +1448,20 @@ void PAINT_OT_texture_paint_toggle(wmOperatorType *ot) static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op)) { UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; - Brush *br = image_paint_brush(C); + + Brush *br; + Object *ob = CTX_data_active_object(C); + if (!(ob && (ob->mode & OB_MODE_VERTEX_PAINT))) { + br = image_paint_brush(C); + } + else { + /* At the moment, wpaint does not support the color flipper. + * So for now we're only handling vpaint */ + ToolSettings *ts = CTX_data_tool_settings(C); + VPaint *vp = ts->vpaint; + br = BKE_paint_brush(&vp->paint); + } + if (ups->flag & UNIFIED_PAINT_COLOR) { swap_v3_v3(ups->rgb, ups->secondary_rgb); } @@ -1467,7 +1480,12 @@ static int brush_colors_flip_poll(bContext *C) if (br->imagepaint_tool == PAINT_TOOL_DRAW) return 1; } - + else { + Object *ob = CTX_data_active_object(C); + if (ob && (ob->mode & OB_MODE_VERTEX_PAINT)) { + return 1; + } + } return 0; } diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 4f93c12385d..09b0847b306 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -797,6 +797,7 @@ static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus float map_alpha = (rgb[3] == 0.0f) ? rrgbf[3] : rrgbf[3] / rgb[3]; mul_v3_v3fl(rrgbf, rgb, map_alpha); + rrgbf[3] = rgb[3]; } else { unsigned char straight[4]; @@ -806,6 +807,7 @@ static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus rrgb[0] = straight[0]; rrgb[1] = straight[1]; rrgb[2] = straight[2]; + rrgb[3] = straight[3]; } } @@ -995,7 +997,7 @@ static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short tile) IMB_rectblend(ibufb, ibufb, ibuf, NULL, NULL, NULL, 0, region[a].destx, region[a].desty, region[a].destx, region[a].desty, region[a].srcx, region[a].srcy, - region[a].width, region[a].height, IMB_BLEND_COPY_RGB, false); + region[a].width, region[a].height, IMB_BLEND_COPY, false); } static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos) @@ -1096,6 +1098,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign /* lift from canvas */ if (s->tool == PAINT_TOOL_SOFTEN) { paint_2d_lift_soften(s, s->canvas, ibufb, bpos, tile); + blend = IMB_BLEND_INTERPOLATE; } else if (s->tool == PAINT_TOOL_SMEAR) { if (lastpos[0] == pos[0] && lastpos[1] == pos[1]) @@ -1103,6 +1106,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign paint_2d_convert_brushco(ibufb, lastpos, blastpos); paint_2d_lift_smear(s->canvas, ibufb, blastpos, tile); + blend = IMB_BLEND_INTERPOLATE; } else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) { liftpos[0] = pos[0] - offset[0] * s->canvas->x; diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index b43581170d0..8586eb42bec 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -4295,7 +4295,7 @@ static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, f return; } else { - blend_color_interpolate_float(rgba, rgba, projPixel->pixel.f_pt, mask); + blend_color_interpolate_float(rgba, projPixel->pixel.f_pt, rgba, mask); } BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena); @@ -4754,6 +4754,9 @@ static void *do_projectpaint_thread(void *ph_v) copy_v3_v3(texrgb, texrgba); mask *= texrgba[3]; } + else { + zero_v3(texrgb); + } /* extra mask for normal, layer stencil, .. */ mask *= ((float)projPixel->mask) * (1.0f / 65535.0f); diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 7e05ab929ae..bd35218bb64 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -96,21 +96,11 @@ int weight_paint_mode_poll(struct bContext *C); int vertex_paint_poll(struct bContext *C); int vertex_paint_mode_poll(struct bContext *C); -bool ED_vpaint_fill(struct Object *ob, unsigned int paintcol); -bool ED_wpaint_fill(struct VPaint *wp, struct Object *ob, float paintweight); - -bool ED_vpaint_smooth(struct Object *ob); - typedef void (*VPaintTransform_Callback)(const float col[3], const void *user_data, float r_col[3]); -bool ED_vpaint_color_transform(struct Object *ob, VPaintTransform_Callback vpaint_tx_fn, const void *user_data); - void PAINT_OT_weight_paint_toggle(struct wmOperatorType *ot); void PAINT_OT_weight_paint(struct wmOperatorType *ot); void PAINT_OT_weight_set(struct wmOperatorType *ot); -void PAINT_OT_weight_from_bones(struct wmOperatorType *ot); -void PAINT_OT_weight_sample(struct wmOperatorType *ot); -void PAINT_OT_weight_sample_group(struct wmOperatorType *ot); enum { WPAINT_GRADIENT_TYPE_LINEAR, @@ -123,6 +113,44 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot); unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp); +/* paint_vertex_color_utils.c */ +unsigned int ED_vpaint_blend_tool( + const int tool, const uint col, + const uint paintcol, const int alpha_i); +bool ED_vpaint_color_transform( + struct Object *ob, VPaintTransform_Callback vpaint_tx_fn, const void *user_data); + +/* paint_vertex_weight_utils.c */ +float ED_wpaint_blend_tool( + const int tool, + const float weight, + const float paintval, const float alpha); +/* Utility for tools to ensure vertex groups exist before they begin. */ +enum eWPaintFlag { + WPAINT_ENSURE_MIRROR = (1 << 0), +}; +struct WPaintVGroupIndex { + int active; + int mirror; +}; +bool ED_wpaint_ensure_data( + struct bContext *C, struct ReportList *reports, + enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index); +int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, const int vgroup_active); + +/* paint_vertex_color_ops.c */ +void PAINT_OT_vertex_color_set(struct wmOperatorType *ot); +void PAINT_OT_vertex_color_from_weight(struct wmOperatorType *ot); +void PAINT_OT_vertex_color_smooth(struct wmOperatorType *ot); +void PAINT_OT_vertex_color_brightness_contrast(struct wmOperatorType *ot); +void PAINT_OT_vertex_color_hsv(struct wmOperatorType *ot); +void PAINT_OT_vertex_color_invert(struct wmOperatorType *ot); +void PAINT_OT_vertex_color_levels(struct wmOperatorType *ot); + +/* paint_vertex_weight_ops.c */ +void PAINT_OT_weight_from_bones(struct wmOperatorType *ot); +void PAINT_OT_weight_sample(struct wmOperatorType *ot); +void PAINT_OT_weight_sample_group(struct wmOperatorType *ot); /* paint_vertex_proj.c */ struct VertProjHandle; @@ -160,7 +188,7 @@ void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr); void imapaint_region_tiles(struct ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th); int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy); void *paint_2d_new_stroke(struct bContext *, struct wmOperator *, int mode); -void paint_2d_redraw(const bContext *C, void *ps, bool final); +void paint_2d_redraw(const struct bContext *C, void *ps, bool final); void paint_2d_stroke_done(void *ps); void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], const bool eraser, float pressure, float distance, float size); void paint_2d_bucket_fill(const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], void *ps); @@ -217,7 +245,7 @@ float paint_calc_object_space_radius(struct ViewContext *vc, const float center[ float paint_get_tex_pixel(struct MTex *mtex, float u, float v, struct ImagePool *pool, int thread); void paint_get_tex_pixel_col(struct MTex *mtex, float u, float v, float rgba[4], struct ImagePool *pool, int thread, bool convert, struct ColorSpace *colorspace); -void paint_sample_color(bContext *C, struct ARegion *ar, int x, int y, bool texpaint_proj, bool palette); +void paint_sample_color(struct bContext *C, struct ARegion *ar, int x, int y, bool texpaint_proj, bool palette); void paint_stroke_operator_properties(struct wmOperatorType *ot); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index f88b64129e7..4f6b3d100c5 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -256,300 +256,6 @@ static void PALETTE_OT_color_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - - -static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Scene *scene = CTX_data_scene(C); - Object *obact = CTX_data_active_object(C); - unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint); - - if (ED_vpaint_fill(obact, paintcol)) { - ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static void PAINT_OT_vertex_color_set(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Set Vertex Colors"; - ot->idname = "PAINT_OT_vertex_color_set"; - ot->description = "Fill the active vertex color layer with the current paint color"; - - /* api callbacks */ - ot->exec = vertex_color_set_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obact = CTX_data_active_object(C); - if (ED_vpaint_smooth(obact)) { - ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static void PAINT_OT_vertex_color_smooth(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Smooth Vertex Colors"; - ot->idname = "PAINT_OT_vertex_color_smooth"; - ot->description = "Smooth colors across vertices"; - - /* api callbacks */ - ot->exec = vertex_color_smooth_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - - -/** \name Vertex Color Transformations - * \{ */ - -struct VPaintTx_BrightContrastData { - /* pre-calculated */ - float gain; - float offset; -}; - -static void vpaint_tx_brightness_contrast(const float col[3], const void *user_data, float r_col[3]) -{ - const struct VPaintTx_BrightContrastData *data = user_data; - - for (int i = 0; i < 3; i++) { - r_col[i] = data->gain * col[i] + data->offset; - } -} - -static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op) -{ - Object *obact = CTX_data_active_object(C); - - float gain, offset; - { - float brightness = RNA_float_get(op->ptr, "brightness"); - float contrast = RNA_float_get(op->ptr, "contrast"); - brightness /= 100.0f; - float delta = contrast / 200.0f; - gain = 1.0f - delta * 2.0f; - /* - * The algorithm is by Werner D. Streidt - * (http://visca.com/ffactory/archives/5-99/msg00021.html) - * Extracted of OpenCV demhist.c - */ - if (contrast > 0) { - gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON); - offset = gain * (brightness - delta); - } - else { - delta *= -1; - offset = gain * (brightness + delta); - } - } - - const struct VPaintTx_BrightContrastData user_data = { - .gain = gain, - .offset = offset, - }; - - if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) { - ED_region_tag_redraw(CTX_wm_region(C)); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Vertex Paint Bright/Contrast"; - ot->idname = "PAINT_OT_vertex_color_brightness_contrast"; - ot->description = "Adjust vertex color brightness/contrast"; - - /* api callbacks */ - ot->exec = vertex_color_brightness_contrast_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* params */ - const float min = -100, max = +100; - prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max); - prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max); - RNA_def_property_ui_range(prop, min, max, 1, 1); -} - -struct VPaintTx_HueSatData { - float hue; - float sat; - float val; -}; - -static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3]) -{ - const struct VPaintTx_HueSatData *data = user_data; - float hsv[3]; - rgb_to_hsv_v(col, hsv); - - hsv[0] += (data->hue - 0.5f); - if (hsv[0] > 1.0f) { - hsv[0] -= 1.0f; - } - else if (hsv[0] < 0.0f) { - hsv[0] += 1.0f; - } - hsv[1] *= data->sat; - hsv[2] *= data->val; - - hsv_to_rgb_v(hsv, r_col); -} - -static int vertex_color_hsv_exec(bContext *C, wmOperator *op) -{ - Object *obact = CTX_data_active_object(C); - - const struct VPaintTx_HueSatData user_data = { - .hue = RNA_float_get(op->ptr, "h"), - .sat = RNA_float_get(op->ptr, "s"), - .val = RNA_float_get(op->ptr, "v"), - }; - - if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) { - ED_region_tag_redraw(CTX_wm_region(C)); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static void PAINT_OT_vertex_color_hsv(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Vertex Paint Hue Saturation Value"; - ot->idname = "PAINT_OT_vertex_color_hsv"; - ot->description = "Adjust vertex color HSV values"; - - /* api callbacks */ - ot->exec = vertex_color_hsv_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* params */ - RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f); - RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f); - RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f); -} - -static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3]) -{ - for (int i = 0; i < 3; i++) { - r_col[i] = 1.0f - col[i]; - } -} - -static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obact = CTX_data_active_object(C); - - if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) { - ED_region_tag_redraw(CTX_wm_region(C)); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static void PAINT_OT_vertex_color_invert(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Vertex Paint Invert"; - ot->idname = "PAINT_OT_vertex_color_invert"; - ot->description = "Invert RGB values"; - - /* api callbacks */ - ot->exec = vertex_color_invert_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - - -struct VPaintTx_LevelsData { - float gain; - float offset; -}; - -static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3]) -{ - const struct VPaintTx_LevelsData *data = user_data; - for (int i = 0; i < 3; i++) { - r_col[i] = data->gain * (col[i] + data->offset); - } -} - -static int vertex_color_levels_exec(bContext *C, wmOperator *op) -{ - Object *obact = CTX_data_active_object(C); - - const struct VPaintTx_LevelsData user_data = { - .gain = RNA_float_get(op->ptr, "gain"), - .offset = RNA_float_get(op->ptr, "offset"), - }; - - if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) { - ED_region_tag_redraw(CTX_wm_region(C)); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static void PAINT_OT_vertex_color_levels(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Vertex Paint Levels"; - ot->idname = "PAINT_OT_vertex_color_levels"; - ot->description = "Adjust levels of vertex colors"; - - /* api callbacks */ - ot->exec = vertex_color_levels_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* params */ - RNA_def_float(ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f); - RNA_def_float(ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f); -} - -/** \} */ - - static int brush_reset_exec(bContext *C, wmOperator *UNUSED(op)) { Paint *paint = BKE_paint_get_active_from_context(C); @@ -821,8 +527,6 @@ static int brush_uv_sculpt_tool_set_exec(bContext *C, wmOperator *op) static void BRUSH_OT_uv_sculpt_tool_set(wmOperatorType *ot) { - /* from rna_scene.c */ - extern EnumPropertyItem uv_sculpt_tool_items[]; /* identifiers */ ot->name = "UV Sculpt Tool Set"; ot->description = "Set the UV sculpt tool"; @@ -836,7 +540,7 @@ static void BRUSH_OT_uv_sculpt_tool_set(wmOperatorType *ot) ot->flag = 0; /* props */ - ot->prop = RNA_def_enum(ot->srna, "tool", uv_sculpt_tool_items, 0, "Tool", ""); + ot->prop = RNA_def_enum(ot->srna, "tool", rna_enum_uv_sculpt_tool_items, 0, "Tool", ""); } /***** Stencil Control *****/ @@ -1351,6 +1055,7 @@ void ED_operatortypes_paint(void) WM_operatortype_append(PAINT_OT_vertex_color_hsv); WM_operatortype_append(PAINT_OT_vertex_color_invert); WM_operatortype_append(PAINT_OT_vertex_color_levels); + WM_operatortype_append(PAINT_OT_vertex_color_from_weight); /* face-select */ WM_operatortype_append(PAINT_OT_face_select_linked); @@ -1615,6 +1320,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) keymap->poll = vertex_paint_mode_poll; WM_keymap_verify_item(keymap, "PAINT_OT_vertex_paint", LEFTMOUSE, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "PAINT_OT_brush_colors_flip", XKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "PAINT_OT_sample_color", SKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 05270dbfa09..bb2cd52a41e 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -580,7 +580,10 @@ static float paint_stroke_integrate_overlap(Brush *br, float factor) max = overlap; } - return 1.0f / max; + if (max == 0.0f) + return 1.0f; + else + return 1.0f / max; } static float paint_space_stroke_spacing_variable(const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length) diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 31c471c3517..10628d8cccb 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -426,7 +426,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr Scene *scene = CTX_data_scene(C); Paint *paint = BKE_paint_get_active_from_context(C); Palette *palette = BKE_paint_palette(paint); - PaletteColor *color; + PaletteColor *color = NULL; Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C)); unsigned int col; const unsigned char *cp; diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 729dd9dc57b..4d6222a4301 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -27,20 +27,20 @@ /** \file blender/editors/sculpt_paint/paint_vertex.c * \ingroup edsculpt + * + * Used for vertex color & weight paint and mode switching. + * + * \note This file is already big, + * use `paint_vertex_color_ops.c` & `paint_vertex_weight_ops.c` for general purpose operators. */ #include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" +#include "BLI_listbase.h" +#include "BLI_rect.h" #include "BLI_math.h" #include "BLI_array_utils.h" -#include "BLI_bitmap.h" -#include "BLI_stack.h" -#include "BLI_string_utils.h" - -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" -#include "IMB_colormanagement.h" +#include "BLI_task.h" #include "DNA_armature_types.h" #include "DNA_mesh_types.h" @@ -51,39 +51,50 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "RNA_enum_types.h" -#include "BKE_DerivedMesh.h" -#include "BKE_action.h" #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_deform.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" -#include "BKE_modifier.h" #include "BKE_object_deform.h" #include "BKE_paint.h" #include "BKE_report.h" -#include "BKE_colortools.h" +#include "BKE_subsurf.h" #include "WM_api.h" #include "WM_types.h" -#include "ED_armature.h" #include "ED_object.h" #include "ED_mesh.h" #include "ED_screen.h" #include "ED_view3d.h" +#include "bmesh.h" +#include "BKE_ccg.h" + +#include "sculpt_intern.h" #include "paint_intern.h" /* own include */ -/* small structure to defer applying weight-paint results */ -struct WPaintDefer { - int index; - float alpha, weight; +/* Use for 'blur' brush, align with PBVH nodes, created and freed on each update. */ +struct VPaintAverageAccum { + uint len; + uint value[3]; +}; + +struct WPaintAverageAccum { + uint len; + double value; }; +static void defweight_prev_init(const MDeformWeight *dw, float *weight_prev) +{ + if (UNLIKELY(*weight_prev == -1.0f)) { + *weight_prev = dw ? dw->weight : 0.0f; + } +} + /* check if we can do partial updates and have them draw realtime * (without rebuilding the 'derivedFinal') */ static bool vertex_paint_use_fast_update_check(Object *ob) @@ -174,629 +185,38 @@ static VPaint *new_vpaint(int wpaint) return vp; } -static int *get_indexarray(Mesh *me) -{ - return MEM_mallocN(sizeof(int) * (me->totpoly + 1), "vertexpaint"); -} - -unsigned int vpaint_get_current_col(Scene *scene, VPaint *vp) +uint vpaint_get_current_col(Scene *scene, VPaint *vp) { Brush *brush = BKE_paint_brush(&vp->paint); - unsigned char col[4]; + uchar col[4]; rgb_float_to_uchar(col, BKE_brush_color_get(scene, brush)); col[3] = 255; /* alpha isn't used, could even be removed to speedup paint a little */ - return *(unsigned int *)col; -} - -static void do_shared_vertexcol(Mesh *me, bool *mlooptag) -{ - const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - MPoly *mp; - int (*scol)[4]; - int i, j; - bool has_shared = false; - - /* if no mloopcol: do not do */ - /* if mtexpoly: only the involved faces, otherwise all */ - - if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) return; - - scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol"); - - for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) { - if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) { - MLoop *ml = me->mloop + mp->loopstart; - MLoopCol *lcol = me->mloopcol + mp->loopstart; - for (j = 0; j < mp->totloop; j++, ml++, lcol++) { - scol[ml->v][0] += lcol->r; - scol[ml->v][1] += lcol->g; - scol[ml->v][2] += lcol->b; - scol[ml->v][3] += 1; - has_shared = 1; - } - } - } - - if (has_shared) { - for (i = 0; i < me->totvert; i++) { - if (scol[i][3] != 0) { - scol[i][0] = divide_round_i(scol[i][0], scol[i][3]); - scol[i][1] = divide_round_i(scol[i][1], scol[i][3]); - scol[i][2] = divide_round_i(scol[i][2], scol[i][3]); - } - } - - for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) { - if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) { - MLoop *ml = me->mloop + mp->loopstart; - MLoopCol *lcol = me->mloopcol + mp->loopstart; - for (j = 0; j < mp->totloop; j++, ml++, lcol++) { - if (mlooptag[mp->loopstart + j]) { - lcol->r = scol[ml->v][0]; - lcol->g = scol[ml->v][1]; - lcol->b = scol[ml->v][2]; - } - } - } - } - } - - MEM_freeN(scol); -} - -static bool make_vertexcol(Object *ob) /* single ob */ -{ - Mesh *me; - - if (ID_IS_LINKED_DATABLOCK(ob) || - ((me = BKE_mesh_from_object(ob)) == NULL) || - (me->totpoly == 0) || - (me->edit_btmesh)) - { - return false; - } - - /* copies from shadedisplist to mcol */ - if (!me->mloopcol && me->totloop) { - CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop); - BKE_mesh_update_customdata_pointers(me, true); - } - - DAG_id_tag_update(&me->id, 0); - - return (me->mloopcol != NULL); -} - -/* mirror_vgroup is set to -1 when invalid */ -static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active) -{ - bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active); - - if (defgroup) { - int mirrdef; - char name_flip[MAXBONENAME]; - - BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip)); - mirrdef = defgroup_name_index(ob, name_flip); - if (mirrdef == -1) { - if (BKE_defgroup_new(ob, name_flip)) { - mirrdef = BLI_listbase_count(&ob->defbase) - 1; - } - } - - /* curdef should never be NULL unless this is - * a lamp and BKE_object_defgroup_add_name fails */ - return mirrdef; - } - - return -1; -} - -static void free_vpaint_prev(VPaint *vp) -{ - if (vp->vpaint_prev) { - MEM_freeN(vp->vpaint_prev); - vp->vpaint_prev = NULL; - vp->tot = 0; - } -} - -static void free_wpaint_prev(VPaint *vp) -{ - if (vp->wpaint_prev) { - BKE_defvert_array_free(vp->wpaint_prev, vp->tot); - vp->wpaint_prev = NULL; - vp->tot = 0; - } -} - -static void copy_vpaint_prev(VPaint *vp, unsigned int *lcol, int tot) -{ - free_vpaint_prev(vp); - - vp->tot = tot; - - if (lcol == NULL || tot == 0) return; - - vp->vpaint_prev = MEM_mallocN(sizeof(int) * tot, "vpaint_prev"); - memcpy(vp->vpaint_prev, lcol, sizeof(int) * tot); - -} - -static void copy_wpaint_prev(VPaint *wp, MDeformVert *dverts, int dcount) -{ - free_wpaint_prev(wp); - - if (dverts && dcount) { - - wp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev"); - wp->tot = dcount; - BKE_defvert_array_copy(wp->wpaint_prev, dverts, dcount); - } -} - -bool ED_vpaint_fill(Object *ob, unsigned int paintcol) -{ - Mesh *me; - MPoly *mp; - int i, j; - bool selected; - - if (((me = BKE_mesh_from_object(ob)) == NULL) || - (me->mloopcol == NULL && (make_vertexcol(ob) == false))) - { - return false; - } - - selected = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - - mp = me->mpoly; - for (i = 0; i < me->totpoly; i++, mp++) { - MLoopCol *lcol = me->mloopcol + mp->loopstart; - - if (selected && !(mp->flag & ME_FACE_SEL)) - continue; - - for (j = 0; j < mp->totloop; j++, lcol++) { - *(int *)lcol = paintcol; - } - } - - /* remove stale me->mcol, will be added later */ - BKE_mesh_tessface_clear(me); - - DAG_id_tag_update(&me->id, 0); - - return true; -} - - -/* fills in the selected faces with the current weight and vertex group */ -bool ED_wpaint_fill(VPaint *wp, Object *ob, float paintweight) -{ - Mesh *me = ob->data; - MPoly *mp; - MDeformWeight *dw, *dw_prev; - int vgroup_active, vgroup_mirror = -1; - unsigned int index; - const bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; - - /* mutually exclusive, could be made into a */ - const short paint_selmode = ME_EDIT_PAINT_SEL_MODE(me); - - if (me->totpoly == 0 || me->dvert == NULL || !me->mpoly) { - return false; - } - - vgroup_active = ob->actdef - 1; - - /* if mirror painting, find the other group */ - if (me->editflag & ME_EDIT_MIRROR_X) { - vgroup_mirror = wpaint_mirror_vgroup_ensure(ob, vgroup_active); - } - - copy_wpaint_prev(wp, me->dvert, me->totvert); - - for (index = 0, mp = me->mpoly; index < me->totpoly; index++, mp++) { - unsigned int fidx = mp->totloop - 1; - - if ((paint_selmode == SCE_SELECT_FACE) && !(mp->flag & ME_FACE_SEL)) { - continue; - } - - do { - unsigned int vidx = me->mloop[mp->loopstart + fidx].v; - - if (!me->dvert[vidx].flag) { - if ((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) { - continue; - } - - dw = defvert_verify_index(&me->dvert[vidx], vgroup_active); - if (dw) { - dw_prev = defvert_verify_index(wp->wpaint_prev + vidx, vgroup_active); - dw_prev->weight = dw->weight; /* set the undo weight */ - dw->weight = paintweight; - - if (me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */ - int j = mesh_get_x_mirror_vert(ob, NULL, vidx, topology); - if (j >= 0) { - /* copy, not paint again */ - if (vgroup_mirror != -1) { - dw = defvert_verify_index(me->dvert + j, vgroup_mirror); - dw_prev = defvert_verify_index(wp->wpaint_prev + j, vgroup_mirror); - } - else { - dw = defvert_verify_index(me->dvert + j, vgroup_active); - dw_prev = defvert_verify_index(wp->wpaint_prev + j, vgroup_active); - } - dw_prev->weight = dw->weight; /* set the undo weight */ - dw->weight = paintweight; - } - } - } - me->dvert[vidx].flag = 1; - } - - } while (fidx--); - } - - { - MDeformVert *dv = me->dvert; - for (index = me->totvert; index != 0; index--, dv++) { - dv->flag = 0; - } - } - - copy_wpaint_prev(wp, NULL, 0); - - DAG_id_tag_update(&me->id, 0); - - return true; -} - -bool ED_vpaint_smooth(Object *ob) -{ - Mesh *me; - MPoly *mp; - - int i, j; - - bool *mlooptag; - bool selected; - - if (((me = BKE_mesh_from_object(ob)) == NULL) || - (me->mloopcol == NULL && (make_vertexcol(ob) == false))) - { - return false; - } - - selected = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - - mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag"); - - /* simply tag loops of selected faces */ - mp = me->mpoly; - for (i = 0; i < me->totpoly; i++, mp++) { - MLoop *ml = me->mloop + mp->loopstart; - int ml_index = mp->loopstart; - - if (selected && !(mp->flag & ME_FACE_SEL)) - continue; - - for (j = 0; j < mp->totloop; j++, ml_index++, ml++) { - mlooptag[ml_index] = true; - } - } - - /* remove stale me->mcol, will be added later */ - BKE_mesh_tessface_clear(me); - - do_shared_vertexcol(me, mlooptag); - - MEM_freeN(mlooptag); - - DAG_id_tag_update(&me->id, 0); - - return true; -} - -/** - * Apply callback to each vertex of the active vertex color layer. - */ -bool ED_vpaint_color_transform( - struct Object *ob, - VPaintTransform_Callback vpaint_tx_fn, - const void *user_data) -{ - Mesh *me; - const MPoly *mp; - - if (((me = BKE_mesh_from_object(ob)) == NULL) || - (me->mloopcol == NULL && (make_vertexcol(ob) == false))) - { - return false; - } - - const bool do_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - mp = me->mpoly; - - for (int i = 0; i < me->totpoly; i++, mp++) { - MLoopCol *lcol = &me->mloopcol[mp->loopstart]; - - if (do_face_sel && !(mp->flag & ME_FACE_SEL)) { - continue; - } - - for (int j = 0; j < mp->totloop; j++, lcol++) { - float col[3]; - rgb_uchar_to_float(col, &lcol->r); - - vpaint_tx_fn(col, user_data, col); - - rgb_float_to_uchar(&lcol->r, col); - } - } - - /* remove stale me->mcol, will be added later */ - BKE_mesh_tessface_clear(me); - - DAG_id_tag_update(&me->id, 0); - - return true; -} - -/* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator */ -#if 0 -void vpaint_dogamma(Scene *scene) -{ - VPaint *vp = scene->toolsettings->vpaint; - Mesh *me; - Object *ob; - float igam, fac; - int a, temp; - unsigned char *cp, gamtab[256]; - - ob = OBACT; - me = BKE_mesh_from_object(ob); - - if (!(ob->mode & OB_MODE_VERTEX_PAINT)) return; - if (me == 0 || me->mcol == 0 || me->totface == 0) return; - - igam = 1.0 / vp->gamma; - for (a = 0; a < 256; a++) { - - fac = ((float)a) / 255.0; - fac = vp->mul * pow(fac, igam); - - temp = 255.9 * fac; - - if (temp <= 0) gamtab[a] = 0; - else if (temp >= 255) gamtab[a] = 255; - else gamtab[a] = temp; - } - - a = 4 * me->totface; - cp = (unsigned char *)me->mcol; - while (a--) { - - cp[1] = gamtab[cp[1]]; - cp[2] = gamtab[cp[2]]; - cp[3] = gamtab[cp[3]]; - - cp += 4; - } -} -#endif - -BLI_INLINE unsigned int mcol_blend(unsigned int col1, unsigned int col2, int fac) -{ - unsigned char *cp1, *cp2, *cp; - int mfac; - unsigned int col = 0; - - if (fac == 0) { - return col1; - } - - if (fac >= 255) { - return col2; - } - - mfac = 255 - fac; - - cp1 = (unsigned char *)&col1; - cp2 = (unsigned char *)&col2; - cp = (unsigned char *)&col; - - cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255); - cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255); - cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255); - cp[3] = 255; - - return col; -} - -BLI_INLINE unsigned int mcol_add(unsigned int col1, unsigned int col2, int fac) -{ - unsigned char *cp1, *cp2, *cp; - int temp; - unsigned int col = 0; - - if (fac == 0) { - return col1; - } - - cp1 = (unsigned char *)&col1; - cp2 = (unsigned char *)&col2; - cp = (unsigned char *)&col; - - temp = cp1[0] + divide_round_i((fac * cp2[0]), 255); - cp[0] = (temp > 254) ? 255 : temp; - temp = cp1[1] + divide_round_i((fac * cp2[1]), 255); - cp[1] = (temp > 254) ? 255 : temp; - temp = cp1[2] + divide_round_i((fac * cp2[2]), 255); - cp[2] = (temp > 254) ? 255 : temp; - cp[3] = 255; - - return col; -} - -BLI_INLINE unsigned int mcol_sub(unsigned int col1, unsigned int col2, int fac) -{ - unsigned char *cp1, *cp2, *cp; - int temp; - unsigned int col = 0; - - if (fac == 0) { - return col1; - } - - cp1 = (unsigned char *)&col1; - cp2 = (unsigned char *)&col2; - cp = (unsigned char *)&col; - - temp = cp1[0] - divide_round_i((fac * cp2[0]), 255); - cp[0] = (temp < 0) ? 0 : temp; - temp = cp1[1] - divide_round_i((fac * cp2[1]), 255); - cp[1] = (temp < 0) ? 0 : temp; - temp = cp1[2] - divide_round_i((fac * cp2[2]), 255); - cp[2] = (temp < 0) ? 0 : temp; - cp[3] = 255; - - return col; -} - -BLI_INLINE unsigned int mcol_mul(unsigned int col1, unsigned int col2, int fac) -{ - unsigned char *cp1, *cp2, *cp; - int mfac; - unsigned int col = 0; - - if (fac == 0) { - return col1; - } - - mfac = 255 - fac; - - cp1 = (unsigned char *)&col1; - cp2 = (unsigned char *)&col2; - cp = (unsigned char *)&col; - - /* first mul, then blend the fac */ - cp[0] = divide_round_i(mfac * cp1[0] * 255 + fac * cp2[0] * cp1[0], 255 * 255); - cp[1] = divide_round_i(mfac * cp1[1] * 255 + fac * cp2[1] * cp1[1], 255 * 255); - cp[2] = divide_round_i(mfac * cp1[2] * 255 + fac * cp2[2] * cp1[2], 255 * 255); - cp[3] = 255; - - return col; -} - -BLI_INLINE unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int fac) -{ - unsigned char *cp1, *cp2, *cp; - int mfac; - unsigned int col = 0; - - if (fac == 0) { - return col1; - } - else if (fac >= 255) { - return col2; - } - - mfac = 255 - fac; - - cp1 = (unsigned char *)&col1; - cp2 = (unsigned char *)&col2; - cp = (unsigned char *)&col; - - /* See if are lighter, if so mix, else don't do anything. - * if the paint col is darker then the original, then ignore */ - if (IMB_colormanagement_get_luminance_byte(cp1) > IMB_colormanagement_get_luminance_byte(cp2)) { - return col1; - } - - cp[0] = divide_round_i(mfac * cp1[0] + fac * cp2[0], 255); - cp[1] = divide_round_i(mfac * cp1[1] + fac * cp2[1], 255); - cp[2] = divide_round_i(mfac * cp1[2] + fac * cp2[2], 255); - cp[3] = 255; - - return col; -} - -BLI_INLINE unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fac) -{ - unsigned char *cp1, *cp2, *cp; - int mfac; - unsigned int col = 0; - - if (fac == 0) { - return col1; - } - else if (fac >= 255) { - return col2; - } - - mfac = 255 - fac; - - cp1 = (unsigned char *)&col1; - cp2 = (unsigned char *)&col2; - cp = (unsigned char *)&col; - - /* See if were darker, if so mix, else don't do anything. - * if the paint col is brighter then the original, then ignore */ - if (IMB_colormanagement_get_luminance_byte(cp1) < IMB_colormanagement_get_luminance_byte(cp2)) { - return col1; - } - - cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255); - cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255); - cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255); - cp[3] = 255; - return col; -} - -/* wpaint has 'wpaint_blend_tool' */ -static unsigned int vpaint_blend_tool(const int tool, const unsigned int col, - const unsigned int paintcol, const int alpha_i) -{ - switch (tool) { - case PAINT_BLEND_MIX: - case PAINT_BLEND_BLUR: return mcol_blend(col, paintcol, alpha_i); - case PAINT_BLEND_ADD: return mcol_add(col, paintcol, alpha_i); - case PAINT_BLEND_SUB: return mcol_sub(col, paintcol, alpha_i); - case PAINT_BLEND_MUL: return mcol_mul(col, paintcol, alpha_i); - case PAINT_BLEND_LIGHTEN: return mcol_lighten(col, paintcol, alpha_i); - case PAINT_BLEND_DARKEN: return mcol_darken(col, paintcol, alpha_i); - default: - BLI_assert(0); - return 0; - } + return *(uint *)col; } /* wpaint has 'wpaint_blend' */ -static unsigned int vpaint_blend(VPaint *vp, unsigned int col, unsigned int colorig, const - unsigned int paintcol, const int alpha_i, - /* pre scaled from [0-1] --> [0-255] */ - const int brush_alpha_value_i) +static uint vpaint_blend( + VPaint *vp, uint color_curr, uint color_orig, + uint color_paint, const int alpha_i, + /* pre scaled from [0-1] --> [0-255] */ + const int brush_alpha_value_i) { Brush *brush = BKE_paint_brush(&vp->paint); const int tool = brush->vertexpaint_tool; - col = vpaint_blend_tool(tool, col, paintcol, alpha_i); + uint color_blend = ED_vpaint_blend_tool(tool, color_curr, color_paint, alpha_i); /* if no spray, clip color adding with colorig & orig alpha */ if ((vp->flag & VP_SPRAY) == 0) { - unsigned int testcol, a; + uint color_test, a; char *cp, *ct, *co; - - testcol = vpaint_blend_tool(tool, colorig, paintcol, brush_alpha_value_i); - - cp = (char *)&col; - ct = (char *)&testcol; - co = (char *)&colorig; - + + color_test = ED_vpaint_blend_tool(tool, color_orig, color_paint, brush_alpha_value_i); + + cp = (char *)&color_blend; + ct = (char *)&color_test; + co = (char *)&color_orig; + for (a = 0; a < 4; a++) { if (ct[a] < co[a]) { if (cp[a] < ct[a]) cp[a] = ct[a]; @@ -809,53 +229,23 @@ static unsigned int vpaint_blend(VPaint *vp, unsigned int col, unsigned int colo } } - return col; -} - - -static int sample_backbuf_area(ViewContext *vc, int *indexar, int totpoly, int x, int y, float size) -{ - struct ImBuf *ibuf; - int a, tot = 0, index; - - /* brecht: disabled this because it obviously fails for - * brushes with size > 64, why is this here? */ - /*if (size > 64.0) size = 64.0;*/ - - ibuf = ED_view3d_backbuf_read(vc, x - size, y - size, x + size, y + size); - if (ibuf) { - unsigned int *rt = ibuf->rect; - - memset(indexar, 0, sizeof(int) * (totpoly + 1)); - - size = ibuf->x * ibuf->y; - while (size--) { - - if (*rt) { - index = *rt; - if (index > 0 && index <= totpoly) { - indexar[index] = 1; - } - } - - rt++; - } - - for (a = 1; a <= totpoly; a++) { - if (indexar[a]) { - indexar[tot++] = a; - } - } - - IMB_freeImBuf(ibuf); + if ((brush->flag & BRUSH_LOCK_ALPHA) && + !ELEM(tool, PAINT_BLEND_ALPHA_SUB, PAINT_BLEND_ALPHA_ADD)) + { + char *cp, *cc; + cp = (char *)&color_blend; + cc = (char *)&color_curr; + cp[3] = cc[3]; } - - return tot; + + return color_blend; } + /* whats _dl mean? */ -static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co[3], - const float mval[2], const float brush_size_pressure, float rgba[4]) +static float calc_vp_strength_col_dl( + VPaint *vp, const ViewContext *vc, const float co[3], + const float mval[2], const float brush_size_pressure, float rgba[4]) { float co_ss[2]; /* screenspace */ @@ -891,10 +281,11 @@ static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co return 0.0f; } -static float calc_vp_alpha_col_dl(VPaint *vp, ViewContext *vc, - float vpimat[3][3], const DMCoNo *v_co_no, - const float mval[2], - const float brush_size_pressure, const float brush_alpha_pressure, float rgba[4]) +static float calc_vp_alpha_col_dl( + VPaint *vp, const ViewContext *vc, + float vpimat[3][3], const DMCoNo *v_co_no, + const float mval[2], + const float brush_size_pressure, const float brush_alpha_pressure, float rgba[4]) { float strength = calc_vp_strength_col_dl(vp, vc, v_co_no->co, mval, brush_size_pressure, rgba); @@ -923,59 +314,10 @@ static float calc_vp_alpha_col_dl(VPaint *vp, ViewContext *vc, return 0.0f; } - -BLI_INLINE float wval_blend(const float weight, const float paintval, const float alpha) -{ - const float talpha = min_ff(alpha, 1.0f); /* blending with values over 1 doesn't make sense */ - return (paintval * talpha) + (weight * (1.0f - talpha)); -} -BLI_INLINE float wval_add(const float weight, const float paintval, const float alpha) -{ - return weight + (paintval * alpha); -} -BLI_INLINE float wval_sub(const float weight, const float paintval, const float alpha) -{ - return weight - (paintval * alpha); -} -BLI_INLINE float wval_mul(const float weight, const float paintval, const float alpha) -{ /* first mul, then blend the fac */ - return ((1.0f - alpha) + (alpha * paintval)) * weight; -} -BLI_INLINE float wval_lighten(const float weight, const float paintval, const float alpha) -{ - return (weight < paintval) ? wval_blend(weight, paintval, alpha) : weight; -} -BLI_INLINE float wval_darken(const float weight, const float paintval, const float alpha) -{ - return (weight > paintval) ? wval_blend(weight, paintval, alpha) : weight; -} - - -/* vpaint has 'vpaint_blend_tool' */ -/* result is not clamped from [0-1] */ -static float wpaint_blend_tool(const int tool, - /* dw->weight */ - const float weight, - const float paintval, const float alpha) -{ - switch (tool) { - case PAINT_BLEND_MIX: - case PAINT_BLEND_BLUR: return wval_blend(weight, paintval, alpha); - case PAINT_BLEND_ADD: return wval_add(weight, paintval, alpha); - case PAINT_BLEND_SUB: return wval_sub(weight, paintval, alpha); - case PAINT_BLEND_MUL: return wval_mul(weight, paintval, alpha); - case PAINT_BLEND_LIGHTEN: return wval_lighten(weight, paintval, alpha); - case PAINT_BLEND_DARKEN: return wval_darken(weight, paintval, alpha); - default: - BLI_assert(0); - return 0.0f; - } -} - /* vpaint has 'vpaint_blend' */ -static float wpaint_blend(VPaint *wp, float weight, float weight_prev, +static float wpaint_blend(VPaint *wp, float weight, const float alpha, float paintval, - const float brush_alpha_value, + const float UNUSED(brush_alpha_value), const short do_flip) { Brush *brush = BKE_paint_brush(&wp->paint); @@ -996,256 +338,19 @@ static float wpaint_blend(VPaint *wp, float weight, float weight_prev, } } - weight = wpaint_blend_tool(tool, weight, paintval, alpha); + weight = ED_wpaint_blend_tool(tool, weight, paintval, alpha); CLAMP(weight, 0.0f, 1.0f); - /* if no spray, clip result with orig weight & orig alpha */ - if ((wp->flag & VP_SPRAY) == 0) { - float testw = wpaint_blend_tool(tool, weight_prev, paintval, brush_alpha_value); - - CLAMP(testw, 0.0f, 1.0f); - if (testw < weight_prev) { - if (weight < testw) weight = testw; - else if (weight > weight_prev) weight = weight_prev; - } - else { - if (weight > testw) weight = testw; - else if (weight < weight_prev) weight = weight_prev; - } - } - return weight; } /* ----------------------------------------------------- */ - -/* sets wp->weight to the closest weight value to vertex */ -/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */ -static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ViewContext vc; - Mesh *me; - bool changed = false; - - view3d_set_viewcontext(C, &vc); - me = BKE_mesh_from_object(vc.obact); - - if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) { - const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; - int v_idx_best = -1; - unsigned int index; - - view3d_operator_needs_opengl(C); - ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d); - - if (use_vert_sel) { - if (ED_mesh_pick_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, true)) { - v_idx_best = index; - } - } - else { - if (ED_mesh_pick_face_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { - v_idx_best = index; - } - else if (ED_mesh_pick_face(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { - /* this relies on knowning the internal worksings of ED_mesh_pick_face_vert() */ - BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations"); - } - } - - if (v_idx_best != -1) { /* should always be valid */ - ToolSettings *ts = vc.scene->toolsettings; - Brush *brush = BKE_paint_brush(&ts->wpaint->paint); - const int vgroup_active = vc.obact->actdef - 1; - float vgroup_weight = defvert_find_weight(&me->dvert[v_idx_best], vgroup_active); - - /* use combined weight in multipaint mode, since that's what is displayed to the user in the colors */ - if (ts->multipaint) { - int defbase_tot_sel; - const int defbase_tot = BLI_listbase_count(&vc.obact->defbase); - bool *defbase_sel = BKE_object_defgroup_selected_get(vc.obact, defbase_tot, &defbase_tot_sel); - - if (defbase_tot_sel > 1) { - if (me->editflag & ME_EDIT_MIRROR_X) { - BKE_object_defgroup_mirror_selection( - vc.obact, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel); - } - - vgroup_weight = BKE_defvert_multipaint_collective_weight( - &me->dvert[v_idx_best], defbase_tot, defbase_sel, defbase_tot_sel, ts->auto_normalize); - - /* if autonormalize is enabled, but weights are not normalized, the value can exceed 1 */ - CLAMP(vgroup_weight, 0.0f, 1.0f); - } - - MEM_freeN(defbase_sel); - } - - BKE_brush_weight_set(vc.scene, brush, vgroup_weight); - changed = true; - } - } - - if (changed) { - /* not really correct since the brush didnt change, but redraws the toolbar */ - WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL); /* ts->wpaint->paint.brush */ - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -void PAINT_OT_weight_sample(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Weight Paint Sample Weight"; - ot->idname = "PAINT_OT_weight_sample"; - ot->description = "Use the mouse to sample a weight in the 3D view"; - - /* api callbacks */ - ot->invoke = weight_sample_invoke; - ot->poll = weight_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_UNDO; -} - -/* samples cursor location, and gives menu with vertex groups to activate */ -static bool weight_paint_sample_enum_itemf__helper(const MDeformVert *dvert, const int defbase_tot, int *groups) -{ - /* this func fills in used vgroup's */ - bool found = false; - int i = dvert->totweight; - MDeformWeight *dw; - for (dw = dvert->dw; i > 0; dw++, i--) { - if (dw->def_nr < defbase_tot) { - groups[dw->def_nr] = true; - found = true; - } - } - return found; -} -static EnumPropertyItem *weight_paint_sample_enum_itemf( - bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ - if (C) { - wmWindow *win = CTX_wm_window(C); - if (win && win->eventstate) { - ViewContext vc; - Mesh *me; - - view3d_set_viewcontext(C, &vc); - me = BKE_mesh_from_object(vc.obact); - - if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) { - const int defbase_tot = BLI_listbase_count(&vc.obact->defbase); - const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; - int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups"); - bool found = false; - unsigned int index; - - const int mval[2] = { - win->eventstate->x - vc.ar->winrct.xmin, - win->eventstate->y - vc.ar->winrct.ymin, - }; - - view3d_operator_needs_opengl(C); - ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d); - - if (use_vert_sel) { - if (ED_mesh_pick_vert(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, true)) { - MDeformVert *dvert = &me->dvert[index]; - found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups); - } - } - else { - if (ED_mesh_pick_face(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { - MPoly *mp = &me->mpoly[index]; - unsigned int fidx = mp->totloop - 1; - - do { - MDeformVert *dvert = &me->dvert[me->mloop[mp->loopstart + fidx].v]; - found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups); - } while (fidx--); - } - } - - if (found == false) { - MEM_freeN(groups); - } - else { - EnumPropertyItem *item = NULL, item_tmp = {0}; - int totitem = 0; - int i = 0; - bDeformGroup *dg; - for (dg = vc.obact->defbase.first; dg && i < defbase_tot; i++, dg = dg->next) { - if (groups[i]) { - item_tmp.identifier = item_tmp.name = dg->name; - item_tmp.value = i; - RNA_enum_item_add(&item, &totitem, &item_tmp); - } - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - MEM_freeN(groups); - return item; - } - } - } - } - - return DummyRNA_NULL_items; -} - -static int weight_sample_group_exec(bContext *C, wmOperator *op) -{ - int type = RNA_enum_get(op->ptr, "group"); - ViewContext vc; - view3d_set_viewcontext(C, &vc); - - BLI_assert(type + 1 >= 0); - vc.obact->actdef = type + 1; - - DAG_id_tag_update(&vc.obact->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, vc.obact); - return OPERATOR_FINISHED; -} - -/* TODO, we could make this a menu into OBJECT_OT_vertex_group_set_active rather than its own operator */ -void PAINT_OT_weight_sample_group(wmOperatorType *ot) -{ - PropertyRNA *prop = NULL; - - /* identifiers */ - ot->name = "Weight Paint Sample Group"; - ot->idname = "PAINT_OT_weight_sample_group"; - ot->description = "Select one of the vertex groups available under current mouse position"; - - /* api callbacks */ - ot->exec = weight_sample_group_exec; - ot->invoke = WM_menu_invoke; - ot->poll = weight_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_UNDO; - - /* keyingset to use (dynamic enum) */ - prop = RNA_def_enum(ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); - RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; -} - static void do_weight_paint_normalize_all(MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap) { float sum = 0.0f, fac; - unsigned int i, tot = 0; + uint i, tot = 0; MDeformWeight *dw; for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) { @@ -1291,7 +396,7 @@ static bool do_weight_paint_normalize_all_locked( float sum = 0.0f, fac; float sum_unlock = 0.0f; float lock_weight = 0.0f; - unsigned int i, tot = 0; + uint i, tot = 0; MDeformWeight *dw; if (lock_flags == NULL) { @@ -1476,7 +581,7 @@ static void multipaint_apply_change(MDeformVert *dvert, const int defbase_tot, f * Variables stored both for 'active' and 'mirror' sides. */ struct WeightPaintGroupData { - /** index of active group or its mirror + /** index of active group or its mirror * * - 'active' is always `ob->actdef`. * - 'mirror' is -1 when 'ME_EDIT_MIRROR_X' flag id disabled, @@ -1524,14 +629,14 @@ static void do_weight_paint_vertex_single( /* vars which remain the same for every vert */ VPaint *wp, Object *ob, const WeightPaintInfo *wpi, /* vars which change on each stroke */ - const unsigned int index, float alpha, float paintweight + const uint index, float alpha, float paintweight ) { Mesh *me = ob->data; MDeformVert *dv = &me->dvert[index]; bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; - - MDeformWeight *dw, *dw_prev; + + MDeformWeight *dw; /* mirror vars */ int index_mirr; @@ -1542,14 +647,12 @@ static void do_weight_paint_vertex_single( if (wp->flag & VP_ONLYVGROUP) { dw = defvert_find_index(dv, wpi->active.index); - dw_prev = defvert_find_index(wp->wpaint_prev + index, wpi->active.index); } else { dw = defvert_verify_index(dv, wpi->active.index); - dw_prev = defvert_verify_index(wp->wpaint_prev + index, wpi->active.index); } - if (dw == NULL || dw_prev == NULL) { + if (dw == NULL) { return; } @@ -1607,7 +710,7 @@ static void do_weight_paint_vertex_single( * then there is no need to run the more complicated checks */ { - dw->weight = wpaint_blend(wp, dw->weight, dw_prev->weight, alpha, paintweight, + dw->weight = wpaint_blend(wp, dw->weight, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip); /* WATCH IT: take care of the ordering of applying mirror -> normalize, @@ -1669,11 +772,10 @@ static void do_weight_paint_vertex_multi( /* vars which remain the same for every vert */ VPaint *wp, Object *ob, const WeightPaintInfo *wpi, /* vars which change on each stroke */ - const unsigned int index, float alpha, float paintweight) + const uint index, float alpha, float paintweight) { Mesh *me = ob->data; MDeformVert *dv = &me->dvert[index]; - MDeformVert *dv_prev = &wp->wpaint_prev[index]; bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; /* mirror vars */ @@ -1681,7 +783,7 @@ static void do_weight_paint_vertex_multi( MDeformVert *dv_mirr = NULL; /* weights */ - float oldw, curw, neww, change, curw_mirr, change_mirr; + float curw, neww, change, curw_mirr, change_mirr; /* from now on we can check if mirrors enabled if this var is -1 and not bother with the flag */ if (me->editflag & ME_EDIT_MIRROR_X) { @@ -1693,8 +795,6 @@ static void do_weight_paint_vertex_multi( } /* compute weight change by applying the brush to average or sum of group weights */ - oldw = BKE_defvert_multipaint_collective_weight( - dv_prev, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize); curw = BKE_defvert_multipaint_collective_weight( dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize); @@ -1703,7 +803,7 @@ static void do_weight_paint_vertex_multi( return; } - neww = wpaint_blend(wp, curw, oldw, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip); + neww = wpaint_blend(wp, curw, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip); change = neww / curw; @@ -1759,7 +859,7 @@ static void do_weight_paint_vertex( /* vars which remain the same for every vert */ VPaint *wp, Object *ob, const WeightPaintInfo *wpi, /* vars which change on each stroke */ - const unsigned int index, float alpha, float paintweight) + const uint index, float alpha, float paintweight) { if (wpi->do_multipaint) { do_weight_paint_vertex_multi(wp, ob, wpi, index, alpha, paintweight); @@ -1769,6 +869,103 @@ static void do_weight_paint_vertex( } } + +/* Toggle operator for turning vertex paint mode on or off (copied from sculpt.c) */ +static void vertex_paint_init_session(Scene *scene, Object *ob) +{ + if (ob->sculpt == NULL) { + ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); + BKE_sculpt_update_mesh_elements(scene, scene->toolsettings->sculpt, ob, 0, false); + } +} + +static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob) +{ + /* Create maps */ + struct SculptVertexPaintGeomMap *gmap = NULL; + const Brush *brush = NULL; + if (ob->mode == OB_MODE_VERTEX_PAINT) { + gmap = &ob->sculpt->mode.vpaint.gmap; + brush = BKE_paint_brush(&ts->vpaint->paint); + ob->sculpt->mode_type = OB_MODE_VERTEX_PAINT; + } + else if (ob->mode == OB_MODE_WEIGHT_PAINT) { + gmap = &ob->sculpt->mode.wpaint.gmap; + brush = BKE_paint_brush(&ts->wpaint->paint); + ob->sculpt->mode_type = OB_MODE_WEIGHT_PAINT; + } + else { + ob->sculpt->mode_type = 0; + BLI_assert(0); + return; + } + + Mesh *me = ob->data; + + if (gmap->vert_to_loop == NULL) { + gmap->vert_map_mem = NULL; + gmap->vert_to_loop = NULL; + gmap->poly_map_mem = NULL; + gmap->vert_to_poly = NULL; + BKE_mesh_vert_loop_map_create( + &gmap->vert_to_loop, + &gmap->vert_map_mem, + me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop); + BKE_mesh_vert_poly_map_create( + &gmap->vert_to_poly, + &gmap->poly_map_mem, + me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop); + } + + /* Create average brush arrays */ + if (ob->mode == OB_MODE_VERTEX_PAINT) { + if ((ts->vpaint->flag & VP_SPRAY) == 0) { + if (ob->sculpt->mode.vpaint.previous_color == NULL) { + ob->sculpt->mode.vpaint.previous_color = + MEM_callocN(me->totloop * sizeof(uint), __func__); + } + } + else { + MEM_SAFE_FREE(ob->sculpt->mode.vpaint.previous_color); + } + + if (brush && brush->flag & BRUSH_ACCUMULATE) { + if (ob->sculpt->mode.vpaint.previous_accum == NULL) { + ob->sculpt->mode.vpaint.previous_accum = + MEM_callocN(me->totloop * sizeof(float), __func__); + } + } + else { + MEM_SAFE_FREE(ob->sculpt->mode.vpaint.previous_accum); + } + } + else if (ob->mode == OB_MODE_WEIGHT_PAINT) { + if ((ts->wpaint->flag & VP_SPRAY) == 0) { + if (ob->sculpt->mode.wpaint.alpha_weight == NULL) { + ob->sculpt->mode.wpaint.alpha_weight = + MEM_callocN(me->totvert * sizeof(float), __func__); + } + if (ob->sculpt->mode.wpaint.previous_weight == NULL) { + ob->sculpt->mode.wpaint.previous_weight = + MEM_mallocN(me->totvert * sizeof(float), __func__); + } + } + else { + MEM_SAFE_FREE(ob->sculpt->mode.wpaint.alpha_weight); + } + if (brush && brush->flag & BRUSH_ACCUMULATE) { + if (ob->sculpt->mode.wpaint.previous_accum == NULL) { + ob->sculpt->mode.wpaint.previous_accum = + MEM_callocN(me->totvert * sizeof(float), __func__); + } + } + else { + MEM_SAFE_FREE(ob->sculpt->mode.wpaint.previous_accum); + } + } + +} + /* *************** set wpaint operator ****************** */ /** @@ -1805,6 +1002,14 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e'); ED_mesh_mirror_topo_table(NULL, NULL, 'e'); + /* If the cache is not released by a cancel or a done, free it now. */ + if (ob->sculpt->cache) { + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; + } + + BKE_sculptsession_free(ob); + paint_cursor_delete_textures(); } else { @@ -1820,6 +1025,12 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) /* weight paint specific */ ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's'); ED_vgroup_sync_from_pose(ob); + + /* Create vertex/weight paint mode session data */ + if (ob->sculpt) { + BKE_sculptsession_free(ob); + } + vertex_paint_init_session(scene, ob); } /* Weightpaint works by overriding colors in mesh, @@ -1866,18 +1077,8 @@ void PAINT_OT_weight_paint_toggle(wmOperatorType *ot) /* ************ weight paint operator ********** */ -enum eWPaintFlag { - WPAINT_ENSURE_MIRROR = (1 << 0), -}; - -struct WPaintVGroupIndex { - int active; - int mirror; -}; - struct WPaintData { ViewContext vc; - int *indexar; struct WeightPaintGroupData active, mirror; @@ -1895,110 +1096,136 @@ struct WPaintData { int defbase_tot_sel; /* number of selected groups */ bool do_multipaint; /* true if multipaint enabled and multiple groups selected */ - /* variables for blur */ - struct { - MeshElemMap *vmap; - int *vmap_mem; - } blur_data; - - BLI_Stack *accumulate_stack; /* for reuse (WPaintDefer) */ - int defbase_tot; }; -/* ensure we have data on wpaint start, add if needed */ -static bool wpaint_ensure_data( - bContext *C, wmOperator *op, - enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index) +/* Initialize the stroke cache invariants from operator properties */ +static void vwpaint_update_cache_invariants( + bContext *C, VPaint *vd, SculptSession *ss, wmOperator *op, const float mouse[2]) { + StrokeCache *cache; Scene *scene = CTX_data_scene(C); + UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; + Brush *brush = BKE_paint_brush(&vd->paint); + ViewContext *vc = paint_stroke_view_context(op->customdata); Object *ob = CTX_data_active_object(C); - Mesh *me = BKE_mesh_from_object(ob); + float mat[3][3]; + float view_dir[3] = {0.0f, 0.0f, 1.0f}; + int mode; - if (vgroup_index) { - vgroup_index->active = -1; - vgroup_index->mirror = -1; + /* VW paint needs to allocate stroke cache before update is called. */ + if (!ss->cache) { + cache = MEM_callocN(sizeof(StrokeCache), "stroke cache"); + ss->cache = cache; } - - if (scene->obedit) { - return false; + else { + cache = ss->cache; } - if (me == NULL || me->totpoly == 0) { - return false; - } + /* Initial mouse location */ + if (mouse) + copy_v2_v2(cache->initial_mouse, mouse); + else + zero_v2(cache->initial_mouse); - /* if nothing was added yet, we make dverts and a vertex deform group */ - if (!me->dvert) { - BKE_object_defgroup_data_create(&me->id); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); - } + mode = RNA_enum_get(op->ptr, "mode"); + cache->invert = mode == BRUSH_STROKE_INVERT; + cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH; + /* not very nice, but with current events system implementation + * we can't handle brush appearance inversion hotkey separately (sergey) */ + if (cache->invert) ups->draw_inverted = true; + else ups->draw_inverted = false; - /* this happens on a Bone select, when no vgroup existed yet */ - if (ob->actdef <= 0) { - Object *modob; - if ((modob = modifiers_isDeformedByArmature(ob))) { - Bone *actbone = ((bArmature *)modob->data)->act_bone; - if (actbone) { - bPoseChannel *pchan = BKE_pose_channel_find_name(modob->pose, actbone->name); + copy_v2_v2(cache->mouse, cache->initial_mouse); + /* Truly temporary data that isn't stored in properties */ + cache->vc = vc; + cache->brush = brush; + cache->first_time = 1; - if (pchan) { - bDeformGroup *dg = defgroup_find_name(ob, pchan->name); - if (dg == NULL) { - dg = BKE_object_defgroup_add_name(ob, pchan->name); /* sets actdef */ - } - else { - int actdef = 1 + BLI_findindex(&ob->defbase, dg); - BLI_assert(actdef >= 0); - ob->actdef = actdef; - } - } - } - } - } - if (BLI_listbase_is_empty(&ob->defbase)) { - BKE_object_defgroup_add(ob); - } + /* cache projection matrix */ + ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat); - /* ensure we don't try paint onto an invalid group */ - if (ob->actdef <= 0) { - BKE_report(op->reports, RPT_WARNING, "No active vertex group for painting, aborting"); - return false; + invert_m4_m4(ob->imat, ob->obmat); + copy_m3_m4(mat, cache->vc->rv3d->viewinv); + mul_m3_v3(mat, view_dir); + copy_m3_m4(mat, ob->imat); + mul_m3_v3(mat, view_dir); + normalize_v3_v3(cache->true_view_normal, view_dir); + + copy_v3_v3(cache->view_normal, cache->true_view_normal); + cache->bstrength = BKE_brush_alpha_get(scene, brush); + cache->is_last_valid = false; +} + +/* Initialize the stroke cache variants from operator properties */ +static void vwpaint_update_cache_variants(bContext *C, VPaint *vd, Object *ob, PointerRNA *ptr) +{ + Scene *scene = CTX_data_scene(C); + SculptSession *ss = ob->sculpt; + StrokeCache *cache = ss->cache; + Brush *brush = BKE_paint_brush(&vd->paint); + + /* This effects the actual brush radius, so things farther away + * are compared with a larger radius and vise versa. */ + if (cache->first_time) { + RNA_float_get_array(ptr, "location", cache->true_location); } - if (vgroup_index) { - vgroup_index->active = ob->actdef - 1; + RNA_float_get_array(ptr, "mouse", cache->mouse); + + /* XXX: Use pressure value from first brush step for brushes which don't + * support strokes (grab, thumb). They depends on initial state and + * brush coord/pressure/etc. + * It's more an events design issue, which doesn't split coordinate/pressure/angle + * changing events. We should avoid this after events system re-design */ + if (paint_supports_dynamic_size(brush, ePaintSculpt) || cache->first_time) { + cache->pressure = RNA_float_get(ptr, "pressure"); } - if (flag & WPAINT_ENSURE_MIRROR) { - if (me->editflag & ME_EDIT_MIRROR_X) { - int mirror = wpaint_mirror_vgroup_ensure(ob, ob->actdef - 1); - if (vgroup_index) { - vgroup_index->mirror = mirror; - } + /* Truly temporary data that isn't stored in properties */ + if (cache->first_time) { + if (!BKE_brush_use_locked_size(scene, brush)) { + cache->initial_radius = paint_calc_object_space_radius( + cache->vc, cache->true_location, BKE_brush_size_get(scene, brush)); + BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius); + } + else { + cache->initial_radius = BKE_brush_unprojected_radius_get(scene, brush); } } - return true; + if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, ePaintSculpt)) { + cache->radius = cache->initial_radius * cache->pressure; + } + else { + cache->radius = cache->initial_radius; + } + + cache->radius_squared = cache->radius * cache->radius; + + if (ss->pbvh) { + BKE_pbvh_update(ss->pbvh, PBVH_UpdateRedraw, NULL); + BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL); + } } -static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNUSED(mouse[2])) +static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2]) { Scene *scene = CTX_data_scene(C); struct PaintStroke *stroke = op->customdata; ToolSettings *ts = scene->toolsettings; - VPaint *wp = ts->wpaint; Object *ob = CTX_data_active_object(C); Mesh *me = BKE_mesh_from_object(ob); struct WPaintData *wpd; struct WPaintVGroupIndex vgroup_index; int defbase_tot, defbase_tot_sel; bool *defbase_sel; - const Brush *brush = BKE_paint_brush(&wp->paint); + SculptSession *ss = ob->sculpt; + VPaint *vd = CTX_data_tool_settings(C)->wpaint; float mat[4][4], imat[4][4]; - if (wpaint_ensure_data(C, op, WPAINT_ENSURE_MIRROR, &vgroup_index) == false) { + if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, &vgroup_index) == false) { return false; } @@ -2094,62 +1321,483 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UN } /* painting on subsurfs should give correct points too, this returns me->totvert amount */ + ob->sculpt->building_vp_handle = true; wpd->vp_handle = ED_vpaint_proj_handle_create(scene, ob, &wpd->vertexcosnos); - - wpd->indexar = get_indexarray(me); - copy_wpaint_prev(wp, me->dvert, me->totvert); - - if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { - BKE_mesh_vert_edge_vert_map_create( - &wpd->blur_data.vmap, &wpd->blur_data.vmap_mem, - me->medge, me->totvert, me->totedge); - } - - if ((brush->vertexpaint_tool == PAINT_BLEND_BLUR) && - (brush->flag & BRUSH_ACCUMULATE)) - { - wpd->accumulate_stack = BLI_stack_new(sizeof(struct WPaintDefer), __func__); - } + ob->sculpt->building_vp_handle = false; /* imat for normals */ mul_m4_m4m4(mat, wpd->vc.rv3d->viewmat, ob->obmat); invert_m4_m4(imat, mat); copy_m3_m4(wpd->wpimat, imat); + /* If not previously created, create vertex/weight paint mode session data */ + vertex_paint_init_session(scene, ob); + vwpaint_update_cache_invariants(C, vd, ss, op, mouse); + vertex_paint_init_session_data(ts, ob); + + if (ss->mode.wpaint.previous_weight != NULL) { + copy_vn_fl(ss->mode.wpaint.previous_weight, me->totvert, -1.0f); + } + return true; } -static float wpaint_blur_weight_single(const MDeformVert *dv, const WeightPaintInfo *wpi) +static float dot_vf3vs3(const float brushNormal[3], const short vertexNormal[3]) { - return defvert_find_weight(dv, wpi->active.index); + float normal[3]; + normal_short_to_float_v3(normal, vertexNormal); + return dot_v3v3(brushNormal, normal); } -static float wpaint_blur_weight_multi(const MDeformVert *dv, const WeightPaintInfo *wpi) +static void get_brush_alpha_data( + Scene *scene, SculptSession *ss, Brush *brush, + float *r_brush_size_pressure, float *r_brush_alpha_value, float *r_brush_alpha_pressure) { - float weight = BKE_defvert_multipaint_collective_weight( - dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize); - CLAMP(weight, 0.0f, 1.0f); - return weight; + *r_brush_size_pressure = + BKE_brush_size_get(scene, brush) * + (BKE_brush_use_size_pressure(scene, brush) ? ss->cache->pressure : 1.0f); + *r_brush_alpha_value = + BKE_brush_alpha_get(scene, brush); + *r_brush_alpha_pressure = + (BKE_brush_use_alpha_pressure(scene, brush) ? ss->cache->pressure : 1.0f); } -static float wpaint_blur_weight_calc_from_connected( - const MDeformVert *dvert, WeightPaintInfo *wpi, struct WPaintData *wpd, const unsigned int vidx, - float (*blur_weight_func)(const MDeformVert *, const WeightPaintInfo *)) +static void do_wpaint_brush_blur_task_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) { - const MeshElemMap *map = &wpd->blur_data.vmap[vidx]; - float paintweight; - if (map->count != 0) { - paintweight = 0.0f; - for (int j = 0; j < map->count; j++) { - paintweight += blur_weight_func(&dvert[map->indices[j]], wpi); + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap; + + Brush *brush = data->brush; + StrokeCache *cache = ss->cache; + Scene *scene = CTX_data_scene(data->C); + + const float brush_strength = cache->bstrength; + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); + + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test_sq(&test, vd.co)) { + /* For grid based pbvh, take the vert whose loop coopresponds to the current grid. + * Otherwise, take the current vert. */ + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; + const char v_flag = data->me->mvert[v_index].flag; + /* If the vertex is selected */ + if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) { + /* Get the average poly weight */ + int total_hit_loops = 0; + float weight_final = 0.0f; + for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { + const int p_index = gmap->vert_to_poly[v_index].indices[j]; + const MPoly *mp = &data->me->mpoly[p_index]; + + total_hit_loops += mp->totloop; + for (int k = 0; k < mp->totloop; k++) { + const int l_index = mp->loopstart + k; + const MLoop *ml = &data->me->mloop[l_index]; + const MDeformVert *dv = &data->me->dvert[ml->v]; + weight_final += defvert_find_weight(dv, data->wpi->active.index); + } + } + + /* Apply the weight to the vertex. */ + if (total_hit_loops != 0) { + const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; + if (view_dot > 0.0f) { + const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius); + float final_alpha = + view_dot * brush_fade * brush_strength * + grid_alpha * brush_alpha_pressure; + + if (brush->flag & BRUSH_ACCUMULATE) { + float mask_accum = ss->mode.wpaint.previous_accum[v_index]; + final_alpha = min_ff(final_alpha + mask_accum, brush_strength); + ss->mode.wpaint.previous_accum[v_index] = final_alpha; + } + + weight_final /= total_hit_loops; + /* Only paint visable verts */ + do_weight_paint_vertex( + data->vp, data->ob, data->wpi, + v_index, final_alpha, weight_final); + } + } + } } - paintweight /= map->count; } - else { - paintweight = blur_weight_func(&dvert[vidx], wpi); + BKE_pbvh_vertex_iter_end; +} + +static void do_wpaint_brush_smear_task_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap; + + Brush *brush = data->brush; + Scene *scene = CTX_data_scene(data->C); + StrokeCache *cache = ss->cache; + const float brush_strength = cache->bstrength; + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + float brush_dir[3]; + + sub_v3_v3v3(brush_dir, cache->location, cache->last_location); + project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal); + + if (normalize_v3(brush_dir) != 0.0f) { + + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); + + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test_fast(&test, vd.co)) { + const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; + if (view_dot > 0.0f) { + bool do_color = false; + + /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. + * Otherwise, take the current vert. */ + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; + const MVert *mv_curr = &data->me->mvert[v_index]; + + /* If the vertex is selected */ + if (!(use_face_sel || use_vert_sel) || mv_curr->flag & SELECT) { + /* Minimum dot product between brush direction and current + * to neighbor direction is 0.0, meaning orthogonal. */ + float stroke_dot_max = 0.0f; + + /* Get the color of the loop in the opposite direction of the brush movement + * (this callback is specifically for smear.) */ + float weight_final = 0.0; + for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { + const int p_index = gmap->vert_to_poly[v_index].indices[j]; + const MPoly *mp = &data->me->mpoly[p_index]; + const MLoop *ml_other = &data->me->mloop[mp->loopstart]; + for (int k = 0; k < mp->totloop; k++, ml_other++) { + const uint v_other_index = ml_other->v; + if (v_other_index != v_index) { + const MVert *mv_other = &data->me->mvert[v_other_index]; + + /* Get the direction from the selected vert to the neighbor. */ + float other_dir[3]; + sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co); + project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal); + + normalize_v3(other_dir); + + const float stroke_dot = dot_v3v3(other_dir, brush_dir); + + if (stroke_dot > stroke_dot_max) { + stroke_dot_max = stroke_dot; + MDeformVert *dv = &data->me->dvert[v_other_index]; + weight_final = defvert_find_weight(dv, data->wpi->active.index); + do_color = true; + } + } + } + } + /* Apply weight to vertex */ + if (do_color) { + const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); + const float final_alpha = + view_dot * brush_fade * brush_strength * + grid_alpha * brush_alpha_pressure; + do_weight_paint_vertex( + data->vp, data->ob, data->wpi, + v_index, final_alpha, (float)weight_final); + } + } + } + } + } + BKE_pbvh_vertex_iter_end; + } +} + +static void do_wpaint_brush_draw_task_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + Scene *scene = CTX_data_scene(data->C); + + Brush *brush = data->brush; + StrokeCache *cache = ss->cache; + const float brush_strength = cache->bstrength; + const float paintweight = BKE_brush_weight_get(scene, brush); + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); + + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test_sq(&test, vd.co)) { + /* Note: grids are 1:1 with corners (aka loops). + * For multires, take the vert whose loop cooresponds to the current grid. + * Otherwise, take the current vert. */ + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; + + const char v_flag = data->me->mvert[v_index].flag; + /* If the vertex is selected */ + if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) { + const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; + if (view_dot > 0.0f) { + const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius); + float final_alpha = view_dot * brush_fade * brush_strength * grid_alpha * brush_alpha_pressure; + + if (brush->flag & BRUSH_ACCUMULATE) { + float mask_accum = ss->mode.wpaint.previous_accum[v_index]; + final_alpha = min_ff(final_alpha + mask_accum, brush_strength); + ss->mode.wpaint.previous_accum[v_index] = final_alpha; + } + + /* Non-spray logic. */ + if ((data->vp->flag & VP_SPRAY) == 0) { + /* Only paint if we have greater alpha. */ + if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) { + ss->mode.wpaint.alpha_weight[v_index] = final_alpha; + } + else { + continue; + } + + MDeformVert *dv = &data->me->dvert[v_index]; + MDeformWeight *dw = defvert_find_index(dv, data->wpi->active.index); + float *weight_prev = &ss->mode.wpaint.previous_weight[v_index]; + defweight_prev_init(dw, weight_prev); + if (dw) { + dw->weight = *weight_prev; + } + } + + do_weight_paint_vertex( + data->vp, data->ob, data->wpi, + v_index, final_alpha, paintweight); + } + } + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_wpaint_brush_calc_average_weight_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + StrokeCache *cache = ss->cache; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + + const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + + struct WPaintAverageAccum *accum = (struct WPaintAverageAccum *)data->custom_data + n; + accum->len = 0; + accum->value = 0.0; + + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); + + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test_sq(&test, vd.co)) { + const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; + if (view_dot > 0.0 && BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) { + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + // const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; + const char v_flag = data->me->mvert[v_index].flag; + + /* If the vertex is selected. */ + if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) { + const MDeformVert *dv = &data->me->dvert[v_index]; + accum->len += 1; + accum->value += defvert_find_weight(dv, data->wpi->active.index); + } + } + } + } + BKE_pbvh_vertex_iter_end; +} + +static void calculate_average_weight(SculptThreadedTaskData *data, PBVHNode **UNUSED(nodes), int totnode) +{ + Scene *scene = CTX_data_scene(data->C); + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; + + struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); + data->custom_data = accum; + + BLI_task_parallel_range_ex( + 0, totnode, data, NULL, 0, do_wpaint_brush_calc_average_weight_cb_ex, + ((data->sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + + uint accum_len = 0; + double accum_weight = 0.0; + for (int i = 0; i < totnode; i++) { + accum_len += accum[i].len; + accum_weight += accum[i].value; + } + if (accum_len != 0) { + accum_weight /= accum_len; + if (ups->flag & UNIFIED_PAINT_WEIGHT) + ups->weight = (float)accum_weight; + else + data->brush->weight = (float)accum_weight; } - return paintweight; + MEM_SAFE_FREE(data->custom_data); /* 'accum' */ +} + + +static void wpaint_paint_leaves( + bContext *C, Object *ob, Sculpt *sd, VPaint *vp, struct WPaintData *wpd, WeightPaintInfo *wpi, + Mesh *me, PBVHNode **nodes, int totnode) +{ + Brush *brush = ob->sculpt->cache->brush; + + /* threaded loop over nodes */ + SculptThreadedTaskData data = { + .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .wpd = wpd, .wpi = wpi, .me = me, .C = C, + }; + + switch (brush->vertexpaint_tool) { + case PAINT_BLEND_AVERAGE: + calculate_average_weight(&data, nodes, totnode); + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_wpaint_brush_draw_task_cb_ex, true, false); + break; + case PAINT_BLEND_SMEAR: + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_wpaint_brush_smear_task_cb_ex, true, false); + break; + case PAINT_BLEND_BLUR: + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_wpaint_brush_blur_task_cb_ex, true, false); + break; + default: + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_wpaint_brush_draw_task_cb_ex, true, false); + break; + } +} + +static void wpaint_do_paint( + bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi, + Mesh *me, Brush *brush, const char symm, const int axis, const int i, const float angle) +{ + SculptSession *ss = ob->sculpt; + ss->cache->radial_symmetry_pass = i; + sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle); + + SculptSearchSphereData data; + PBVHNode **nodes = NULL; + int totnode; + + + /* Build a list of all nodes that are potentially within the brush's area of influence */ + data.ss = ss; + data.sd = sd; + data.radius_squared = ss->cache->radius_squared; + data.original = true; + BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); + + sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, true, ss->cache->sculpt_normal_symm); + wpaint_paint_leaves(C, ob, sd, wp, wpd, wpi, me, nodes, totnode); + + if (nodes) + MEM_freeN(nodes); +} + +static void wpaint_do_radial_symmetry( + bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi, + Mesh *me, Brush *brush, const char symm, const int axis) +{ + for (int i = 1; i < wp->radial_symm[axis - 'X']; i++) { + const float angle = (2.0 * M_PI) * i / wp->radial_symm[axis - 'X']; + wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, symm, axis, i, angle); + } +} + +/* near duplicate of: sculpt.c's, 'do_symmetrical_brush_actions' and 'vpaint_do_symmetrical_brush_actions'. */ +static void wpaint_do_symmetrical_brush_actions( + bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi) +{ + Brush *brush = BKE_paint_brush(&wp->paint); + Mesh *me = ob->data; + SculptSession *ss = ob->sculpt; + StrokeCache *cache = ss->cache; + const char symm = wp->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + int i = 0; + + /* initial stroke */ + wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X', 0, 0); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X'); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Y'); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Z'); + + cache->symmetry = symm; + + /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ + for (i = 1; i <= symm; i++) { + if ((symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) { + cache->mirror_symmetry_pass = i; + cache->radial_symmetry_pass = 0; + sculpt_cache_calc_brushdata_symm(cache, i, 0, 0); + + if (i & (1 << 0)) { + wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X', 0, 0); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X'); + } + if (i & (1 << 1)) { + wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y', 0, 0); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y'); + } + if (i & (1 << 2)) { + wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z', 0, 0); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z'); + } + } + } + copy_v3_v3(cache->true_last_location, cache->true_location); + cache->is_last_valid = true; } static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) @@ -2160,24 +1808,17 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P Brush *brush = BKE_paint_brush(&wp->paint); struct WPaintData *wpd = paint_stroke_mode_data(stroke); ViewContext *vc; - Object *ob; - Mesh *me; + Object *ob = CTX_data_active_object(C); + + SculptSession *ss = ob->sculpt; + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + + vwpaint_update_cache_variants(C, wp, ob, itemptr); + float mat[4][4]; - float paintweight; - int *indexar; - unsigned int index, totindex; float mval[2]; - const bool use_blur = (brush->vertexpaint_tool == PAINT_BLEND_BLUR); - bool use_vert_sel; - bool use_face_sel; - bool use_depth; - - const float pressure = RNA_float_get(itemptr, "pressure"); - const float brush_size_pressure = - BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f); + const float brush_alpha_value = BKE_brush_alpha_get(scene, brush); - const float brush_alpha_pressure = - brush_alpha_value * (BKE_brush_use_alpha_pressure(scene, brush) ? pressure : 1.0f); /* intentionally don't initialize as NULL, make sure we initialize all members below */ WeightPaintInfo wpi; @@ -2190,13 +1831,8 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P return; } - float (*blur_weight_func)(const MDeformVert *, const WeightPaintInfo *) = - wpd->do_multipaint ? wpaint_blur_weight_multi : wpaint_blur_weight_single; - vc = &wpd->vc; ob = vc->obact; - me = ob->data; - indexar = wpd->indexar; view3d_operator_needs_opengl(C); ED_view3d_init_mats_rv3d(ob, vc->rv3d); @@ -2204,7 +1840,6 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P /* load projection matrix */ mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); - RNA_float_get_array(itemptr, "mouse", mval); /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */ wpi.defbase_tot = wpd->defbase_tot; @@ -2222,180 +1857,49 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P wpi.brush_alpha_value = brush_alpha_value; /* *** done setting up WeightPaintInfo *** */ + wpaint_do_symmetrical_brush_actions(C, ob, wp, sd, wpd, &wpi); + swap_m4m4(vc->rv3d->persmat, mat); - swap_m4m4(wpd->vc.rv3d->persmat, mat); - - use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; - use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - use_depth = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0; - - /* which faces are involved */ - if (use_depth) { - char editflag_prev = me->editflag; - - /* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */ - me->editflag &= ~ME_EDIT_PAINT_VERT_SEL; - if (use_vert_sel) { - /* Ugly x2, we need this so hidden faces don't draw */ - me->editflag |= ME_EDIT_PAINT_FACE_SEL; - } - totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure); - me->editflag = editflag_prev; - - if (use_face_sel && me->totpoly) { - MPoly *mpoly = me->mpoly; - for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mp = &mpoly[indexar[index] - 1]; - - if ((mp->flag & ME_FACE_SEL) == 0) { - indexar[index] = 0; - } - } - } - } - } - else { - indexar = NULL; - } - - /* incase we have modifiers */ - ED_vpaint_proj_handle_update(wpd->vp_handle, vc->ar, mval); - - /* make sure each vertex gets treated only once */ - /* and calculate filter weight */ - paintweight = BKE_brush_weight_get(scene, brush); + /* calculate pivot for rotation around seletion if needed */ + /* also needed for "View Selected" on last stroke */ + paint_last_stroke_update(scene, vc->ar, mval); - if (use_depth) { - for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mpoly = me->mpoly + (indexar[index] - 1); - MLoop *ml = me->mloop + mpoly->loopstart; - int i; + DAG_id_tag_update(ob->data, 0); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + swap_m4m4(wpd->vc.rv3d->persmat, mat); - if (use_vert_sel) { - for (i = 0; i < mpoly->totloop; i++, ml++) { - me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT); - } - } - else { - for (i = 0; i < mpoly->totloop; i++, ml++) { - me->dvert[ml->v].flag = 1; - } - } - } + rcti r; + if (sculpt_get_redraw_rect(vc->ar, CTX_wm_region_view3d(C), ob, &r)) { + if (ss->cache) { + ss->cache->current_r = r; } - } - else { - const unsigned int totvert = me->totvert; - unsigned int i; - /* in the case of face selection we need to flush */ - if (use_vert_sel || use_face_sel) { - for (i = 0; i < totvert; i++) { - me->dvert[i].flag = me->mvert[i].flag & SELECT; - } - } - else { - for (i = 0; i < totvert; i++) { - me->dvert[i].flag = SELECT; - } + /* previous is not set in the current cache else + * the partial rect will always grow */ + if (ss->cache) { + if (!BLI_rcti_is_empty(&ss->cache->previous_r)) + BLI_rcti_union(&r, &ss->cache->previous_r); } - } - /* accumulate means we refer to the previous, - * which is either the last update, or when we started painting */ - BLI_Stack *accumulate_stack = wpd->accumulate_stack; - const bool use_accumulate = (accumulate_stack != NULL); - BLI_assert(accumulate_stack == NULL || BLI_stack_is_empty(accumulate_stack)); - - const MDeformVert *dvert_prev = use_accumulate ? me->dvert : wp->wpaint_prev; - -#define WP_PAINT(v_idx_var) \ - { \ - unsigned int vidx = v_idx_var; \ - if (me->dvert[vidx].flag) { \ - const float alpha = calc_vp_alpha_col_dl( \ - wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \ - mval, brush_size_pressure, brush_alpha_pressure, NULL); \ - if (alpha) { \ - if (use_blur) { \ - paintweight = wpaint_blur_weight_calc_from_connected( \ - dvert_prev, &wpi, wpd, vidx, blur_weight_func); \ - } \ - if (use_accumulate) { \ - struct WPaintDefer *dweight = BLI_stack_push_r(accumulate_stack); \ - dweight->index = vidx; \ - dweight->alpha = alpha; \ - dweight->weight = paintweight; \ - } \ - else { \ - do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \ - } \ - } \ - me->dvert[vidx].flag = 0; \ - } \ - } (void)0 - - if (use_depth) { - for (index = 0; index < totindex; index++) { - - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mpoly = me->mpoly + (indexar[index] - 1); - MLoop *ml = me->mloop + mpoly->loopstart; - int i; - - for (i = 0; i < mpoly->totloop; i++, ml++) { - WP_PAINT(ml->v); - } - } - } - } - else { - const unsigned int totvert = me->totvert; - unsigned int i; - - for (i = 0; i < totvert; i++) { - WP_PAINT(i); - } - } -#undef WP_PAINT + r.xmin += vc->ar->winrct.xmin - 2; + r.xmax += vc->ar->winrct.xmin + 2; + r.ymin += vc->ar->winrct.ymin - 2; + r.ymax += vc->ar->winrct.ymin + 2; - if (use_accumulate) { - unsigned int defer_count = BLI_stack_count(accumulate_stack); - while (defer_count--) { - struct WPaintDefer *dweight = BLI_stack_peek(accumulate_stack); - do_weight_paint_vertex(wp, ob, &wpi, dweight->index, dweight->alpha, dweight->weight); - BLI_stack_discard(accumulate_stack); - } + ss->partial_redraw = 1; } - - - /* *** free wpi members */ - /* *** done freeing wpi members */ - - - swap_m4m4(vc->rv3d->persmat, mat); - - /* calculate pivot for rotation around seletion if needed */ - /* also needed for "View Selected" on last stroke */ - paint_last_stroke_update(scene, vc->ar, mval); - - DAG_id_tag_update(ob->data, 0); - ED_region_tag_redraw(vc->ar); + ED_region_tag_redraw_partial(vc->ar, &r); } static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) { - ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); struct WPaintData *wpd = paint_stroke_mode_data(stroke); if (wpd) { ED_vpaint_proj_handle_free(wpd->vp_handle); - MEM_freeN(wpd->indexar); - + if (wpd->defbase_sel) MEM_freeN((void *)wpd->defbase_sel); if (wpd->vgroup_validmap) @@ -2407,23 +1911,9 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) if (wpd->mirror.lock) MEM_freeN((void *)wpd->mirror.lock); - if (wpd->blur_data.vmap) { - MEM_freeN(wpd->blur_data.vmap); - } - if (wpd->blur_data.vmap_mem) { - MEM_freeN(wpd->blur_data.vmap_mem); - } - - if (wpd->accumulate_stack) { - BLI_stack_free(wpd->accumulate_stack); - } - MEM_freeN(wpd); } - /* frees prev buffer */ - copy_wpaint_prev(ts->wpaint, NULL, 0); - /* and particles too */ if (ob->particlesystem.first) { ParticleSystem *psys; @@ -2442,6 +1932,9 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) DAG_id_tag_update(ob->data, 0); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; } @@ -2449,9 +1942,10 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int retval; - op->customdata = paint_stroke_new(C, op, NULL, wpaint_stroke_test_start, - wpaint_stroke_update_step, NULL, - wpaint_stroke_done, event->type); + op->customdata = paint_stroke_new( + C, op, sculpt_stroke_get_location, wpaint_stroke_test_start, + wpaint_stroke_update_step, NULL, + wpaint_stroke_done, event->type); if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { paint_stroke_data_free(op); @@ -2468,9 +1962,10 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) static int wpaint_exec(bContext *C, wmOperator *op) { - op->customdata = paint_stroke_new(C, op, NULL, wpaint_stroke_test_start, - wpaint_stroke_update_step, NULL, - wpaint_stroke_done, 0); + op->customdata = paint_stroke_new( + C, op, sculpt_stroke_get_location, wpaint_stroke_test_start, + wpaint_stroke_update_step, NULL, + wpaint_stroke_done, 0); /* frees op->customdata */ paint_stroke_exec(C, op); @@ -2480,6 +1975,12 @@ static int wpaint_exec(bContext *C, wmOperator *op) static void wpaint_cancel(bContext *C, wmOperator *op) { + Object *ob = CTX_data_active_object(C); + if (ob->sculpt->cache) { + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; + } + paint_stroke_cancel(C, op); } @@ -2504,42 +2005,6 @@ void PAINT_OT_weight_paint(wmOperatorType *ot) paint_stroke_operator_properties(ot); } -static int weight_paint_set_exec(bContext *C, wmOperator *op) -{ - struct Scene *scene = CTX_data_scene(C); - Object *obact = CTX_data_active_object(C); - ToolSettings *ts = CTX_data_tool_settings(C); - Brush *brush = BKE_paint_brush(&ts->wpaint->paint); - float vgroup_weight = BKE_brush_weight_get(scene, brush); - - if (wpaint_ensure_data(C, op, WPAINT_ENSURE_MIRROR, NULL) == false) { - return OPERATOR_CANCELLED; - } - - if (ED_wpaint_fill(scene->toolsettings->wpaint, obact, vgroup_weight)) { - ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */ - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -void PAINT_OT_weight_set(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Set Weight"; - ot->idname = "PAINT_OT_weight_set"; - ot->description = "Fill the active vertex group with the current paint weight"; - - /* api callbacks */ - ot->exec = weight_paint_set_exec; - ot->poll = mask_paint_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - /* ************ set / clear vertex paint mode ********** */ /** @@ -2569,15 +2034,24 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { BKE_mesh_flush_select_from_polys(me); } + else if (me->editflag & ME_EDIT_PAINT_VERT_SEL) { + BKE_mesh_flush_select_from_verts(me); + } + + /* If the cache is not released by a cancel or a done, free it now. */ + if (ob->sculpt->cache) { + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; + } + + BKE_sculptsession_free(ob); paint_cursor_delete_textures(); } else { ob->mode |= mode_flag; - if (me->mloopcol == NULL) { - make_vertexcol(ob); - } + ED_mesh_color_ensure(me, NULL); if (vp == NULL) vp = scene->toolsettings->vpaint = new_vpaint(0); @@ -2585,6 +2059,16 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) paint_cursor_start(C, vertex_paint_poll); BKE_paint_init(scene, ePaintVertex, PAINT_CURSOR_VERTEX_PAINT); + + /* Create vertex/weight paint mode session data */ + if (ob->sculpt) { + if (ob->sculpt->cache) { + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; + } + BKE_sculptsession_free(ob); + } + vertex_paint_init_session(scene, ob); } /* update modifier stack for mapping requirements */ @@ -2638,13 +2122,12 @@ typedef struct PolyFaceMap { int facenr; } PolyFaceMap; -typedef struct VPaintData { +struct VPaintData { ViewContext vc; - unsigned int paintcol; - int *indexar; + uint paintcol; struct VertProjHandle *vp_handle; - DMCoNo *vertexcosnos; + struct DMCoNo *vertexcosnos; float vpimat[3][3]; @@ -2657,9 +2140,9 @@ typedef struct VPaintData { bool *mlooptag; bool is_texbrush; -} VPaintData; +}; -static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float UNUSED(mouse[2])) +static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2]) { Scene *scene = CTX_data_scene(C); ToolSettings *ts = scene->toolsettings; @@ -2670,25 +2153,22 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f Object *ob = CTX_data_active_object(C); Mesh *me; float mat[4][4], imat[4][4]; + SculptSession *ss = ob->sculpt; /* context checks could be a poll() */ me = BKE_mesh_from_object(ob); if (me == NULL || me->totpoly == 0) return false; - if (me->mloopcol == NULL) - make_vertexcol(ob); + ED_mesh_color_ensure(me, NULL); if (me->mloopcol == NULL) return false; /* make mode data storage */ - vpd = MEM_callocN(sizeof(struct VPaintData), "VPaintData"); + vpd = MEM_callocN(sizeof(*vpd), "VPaintData"); paint_stroke_set_mode_data(stroke, vpd); view3d_set_viewcontext(C, &vpd->vc); - vpd->vp_handle = ED_vpaint_proj_handle_create(vpd->vc.scene, ob, &vpd->vertexcosnos); - - vpd->indexar = get_indexarray(me); vpd->paintcol = vpaint_get_current_col(scene, vp); vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) && @@ -2710,84 +2190,551 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f vpd->mlooptag = MEM_mallocN(sizeof(bool) * me->totloop, "VPaintData mlooptag"); } - /* for filtering */ - copy_vpaint_prev(vp, (unsigned int *)me->mloopcol, me->totloop); - + /* Create projection handle */ + if (vpd->is_texbrush) { + ob->sculpt->building_vp_handle = true; + vpd->vp_handle = ED_vpaint_proj_handle_create(scene, ob, &vpd->vertexcosnos); + ob->sculpt->building_vp_handle = false; + } + /* some old cruft to sort out later */ mul_m4_m4m4(mat, vpd->vc.rv3d->viewmat, ob->obmat); invert_m4_m4(imat, mat); copy_m3_m4(vpd->vpimat, imat); + /* If not previously created, create vertex/weight paint mode session data */ + vertex_paint_init_session(scene, ob); + vwpaint_update_cache_invariants(C, vp, ss, op, mouse); + vertex_paint_init_session_data(ts, ob); + + if (ob->sculpt->mode.vpaint.previous_color != NULL) { + memset(ob->sculpt->mode.vpaint.previous_color, 0, sizeof(uint) * me->totloop); + } + return 1; } -static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me, - const unsigned int index, const float mval[2], - const float brush_size_pressure, const float brush_alpha_pressure) +static void do_vpaint_brush_calc_average_color_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) { - ViewContext *vc = &vpd->vc; - Brush *brush = BKE_paint_brush(&vp->paint); - MPoly *mpoly = &me->mpoly[index]; - MLoop *ml; - unsigned int *lcol = ((unsigned int *)me->mloopcol) + mpoly->loopstart; - unsigned int *lcolorig = ((unsigned int *)vp->vpaint_prev) + mpoly->loopstart; - bool *mlooptag = (vpd->mlooptag) ? vpd->mlooptag + mpoly->loopstart : NULL; - float alpha; - int i, j; - int totloop = mpoly->totloop; + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; - int brush_alpha_pressure_i = (int)(brush_alpha_pressure * 255.0f); + StrokeCache *cache = ss->cache; + uint *lcol = data->lcol; + char *col; + const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; - if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { - unsigned int blend[4] = {0}; - unsigned int tcol; - char *col; - - for (j = 0; j < totloop; j++) { - col = (char *)(lcol + j); - blend[0] += col[0]; - blend[1] += col[1]; - blend[2] += col[2]; - blend[3] += col[3]; - } - - blend[0] = divide_round_i(blend[0], totloop); - blend[1] = divide_round_i(blend[1], totloop); - blend[2] = divide_round_i(blend[2], totloop); - blend[3] = divide_round_i(blend[3], totloop); - col = (char *)&tcol; - col[0] = blend[0]; - col[1] = blend[1]; - col[2] = blend[2]; - col[3] = blend[3]; - - vpd->paintcol = *((unsigned int *)col); - } - - ml = me->mloop + mpoly->loopstart; - for (i = 0; i < totloop; i++, ml++) { - float rgba[4]; - unsigned int paintcol; - alpha = calc_vp_alpha_col_dl(vp, vc, vpd->vpimat, - &vpd->vertexcosnos[ml->v], mval, - brush_size_pressure, brush_alpha_pressure, rgba); - - if (vpd->is_texbrush) { - float rgba_br[3]; - rgb_uchar_to_float(rgba_br, (const unsigned char *)&vpd->paintcol); - mul_v3_v3(rgba_br, rgba); - rgb_float_to_uchar((unsigned char *)&paintcol, rgba_br); + struct VPaintAverageAccum *accum = (struct VPaintAverageAccum *)data->custom_data + n; + accum->len = 0; + memset(accum->value, 0, sizeof(accum->value)); + + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); + + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test_fast(&test, vd.co)) { + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + if (BKE_brush_curve_strength(data->brush, test.dist, cache->radius) > 0.0) { + /* If the vertex is selected for painting. */ + const MVert *mv = &data->me->mvert[v_index]; + if (!use_vert_sel || mv->flag & SELECT) { + accum->len += gmap->vert_to_loop[v_index].count; + /* if a vertex is within the brush region, then add it's color to the blend. */ + for (int j = 0; j < gmap->vert_to_loop[v_index].count; j++) { + const int l_index = gmap->vert_to_loop[v_index].indices[j]; + col = (char *)(&lcol[l_index]); + /* Color is squared to compensate the sqrt color encoding. */ + accum->value[0] += col[0] * col[0]; + accum->value[1] += col[1] * col[1]; + accum->value[2] += col[2] * col[2]; + } + } + } } - else - paintcol = vpd->paintcol; + } + BKE_pbvh_vertex_iter_end; +} + +static void handle_texture_brush( + SculptThreadedTaskData *data, PBVHVertexIter vd, float size_pressure, float alpha_pressure, + float *r_alpha, uint *r_color) +{ + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + + float rgba[4]; + float rgba_br[3]; + + *r_alpha = calc_vp_alpha_col_dl( + data->vp, &data->vpd->vc, data->vpd->vpimat, + &data->vpd->vertexcosnos[v_index], ss->cache->mouse, size_pressure, alpha_pressure, rgba); + rgb_uchar_to_float(rgba_br, (const uchar *)&data->vpd->paintcol); + mul_v3_v3(rgba_br, rgba); + rgb_float_to_uchar((uchar *)r_color, rgba_br); +} + +static void do_vpaint_brush_draw_task_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; + + Brush *brush = data->brush; + StrokeCache *cache = ss->cache; + const float brush_strength = cache->bstrength; + uint *lcol = data->lcol; + Scene *scene = CTX_data_scene(data->C); + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; + const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - if (alpha > 0.0f) { - const int alpha_i = (int)(alpha * 255.0f); - lcol[i] = vpaint_blend(vp, lcol[i], lcolorig[i], paintcol, alpha_i, brush_alpha_pressure_i); + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); - if (mlooptag) mlooptag[i] = 1; + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test(&test, vd.co)) { + /* Note: Grids are 1:1 with corners (aka loops). + * For grid based pbvh, take the vert whose loop cooresponds to the current grid. + * Otherwise, take the current vert. */ + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; + const MVert *mv = &data->me->mvert[v_index]; + + /* If the vertex is selected for painting. */ + if (!use_vert_sel || mv->flag & SELECT) { + /* Calc the dot prod. between ray norm on surf and current vert + * (ie splash prevention factor), and only paint front facing verts. */ + const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; + if (view_dot > 0.0f) { + const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); + uint color_final = data->vpd->paintcol; + + /* If we're painting with a texture, sample the texture color and alpha. */ + float tex_alpha = 1.0; + if (data->vpd->is_texbrush) { + handle_texture_brush( + data, vd, brush_size_pressure, brush_alpha_pressure, + &tex_alpha, &color_final); + } + /* For each poly owning this vert, paint each loop belonging to this vert. */ + for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { + const int p_index = gmap->vert_to_poly[v_index].indices[j]; + const int l_index = gmap->vert_to_loop[v_index].indices[j]; + BLI_assert(data->me->mloop[l_index].v == v_index); + const MPoly *mp = &data->me->mpoly[p_index]; + if (!use_face_sel || mp->flag & ME_FACE_SEL) { + uint color_orig = 0; /* unused when array is NULL */ + if (ss->mode.vpaint.previous_color != NULL) { + /* Get the previous loop color */ + if (ss->mode.vpaint.previous_color[l_index] == 0) { + ss->mode.vpaint.previous_color[l_index] = lcol[l_index]; + } + color_orig = ss->mode.vpaint.previous_color[l_index]; + } + float final_alpha = + 255 * brush_fade * brush_strength * view_dot * + tex_alpha * brush_alpha_pressure * grid_alpha; + + if (brush->flag & BRUSH_ACCUMULATE) { + float mask_accum = ss->mode.vpaint.previous_accum[l_index]; + final_alpha = min_ff(final_alpha + mask_accum, 255.0f * brush_strength); + ss->mode.vpaint.previous_accum[l_index] = final_alpha; + } + + /* Mix the new color with the original based on final_alpha. */ + lcol[l_index] = vpaint_blend( + data->vp, lcol[l_index], color_orig, color_final, + final_alpha, 255 * brush_strength); + } + } + } + } + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_vpaint_brush_blur_task_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + + Scene *scene = CTX_data_scene(data->C); + const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; + Brush *brush = data->brush; + StrokeCache *cache = ss->cache; + const float brush_strength = cache->bstrength; + uint *lcol = data->lcol; + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; + const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); + + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test(&test, vd.co)) { + /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. + * Otherwise, take the current vert. */ + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; + const MVert *mv = &data->me->mvert[v_index]; + + const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; + if (view_dot > 0.0f) { + const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); + + /* If the vertex is selected for painting. */ + if (!use_vert_sel || mv->flag & SELECT) { + /* Get the average poly color */ + uint color_final = 0; + int total_hit_loops = 0; + uint blend[4] = {0}; + for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { + int p_index = gmap->vert_to_poly[v_index].indices[j]; + const MPoly *mp = &data->me->mpoly[p_index]; + if (!use_face_sel || mp->flag & ME_FACE_SEL) { + total_hit_loops += mp->totloop; + for (int k = 0; k < mp->totloop; k++) { + const uint l_index = mp->loopstart + k; + const char *col = (const char *)(&lcol[l_index]); + /* Color is squared to compensate the sqrt color encoding. */ + blend[0] += (uint)col[0] * (uint)col[0]; + blend[1] += (uint)col[1] * (uint)col[1]; + blend[2] += (uint)col[2] * (uint)col[2]; + blend[3] += (uint)col[3] * (uint)col[3]; + } + } + } + if (total_hit_loops != 0) { + /* Use rgb^2 color averaging. */ + char *col = (char *)(&color_final); + col[0] = round_fl_to_uchar(sqrtf(divide_round_i(blend[0], total_hit_loops))); + col[1] = round_fl_to_uchar(sqrtf(divide_round_i(blend[1], total_hit_loops))); + col[2] = round_fl_to_uchar(sqrtf(divide_round_i(blend[2], total_hit_loops))); + col[3] = round_fl_to_uchar(sqrtf(divide_round_i(blend[3], total_hit_loops))); + + /* For each poly owning this vert, paint each loop belonging to this vert. */ + for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { + const int p_index = gmap->vert_to_poly[v_index].indices[j]; + const int l_index = gmap->vert_to_loop[v_index].indices[j]; + BLI_assert(data->me->mloop[l_index].v == v_index); + const MPoly *mp = &data->me->mpoly[p_index]; + if (!use_face_sel || mp->flag & ME_FACE_SEL) { + uint color_orig = 0; /* unused when array is NULL */ + if (ss->mode.vpaint.previous_color != NULL) { + /* Get the previous loop color */ + if (ss->mode.vpaint.previous_color[l_index] == 0) { + ss->mode.vpaint.previous_color[l_index] = lcol[l_index]; + } + color_orig = ss->mode.vpaint.previous_color[l_index]; + } + const float final_alpha = + 255 * brush_fade * brush_strength * view_dot * + brush_alpha_pressure * grid_alpha; + /* Mix the new color with the original + * based on the brush strength and the curve. */ + lcol[l_index] = vpaint_blend( + data->vp, lcol[l_index], color_orig, *((uint *)col), + final_alpha, 255 * brush_strength); + } + } + } + } + } + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_vpaint_brush_smear_task_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh); + + Scene *scene = CTX_data_scene(data->C); + const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; + Brush *brush = data->brush; + StrokeCache *cache = ss->cache; + const float brush_strength = cache->bstrength; + uint *lcol = data->lcol; + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + float brush_dir[3]; + const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; + const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + + sub_v3_v3v3(brush_dir, cache->location, cache->last_location); + project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal); + + if (normalize_v3(brush_dir) != 0.0f) { + + SculptBrushTest test; + sculpt_brush_test_init(ss, &test); + + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (sculpt_brush_test(&test, vd.co)) { + /* For grid based pbvh, take the vert whose loop cooresponds to the current grid. + * Otherwise, take the current vert. */ + const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; + const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; + const MVert *mv_curr = &data->me->mvert[v_index]; + + /* if the vertex is selected for painting. */ + if (!use_vert_sel || mv_curr->flag & SELECT) { + /* Calc the dot prod. between ray norm on surf and current vert + * (ie splash prevention factor), and only paint front facing verts. */ + const float view_dot = (vd.no) ? dot_vf3vs3(cache->sculpt_normal_symm, vd.no) : 1.0; + if (view_dot > 0.0f) { + const float brush_fade = BKE_brush_curve_strength(brush, test.dist, cache->radius); + + bool do_color = false; + /* Minimum dot product between brush direction and current + * to neighbor direction is 0.0, meaning orthogonal. */ + float stroke_dot_max = 0.0f; + + /* Get the color of the loop in the opposite direction of the brush movement */ + uint color_final = 0; + for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { + const int p_index = gmap->vert_to_poly[v_index].indices[j]; + const int l_index = gmap->vert_to_loop[v_index].indices[j]; + BLI_assert(data->me->mloop[l_index].v == v_index); + const MPoly *mp = &data->me->mpoly[p_index]; + if (!use_face_sel || mp->flag & ME_FACE_SEL) { + const MLoop *ml_other = &data->me->mloop[mp->loopstart]; + for (int k = 0; k < mp->totloop; k++, ml_other++) { + const uint v_other_index = ml_other->v; + if (v_other_index != v_index) { + const MVert *mv_other = &data->me->mvert[v_other_index]; + + /* Get the direction from the selected vert to the neighbor. */ + float other_dir[3]; + sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co); + project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal); + + normalize_v3(other_dir); + + const float stroke_dot = dot_v3v3(other_dir, brush_dir); + + if (stroke_dot > stroke_dot_max) { + stroke_dot_max = stroke_dot; + color_final = lcol[mp->loopstart + k]; + do_color = true; + } + } + } + } + } + + if (do_color) { + /* For each poly owning this vert, paint each loop belonging to this vert. */ + for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { + const int p_index = gmap->vert_to_poly[v_index].indices[j]; + const int l_index = gmap->vert_to_loop[v_index].indices[j]; + BLI_assert(data->me->mloop[l_index].v == v_index); + const MPoly *mp = &data->me->mpoly[p_index]; + if (!use_face_sel || mp->flag & ME_FACE_SEL) { + /* Get the previous loop color */ + uint color_orig = 0; /* unused when array is NULL */ + if (ss->mode.vpaint.previous_color != NULL) { + /* Get the previous loop color */ + if (ss->mode.vpaint.previous_color[l_index] == 0) { + ss->mode.vpaint.previous_color[l_index] = lcol[l_index]; + } + color_orig = ss->mode.vpaint.previous_color[l_index]; + } + const float final_alpha = + 255 * brush_fade * brush_strength * + view_dot * brush_alpha_pressure * grid_alpha; + /* Mix the new color with the original + * based on the brush strength and the curve. */ + lcol[l_index] = vpaint_blend( + data->vp, lcol[l_index], color_orig, color_final, + final_alpha, 255 * brush_strength); + } + } + } + } + } + } + } + BKE_pbvh_vertex_iter_end; + } +} + +static void calculate_average_color(SculptThreadedTaskData *data, PBVHNode **UNUSED(nodes), int totnode) +{ + struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); + data->custom_data = accum; + + BLI_task_parallel_range_ex( + 0, totnode, data, NULL, 0, do_vpaint_brush_calc_average_color_cb_ex, + true, false); + + uint accum_len = 0; + uint accum_value[3] = {0}; + uchar blend[4] = {0}; + for (int i = 0; i < totnode; i++) { + accum_len += accum[i].len; + accum_value[0] += accum[i].value[0]; + accum_value[1] += accum[i].value[1]; + accum_value[2] += accum[i].value[2]; + } + if (accum_len != 0) { + blend[0] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[0], accum_len))); + blend[1] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[1], accum_len))); + blend[2] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[2], accum_len))); + blend[3] = 255; + data->vpd->paintcol = *((uint *)blend); + } + + MEM_SAFE_FREE(data->custom_data); /* 'accum' */ +} + +static void vpaint_paint_leaves( + bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd, + Object *ob, Mesh *me, PBVHNode **nodes, int totnode) +{ + Brush *brush = ob->sculpt->cache->brush; + + SculptThreadedTaskData data = { + .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .vpd = vpd, + .lcol = (uint *)me->mloopcol, .me = me, .C = C, + }; + switch (brush->vertexpaint_tool) { + case PAINT_BLEND_AVERAGE: + calculate_average_color(&data, nodes, totnode); + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_vpaint_brush_draw_task_cb_ex, true, false); + break; + case PAINT_BLEND_BLUR: + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_vpaint_brush_blur_task_cb_ex, true, false); + break; + case PAINT_BLEND_SMEAR: + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_vpaint_brush_smear_task_cb_ex, true, false); + break; + default: + BLI_task_parallel_range_ex( + 0, totnode, &data, NULL, 0, + do_vpaint_brush_draw_task_cb_ex, true, false); + break; + } +} + +static void vpaint_do_paint( + bContext *C, Sculpt *sd, VPaint *vd, struct VPaintData *vpd, + Object *ob, Mesh *me, Brush *brush, const char symm, const int axis, const int i, const float angle) +{ + SculptSession *ss = ob->sculpt; + ss->cache->radial_symmetry_pass = i; + sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle); + SculptSearchSphereData data; + PBVHNode **nodes = NULL; + int totnode; + + /* Build a list of all nodes that are potentially within the brush's area of influence */ + data.ss = ss; + data.sd = sd; + data.radius_squared = ss->cache->radius_squared; + data.original = true; + BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); + + sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, true, ss->cache->sculpt_normal_symm); + + /* Paint those leaves. */ + vpaint_paint_leaves(C, sd, vd, vpd, ob, me, nodes, totnode); + + if (nodes) { + MEM_freeN(nodes); + } +} + +static void vpaint_do_radial_symmetry( + bContext *C, Sculpt *sd, VPaint *vd, struct VPaintData *vpd, Object *ob, Mesh *me, + Brush *brush, const char symm, const int axis) +{ + for (int i = 1; i < vd->radial_symm[axis - 'X']; i++) { + const float angle = (2.0 * M_PI) * i / vd->radial_symm[axis - 'X']; + vpaint_do_paint(C, sd, vd, vpd, ob, me, brush, symm, axis, i, angle); + } +} + +/* near duplicate of: sculpt.c's, 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */ +static void vpaint_do_symmetrical_brush_actions( + bContext *C, Sculpt *sd, VPaint *vd, struct VPaintData *vpd, Object *ob) +{ + Brush *brush = BKE_paint_brush(&vd->paint); + Mesh *me = ob->data; + SculptSession *ss = ob->sculpt; + StrokeCache *cache = ss->cache; + const char symm = vd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + int i = 0; + + /* initial stroke */ + vpaint_do_paint(C, sd, vd, vpd, ob, me, brush, i, 'X', 0, 0); + vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'X'); + vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'Y'); + vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'Z'); + + cache->symmetry = symm; + + /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ + for (i = 1; i <= symm; i++) { + if (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5))) { + cache->mirror_symmetry_pass = i; + cache->radial_symmetry_pass = 0; + sculpt_cache_calc_brushdata_symm(cache, i, 0, 0); + + if (i & (1 << 0)) { + vpaint_do_paint(C, sd, vd, vpd, ob, me, brush, i, 'X', 0, 0); + vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'X'); + } + if (i & (1 << 1)) { + vpaint_do_paint(C, sd, vd, vpd, ob, me, brush, i, 'Y', 0, 0); + vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'Y'); + } + if (i & (1 << 2)) { + vpaint_do_paint(C, sd, vd, vpd, ob, me, brush, i, 'Z', 0, 0); + vpaint_do_radial_symmetry(C, sd, vd, vpd, ob, me, brush, i, 'Z'); + } } } + + copy_v3_v3(cache->true_last_location, cache->true_location); + cache->is_last_valid = true; } static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) @@ -2796,65 +2743,26 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P ToolSettings *ts = CTX_data_tool_settings(C); struct VPaintData *vpd = paint_stroke_mode_data(stroke); VPaint *vp = ts->vpaint; - Brush *brush = BKE_paint_brush(&vp->paint); ViewContext *vc = &vpd->vc; Object *ob = vc->obact; - Mesh *me = ob->data; - float mat[4][4]; - int *indexar = vpd->indexar; - int totindex, index; - float mval[2]; + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - const float pressure = RNA_float_get(itemptr, "pressure"); - const float brush_size_pressure = - BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f); - const float brush_alpha_pressure = - BKE_brush_alpha_get(scene, brush) * (BKE_brush_use_alpha_pressure(scene, brush) ? pressure : 1.0f); + vwpaint_update_cache_variants(C, vp, ob, itemptr); - RNA_float_get_array(itemptr, "mouse", mval); + float mat[4][4]; + float mval[2]; - view3d_operator_needs_opengl(C); ED_view3d_init_mats_rv3d(ob, vc->rv3d); /* load projection matrix */ mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); - /* which faces are involved */ - totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure); - - if ((me->editflag & ME_EDIT_PAINT_FACE_SEL) && me->mpoly) { - for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - const MPoly *mpoly = &me->mpoly[indexar[index] - 1]; - - if ((mpoly->flag & ME_FACE_SEL) == 0) - indexar[index] = 0; - } - } - } - swap_m4m4(vc->rv3d->persmat, mat); - /* incase we have modifiers */ - ED_vpaint_proj_handle_update(vpd->vp_handle, vc->ar, mval); - - /* clear modified tag for blur tool */ - if (vpd->mlooptag) - memset(vpd->mlooptag, 0, sizeof(bool) * me->totloop); + vpaint_do_symmetrical_brush_actions(C, sd, vp, vpd, ob); - for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - vpaint_paint_poly(vp, vpd, me, indexar[index] - 1, mval, brush_size_pressure, brush_alpha_pressure); - } - } - swap_m4m4(vc->rv3d->persmat, mat); - /* was disabled because it is slow, but necessary for blur */ - if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { - do_shared_vertexcol(me, vpd->mlooptag); - } - /* calculate pivot for rotation around seletion if needed */ /* also needed for "View Selected" on last stroke */ paint_last_stroke_update(scene, vc->ar, mval); @@ -2874,32 +2782,26 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) { - ToolSettings *ts = CTX_data_tool_settings(C); struct VPaintData *vpd = paint_stroke_mode_data(stroke); ViewContext *vc = &vpd->vc; Object *ob = vc->obact; - Mesh *me = ob->data; - - ED_vpaint_proj_handle_free(vpd->vp_handle); - MEM_freeN(vpd->indexar); - - /* frees prev buffer */ - copy_vpaint_prev(ts->vpaint, NULL, 0); if (vpd->mlooptag) MEM_freeN(vpd->mlooptag); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - DAG_id_tag_update(&me->id, 0); MEM_freeN(vpd); + + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; } static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int retval; - op->customdata = paint_stroke_new(C, op, NULL, vpaint_stroke_test_start, + op->customdata = paint_stroke_new(C, op, sculpt_stroke_get_location, vpaint_stroke_test_start, vpaint_stroke_update_step, NULL, vpaint_stroke_done, event->type); @@ -2919,7 +2821,7 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) static int vpaint_exec(bContext *C, wmOperator *op) { - op->customdata = paint_stroke_new(C, op, NULL, vpaint_stroke_test_start, + op->customdata = paint_stroke_new(C, op, sculpt_stroke_get_location, vpaint_stroke_test_start, vpaint_stroke_update_step, NULL, vpaint_stroke_done, 0); @@ -2931,6 +2833,12 @@ static int vpaint_exec(bContext *C, wmOperator *op) static void vpaint_cancel(bContext *C, wmOperator *op) { + Object *ob = CTX_data_active_object(C); + if (ob->sculpt->cache) { + sculpt_cache_free(ob->sculpt->cache); + ob->sculpt->cache = NULL; + } + paint_stroke_cancel(C, op); } @@ -2953,369 +2861,3 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot) paint_stroke_operator_properties(ot); } - -/* ********************** weight from bones operator ******************* */ - -static int weight_from_bones_poll(bContext *C) -{ - Object *ob = CTX_data_active_object(C); - - return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob)); -} - -static int weight_from_bones_exec(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); - Object *armob = modifiers_isDeformedByArmature(ob); - Mesh *me = ob->data; - int type = RNA_enum_get(op->ptr, "type"); - - create_vgroups_from_armature(op->reports, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X)); - - DAG_id_tag_update(&me->id, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); - - return OPERATOR_FINISHED; -} - -void PAINT_OT_weight_from_bones(wmOperatorType *ot) -{ - static EnumPropertyItem type_items[] = { - {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights from bones"}, - {ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"}, - {0, NULL, 0, NULL, NULL}}; - - /* identifiers */ - ot->name = "Weight from Bones"; - ot->idname = "PAINT_OT_weight_from_bones"; - ot->description = "Set the weights of the groups matching the attached armature's selected bones, " - "using the distance between the vertices and the bones"; - - /* api callbacks */ - ot->exec = weight_from_bones_exec; - ot->invoke = WM_menu_invoke; - ot->poll = weight_from_bones_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights"); -} - -/* *** VGroups Gradient *** */ -typedef struct DMGradient_vertStore { - float sco[2]; - float weight_orig; - enum { - VGRAD_STORE_NOP = 0, - VGRAD_STORE_DW_EXIST = (1 << 0) - } flag; -} DMGradient_vertStore; - -typedef struct DMGradient_userData { - struct ARegion *ar; - Scene *scene; - Mesh *me; - Brush *brush; - const float *sco_start; /* [2] */ - const float *sco_end; /* [2] */ - float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */ - int def_nr; - bool is_init; - DMGradient_vertStore *vert_cache; - /* only for init */ - BLI_bitmap *vert_visit; - - /* options */ - short use_select; - short type; - float weightpaint; -} DMGradient_userData; - -static void gradientVert_update(DMGradient_userData *grad_data, int index) -{ - Mesh *me = grad_data->me; - DMGradient_vertStore *vs = &grad_data->vert_cache[index]; - float alpha; - - if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) { - alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end); - } - else { - BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL); - alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div; - } - /* no need to clamp 'alpha' yet */ - - /* adjust weight */ - alpha = BKE_brush_curve_strength_clamped(grad_data->brush, alpha, 1.0f); - - if (alpha != 0.0f) { - MDeformVert *dv = &me->dvert[index]; - MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr); - // dw->weight = alpha; // testing - int tool = grad_data->brush->vertexpaint_tool; - float testw; - - /* init if we just added */ - testw = wpaint_blend_tool(tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha); - CLAMP(testw, 0.0f, 1.0f); - dw->weight = testw; - } - else { - MDeformVert *dv = &me->dvert[index]; - if (vs->flag & VGRAD_STORE_DW_EXIST) { - /* normally we NULL check, but in this case we know it exists */ - MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr); - dw->weight = vs->weight_orig; - } - else { - /* wasn't originally existing, remove */ - MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr); - if (dw) { - defvert_remove_group(dv, dw); - } - } - } -} - -static void gradientVertUpdate__mapFunc( - void *userData, int index, const float UNUSED(co[3]), - const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) -{ - DMGradient_userData *grad_data = userData; - Mesh *me = grad_data->me; - if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) { - DMGradient_vertStore *vs = &grad_data->vert_cache[index]; - if (vs->sco[0] != FLT_MAX) { - gradientVert_update(grad_data, index); - } - } -} - -static void gradientVertInit__mapFunc( - void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) -{ - DMGradient_userData *grad_data = userData; - Mesh *me = grad_data->me; - - if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) { - /* run first pass only, - * the screen coords of the verts need to be cached because - * updating the mesh may move them about (entering feedback loop) */ - - if (BLI_BITMAP_TEST(grad_data->vert_visit, index) == 0) { - DMGradient_vertStore *vs = &grad_data->vert_cache[index]; - if (ED_view3d_project_float_object(grad_data->ar, - co, vs->sco, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) - { - /* ok */ - MDeformVert *dv = &me->dvert[index]; - MDeformWeight *dw; - dw = defvert_find_index(dv, grad_data->def_nr); - if (dw) { - vs->weight_orig = dw->weight; - vs->flag = VGRAD_STORE_DW_EXIST; - } - else { - vs->weight_orig = 0.0f; - vs->flag = VGRAD_STORE_NOP; - } - - BLI_BITMAP_ENABLE(grad_data->vert_visit, index); - - gradientVert_update(grad_data, index); - } - else { - /* no go */ - copy_v2_fl(vs->sco, FLT_MAX); - } - } - } -} - -static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - int ret = WM_gesture_straightline_modal(C, op, event); - - if (ret & OPERATOR_RUNNING_MODAL) { - if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* XXX, hardcoded */ - /* generally crap! redo! */ - WM_gesture_straightline_cancel(C, op); - ret &= ~OPERATOR_RUNNING_MODAL; - ret |= OPERATOR_FINISHED; - } - } - - if (ret & OPERATOR_CANCELLED) { - ToolSettings *ts = CTX_data_tool_settings(C); - VPaint *wp = ts->wpaint; - Object *ob = CTX_data_active_object(C); - Mesh *me = ob->data; - if (wp->wpaint_prev) { - BKE_defvert_array_free_elems(me->dvert, me->totvert); - BKE_defvert_array_copy(me->dvert, wp->wpaint_prev, me->totvert); - free_wpaint_prev(wp); - } - - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - } - else if (ret & OPERATOR_FINISHED) { - ToolSettings *ts = CTX_data_tool_settings(C); - VPaint *wp = ts->wpaint; - free_wpaint_prev(wp); - } - - return ret; -} - -static int paint_weight_gradient_exec(bContext *C, wmOperator *op) -{ - wmGesture *gesture = op->customdata; - DMGradient_vertStore *vert_cache; - struct ARegion *ar = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); - Mesh *me = ob->data; - int x_start = RNA_int_get(op->ptr, "xstart"); - int y_start = RNA_int_get(op->ptr, "ystart"); - int x_end = RNA_int_get(op->ptr, "xend"); - int y_end = RNA_int_get(op->ptr, "yend"); - float sco_start[2] = {x_start, y_start}; - float sco_end[2] = {x_end, y_end}; - const bool is_interactive = (gesture != NULL); - DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); - - DMGradient_userData data = {NULL}; - - if (is_interactive) { - if (gesture->userdata == NULL) { - VPaint *wp = scene->toolsettings->wpaint; - - gesture->userdata = MEM_mallocN(sizeof(DMGradient_vertStore) * me->totvert, __func__); - data.is_init = true; - - copy_wpaint_prev(wp, me->dvert, me->totvert); - - /* on init only, convert face -> vert sel */ - if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { - BKE_mesh_flush_select_from_polys(me); - } - } - - vert_cache = gesture->userdata; - } - else { - if (wpaint_ensure_data(C, op, 0, NULL) == false) { - return OPERATOR_CANCELLED; - } - - data.is_init = true; - vert_cache = MEM_mallocN(sizeof(DMGradient_vertStore) * me->totvert, __func__); - } - - data.ar = ar; - data.scene = scene; - data.me = ob->data; - data.sco_start = sco_start; - data.sco_end = sco_end; - data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end); - data.def_nr = ob->actdef - 1; - data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)); - data.vert_cache = vert_cache; - data.vert_visit = NULL; - data.type = RNA_enum_get(op->ptr, "type"); - - { - ToolSettings *ts = CTX_data_tool_settings(C); - VPaint *wp = ts->wpaint; - struct Brush *brush = BKE_paint_brush(&wp->paint); - - curvemapping_initialize(brush->curve); - - data.brush = brush; - data.weightpaint = BKE_brush_weight_get(scene, brush); - } - - ED_view3d_init_mats_rv3d(ob, ar->regiondata); - - if (data.is_init) { - data.vert_visit = BLI_BITMAP_NEW(me->totvert, __func__); - - dm->foreachMappedVert(dm, gradientVertInit__mapFunc, &data, DM_FOREACH_NOP); - - MEM_freeN(data.vert_visit); - data.vert_visit = NULL; - } - else { - dm->foreachMappedVert(dm, gradientVertUpdate__mapFunc, &data, DM_FOREACH_NOP); - } - - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - if (is_interactive == false) { - MEM_freeN(vert_cache); - } - - return OPERATOR_FINISHED; -} - -static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - int ret; - - if (wpaint_ensure_data(C, op, 0, NULL) == false) { - return OPERATOR_CANCELLED; - } - - ret = WM_gesture_straightline_invoke(C, op, event); - if (ret & OPERATOR_RUNNING_MODAL) { - struct ARegion *ar = CTX_wm_region(C); - if (ar->regiontype == RGN_TYPE_WINDOW) { - /* TODO, hardcoded, extend WM_gesture_straightline_ */ - if (event->type == LEFTMOUSE && event->val == KM_PRESS) { - wmGesture *gesture = op->customdata; - gesture->mode = 1; - } - } - } - return ret; -} - -void PAINT_OT_weight_gradient(wmOperatorType *ot) -{ - /* defined in DNA_space_types.h */ - static EnumPropertyItem gradient_types[] = { - {WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""}, - {WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""}, - {0, NULL, 0, NULL, NULL} - }; - - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Weight Gradient"; - ot->idname = "PAINT_OT_weight_gradient"; - ot->description = "Draw a line to apply a weight gradient to selected vertices"; - - /* api callbacks */ - ot->invoke = paint_weight_gradient_invoke; - ot->modal = paint_weight_gradient_modal; - ot->exec = paint_weight_gradient_exec; - ot->poll = weight_paint_poll; - ot->cancel = WM_gesture_straightline_cancel; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", ""); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); -} diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c new file mode 100644 index 00000000000..4acd4ddbd8d --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c @@ -0,0 +1,574 @@ +/* + * ***** 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 ***** + */ + +/** \file blender/editors/sculpt_paint/paint_vertex_color_ops.c + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_math_base.h" +#include "BLI_math_color.h" + +#include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_mesh.h" +#include "BKE_deform.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" + +#include "paint_intern.h" /* own include */ + + +static int vertex_weight_paint_mode_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + Mesh *me = BKE_mesh_from_object(ob); + return (ob && (ob->mode == OB_MODE_VERTEX_PAINT || ob->mode == OB_MODE_WEIGHT_PAINT)) && + (me && me->totpoly && me->dvert); +} + +/* -------------------------------------------------------------------- */ +/** \name Set Vertex Colors Operator + * \{ */ + +static bool vertex_color_set(Object *ob, uint paintcol) +{ + Mesh *me; + const MPoly *mp; + int i, j; + + if (((me = BKE_mesh_from_object(ob)) == NULL) || + (ED_mesh_color_ensure(me, NULL) == false)) + { + return false; + } + + const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + + mp = me->mpoly; + for (i = 0; i < me->totpoly; i++, mp++) { + MLoopCol *lcol = me->mloopcol + mp->loopstart; + + if (use_face_sel && !(mp->flag & ME_FACE_SEL)) + continue; + + j = 0; + do { + uint vidx = me->mloop[mp->loopstart + j].v; + if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) { + *(int *)lcol = paintcol; + } + lcol++; + j++; + } while (j < mp->totloop); + + } + + /* remove stale me->mcol, will be added later */ + BKE_mesh_tessface_clear(me); + + DAG_id_tag_update(&me->id, 0); + + return true; +} + +static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + Object *obact = CTX_data_active_object(C); + unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint); + + if (vertex_color_set(obact, paintcol)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_vertex_color_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set Vertex Colors"; + ot->idname = "PAINT_OT_vertex_color_set"; + ot->description = "Fill the active vertex color layer with the current paint color"; + + /* api callbacks */ + ot->exec = vertex_color_set_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Color from Weight Operator + * \{ */ + +static bool vertex_paint_from_weight(Object *ob) +{ + Mesh *me; + const MPoly *mp; + int vgroup_active; + + if (((me = BKE_mesh_from_object(ob)) == NULL || + (ED_mesh_color_ensure(me, NULL)) == false)) + { + return false; + } + + /* TODO: respect selection. */ + mp = me->mpoly; + vgroup_active = ob->actdef - 1; + for (int i = 0; i < me->totpoly; i++, mp++) { + MLoopCol *lcol = &me->mloopcol[mp->loopstart]; + uint j = 0; + do { + uint vidx = me->mloop[mp->loopstart + j].v; + const float weight = defvert_find_weight(&me->dvert[vidx], vgroup_active); + const uchar grayscale = weight * 255; + lcol->r = grayscale; + lcol->b = grayscale; + lcol->g = grayscale; + lcol++; + j++; + } while (j < mp->totloop); + } + + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + + return true; +} + +static int vertex_paint_from_weight_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obact = CTX_data_active_object(C); + if (vertex_paint_from_weight(obact)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Color from Weight"; + ot->idname = "PAINT_OT_vertex_color_from_weight"; + ot->description = "Converts active weight into greyscale vertex colors"; + + /* api callback */ + ot->exec = vertex_paint_from_weight_exec; + ot->poll = vertex_weight_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* TODO: invert, alpha */ +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Smooth Vertex Colors Operator + * \{ */ + +static void vertex_color_smooth_looptag(Mesh *me, bool *mlooptag) +{ + const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const MPoly *mp; + int (*scol)[4]; + int i, j; + bool has_shared = false; + + /* if no mloopcol: do not do */ + /* if mtexpoly: only the involved faces, otherwise all */ + + if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) return; + + scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol"); + + for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) { + if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) { + const MLoop *ml = me->mloop + mp->loopstart; + MLoopCol *lcol = me->mloopcol + mp->loopstart; + for (j = 0; j < mp->totloop; j++, ml++, lcol++) { + scol[ml->v][0] += lcol->r; + scol[ml->v][1] += lcol->g; + scol[ml->v][2] += lcol->b; + scol[ml->v][3] += 1; + has_shared = 1; + } + } + } + + if (has_shared) { + for (i = 0; i < me->totvert; i++) { + if (scol[i][3] != 0) { + scol[i][0] = divide_round_i(scol[i][0], scol[i][3]); + scol[i][1] = divide_round_i(scol[i][1], scol[i][3]); + scol[i][2] = divide_round_i(scol[i][2], scol[i][3]); + } + } + + for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) { + if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) { + const MLoop *ml = me->mloop + mp->loopstart; + MLoopCol *lcol = me->mloopcol + mp->loopstart; + for (j = 0; j < mp->totloop; j++, ml++, lcol++) { + if (mlooptag[mp->loopstart + j]) { + lcol->r = scol[ml->v][0]; + lcol->g = scol[ml->v][1]; + lcol->b = scol[ml->v][2]; + } + } + } + } + } + + MEM_freeN(scol); +} + +static bool vertex_color_smooth(Object *ob) +{ + Mesh *me; + const MPoly *mp; + + int i, j; + + bool *mlooptag; + + if (((me = BKE_mesh_from_object(ob)) == NULL) || + (ED_mesh_color_ensure(me, NULL) == false)) + { + return false; + } + + const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + + mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag"); + + /* simply tag loops of selected faces */ + mp = me->mpoly; + for (i = 0; i < me->totpoly; i++, mp++) { + const MLoop *ml = me->mloop + mp->loopstart; + int ml_index = mp->loopstart; + + if (use_face_sel && !(mp->flag & ME_FACE_SEL)) + continue; + + for (j = 0; j < mp->totloop; j++, ml_index++, ml++) { + mlooptag[ml_index] = true; + } + } + + /* remove stale me->mcol, will be added later */ + BKE_mesh_tessface_clear(me); + + vertex_color_smooth_looptag(me, mlooptag); + + MEM_freeN(mlooptag); + + DAG_id_tag_update(&me->id, 0); + + return true; +} + + +static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obact = CTX_data_active_object(C); + if (vertex_color_smooth(obact)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_vertex_color_smooth(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Smooth Vertex Colors"; + ot->idname = "PAINT_OT_vertex_color_smooth"; + ot->description = "Smooth colors across vertices"; + + /* api callbacks */ + ot->exec = vertex_color_smooth_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Color Transformation Operators + * \{ */ + +struct VPaintTx_BrightContrastData { + /* pre-calculated */ + float gain; + float offset; +}; + +static void vpaint_tx_brightness_contrast(const float col[3], const void *user_data, float r_col[3]) +{ + const struct VPaintTx_BrightContrastData *data = user_data; + + for (int i = 0; i < 3; i++) { + r_col[i] = data->gain * col[i] + data->offset; + } +} + +static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + float gain, offset; + { + float brightness = RNA_float_get(op->ptr, "brightness"); + float contrast = RNA_float_get(op->ptr, "contrast"); + brightness /= 100.0f; + float delta = contrast / 200.0f; + gain = 1.0f - delta * 2.0f; + /* + * The algorithm is by Werner D. Streidt + * (http://visca.com/ffactory/archives/5-99/msg00021.html) + * Extracted of OpenCV demhist.c + */ + if (contrast > 0) { + gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON); + offset = gain * (brightness - delta); + } + else { + delta *= -1; + offset = gain * (brightness + delta); + } + } + + const struct VPaintTx_BrightContrastData user_data = { + .gain = gain, + .offset = offset, + }; + + if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Vertex Paint Bright/Contrast"; + ot->idname = "PAINT_OT_vertex_color_brightness_contrast"; + ot->description = "Adjust vertex color brightness/contrast"; + + /* api callbacks */ + ot->exec = vertex_color_brightness_contrast_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + const float min = -100, max = +100; + prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max); + prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max); + RNA_def_property_ui_range(prop, min, max, 1, 1); +} + +struct VPaintTx_HueSatData { + float hue; + float sat; + float val; +}; + +static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3]) +{ + const struct VPaintTx_HueSatData *data = user_data; + float hsv[3]; + rgb_to_hsv_v(col, hsv); + + hsv[0] += (data->hue - 0.5f); + if (hsv[0] > 1.0f) { + hsv[0] -= 1.0f; + } + else if (hsv[0] < 0.0f) { + hsv[0] += 1.0f; + } + hsv[1] *= data->sat; + hsv[2] *= data->val; + + hsv_to_rgb_v(hsv, r_col); +} + +static int vertex_color_hsv_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + const struct VPaintTx_HueSatData user_data = { + .hue = RNA_float_get(op->ptr, "h"), + .sat = RNA_float_get(op->ptr, "s"), + .val = RNA_float_get(op->ptr, "v"), + }; + + if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_vertex_color_hsv(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Hue Saturation Value"; + ot->idname = "PAINT_OT_vertex_color_hsv"; + ot->description = "Adjust vertex color HSV values"; + + /* api callbacks */ + ot->exec = vertex_color_hsv_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f); + RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f); + RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f); +} + +static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3]) +{ + for (int i = 0; i < 3; i++) { + r_col[i] = 1.0f - col[i]; + } +} + +static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obact = CTX_data_active_object(C); + + if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_vertex_color_invert(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Invert"; + ot->idname = "PAINT_OT_vertex_color_invert"; + ot->description = "Invert RGB values"; + + /* api callbacks */ + ot->exec = vertex_color_invert_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + +struct VPaintTx_LevelsData { + float gain; + float offset; +}; + +static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3]) +{ + const struct VPaintTx_LevelsData *data = user_data; + for (int i = 0; i < 3; i++) { + r_col[i] = data->gain * (col[i] + data->offset); + } +} + +static int vertex_color_levels_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + const struct VPaintTx_LevelsData user_data = { + .gain = RNA_float_get(op->ptr, "gain"), + .offset = RNA_float_get(op->ptr, "offset"), + }; + + if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_vertex_color_levels(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Levels"; + ot->idname = "PAINT_OT_vertex_color_levels"; + ot->description = "Adjust levels of vertex colors"; + + /* api callbacks */ + ot->exec = vertex_color_levels_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + RNA_def_float(ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f); + RNA_def_float(ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f); +} + +/** \} */
\ No newline at end of file diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c new file mode 100644 index 00000000000..a2ba8818c1f --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c @@ -0,0 +1,648 @@ +/* + * ***** 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 ***** + */ + +/** \file blender/editors/sculpt_paint/paint_vertex_color_utils.c + * \ingroup edsculpt + * + * Intended for use by `paint_vertex.c` & `paint_vertex_color_ops.c`. + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_math_base.h" +#include "BLI_math_color.h" + +#include "IMB_colormanagement.h" + +#include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_mesh.h" + +#include "ED_mesh.h" + +#include "paint_intern.h" /* own include */ + +#define EPS_SATURATION 0.0005f + +/** + * Apply callback to each vertex of the active vertex color layer. + */ +bool ED_vpaint_color_transform( + struct Object *ob, + VPaintTransform_Callback vpaint_tx_fn, + const void *user_data) +{ + Mesh *me; + const MPoly *mp; + + if (((me = BKE_mesh_from_object(ob)) == NULL) || + (ED_mesh_color_ensure(me, NULL) == false)) + { + return false; + } + + const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + mp = me->mpoly; + + for (int i = 0; i < me->totpoly; i++, mp++) { + MLoopCol *lcol = &me->mloopcol[mp->loopstart]; + + if (use_face_sel && !(mp->flag & ME_FACE_SEL)) { + continue; + } + + for (int j = 0; j < mp->totloop; j++, lcol++) { + float col[3]; + rgb_uchar_to_float(col, &lcol->r); + + vpaint_tx_fn(col, user_data, col); + + rgb_float_to_uchar(&lcol->r, col); + } + } + + /* remove stale me->mcol, will be added later */ + BKE_mesh_tessface_clear(me); + + DAG_id_tag_update(&me->id, 0); + + return true; +} + +/* -------------------------------------------------------------------- */ +/** \name Color Blending Modes + * \{ */ + +BLI_INLINE uint mcol_blend(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac; + uint col = 0; + + if (fac == 0) { + return col1; + } + + if (fac >= 255) { + return col2; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + /* Updated to use the rgb squared color model which blends nicer. */ + int r1 = cp1[0] * cp1[0]; + int g1 = cp1[1] * cp1[1]; + int b1 = cp1[2] * cp1[2]; + int a1 = cp1[3] * cp1[3]; + + int r2 = cp2[0] * cp2[0]; + int g2 = cp2[1] * cp2[1]; + int b2 = cp2[2] * cp2[2]; + int a2 = cp2[3] * cp2[3]; + + cp[0] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * r1 + fac * r2), 255))); + cp[1] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * g1 + fac * g2), 255))); + cp[2] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * b1 + fac * b2), 255))); + cp[3] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * a1 + fac * a2), 255))); + + return col; +} + +BLI_INLINE uint mcol_add(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + temp = cp1[0] + divide_round_i((fac * cp2[0]), 255); + cp[0] = (temp > 254) ? 255 : temp; + temp = cp1[1] + divide_round_i((fac * cp2[1]), 255); + cp[1] = (temp > 254) ? 255 : temp; + temp = cp1[2] + divide_round_i((fac * cp2[2]), 255); + cp[2] = (temp > 254) ? 255 : temp; + temp = cp1[3] + divide_round_i((fac * cp2[3]), 255); + cp[3] = (temp > 254) ? 255 : temp; + + return col; +} + +BLI_INLINE uint mcol_sub(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + temp = cp1[0] - divide_round_i((fac * cp2[0]), 255); + cp[0] = (temp < 0) ? 0 : temp; + temp = cp1[1] - divide_round_i((fac * cp2[1]), 255); + cp[1] = (temp < 0) ? 0 : temp; + temp = cp1[2] - divide_round_i((fac * cp2[2]), 255); + cp[2] = (temp < 0) ? 0 : temp; + temp = cp1[3] - divide_round_i((fac * cp2[3]), 255); + cp[3] = (temp < 0) ? 0 : temp; + + return col; +} + +BLI_INLINE uint mcol_mul(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + /* first mul, then blend the fac */ + cp[0] = divide_round_i(mfac * cp1[0] * 255 + fac * cp2[0] * cp1[0], 255 * 255); + cp[1] = divide_round_i(mfac * cp1[1] * 255 + fac * cp2[1] * cp1[1], 255 * 255); + cp[2] = divide_round_i(mfac * cp1[2] * 255 + fac * cp2[2] * cp1[2], 255 * 255); + cp[3] = divide_round_i(mfac * cp1[3] * 255 + fac * cp2[3] * cp1[3], 255 * 255); + + return col; +} + +BLI_INLINE uint mcol_lighten(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac; + uint col = 0; + + if (fac == 0) { + return col1; + } + else if (fac >= 255) { + return col2; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + /* See if are lighter, if so mix, else don't do anything. + * if the paint col is darker then the original, then ignore */ + if (IMB_colormanagement_get_luminance_byte(cp1) > IMB_colormanagement_get_luminance_byte(cp2)) { + return col1; + } + + cp[0] = divide_round_i(mfac * cp1[0] + fac * cp2[0], 255); + cp[1] = divide_round_i(mfac * cp1[1] + fac * cp2[1], 255); + cp[2] = divide_round_i(mfac * cp1[2] + fac * cp2[2], 255); + cp[3] = divide_round_i(mfac * cp1[3] + fac * cp2[3], 255); + + return col; +} + +BLI_INLINE uint mcol_darken(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac; + uint col = 0; + + if (fac == 0) { + return col1; + } + else if (fac >= 255) { + return col2; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + /* See if were darker, if so mix, else don't do anything. + * if the paint col is brighter then the original, then ignore */ + if (IMB_colormanagement_get_luminance_byte(cp1) < IMB_colormanagement_get_luminance_byte(cp2)) { + return col1; + } + + cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255); + cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255); + cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255); + cp[3] = divide_round_i((mfac * cp1[3] + fac * cp2[3]), 255); + return col; +} + +BLI_INLINE uint mcol_colordodge(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac,temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + temp = (cp2[0] == 255) ? 255 : min_ii((cp1[0] * 225) / (255 - cp2[0]), 255); + cp[0] = (mfac * cp1[0] + temp * fac) / 255; + temp = (cp2[1] == 255) ? 255 : min_ii((cp1[1] * 225) / (255 - cp2[1]), 255); + cp[1] = (mfac * cp1[1] + temp * fac) / 255; + temp = (cp2[2] == 255) ? 255 : min_ii((cp1[2] * 225 )/ (255 - cp2[2]), 255); + cp[2] = (mfac * cp1[2] + temp * fac) / 255; + temp = (cp2[3] == 255) ? 255 : min_ii((cp1[3] * 225) / (255 - cp2[3]), 255); + cp[3] = (mfac * cp1[3] + temp * fac) / 255; + return col; +} + +BLI_INLINE uint mcol_difference(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac, temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + temp = abs(cp1[0] - cp2[0]); + cp[0] = (mfac * cp1[0] + temp * fac) / 255; + temp = abs(cp1[1] - cp2[1]); + cp[1] = (mfac * cp1[1] + temp * fac) / 255; + temp = abs(cp1[2] - cp2[2]); + cp[2] = (mfac * cp1[2] + temp * fac) / 255; + temp = abs(cp1[3] - cp2[3]); + cp[3] = (mfac * cp1[3] + temp * fac) / 255; + return col; +} + +BLI_INLINE uint mcol_screen(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac, temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + temp = max_ii(255 - (((255 - cp1[0]) * (255 - cp2[0])) / 255), 0); + cp[0] = (mfac * cp1[0] + temp * fac) / 255; + temp = max_ii(255 - (((255 - cp1[1]) * (255 - cp2[1])) / 255), 0); + cp[1] = (mfac * cp1[1] + temp * fac) / 255; + temp = max_ii(255 - (((255 - cp1[2]) * (255 - cp2[2])) / 255), 0); + cp[2] = (mfac * cp1[2] + temp * fac) / 255; + temp = max_ii(255 - (((255 - cp1[3]) * (255 - cp2[3])) / 255), 0); + cp[3] = (mfac * cp1[3] + temp * fac) / 255; + return col; +} + +BLI_INLINE uint mcol_hardlight(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac, temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + int i = 0; + + for (i = 0; i < 4; i++) { + if (cp2[i] > 127) { + temp = 255 - ((255 - 2 * (cp2[i] - 127)) * (255 - cp1[i]) / 255); + } + else { + temp = (2 * cp2[i] * cp1[i]) >> 8; + } + cp[i] = min_ii((mfac * cp1[i] + temp * fac) / 255, 255); + } + return col; +} + +BLI_INLINE uint mcol_overlay(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac, temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + int i = 0; + + for (i = 0; i < 4; i++) { + if (cp1[i] > 127) { + temp = 255 - ((255 - 2 * (cp1[i] - 127)) * (255 - cp2[i]) / 255); + } + else { + temp = (2 * cp2[i] * cp1[i]) >> 8; + } + cp[i] = min_ii((mfac * cp1[i] + temp * fac) / 255, 255); + } + return col; +} + +BLI_INLINE uint mcol_softlight(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac, temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + int i = 0; + + for (i = 0; i < 4; i++) { + if (cp1[i] < 127) { + temp = ((2 * ((cp2[i] / 2) + 64)) * cp1[i]) / 255; + } + else { + temp = 255 - (2 * (255 - ((cp2[i] / 2) + 64)) * (255 - cp1[i]) / 255); + } + cp[i] = (temp * fac + cp1[i] * mfac) / 255; + } + return col; +} + +BLI_INLINE uint mcol_exclusion(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac, temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + int i = 0; + + for (i = 0; i < 4; i++) { + temp = 127 - ((2 * (cp1[i] - 127) * (cp2[i] - 127)) / 255); + cp[i] = (temp * fac + cp1[i] * mfac) / 255; + } + return col; +} + +BLI_INLINE uint mcol_luminosity(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + rgb_to_hsv(cp1[0] / 255.0f, cp1[1] / 255.0f, cp1[2] / 255.0f, &h1, &s1, &v1); + rgb_to_hsv(cp2[0] / 255.0f, cp2[1] / 255.0f, cp2[2] / 255.0f, &h2, &s2, &v2); + + v1 = v2; + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + cp[0] = ((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255; + cp[1] = ((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255; + cp[2] = ((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255; + cp[3] = ((int)(cp2[3]) * fac + mfac * cp1[3]) / 255; + return col; +} + +BLI_INLINE uint mcol_saturation(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + rgb_to_hsv(cp1[0] / 255.0f, cp1[1] / 255.0f, cp1[2] / 255.0f, &h1, &s1, &v1); + rgb_to_hsv(cp2[0] / 255.0f, cp2[1] / 255.0f, cp2[2] / 255.0f, &h2, &s2, &v2); + + if (s1 > EPS_SATURATION) { + s1 = s2; + } + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + cp[0] = ((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255; + cp[1] = ((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255; + cp[2] = ((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255; + return col; +} + +BLI_INLINE uint mcol_hue(uint col1, uint col2, int fac) +{ + uchar *cp1, *cp2, *cp; + int mfac; + uint col = 0; + + if (fac == 0) { + return col1; + } + + mfac = 255 - fac; + + cp1 = (uchar *)&col1; + cp2 = (uchar *)&col2; + cp = (uchar *)&col; + + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + rgb_to_hsv(cp1[0] / 255.0f, cp1[1] / 255.0f, cp1[2] / 255.0f, &h1, &s1, &v1); + rgb_to_hsv(cp2[0] / 255.0f, cp2[1] / 255.0f, cp2[2] / 255.0f, &h2, &s2, &v2); + + h1 = h2; + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + cp[0] = ((int)(r * 255.0f) * fac + mfac * cp1[0]) / 255; + cp[1] = ((int)(g * 255.0f) * fac + mfac * cp1[1]) / 255; + cp[2] = ((int)(b * 255.0f) * fac + mfac * cp1[2]) / 255; + cp[3] = ((int)(cp2[3]) * fac + mfac * cp1[3]) / 255; + return col; +} + +BLI_INLINE uint mcol_alpha_add(uint col1, int fac) +{ + uchar *cp1, *cp; + int temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + cp1 = (uchar *)&col1; + cp = (uchar *)&col; + + temp = cp1[3] + fac; + cp[3] = (temp > 254) ? 255 : temp; + + return col; +} + +BLI_INLINE uint mcol_alpha_sub(uint col1, int fac) +{ + uchar *cp1, *cp; + int temp; + uint col = 0; + + if (fac == 0) { + return col1; + } + + cp1 = (uchar *)&col1; + cp = (uchar *)&col; + + temp = cp1[3] - fac; + cp[3] = temp < 0 ? 0 : temp; + + return col; +} + +/* wpaint has 'ED_wpaint_blend_tool' */ +uint ED_vpaint_blend_tool( + const int tool, const uint col, + const uint paintcol, const int alpha_i) +{ + switch (tool) { + case PAINT_BLEND_MIX: + case PAINT_BLEND_BLUR: return mcol_blend(col, paintcol, alpha_i); + case PAINT_BLEND_AVERAGE: return mcol_blend(col, paintcol, alpha_i); + case PAINT_BLEND_SMEAR: return mcol_blend(col, paintcol, alpha_i); + case PAINT_BLEND_ADD: return mcol_add(col, paintcol, alpha_i); + case PAINT_BLEND_SUB: return mcol_sub(col, paintcol, alpha_i); + case PAINT_BLEND_MUL: return mcol_mul(col, paintcol, alpha_i); + case PAINT_BLEND_LIGHTEN: return mcol_lighten(col, paintcol, alpha_i); + case PAINT_BLEND_DARKEN: return mcol_darken(col, paintcol, alpha_i); + case PAINT_BLEND_COLORDODGE: return mcol_colordodge(col, paintcol, alpha_i); + case PAINT_BLEND_DIFFERENCE: return mcol_difference(col, paintcol, alpha_i); + case PAINT_BLEND_SCREEN: return mcol_screen(col, paintcol, alpha_i); + case PAINT_BLEND_HARDLIGHT: return mcol_hardlight(col, paintcol, alpha_i); + case PAINT_BLEND_OVERLAY: return mcol_overlay(col, paintcol, alpha_i); + case PAINT_BLEND_SOFTLIGHT: return mcol_softlight(col, paintcol, alpha_i); + case PAINT_BLEND_EXCLUSION: return mcol_exclusion(col, paintcol, alpha_i); + case PAINT_BLEND_LUMINOCITY: return mcol_luminosity(col, paintcol, alpha_i); + case PAINT_BLEND_SATURATION: return mcol_saturation(col, paintcol, alpha_i); + case PAINT_BLEND_HUE: return mcol_hue(col, paintcol, alpha_i); + /* non-color */ + case PAINT_BLEND_ALPHA_SUB: return mcol_alpha_sub(col, alpha_i); + case PAINT_BLEND_ALPHA_ADD: return mcol_alpha_add(col, alpha_i); + default: + BLI_assert(0); + return 0; + } +} + +/** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c new file mode 100644 index 00000000000..4e807ccb4ef --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c @@ -0,0 +1,861 @@ +/* + * ***** 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 ***** + */ + +/** \file blender/editors/sculpt_paint/paint_vertex_weight_ops.c + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_array_utils.h" +#include "BLI_bitmap.h" +#include "BLI_task.h" +#include "BLI_string_utils.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" +#include "IMB_colormanagement.h" + +//#include "DNA_armature_types.h" +#include "DNA_mesh_types.h" +#include "DNA_particle_types.h" +#include "DNA_brush_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_brush.h" +#include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_deform.h" +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_modifier.h" +#include "BKE_object_deform.h" +#include "BKE_paint.h" +#include "BKE_report.h" +#include "BKE_colortools.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_armature.h" +#include "ED_mesh.h" +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "paint_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name Store Previous Weights + * + * Use to avoid feedback loop w/ mirrored edits. + * \{ */ + +struct WPaintPrev { + /* previous vertex weights */ + struct MDeformVert *wpaint_prev; + /* allocation size of prev buffers */ + int tot; +}; + + +static void wpaint_prev_init(struct WPaintPrev *wpp) +{ + wpp->wpaint_prev = NULL; + wpp->tot = 0; +} + +static void wpaint_prev_create(struct WPaintPrev *wpp, MDeformVert *dverts, int dcount) +{ + wpaint_prev_init(wpp); + + if (dverts && dcount) { + wpp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev"); + wpp->tot = dcount; + BKE_defvert_array_copy(wpp->wpaint_prev, dverts, dcount); + } +} + +static void wpaint_prev_destroy(struct WPaintPrev *wpp) +{ + if (wpp->wpaint_prev) { + BKE_defvert_array_free(wpp->wpaint_prev, wpp->tot); + } + wpp->wpaint_prev = NULL; + wpp->tot = 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weight from Bones Operator + * \{ */ + +static int weight_from_bones_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + + return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob)); +} + +static int weight_from_bones_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Object *armob = modifiers_isDeformedByArmature(ob); + Mesh *me = ob->data; + int type = RNA_enum_get(op->ptr, "type"); + + create_vgroups_from_armature(op->reports, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X)); + + DAG_id_tag_update(&me->id, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + + return OPERATOR_FINISHED; +} + +void PAINT_OT_weight_from_bones(wmOperatorType *ot) +{ + static EnumPropertyItem type_items[] = { + {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights from bones"}, + {ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"}, + {0, NULL, 0, NULL, NULL}}; + + /* identifiers */ + ot->name = "Weight from Bones"; + ot->idname = "PAINT_OT_weight_from_bones"; + ot->description = "Set the weights of the groups matching the attached armature's selected bones, " + "using the distance between the vertices and the bones"; + + /* api callbacks */ + ot->exec = weight_from_bones_exec; + ot->invoke = WM_menu_invoke; + ot->poll = weight_from_bones_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights"); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sample Weight Operator + * \{ */ + +/* sets wp->weight to the closest weight value to vertex */ +/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */ +static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewContext vc; + Mesh *me; + bool changed = false; + + view3d_set_viewcontext(C, &vc); + me = BKE_mesh_from_object(vc.obact); + + if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) { + const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + int v_idx_best = -1; + uint index; + + view3d_operator_needs_opengl(C); + ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d); + + if (use_vert_sel) { + if (ED_mesh_pick_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, true)) { + v_idx_best = index; + } + } + else { + if (ED_mesh_pick_face_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + v_idx_best = index; + } + else if (ED_mesh_pick_face(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + /* this relies on knowning the internal worksings of ED_mesh_pick_face_vert() */ + BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations"); + } + } + + if (v_idx_best != -1) { /* should always be valid */ + ToolSettings *ts = vc.scene->toolsettings; + Brush *brush = BKE_paint_brush(&ts->wpaint->paint); + const int vgroup_active = vc.obact->actdef - 1; + float vgroup_weight = defvert_find_weight(&me->dvert[v_idx_best], vgroup_active); + + /* use combined weight in multipaint mode, since that's what is displayed to the user in the colors */ + if (ts->multipaint) { + int defbase_tot_sel; + const int defbase_tot = BLI_listbase_count(&vc.obact->defbase); + bool *defbase_sel = BKE_object_defgroup_selected_get(vc.obact, defbase_tot, &defbase_tot_sel); + + if (defbase_tot_sel > 1) { + if (me->editflag & ME_EDIT_MIRROR_X) { + BKE_object_defgroup_mirror_selection( + vc.obact, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel); + } + + vgroup_weight = BKE_defvert_multipaint_collective_weight( + &me->dvert[v_idx_best], defbase_tot, defbase_sel, defbase_tot_sel, ts->auto_normalize); + + /* if autonormalize is enabled, but weights are not normalized, the value can exceed 1 */ + CLAMP(vgroup_weight, 0.0f, 1.0f); + } + + MEM_freeN(defbase_sel); + } + + BKE_brush_weight_set(vc.scene, brush, vgroup_weight); + changed = true; + } + } + + if (changed) { + /* not really correct since the brush didnt change, but redraws the toolbar */ + WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL); /* ts->wpaint->paint.brush */ + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_weight_sample(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Weight Paint Sample Weight"; + ot->idname = "PAINT_OT_weight_sample"; + ot->description = "Use the mouse to sample a weight in the 3D view"; + + /* api callbacks */ + ot->invoke = weight_sample_invoke; + ot->poll = weight_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weight Paint Sample Group Operator + * \{ */ + +/* samples cursor location, and gives menu with vertex groups to activate */ +static bool weight_paint_sample_enum_itemf__helper(const MDeformVert *dvert, const int defbase_tot, int *groups) +{ + /* this func fills in used vgroup's */ + bool found = false; + int i = dvert->totweight; + MDeformWeight *dw; + for (dw = dvert->dw; i > 0; dw++, i--) { + if (dw->def_nr < defbase_tot) { + groups[dw->def_nr] = true; + found = true; + } + } + return found; +} +static EnumPropertyItem *weight_paint_sample_enum_itemf( + bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + if (C) { + wmWindow *win = CTX_wm_window(C); + if (win && win->eventstate) { + ViewContext vc; + Mesh *me; + + view3d_set_viewcontext(C, &vc); + me = BKE_mesh_from_object(vc.obact); + + if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) { + const int defbase_tot = BLI_listbase_count(&vc.obact->defbase); + const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups"); + bool found = false; + uint index; + + const int mval[2] = { + win->eventstate->x - vc.ar->winrct.xmin, + win->eventstate->y - vc.ar->winrct.ymin, + }; + + view3d_operator_needs_opengl(C); + ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d); + + if (use_vert_sel) { + if (ED_mesh_pick_vert(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, true)) { + MDeformVert *dvert = &me->dvert[index]; + found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups); + } + } + else { + if (ED_mesh_pick_face(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + const MPoly *mp = &me->mpoly[index]; + uint fidx = mp->totloop - 1; + + do { + MDeformVert *dvert = &me->dvert[me->mloop[mp->loopstart + fidx].v]; + found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups); + } while (fidx--); + } + } + + if (found == false) { + MEM_freeN(groups); + } + else { + EnumPropertyItem *item = NULL, item_tmp = {0}; + int totitem = 0; + int i = 0; + bDeformGroup *dg; + for (dg = vc.obact->defbase.first; dg && i < defbase_tot; i++, dg = dg->next) { + if (groups[i]) { + item_tmp.identifier = item_tmp.name = dg->name; + item_tmp.value = i; + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + MEM_freeN(groups); + return item; + } + } + } + } + + return DummyRNA_NULL_items; +} + +static int weight_sample_group_exec(bContext *C, wmOperator *op) +{ + int type = RNA_enum_get(op->ptr, "group"); + ViewContext vc; + view3d_set_viewcontext(C, &vc); + + BLI_assert(type + 1 >= 0); + vc.obact->actdef = type + 1; + + DAG_id_tag_update(&vc.obact->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, vc.obact); + return OPERATOR_FINISHED; +} + +/* TODO, we could make this a menu into OBJECT_OT_vertex_group_set_active rather than its own operator */ +void PAINT_OT_weight_sample_group(wmOperatorType *ot) +{ + PropertyRNA *prop = NULL; + + /* identifiers */ + ot->name = "Weight Paint Sample Group"; + ot->idname = "PAINT_OT_weight_sample_group"; + ot->description = "Select one of the vertex groups available under current mouse position"; + + /* api callbacks */ + ot->exec = weight_sample_group_exec; + ot->invoke = WM_menu_invoke; + ot->poll = weight_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* keyingset to use (dynamic enum) */ + prop = RNA_def_enum(ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); + RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weight Set Operator + * \{ */ + +/* fills in the selected faces with the current weight and vertex group */ +static bool weight_paint_set(Object *ob, float paintweight) +{ + Mesh *me = ob->data; + const MPoly *mp; + MDeformWeight *dw, *dw_prev; + int vgroup_active, vgroup_mirror = -1; + uint index; + const bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; + + /* mutually exclusive, could be made into a */ + const short paint_selmode = ME_EDIT_PAINT_SEL_MODE(me); + + if (me->totpoly == 0 || me->dvert == NULL || !me->mpoly) { + return false; + } + + vgroup_active = ob->actdef - 1; + + /* if mirror painting, find the other group */ + if (me->editflag & ME_EDIT_MIRROR_X) { + vgroup_mirror = ED_wpaint_mirror_vgroup_ensure(ob, vgroup_active); + } + + struct WPaintPrev wpp; + wpaint_prev_create(&wpp, me->dvert, me->totvert); + + for (index = 0, mp = me->mpoly; index < me->totpoly; index++, mp++) { + uint fidx = mp->totloop - 1; + + if ((paint_selmode == SCE_SELECT_FACE) && !(mp->flag & ME_FACE_SEL)) { + continue; + } + + do { + uint vidx = me->mloop[mp->loopstart + fidx].v; + + if (!me->dvert[vidx].flag) { + if ((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) { + continue; + } + + dw = defvert_verify_index(&me->dvert[vidx], vgroup_active); + if (dw) { + dw_prev = defvert_verify_index(wpp.wpaint_prev + vidx, vgroup_active); + dw_prev->weight = dw->weight; /* set the undo weight */ + dw->weight = paintweight; + + if (me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */ + int j = mesh_get_x_mirror_vert(ob, NULL, vidx, topology); + if (j >= 0) { + /* copy, not paint again */ + if (vgroup_mirror != -1) { + dw = defvert_verify_index(me->dvert + j, vgroup_mirror); + dw_prev = defvert_verify_index(wpp.wpaint_prev + j, vgroup_mirror); + } + else { + dw = defvert_verify_index(me->dvert + j, vgroup_active); + dw_prev = defvert_verify_index(wpp.wpaint_prev + j, vgroup_active); + } + dw_prev->weight = dw->weight; /* set the undo weight */ + dw->weight = paintweight; + } + } + } + me->dvert[vidx].flag = 1; + } + + } while (fidx--); + } + + { + MDeformVert *dv = me->dvert; + for (index = me->totvert; index != 0; index--, dv++) { + dv->flag = 0; + } + } + + wpaint_prev_destroy(&wpp); + + DAG_id_tag_update(&me->id, 0); + + return true; +} + + +static int weight_paint_set_exec(bContext *C, wmOperator *op) +{ + struct Scene *scene = CTX_data_scene(C); + Object *obact = CTX_data_active_object(C); + ToolSettings *ts = CTX_data_tool_settings(C); + Brush *brush = BKE_paint_brush(&ts->wpaint->paint); + float vgroup_weight = BKE_brush_weight_get(scene, brush); + + if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, NULL) == false) { + return OPERATOR_CANCELLED; + } + + if (weight_paint_set(obact, vgroup_weight)) { + ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */ + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void PAINT_OT_weight_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set Weight"; + ot->idname = "PAINT_OT_weight_set"; + ot->description = "Fill the active vertex group with the current paint weight"; + + /* api callbacks */ + ot->exec = weight_paint_set_exec; + ot->poll = mask_paint_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Interactive Weight Gradient Operator + * \{ */ + +/* *** VGroups Gradient *** */ +typedef struct DMGradient_vertStore { + float sco[2]; + float weight_orig; + enum { + VGRAD_STORE_NOP = 0, + VGRAD_STORE_DW_EXIST = (1 << 0) + } flag; +} DMGradient_vertStore; + +typedef struct DMGradient_vertStoreBase { + struct WPaintPrev wpp; + DMGradient_vertStore elem[0]; +} DMGradient_vertStoreBase; + +typedef struct DMGradient_userData { + struct ARegion *ar; + Scene *scene; + Mesh *me; + Brush *brush; + const float *sco_start; /* [2] */ + const float *sco_end; /* [2] */ + float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */ + int def_nr; + bool is_init; + DMGradient_vertStoreBase *vert_cache; + /* only for init */ + BLI_bitmap *vert_visit; + + /* options */ + short use_select; + short type; + float weightpaint; +} DMGradient_userData; + +static void gradientVert_update(DMGradient_userData *grad_data, int index) +{ + Mesh *me = grad_data->me; + DMGradient_vertStore *vs = &grad_data->vert_cache->elem[index]; + float alpha; + + if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) { + alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end); + } + else { + BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL); + alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div; + } + /* no need to clamp 'alpha' yet */ + + /* adjust weight */ + alpha = BKE_brush_curve_strength_clamped(grad_data->brush, alpha, 1.0f); + + if (alpha != 0.0f) { + MDeformVert *dv = &me->dvert[index]; + MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr); + // dw->weight = alpha; // testing + int tool = grad_data->brush->vertexpaint_tool; + float testw; + + /* init if we just added */ + testw = ED_wpaint_blend_tool(tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha); + CLAMP(testw, 0.0f, 1.0f); + dw->weight = testw; + } + else { + MDeformVert *dv = &me->dvert[index]; + if (vs->flag & VGRAD_STORE_DW_EXIST) { + /* normally we NULL check, but in this case we know it exists */ + MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr); + dw->weight = vs->weight_orig; + } + else { + /* wasn't originally existing, remove */ + MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr); + if (dw) { + defvert_remove_group(dv, dw); + } + } + } +} + +static void gradientVertUpdate__mapFunc( + void *userData, int index, const float UNUSED(co[3]), + const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +{ + DMGradient_userData *grad_data = userData; + Mesh *me = grad_data->me; + if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) { + DMGradient_vertStore *vs = &grad_data->vert_cache->elem[index]; + if (vs->sco[0] != FLT_MAX) { + gradientVert_update(grad_data, index); + } + } +} + +static void gradientVertInit__mapFunc( + void *userData, int index, const float co[3], + const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +{ + DMGradient_userData *grad_data = userData; + Mesh *me = grad_data->me; + + if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) { + /* run first pass only, + * the screen coords of the verts need to be cached because + * updating the mesh may move them about (entering feedback loop) */ + + if (BLI_BITMAP_TEST(grad_data->vert_visit, index) == 0) { + DMGradient_vertStore *vs = &grad_data->vert_cache->elem[index]; + if (ED_view3d_project_float_object(grad_data->ar, + co, vs->sco, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + { + /* ok */ + MDeformVert *dv = &me->dvert[index]; + const MDeformWeight *dw; + dw = defvert_find_index(dv, grad_data->def_nr); + if (dw) { + vs->weight_orig = dw->weight; + vs->flag = VGRAD_STORE_DW_EXIST; + } + else { + vs->weight_orig = 0.0f; + vs->flag = VGRAD_STORE_NOP; + } + + BLI_BITMAP_ENABLE(grad_data->vert_visit, index); + + gradientVert_update(grad_data, index); + } + else { + /* no go */ + copy_v2_fl(vs->sco, FLT_MAX); + } + } + } +} + +static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + int ret = WM_gesture_straightline_modal(C, op, event); + wmGesture *gesture = op->customdata; + DMGradient_vertStoreBase *vert_cache = gesture->userdata; + bool do_gesture_free = false; + + if (ret & OPERATOR_RUNNING_MODAL) { + if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* XXX, hardcoded */ + /* generally crap! redo! */ + do_gesture_free = true; + ret &= ~OPERATOR_RUNNING_MODAL; + ret |= OPERATOR_FINISHED; + } + } + + if (ret & OPERATOR_CANCELLED) { + Object *ob = CTX_data_active_object(C); + Mesh *me = ob->data; + if (vert_cache->wpp.wpaint_prev) { + BKE_defvert_array_free_elems(me->dvert, me->totvert); + BKE_defvert_array_copy(me->dvert, vert_cache->wpp.wpaint_prev, me->totvert); + wpaint_prev_destroy(&vert_cache->wpp); + } + + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + } + else if (ret & OPERATOR_FINISHED) { + wpaint_prev_destroy(&vert_cache->wpp); + } + + if (do_gesture_free) { + WM_gesture_straightline_cancel(C, op); + } + + return ret; +} + +static int paint_weight_gradient_exec(bContext *C, wmOperator *op) +{ + wmGesture *gesture = op->customdata; + DMGradient_vertStoreBase *vert_cache; + struct ARegion *ar = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Mesh *me = ob->data; + int x_start = RNA_int_get(op->ptr, "xstart"); + int y_start = RNA_int_get(op->ptr, "ystart"); + int x_end = RNA_int_get(op->ptr, "xend"); + int y_end = RNA_int_get(op->ptr, "yend"); + float sco_start[2] = {x_start, y_start}; + float sco_end[2] = {x_end, y_end}; + const bool is_interactive = (gesture != NULL); + DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); + + DMGradient_userData data = {NULL}; + + if (is_interactive) { + if (gesture->userdata == NULL) { + gesture->userdata = MEM_mallocN( + sizeof(DMGradient_vertStoreBase) + + (sizeof(DMGradient_vertStore) * me->totvert), + __func__); + data.is_init = true; + + wpaint_prev_create(&((DMGradient_vertStoreBase *)gesture->userdata)->wpp, me->dvert, me->totvert); + + /* on init only, convert face -> vert sel */ + if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { + BKE_mesh_flush_select_from_polys(me); + } + } + + vert_cache = gesture->userdata; + } + else { + if (ED_wpaint_ensure_data(C, op->reports, 0, NULL) == false) { + return OPERATOR_CANCELLED; + } + + data.is_init = true; + vert_cache = MEM_mallocN( + sizeof(DMGradient_vertStoreBase) + + (sizeof(DMGradient_vertStore) * me->totvert), + __func__); + } + + data.ar = ar; + data.scene = scene; + data.me = ob->data; + data.sco_start = sco_start; + data.sco_end = sco_end; + data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end); + data.def_nr = ob->actdef - 1; + data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)); + data.vert_cache = vert_cache; + data.vert_visit = NULL; + data.type = RNA_enum_get(op->ptr, "type"); + + { + ToolSettings *ts = CTX_data_tool_settings(C); + VPaint *wp = ts->wpaint; + struct Brush *brush = BKE_paint_brush(&wp->paint); + + curvemapping_initialize(brush->curve); + + data.brush = brush; + data.weightpaint = BKE_brush_weight_get(scene, brush); + } + + ED_view3d_init_mats_rv3d(ob, ar->regiondata); + + if (data.is_init) { + data.vert_visit = BLI_BITMAP_NEW(me->totvert, __func__); + + dm->foreachMappedVert(dm, gradientVertInit__mapFunc, &data, DM_FOREACH_NOP); + + MEM_freeN(data.vert_visit); + data.vert_visit = NULL; + } + else { + dm->foreachMappedVert(dm, gradientVertUpdate__mapFunc, &data, DM_FOREACH_NOP); + } + + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + if (is_interactive == false) { + MEM_freeN(vert_cache); + } + + return OPERATOR_FINISHED; +} + +static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int ret; + + if (ED_wpaint_ensure_data(C, op->reports, 0, NULL) == false) { + return OPERATOR_CANCELLED; + } + + ret = WM_gesture_straightline_invoke(C, op, event); + if (ret & OPERATOR_RUNNING_MODAL) { + struct ARegion *ar = CTX_wm_region(C); + if (ar->regiontype == RGN_TYPE_WINDOW) { + /* TODO, hardcoded, extend WM_gesture_straightline_ */ + if (event->type == LEFTMOUSE && event->val == KM_PRESS) { + wmGesture *gesture = op->customdata; + gesture->mode = 1; + } + } + } + return ret; +} + +void PAINT_OT_weight_gradient(wmOperatorType *ot) +{ + /* defined in DNA_space_types.h */ + static EnumPropertyItem gradient_types[] = { + {WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""}, + {WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""}, + {0, NULL, 0, NULL, NULL} + }; + + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Weight Gradient"; + ot->idname = "PAINT_OT_weight_gradient"; + ot->description = "Draw a line to apply a weight gradient to selected vertices"; + + /* api callbacks */ + ot->invoke = paint_weight_gradient_invoke; + ot->modal = paint_weight_gradient_modal; + ot->exec = paint_weight_gradient_exec; + ot->poll = weight_paint_poll; + ot->cancel = WM_gesture_straightline_cancel; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); +} + +/** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c new file mode 100644 index 00000000000..c05b0ba89cf --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c @@ -0,0 +1,212 @@ +/* + * ***** 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 ***** + */ + +/** \file blender/editors/sculpt_paint/paint_vertex_weight_utils.c + * \ingroup edsculpt + * + * Intended for use by `paint_vertex.c` & `paint_vertex_weight_ops.c`. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_string_utils.h" + +#include "DNA_armature_types.h" +#include "DNA_mesh_types.h" +#include "DNA_scene_types.h" +#include "DNA_brush_types.h" +#include "DNA_object_types.h" + +#include "BKE_action.h" +#include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_object_deform.h" +#include "BKE_report.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "paint_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name Weight Paint Sanity Checks + * \{ */ + +/* ensure we have data on wpaint start, add if needed */ +bool ED_wpaint_ensure_data( + bContext *C, struct ReportList *reports, + enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Mesh *me = BKE_mesh_from_object(ob); + + if (vgroup_index) { + vgroup_index->active = -1; + vgroup_index->mirror = -1; + } + + if (scene->obedit) { + return false; + } + + if (me == NULL || me->totpoly == 0) { + return false; + } + + /* if nothing was added yet, we make dverts and a vertex deform group */ + if (!me->dvert) { + BKE_object_defgroup_data_create(&me->id); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + } + + /* this happens on a Bone select, when no vgroup existed yet */ + if (ob->actdef <= 0) { + Object *modob; + if ((modob = modifiers_isDeformedByArmature(ob))) { + Bone *actbone = ((bArmature *)modob->data)->act_bone; + if (actbone) { + bPoseChannel *pchan = BKE_pose_channel_find_name(modob->pose, actbone->name); + + if (pchan) { + bDeformGroup *dg = defgroup_find_name(ob, pchan->name); + if (dg == NULL) { + dg = BKE_object_defgroup_add_name(ob, pchan->name); /* sets actdef */ + } + else { + int actdef = 1 + BLI_findindex(&ob->defbase, dg); + BLI_assert(actdef >= 0); + ob->actdef = actdef; + } + } + } + } + } + if (BLI_listbase_is_empty(&ob->defbase)) { + BKE_object_defgroup_add(ob); + } + + /* ensure we don't try paint onto an invalid group */ + if (ob->actdef <= 0) { + BKE_report(reports, RPT_WARNING, "No active vertex group for painting, aborting"); + return false; + } + + if (vgroup_index) { + vgroup_index->active = ob->actdef - 1; + } + + if (flag & WPAINT_ENSURE_MIRROR) { + if (me->editflag & ME_EDIT_MIRROR_X) { + int mirror = ED_wpaint_mirror_vgroup_ensure(ob, ob->actdef - 1); + if (vgroup_index) { + vgroup_index->mirror = mirror; + } + } + } + + return true; +} +/** \} */ + +/* mirror_vgroup is set to -1 when invalid */ +int ED_wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active) +{ + bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active); + + if (defgroup) { + int mirrdef; + char name_flip[MAXBONENAME]; + + BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip)); + mirrdef = defgroup_name_index(ob, name_flip); + if (mirrdef == -1) { + if (BKE_defgroup_new(ob, name_flip)) { + mirrdef = BLI_listbase_count(&ob->defbase) - 1; + } + } + + /* curdef should never be NULL unless this is + * a lamp and BKE_object_defgroup_add_name fails */ + return mirrdef; + } + + return -1; +} + +/* -------------------------------------------------------------------- */ +/** \name Weight Blending Modes + * \{ */ + +BLI_INLINE float wval_blend(const float weight, const float paintval, const float alpha) +{ + const float talpha = min_ff(alpha, 1.0f); /* blending with values over 1 doesn't make sense */ + return (paintval * talpha) + (weight * (1.0f - talpha)); +} +BLI_INLINE float wval_add(const float weight, const float paintval, const float alpha) +{ + return weight + (paintval * alpha); +} +BLI_INLINE float wval_sub(const float weight, const float paintval, const float alpha) +{ + return weight - (paintval * alpha); +} +BLI_INLINE float wval_mul(const float weight, const float paintval, const float alpha) +{ /* first mul, then blend the fac */ + return ((1.0f - alpha) + (alpha * paintval)) * weight; +} +BLI_INLINE float wval_lighten(const float weight, const float paintval, const float alpha) +{ + return (weight < paintval) ? wval_blend(weight, paintval, alpha) : weight; +} +BLI_INLINE float wval_darken(const float weight, const float paintval, const float alpha) +{ + return (weight > paintval) ? wval_blend(weight, paintval, alpha) : weight; +} + +/* vpaint has 'vpaint_blend_tool' */ +/* result is not clamped from [0-1] */ +float ED_wpaint_blend_tool( + const int tool, + /* dw->weight */ + const float weight, + const float paintval, const float alpha) +{ + switch (tool) { + case PAINT_BLEND_MIX: + case PAINT_BLEND_AVERAGE: + case PAINT_BLEND_SMEAR: + case PAINT_BLEND_BLUR: return wval_blend(weight, paintval, alpha); + case PAINT_BLEND_ADD: return wval_add(weight, paintval, alpha); + case PAINT_BLEND_SUB: return wval_sub(weight, paintval, alpha); + case PAINT_BLEND_MUL: return wval_mul(weight, paintval, alpha); + case PAINT_BLEND_LIGHTEN: return wval_lighten(weight, paintval, alpha); + case PAINT_BLEND_DARKEN: return wval_darken(weight, paintval, alpha); + default: + BLI_assert(0); + return 0.0f; + } +} + +/** \} */
\ No newline at end of file diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 44cc2720a32..bef682868c3 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -39,7 +39,6 @@ #include "BLI_blenlib.h" #include "BLI_dial.h" #include "BLI_task.h" -#include "BLI_threads.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -165,111 +164,12 @@ static bool sculpt_brush_needs_rake_rotation(const Brush *brush) return SCULPT_TOOL_HAS_RAKE(brush->sculpt_tool) && (brush->rake_factor != 0.0f); } -/* Factor of brush to have rake point following behind - * (could be configurable but this is reasonable default). */ -#define SCULPT_RAKE_BRUSH_FACTOR 0.25f - -struct SculptRakeData { - float follow_dist; - float follow_co[3]; -}; - typedef enum StrokeFlags { CLIP_X = 1, CLIP_Y = 2, CLIP_Z = 4 } StrokeFlags; -/* Cache stroke properties. Used because - * RNA property lookup isn't particularly fast. - * - * For descriptions of these settings, check the operator properties. - */ -typedef struct StrokeCache { - /* Invariants */ - float initial_radius; - float scale[3]; - int flag; - float clip_tolerance[3]; - float initial_mouse[2]; - - /* Variants */ - float radius; - float radius_squared; - float true_location[3]; - float location[3]; - - bool pen_flip; - bool invert; - float pressure; - float mouse[2]; - float bstrength; - float normal_weight; /* from brush (with optional override) */ - - /* The rest is temporary storage that isn't saved as a property */ - - bool first_time; /* Beginning of stroke may do some things special */ - - /* from ED_view3d_ob_project_mat_get() */ - float projection_mat[4][4]; - - /* Clean this up! */ - ViewContext *vc; - Brush *brush; - - float special_rotation; - float grab_delta[3], grab_delta_symmetry[3]; - float old_grab_location[3], orig_grab_location[3]; - - /* screen-space rotation defined by mouse motion */ - float rake_rotation[4], rake_rotation_symmetry[4]; - bool is_rake_rotation_valid; - struct SculptRakeData rake_data; - - int symmetry; /* Symmetry index between 0 and 7 bit combo 0 is Brush only; - * 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ - int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/ - float true_view_normal[3]; - float view_normal[3]; - - /* sculpt_normal gets calculated by calc_sculpt_normal(), then the - * sculpt_normal_symm gets updated quickly with the usual symmetry - * transforms */ - float sculpt_normal[3]; - float sculpt_normal_symm[3]; - - /* Used for area texture mode, local_mat gets calculated by - * calc_brush_local_mat() and used in tex_strength(). */ - float brush_local_mat[4][4]; - - float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */ - int tile_pass; - - float last_center[3]; - int radial_symmetry_pass; - float symm_rot_mat[4][4]; - float symm_rot_mat_inv[4][4]; - bool original; - float anchored_location[3]; - - float vertex_rotation; /* amount to rotate the vertices when using rotate brush */ - Dial *dial; - - char saved_active_brush_name[MAX_ID_NAME]; - char saved_mask_brush_tool; - int saved_smooth_size; /* smooth tool copies the size of the current tool */ - bool alt_smooth; - - float plane_trim_squared; - - bool supports_gravity; - float true_gravity_direction[3]; - float gravity_direction[3]; - - rcti previous_r; /* previous redraw rectangle */ - rcti current_r; /* current redraw rectangle */ -} StrokeCache; - /************** Access to original unmodified vertex data *************/ typedef struct { @@ -476,41 +376,6 @@ static bool sculpt_stroke_is_dynamic_topology( /*** paint mesh ***/ -/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */ -typedef struct SculptThreadedTaskData { - Sculpt *sd; - Object *ob; - Brush *brush; - PBVHNode **nodes; - int totnode; - - /* Data specific to some callbacks. */ - /* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out - * what it is, and memory overhead is ridiculous anyway... */ - float flippedbstrength; - float angle; - float strength; - bool smooth_mask; - bool has_bm_orco; - - SculptProjectVector *spvc; - float *offset; - float *grab_delta; - float *cono; - float *area_no; - float *area_no_sp; - float *area_co; - float (*mat)[4]; - float (*vertCos)[3]; - - /* 0=towards view, 1=flipped */ - float (*area_cos)[3]; - float (*area_nos)[3]; - int *count; - - ThreadMutex mutex; -} SculptThreadedTaskData; - static void paint_mesh_restore_co_task_cb(void *userdata, const int n) { SculptThreadedTaskData *data = userdata; @@ -600,7 +465,7 @@ static void sculpt_extend_redraw_rect_previous(Object *ob, rcti *rect) } /* Get a screen-space rectangle of the modified area */ -static bool sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d, +bool sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d, Object *ob, rcti *rect) { PBVH *pbvh = ob->sculpt->pbvh; @@ -650,17 +515,7 @@ void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *ar, /************************ Brush Testing *******************/ -typedef struct SculptBrushTest { - float radius_squared; - float location[3]; - float dist; - int mirror_symmetry_pass; - - /* View3d clipping - only set rv3d for clipping */ - RegionView3D *clip_rv3d; -} SculptBrushTest; - -static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test) +void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test) { RegionView3D *rv3d = ss->cache->vc->rv3d; @@ -689,7 +544,7 @@ BLI_INLINE bool sculpt_brush_test_clipping(const SculptBrushTest *test, const fl return ED_view3d_clipping_test(rv3d, symm_co, true); } -static bool sculpt_brush_test(SculptBrushTest *test, const float co[3]) +bool sculpt_brush_test(SculptBrushTest *test, const float co[3]) { float distsq = len_squared_v3v3(co, test->location); @@ -705,7 +560,7 @@ static bool sculpt_brush_test(SculptBrushTest *test, const float co[3]) } } -static bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]) +bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]) { float distsq = len_squared_v3v3(co, test->location); @@ -721,7 +576,7 @@ static bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]) } } -static bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3]) +bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3]) { if (sculpt_brush_test_clipping(test, co)) { return 0; @@ -729,7 +584,7 @@ static bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3 return len_squared_v3v3(co, test->location) <= test->radius_squared; } -static bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4]) +bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4]) { float side = M_SQRT1_2; float local_co[3]; @@ -897,17 +752,19 @@ static void calc_area_normal_and_center_task_cb(void *userdata, const int n) PBVHVertexIter vd; SculptBrushTest test; - SculptUndoNode *unode; + SculptUndoNode *unode = NULL; float private_co[2][3] = {{0.0f}}; float private_no[2][3] = {{0.0f}}; int private_count[2] = {0}; - bool use_original; + bool use_original = false; - unode = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS); + if (ss->cache->original) { + unode = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS); + use_original = (unode->co || unode->bm_entry); + } sculpt_brush_test_init(ss, &test); - use_original = (ss->cache->original && (unode->co || unode->bm_entry)); /* when the mesh is edited we can't rely on original coords * (original mesh may not even have verts in brush radius) */ @@ -1029,8 +886,9 @@ static void calc_area_center( int count[2] = {0}; + /* Intentionally set 'sd' to NULL since we share logic with vertex paint. */ SculptThreadedTaskData data = { - .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode, + .sd = NULL, .ob = ob, .nodes = nodes, .totnode = totnode, .has_bm_orco = has_bm_orco, .area_cos = area_cos, .area_nos = NULL, .count = count, }; BLI_mutex_init(&data.mutex); @@ -1053,42 +911,53 @@ static void calc_area_center( } } - static void calc_area_normal( Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]) { const Brush *brush = BKE_paint_brush(&sd->paint); + bool use_threading = (sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT; + sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, use_threading, r_area_no); +} + +/* expose 'calc_area_normal' externally. */ +void sculpt_pbvh_calc_area_normal( + const Brush *brush, Object *ob, + PBVHNode **nodes, int totnode, + bool use_threading, + float r_area_no[3]) +{ SculptSession *ss = ob->sculpt; const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush); - int n; /* 0=towards view, 1=flipped */ float area_nos[2][3] = {{0.0f}}; int count[2] = {0}; + /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */ SculptThreadedTaskData data = { - .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode, + .sd = NULL, .ob = ob, .nodes = nodes, .totnode = totnode, .has_bm_orco = has_bm_orco, .area_cos = NULL, .area_nos = area_nos, .count = count, }; BLI_mutex_init(&data.mutex); BLI_task_parallel_range( 0, totnode, &data, calc_area_normal_and_center_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + use_threading); BLI_mutex_end(&data.mutex); /* for area normal */ - for (n = 0; n < ARRAY_SIZE(area_nos); n++) { - if (normalize_v3_v3(r_area_no, area_nos[n]) != 0.0f) { + for (int i = 0; i < ARRAY_SIZE(area_nos); i++) { + if (normalize_v3_v3(r_area_no, area_nos[i]) != 0.0f) { break; } } } + /* this calculates flatten center and area normal together, * amortizing the memory bandwidth and loop overhead to calculate both at the same time */ static void calc_area_normal_and_center( @@ -1107,8 +976,9 @@ static void calc_area_normal_and_center( int count[2] = {0}; + /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */ SculptThreadedTaskData data = { - .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode, + .sd = NULL, .ob = ob, .nodes = nodes, .totnode = totnode, .has_bm_orco = has_bm_orco, .area_cos = area_cos, .area_nos = area_nos, .count = count, }; BLI_mutex_init(&data.mutex); @@ -1237,13 +1107,13 @@ static float brush_strength( } /* Return a multiplier for brush strength on a particular vertex. */ -static float tex_strength(SculptSession *ss, Brush *br, - const float brush_point[3], - const float len, - const short vno[3], - const float fno[3], - const float mask, - const int thread_id) +float tex_strength(SculptSession *ss, Brush *br, + const float brush_point[3], + const float len, + const short vno[3], + const float fno[3], + const float mask, + const int thread_id) { StrokeCache *cache = ss->cache; const Scene *scene = cache->vc->scene; @@ -1316,15 +1186,8 @@ static float tex_strength(SculptSession *ss, Brush *br, return avg; } -typedef struct { - Sculpt *sd; - SculptSession *ss; - float radius_squared; - bool original; -} SculptSearchSphereData; - /* Test AABB against sphere */ -static bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v) +bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v) { SculptSearchSphereData *data = data_v; float *center = data->ss->cache->location, nearest[3]; @@ -1632,6 +1495,22 @@ typedef struct SculptDoBrushSmoothGridDataChunk { size_t tmpgrid_size; } SculptDoBrushSmoothGridDataChunk; +typedef struct { + SculptSession *ss; + const float *ray_start, *ray_normal; + bool hit; + float dist; + bool original; + PBVHNode* node; +} SculptRaycastData; + +typedef struct { + const float *ray_start, *ray_normal; + bool hit; + float dist; + float detail; +} SculptDetailRaycastData; + static void do_smooth_brush_mesh_task_cb_ex( void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) { @@ -3688,12 +3567,10 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob) /* Flip all the editdata across the axis/axes specified by symm. Used to * calculate multiple modifications to the mesh when symmetry is enabled. */ -static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm, - const char axis, const float angle, - const float UNUSED(feather)) +void sculpt_cache_calc_brushdata_symm( + StrokeCache *cache, const char symm, + const char axis, const float angle) { - (void)sd; /* unused */ - flip_v3_v3(cache->location, cache->true_location, symm); flip_v3_v3(cache->grab_delta_symmetry, cache->grab_delta, symm); flip_v3_v3(cache->view_normal, cache->true_view_normal, symm); @@ -3791,7 +3668,7 @@ static void do_tiled(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups, BrushActionFunc action, const char symm, const int axis, - const float feather) + const float UNUSED(feather)) { SculptSession *ss = ob->sculpt; int i; @@ -3799,7 +3676,7 @@ static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, UnifiedPain for (i = 1; i < sd->radial_symm[axis - 'X']; ++i) { const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X']; ss->cache->radial_symmetry_pass = i; - calc_brushdata_symm(sd, ss->cache, symm, axis, angle, feather); + sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle); do_tiled(sd, ob, brush, ups, action); } } @@ -3817,8 +3694,9 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob) multires_stitch_grids(ob); } -static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob, - BrushActionFunc action, UnifiedPaintSettings *ups) +static void do_symmetrical_brush_actions( + Sculpt *sd, Object *ob, + BrushActionFunc action, UnifiedPaintSettings *ups) { Brush *brush = BKE_paint_brush(&sd->paint); SculptSession *ss = ob->sculpt; @@ -3837,7 +3715,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob, cache->mirror_symmetry_pass = i; cache->radial_symmetry_pass = 0; - calc_brushdata_symm(sd, cache, i, 0, 0, feather); + sculpt_cache_calc_brushdata_symm(cache, i, 0, 0); do_tiled(sd, ob, brush, ups, action); do_radial_symmetry(sd, ob, brush, ups, action, i, 'X', feather); @@ -3948,7 +3826,7 @@ static const char *sculpt_tool_name(Sculpt *sd) * Operator for applying a stroke (various attributes including mouse path) * using the current brush. */ -static void sculpt_cache_free(StrokeCache *cache) +void sculpt_cache_free(StrokeCache *cache) { if (cache->dial) MEM_freeN(cache->dial); @@ -4398,21 +4276,6 @@ static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob) } } -typedef struct { - SculptSession *ss; - const float *ray_start, *ray_normal; - bool hit; - float dist; - bool original; -} SculptRaycastData; - -typedef struct { - const float *ray_start, *ray_normal; - bool hit; - float dist; - float detail; -} SculptDetailRaycastData; - static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin) { if (BKE_pbvh_node_get_tmin(node) < *tmin) { @@ -4437,6 +4300,9 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin) { srd->hit = 1; *tmin = srd->dist; + + //for vwpaint testing + srd->node = node; } } } @@ -4521,12 +4387,17 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) srd.dist = dist; BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, - ray_start, ray_normal, srd.original); + ray_start, ray_normal, srd.original); copy_v3_v3(out, ray_normal); mul_v3_fl(out, srd.dist); add_v3_v3(out, ray_start); + //used in vwpaint + if (cache && srd.hit){ + copy_v3_v3(cache->true_location, out); + } + return srd.hit; } @@ -4656,8 +4527,11 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2]) { /* Don't start the stroke until mouse goes over the mesh. - * note: mouse will only be null when re-executing the saved stroke. */ - if (!mouse || over_mesh(C, op, mouse[0], mouse[1])) { + * note: mouse will only be null when re-executing the saved stroke. + * We have exception for 'exec' strokes since they may not set 'mouse', only 'location', see: T52195. */ + if (((op->flag & OP_IS_INVOKE) == 0) || + (mouse == NULL) || over_mesh(C, op, mouse[0], mouse[1])) + { Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; @@ -5527,7 +5401,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; float size; - float bb_min[3], bb_max[3]; + float bb_min[3], bb_max[3], center[3], dim[3]; int i, totnodes; PBVHNode **nodes; @@ -5539,11 +5413,12 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) for (i = 0; i < totnodes; i++) { BKE_pbvh_node_mark_topology_update(nodes[i]); } - /* get the bounding box, store the size to bb_max and center (zero) to bb_min */ + /* get the bounding box, it's center and size */ BKE_pbvh_bounding_box(ob->sculpt->pbvh, bb_min, bb_max); - sub_v3_v3(bb_max, bb_min); - zero_v3(bb_min); - size = max_fff(bb_max[0], bb_max[1], bb_max[2]); + add_v3_v3v3(center, bb_min, bb_max); + mul_v3_fl(center, 0.5f); + sub_v3_v3v3(dim, bb_max, bb_min); + size = max_fff(dim[0], dim[1], dim[2]); /* update topology size */ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail); @@ -5553,7 +5428,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) while (BKE_pbvh_bmesh_update_topology( ss->pbvh, PBVH_Collapse | PBVH_Subdivide, - bb_min, NULL, size)) + center, NULL, size)) { for (i = 0; i < totnodes; i++) BKE_pbvh_node_mark_topology_update(nodes[i]); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 108fe3532e3..27d8fbaa340 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -38,12 +38,15 @@ #include "DNA_key_types.h" #include "BLI_bitmap.h" +#include "BLI_threads.h" + #include "BKE_pbvh.h" struct bContext; struct KeyBlock; struct Object; struct SculptUndoNode; +struct SculptOrigVertData; int sculpt_mode_poll(struct bContext *C); int sculpt_mode_poll_view3d(struct bContext *C); @@ -52,12 +55,12 @@ int sculpt_poll(struct bContext *C); int sculpt_poll_view3d(struct bContext *C); /* Stroke */ -bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]); +bool sculpt_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]); /* Dynamic topology */ void sculpt_pbvh_clear(Object *ob); void sculpt_dyntopo_node_layers_add(struct SculptSession *ss); -void sculpt_update_after_dynamic_topology_toggle(bContext *C); +void sculpt_update_after_dynamic_topology_toggle(struct bContext *C); void sculpt_dynamic_topology_enable(struct bContext *C); void sculpt_dynamic_topology_disable(struct bContext *C, struct SculptUndoNode *unode); @@ -115,6 +118,203 @@ typedef struct SculptUndoNode { char shapeName[sizeof(((KeyBlock *)0))->name]; } SculptUndoNode; +/* Factor of brush to have rake point following behind +* (could be configurable but this is reasonable default). */ +#define SCULPT_RAKE_BRUSH_FACTOR 0.25f + +struct SculptRakeData { + float follow_dist; + float follow_co[3]; +}; + +/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */ +typedef struct SculptThreadedTaskData { + struct bContext *C; + struct Sculpt *sd; + struct Object *ob; + struct Brush *brush; + struct PBVHNode **nodes; + int totnode; + + struct VPaint *vp; + struct VPaintData *vpd; + struct WPaintData *wpd; + struct WeightPaintInfo *wpi; + unsigned int *lcol; + struct Mesh *me; + /* For passing generic params. */ + void *custom_data; + + + /* Data specific to some callbacks. */ + /* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out + * what it is, and memory overhead is ridiculous anyway... */ + float flippedbstrength; + float angle; + float strength; + bool smooth_mask; + bool has_bm_orco; + + struct SculptProjectVector *spvc; + float *offset; + float *grab_delta; + float *cono; + float *area_no; + float *area_no_sp; + float *area_co; + float(*mat)[4]; + float(*vertCos)[3]; + + /* 0=towards view, 1=flipped */ + float(*area_cos)[3]; + float(*area_nos)[3]; + int *count; + + ThreadMutex mutex; + +} SculptThreadedTaskData; + +/*************** Brush testing declarations ****************/ +typedef struct SculptBrushTest { + float radius_squared; + float location[3]; + float dist; + int mirror_symmetry_pass; + + /* View3d clipping - only set rv3d for clipping */ + struct RegionView3D *clip_rv3d; +} SculptBrushTest; + +typedef struct { + struct Sculpt *sd; + struct SculptSession *ss; + float radius_squared; + bool original; +} SculptSearchSphereData; + +void sculpt_brush_test_init(struct SculptSession *ss, SculptBrushTest *test); +bool sculpt_brush_test(SculptBrushTest *test, const float co[3]); +bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]); +bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3]); +bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4]); +bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v); +float tex_strength( + struct SculptSession *ss, struct Brush *br, + const float point[3], + const float len, + const short vno[3], + const float fno[3], + const float mask, + const int thread_id); + +/* just for vertex paint. */ +void sculpt_pbvh_calc_area_normal( + const struct Brush *brush, Object *ob, + PBVHNode **nodes, int totnode, + bool use_threading, + float r_area_no[3]); + +/* Cache stroke properties. Used because +* RNA property lookup isn't particularly fast. +* +* For descriptions of these settings, check the operator properties. +*/ + +typedef struct StrokeCache { + /* Invariants */ + float initial_radius; + float scale[3]; + int flag; + float clip_tolerance[3]; + float initial_mouse[2]; + + /* Variants */ + float radius; + float radius_squared; + float true_location[3]; + float true_last_location[3]; + float location[3]; + float last_location[3]; + bool is_last_valid; + + bool pen_flip; + bool invert; + float pressure; + float mouse[2]; + float bstrength; + float normal_weight; /* from brush (with optional override) */ + + /* The rest is temporary storage that isn't saved as a property */ + + bool first_time; /* Beginning of stroke may do some things special */ + + /* from ED_view3d_ob_project_mat_get() */ + float projection_mat[4][4]; + + /* Clean this up! */ + struct ViewContext *vc; + struct Brush *brush; + + float special_rotation; + float grab_delta[3], grab_delta_symmetry[3]; + float old_grab_location[3], orig_grab_location[3]; + + /* screen-space rotation defined by mouse motion */ + float rake_rotation[4], rake_rotation_symmetry[4]; + bool is_rake_rotation_valid; + struct SculptRakeData rake_data; + + /* Symmetry index between 0 and 7 bit combo 0 is Brush only; + * 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ + int symmetry; + int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/ + float true_view_normal[3]; + float view_normal[3]; + + /* sculpt_normal gets calculated by calc_sculpt_normal(), then the + * sculpt_normal_symm gets updated quickly with the usual symmetry + * transforms */ + float sculpt_normal[3]; + float sculpt_normal_symm[3]; + + /* Used for area texture mode, local_mat gets calculated by + * calc_brush_local_mat() and used in tex_strength(). */ + float brush_local_mat[4][4]; + + float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */ + int tile_pass; + + float last_center[3]; + int radial_symmetry_pass; + float symm_rot_mat[4][4]; + float symm_rot_mat_inv[4][4]; + bool original; + float anchored_location[3]; + + float vertex_rotation; /* amount to rotate the vertices when using rotate brush */ + struct Dial *dial; + + char saved_active_brush_name[MAX_ID_NAME]; + char saved_mask_brush_tool; + int saved_smooth_size; /* smooth tool copies the size of the current tool */ + bool alt_smooth; + + float plane_trim_squared; + + bool supports_gravity; + float true_gravity_direction[3]; + float gravity_direction[3]; + + rcti previous_r; /* previous redraw rectangle */ + rcti current_r; /* current redraw rectangle */ + +} StrokeCache; + +void sculpt_cache_calc_brushdata_symm( + StrokeCache *cache, const char symm, + const char axis, const float angle); +void sculpt_cache_free(StrokeCache *cache); + SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type); SculptUndoNode *sculpt_undo_get_node(PBVHNode *node); void sculpt_undo_push_begin(const char *name); @@ -124,6 +324,8 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]); void sculpt_update_object_bounding_box(struct Object *ob); +bool sculpt_get_redraw_rect(struct ARegion *ar, struct RegionView3D *rv3d, Object *ob, rcti *rect); + #define SCULPT_THREADED_LIMIT 4 #endif diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index f8db35e2311..a9920389980 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -1522,7 +1522,7 @@ static int actkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op)) /* set the new current frame value, based on the average time */ if (ked.i1) { Scene *scene = ac.scene; - CFRA = iroundf(ked.f1 / ked.i1); + CFRA = round_fl_to_int(ked.f1 / ked.i1); SUBFRA = 0.f; } diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 553be0ad290..17edbc6cc1d 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -262,6 +262,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s { /* loop over data selecting */ switch (ale->type) { +#if 0 /* XXXX: Keyframes are not currently shown here */ case ANIMTYPE_GPDATABLOCK: { bGPdata *gpd = ale->data; @@ -271,6 +272,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s } break; } +#endif case ANIMTYPE_GPLAYER: ED_gplayer_frames_select_border(ale->data, rectf.xmin, rectf.xmax, selectmode); break; diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 83655a2ba9e..5cde224b7dc 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -624,13 +624,17 @@ static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, I { SpaceAction *sact = (SpaceAction *)slink; - if (!ELEM(GS(old_id->name), ID_GR)) { - return; + if ((ID *)sact->action == old_id) { + sact->action = (bAction *)new_id; } if ((ID *)sact->ads.filter_grp == old_id) { sact->ads.filter_grp = (Group *)new_id; } + if ((ID *)sact->ads.source == old_id) { + sact->ads.source = new_id; + } + } /* only called once, from space/spacetypes.c */ diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 695d04d3850..a71b2baa96f 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -365,9 +365,11 @@ static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track) { +#define MAX_STATIC_PATH 64 int count = sc->path_length; int i, a, b, curindex = -1; - float path[102][2]; + float path_static[(MAX_STATIC_PATH + 1) * 2][2]; + float (*path)[2]; int tiny = sc->flag & SC_SHOW_TINY_MARKER, framenr, start_frame; MovieTrackingMarker *marker; @@ -380,6 +382,13 @@ static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackin if (marker->framenr != framenr || marker->flag & MARKER_DISABLED) return; + if (count < MAX_STATIC_PATH) { + path = path_static; + } + else { + path = MEM_mallocN(sizeof(*path) * (count + 1) * 2, "path"); + } + a = count; i = framenr - 1; while (i >= framenr - count) { @@ -470,6 +479,11 @@ static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackin glVertex2f(path[i][0], path[i][1]); } glEnd(); + + if (path != path_static) { + MEM_freeN(path); + } +#undef MAX_STATIC_PATH } static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker, diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 9430ee626ba..970eae0ad14 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -941,7 +941,7 @@ static int frame_from_event(bContext *C, const wmEvent *event) UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &viewx, &viewy); - framenr = iroundf(viewx); + framenr = round_fl_to_int(viewx); } return framenr; diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 237082f948b..58930fa2cf2 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -821,6 +821,7 @@ static void clip_keymap(struct wmKeyConfig *keyconf) #endif } +/* DO NOT make this static, this hides the symbol and breaks API generation script. */ const char *clip_context_dir[] = {"edit_movieclip", "edit_mask", NULL}; static int clip_context(const bContext *C, const char *member, bContextDataResult *result) diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c index 368cbeaf955..0dd0ee8c7d4 100644 --- a/source/blender/editors/space_clip/tracking_ops_track.c +++ b/source/blender/editors/space_clip/tracking_ops_track.c @@ -165,7 +165,7 @@ static int track_markers_initjob(bContext *C, track_init_markers(sc, clip, framenr, &frames_limit); - tmj->sfra = ED_space_clip_get_clip_frame_number(sc); + tmj->sfra = framenr; tmj->clip = clip; tmj->backwards = backwards; @@ -176,6 +176,7 @@ static int track_markers_initjob(bContext *C, else { tmj->efra = EFRA; } + tmj->efra = BKE_movieclip_remap_scene_to_clip_frame(clip, tmj->efra); } else { if (backwards) { @@ -196,8 +197,6 @@ static int track_markers_initjob(bContext *C, } } - tmj->efra = BKE_movieclip_remap_scene_to_clip_frame(clip, tmj->efra); - if (settings->speed != TRACKING_SPEED_FASTEST) { tmj->delay = 1.0f / scene->r.frs_sec * 1000.0f; @@ -212,7 +211,7 @@ static int track_markers_initjob(bContext *C, } } - tmj->context = BKE_autotrack_context_new(clip, &sc->user, backwards, 1); + tmj->context = BKE_autotrack_context_new(clip, &sc->user, backwards, true); clip->tracking_context = tmj->context; @@ -310,6 +309,7 @@ static void track_markers_endjob(void *tmv) static void track_markers_freejob(void *tmv) { TrackMarkersJob *tmj = (TrackMarkersJob *)tmv; + tmj->clip->tracking_context = NULL; BKE_autotrack_context_free(tmj->context); MEM_freeN(tmj); } diff --git a/source/blender/editors/space_console/console_intern.h b/source/blender/editors/space_console/console_intern.h index 5b016b77e9f..f523cf0d476 100644 --- a/source/blender/editors/space_console/console_intern.h +++ b/source/blender/editors/space_console/console_intern.h @@ -70,6 +70,6 @@ void CONSOLE_OT_select_set(struct wmOperatorType *ot); void CONSOLE_OT_select_word(struct wmOperatorType *ot); enum { LINE_BEGIN, LINE_END, PREV_CHAR, NEXT_CHAR, PREV_WORD, NEXT_WORD }; -enum { DEL_ALL, DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_NEXT_WORD, DEL_PREV_WORD, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL }; +enum { DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_NEXT_WORD, DEL_PREV_WORD, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL }; #endif /* __CONSOLE_INTERN_H__ */ diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 6c33091ff01..48f3dd4fde6 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -277,9 +277,10 @@ typedef struct FileListFilter { /* FileListFilter.flags */ enum { - FLF_HIDE_DOT = 1 << 0, - FLF_HIDE_PARENT = 1 << 1, - FLF_HIDE_LIB_DIR = 1 << 2, + FLF_DO_FILTER = 1 << 0, + FLF_HIDE_DOT = 1 << 1, + FLF_HIDE_PARENT = 1 << 2, + FLF_HIDE_LIB_DIR = 1 << 3, }; typedef struct FileList { @@ -594,24 +595,27 @@ static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root) { bool is_filtered = !is_hidden_file(file->relpath, filter); - if (is_filtered && filter->filter && !FILENAME_IS_CURRPAR(file->relpath)) { - if (file->typeflag & FILE_TYPE_DIR) { - if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { - is_filtered = false; + if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) { + /* We only check for types if some type are enabled in filtering. */ + if (filter->filter) { + if (file->typeflag & FILE_TYPE_DIR) { + if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { + is_filtered = false; + } + } + else { + if (!(filter->filter & FILE_TYPE_FOLDER)) { + is_filtered = false; + } } } else { - if (!(filter->filter & FILE_TYPE_FOLDER)) { + if (!(file->typeflag & filter->filter)) { is_filtered = false; } } } - else { - if (!(file->typeflag & filter->filter)) { - is_filtered = false; - } - } if (is_filtered && (filter->filter_search[0] != '\0')) { if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { is_filtered = false; @@ -631,28 +635,31 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis if (BLO_library_path_explode(path, dir, &group, &name)) { is_filtered = !is_hidden_file(file->relpath, filter); - if (is_filtered && filter->filter && !FILENAME_IS_CURRPAR(file->relpath)) { - if (file->typeflag & FILE_TYPE_DIR) { - if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { - is_filtered = false; + if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) { + /* We only check for types if some type are enabled in filtering. */ + if (filter->filter || filter->filter_id) { + if (file->typeflag & FILE_TYPE_DIR) { + if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { + is_filtered = false; + } } - } - else { - if (!(filter->filter & FILE_TYPE_FOLDER)) { - is_filtered = false; + else { + if (!(filter->filter & FILE_TYPE_FOLDER)) { + is_filtered = false; + } } } - } - if (is_filtered && group) { - if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) { - is_filtered = false; - } - else { - unsigned int filter_id = groupname_to_filter_id(group); - if (!(filter_id & filter->filter_id)) { + if (is_filtered && group) { + if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) { is_filtered = false; } + else { + unsigned int filter_id = groupname_to_filter_id(group); + if (!(filter_id & filter->filter_id)) { + is_filtered = false; + } + } } } if (is_filtered && (filter->filter_search[0] != '\0')) { @@ -729,12 +736,17 @@ void filelist_filter(FileList *filelist) MEM_freeN(filtered_tmp); } -void filelist_setfilter_options(FileList *filelist, const bool hide_dot, const bool hide_parent, +void filelist_setfilter_options(FileList *filelist, const bool do_filter, + const bool hide_dot, const bool hide_parent, const unsigned int filter, const unsigned int filter_id, const char *filter_glob, const char *filter_search) { bool update = false; + if (((filelist->filter_data.flags & FLF_DO_FILTER) != 0) != (do_filter != 0)) { + filelist->filter_data.flags ^= FLF_DO_FILTER; + update = true; + } if (((filelist->filter_data.flags & FLF_HIDE_DOT) != 0) != (hide_dot != 0)) { filelist->filter_data.flags ^= FLF_HIDE_DOT; update = true; @@ -1104,7 +1116,10 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat preview->img = IMB_thumb_manage(preview->path, THB_LARGE, source); IMB_thumb_path_unlock(preview->path); - preview->flags = 0; /* Used to tell free func to not free anything! */ + /* Used to tell free func to not free anything. + * Note that we do not care about cas result here, + * we only want value attribution itself to be atomic (and memory barier).*/ + atomic_cas_uint32(&preview->flags, preview->flags, 0); BLI_thread_queue_push(cache->previews_done, preview); // printf("%s: End (%d)...\n", __func__, threadid); @@ -1979,8 +1994,7 @@ int ED_path_extension_type(const char *path) else if (BLI_testextensie(path, ".abc")) { return FILE_TYPE_ALEMBIC; } - else if (BLI_testextensie_array(path, imb_ext_image) || - (G.have_quicktime && BLI_testextensie_array(path, imb_ext_image_qt))) + else if (BLI_testextensie_array(path, imb_ext_image)) { return FILE_TYPE_IMAGE; } diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index f4304681780..4e9c1e0dd1d 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -68,7 +68,8 @@ int folderlist_clear_next(struct SpaceFile *sfile); void filelist_setsorting(struct FileList *filelist, const short sort); void filelist_sort(struct FileList *filelist); -void filelist_setfilter_options(struct FileList *filelist, const bool hide_dot, const bool hide_parent, +void filelist_setfilter_options(struct FileList *filelist, const bool do_filter, + const bool hide_dot, const bool hide_parent, const unsigned int filter, const unsigned int filter_id, const char *filter_glob, const char *filter_search); void filelist_filter(struct FileList *filelist); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 374db92297d..287b98fa589 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -223,9 +223,10 @@ static void file_refresh(const bContext *C, ScrArea *sa) filelist_setdir(sfile->files, params->dir); filelist_setrecursion(sfile->files, params->recursion_level); filelist_setsorting(sfile->files, params->sort); - filelist_setfilter_options(sfile->files, (params->flag & FILE_HIDE_DOT) != 0, + filelist_setfilter_options(sfile->files, (params->flag & FILE_FILTER) != 0, + (params->flag & FILE_HIDE_DOT) != 0, false, /* TODO hide_parent, should be controllable? */ - (params->flag & FILE_FILTER) ? params->filter : 0, + params->filter, params->filter_id, params->filter_glob, params->filter_search); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index f38d36853d7..861a38da2c7 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -195,8 +195,8 @@ static int graphkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op)) /* set the range directly */ get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL, false, false); scene->r.flag |= SCER_PRV_RANGE; - scene->r.psfra = iroundf(min); - scene->r.pefra = iroundf(max); + scene->r.psfra = round_fl_to_int(min); + scene->r.pefra = round_fl_to_int(max); /* set notifier that things have changed */ // XXX err... there's nothing for frame ranges yet, but this should do fine too @@ -2036,7 +2036,7 @@ static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op)) } else { /* Animation Mode - Affects current frame (int) */ - CFRA = iroundf(ked.f1 / ked.i1); + CFRA = round_fl_to_int(ked.f1 / ked.i1); SUBFRA = 0.f; sipo->cursorVal = ked.f2 / (float)ked.i1; } diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 75f0da83e77..5c670a216d8 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -94,7 +94,7 @@ static void graphview_cursor_apply(bContext *C, wmOperator *op) * NOTE: sync this part of the code with ANIM_OT_change_frame */ /* 1) frame is rounded to the nearest int, since frames are ints */ - CFRA = iroundf(frame); + CFRA = round_fl_to_int(frame); if (scene->r.flag & SCER_LOCK_FRAME_SELECTION) { /* Clip to preview range diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index e810f4db7dd..8cb23c9e021 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -88,7 +88,7 @@ static void draw_render_info(const bContext *C, float zoomy) { RenderResult *rr; - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); RenderData *rd = RE_engine_get_render_data(re); Scene *stats_scene = ED_render_job_get_scene(C); if (stats_scene == NULL) { diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index a0d67626940..55fcf9213d6 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1169,6 +1169,7 @@ static int image_sequence_get_len(ListBase *frames, int *ofs) } return frame_curr - (*ofs); } + *ofs = 0; return 0; } @@ -3525,7 +3526,7 @@ static int frame_from_event(bContext *C, const wmEvent *event) UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &viewx, &viewy); - framenr = iroundf(viewx); + framenr = round_fl_to_int(viewx); } return framenr; @@ -3631,7 +3632,7 @@ static int render_border_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); RenderData *rd; rctf border; diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 1f298373a80..f7f7c82171d 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -365,8 +365,8 @@ static int nlaedit_previewrange_exec(bContext *C, wmOperator *UNUSED(op)) /* set the range directly */ get_nlastrip_extents(&ac, &min, &max, true); scene->r.flag |= SCER_PRV_RANGE; - scene->r.psfra = iroundf(min); - scene->r.pefra = iroundf(max); + scene->r.psfra = round_fl_to_int(min); + scene->r.pefra = round_fl_to_int(max); /* set notifier that things have changed */ // XXX err... there's nothing for frame ranges yet, but this should do fine too diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index f58b4050834..7ef34669ee2 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -638,7 +638,7 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED( * highlight also if node itself is selected, since we don't display the node body separately! */ for (sock = node->inputs.first; sock; sock = sock->next) { - node_socket_circle_draw(C, ntree, node, sock, socket_size, (sock->flag & SELECT) || (node->flag & SELECT)); + node_socket_draw(C, ntree, node, sock, socket_size, (sock->flag & SELECT) || (node->flag & SELECT)); } UI_block_end(C, node->block); @@ -2204,16 +2204,17 @@ static void node_composit_backdrop_viewer(SpaceNode *snode, ImBuf *backdrop, bNo if (node->custom1 == 0) { const float backdropWidth = backdrop->x; const float backdropHeight = backdrop->y; - const float cx = x + snode->zoom * backdropWidth * node->custom3; + const float cx = x + snode->zoom * backdropWidth * node->custom3; const float cy = y + snode->zoom * backdropHeight * node->custom4; + const float cross_size = 12 * U.pixelsize; glColor3f(1.0, 1.0, 1.0); glBegin(GL_LINES); - glVertex2f(cx - 25, cy - 25); - glVertex2f(cx + 25, cy + 25); - glVertex2f(cx + 25, cy - 25); - glVertex2f(cx - 25, cy + 25); + glVertex2f(cx - cross_size, cy - cross_size); + glVertex2f(cx + cross_size, cy + cross_size); + glVertex2f(cx + cross_size, cy - cross_size); + glVertex2f(cx - cross_size, cy + cross_size); glEnd(); } } diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index 6e25c87d274..d7119302611 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -617,34 +617,22 @@ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node) glDisable(GL_LINE_SMOOTH); } -/* this might have some more generic use */ -static void node_circle_draw(float x, float y, float size, const float col[4], int highlight) +static void node_socket_shape_draw( + float x, float y, float size, const float col[4], bool highlight, + const float coords[][2], int coords_len) { - /* 16 values of sin function */ - static const float si[16] = { - 0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f, - 0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f, - -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f, - -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f - }; - /* 16 values of cos function */ - static const float co[16] = { - 1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f, - -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f, - -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f, - 0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f, - }; int a; - + glColor4fv(col); - + glEnable(GL_BLEND); glBegin(GL_POLYGON); - for (a = 0; a < 16; a++) - glVertex2f(x + size * si[a], y + size * co[a]); + for (a = 0; a < coords_len; a++) { + glVertex2f(x + size * coords[a][0], y + size * coords[a][1]); + } glEnd(); glDisable(GL_BLEND); - + if (highlight) { UI_ThemeColor(TH_TEXT_HI); glLineWidth(1.5f); @@ -655,14 +643,16 @@ static void node_circle_draw(float x, float y, float size, const float col[4], i glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); glBegin(GL_LINE_LOOP); - for (a = 0; a < 16; a++) - glVertex2f(x + size * si[a], y + size * co[a]); + for (a = 0; a < coords_len; a++) { + glVertex2f(x + size * coords[a][0], y + size * coords[a][1]); + } glEnd(); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); } -void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock, float size, int highlight) + +void node_socket_draw(const bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock, float size, bool highlight) { PointerRNA ptr, node_ptr; float color[4]; @@ -670,7 +660,60 @@ void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, bNode *node, b RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr); sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color); - node_circle_draw(sock->locx, sock->locy, size, color, highlight); + + /* 16 values of {sin, cos} function */ + const float shape_circle[16][2] = { + {0.00000000f, 1.00000000f}, + {0.39435585f, 0.91895781f}, + {0.72479278f, 0.68896691f}, + {0.93775213f, 0.34730525f}, + {0.99871650f, -0.05064916f}, + {0.89780453f, -0.44039415f}, + {0.65137248f, -0.75875812f}, + {0.29936312f, -0.95413925f}, + {-0.10116832f, -0.99486932f}, + {-0.48530196f, -0.87434661f}, + {-0.79077573f, -0.61210598f}, + {-0.96807711f, -0.25065253f}, + {-0.98846832f, 0.15142777f}, + {-0.84864425f, 0.52896401f}, + {-0.57126821f, 0.82076344f}, + {-0.20129852f, 0.97952994f } + }; + + const float shape_diamond[4][2] = { + {0.0f, 1.2f}, + {1.2f, 0.0f}, + {0.0f, -1.2f}, + {-1.2f, 0.0f}, + }; + + const float shape_square[4][2] = { + {-0.9f, 0.9f}, + {0.9f, 0.9f}, + {0.9f, -0.9f}, + {-0.9f, -0.9f}, + }; + + const float (*shape)[2]; + int shape_len; + switch (sock->draw_shape) { + default: + case SOCK_DRAW_SHAPE_CIRCLE: + shape = shape_circle; + shape_len = ARRAY_SIZE(shape_circle); + break; + case SOCK_DRAW_SHAPE_DIAMOND: + shape = shape_diamond; + shape_len = ARRAY_SIZE(shape_diamond); + break; + case SOCK_DRAW_SHAPE_SQUARE: + shape = shape_square; + shape_len = ARRAY_SIZE(shape_square); + break; + } + + node_socket_shape_draw(sock->locx, sock->locy, size, color, highlight, shape, shape_len); } /* ************** Socket callbacks *********** */ @@ -935,7 +978,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN if (nodeSocketIsHidden(sock)) continue; - node_socket_circle_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT); + node_socket_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT); } /* socket outputs */ @@ -943,7 +986,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN if (nodeSocketIsHidden(sock)) continue; - node_socket_circle_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT); + node_socket_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT); } /* preview */ @@ -1048,7 +1091,7 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b // BLI_snprintf(showname, sizeof(showname), "[%s]", showname); /* XXX - don't print into self! */ uiDefBut(node->block, UI_BTYPE_LABEL, 0, showname, - iroundf(rct->xmin + NODE_MARGIN_X), iroundf(centy - NODE_DY * 0.5f), + round_fl_to_int(rct->xmin + NODE_MARGIN_X), round_fl_to_int(centy - NODE_DY * 0.5f), (short)(BLI_rctf_size_x(rct) - 18.0f - 12.0f), (short)NODE_DY, NULL, 0, 0, 0, 0, ""); } @@ -1066,13 +1109,15 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b /* sockets */ for (sock = node->inputs.first; sock; sock = sock->next) { - if (!nodeSocketIsHidden(sock)) - node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT); + if (!nodeSocketIsHidden(sock)) { + node_socket_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT); + } } for (sock = node->outputs.first; sock; sock = sock->next) { - if (!nodeSocketIsHidden(sock)) - node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT); + if (!nodeSocketIsHidden(sock)) { + node_socket_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT); + } } UI_block_end(C, node->block); diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 5f8f839025f..e91fd1ee575 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -1321,7 +1321,7 @@ static int node_read_fullsamplelayers_exec(bContext *C, wmOperator *UNUSED(op)) Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); Scene *curscene = CTX_data_scene(C); - Render *re = RE_NewRender(curscene->id.name); + Render *re = RE_NewSceneRender(curscene); WM_cursor_wait(1); RE_MergeFullSample(re, bmain, curscene, snode->nodetree); diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c index 914f8ffbe10..9d750bfe348 100644 --- a/source/blender/editors/space_node/node_group.c +++ b/source/blender/editors/space_node/node_group.c @@ -37,6 +37,7 @@ #include "DNA_anim_types.h" #include "BLI_listbase.h" +#include "BLI_linklist.h" #include "BLI_math.h" #include "BLT_translation.h" @@ -186,6 +187,7 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode) bNode *node, *nextnode; bNodeTree *ngroup, *wgroup; ListBase anim_basepaths = {NULL, NULL}; + LinkNode *nodes_delayed_free = NULL; ngroup = (bNodeTree *)gnode->id; @@ -208,8 +210,8 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode) * This also removes remaining links to and from interface nodes. */ if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { - nodeFreeNode(wgroup, node); - continue; + /* We must delay removal since sockets will reference this node. see: T52092 */ + BLI_linklist_prepend(&nodes_delayed_free, node); } /* keep track of this node's RNA "base" path (the part of the path identifying the node) @@ -336,6 +338,11 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode) } } + while (nodes_delayed_free) { + node = BLI_linklist_pop(&nodes_delayed_free); + nodeFreeNode(ntree, node); + } + /* delete the group instance */ nodeFreeNode(ntree, gnode); diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 6b8fa0b88fe..352f9e51012 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -67,8 +67,9 @@ void snode_group_offset(struct SpaceNode *snode, float *x, float *y); /* transfo /* node_draw.c */ int node_get_colorid(struct bNode *node); -void node_socket_circle_draw(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node, - struct bNodeSocket *sock, float size, int highlight); +void node_socket_draw( + const struct bContext *C, struct bNodeTree *ntree, struct bNode *node, + struct bNodeSocket *sock, float size, bool highlight); int node_get_resize_cursor(int directions); void node_draw_shadow(struct SpaceNode *snode, struct bNode *node, float radius, float alpha); void node_draw_default(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 5f592431558..3b03399a5e7 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -567,7 +567,13 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) ntree->is_updating = true; for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) { bNodeLink *link = linkdata->data; - + + /* See note below, but basically TEST flag means that the link + * was connected to output (or to a node which affects the + * output). + */ + do_tag_update |= (link->flag & NODE_LINK_TEST) != 0; + if (apply_links && link->tosock && link->fromsock) { /* before actually adding the link, * let nodes perform special link insertion handling @@ -593,11 +599,6 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) } } else { - /* See note below, but basically TEST flag means that the link - * was connected to output (or to a node which affects the - * output). - */ - do_tag_update |= (link->flag & NODE_LINK_TEST) != 0; nodeRemLink(ntree, link); } } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 121fe812016..af6fdf2ab86 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1273,7 +1273,10 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto } } else { - switch (GS(tselem->id->name)) { + /* TODO(sergey): Casting to short here just to handle ID_NLA which is + * NOT inside of IDType enum. + */ + switch ((short)GS(tselem->id->name)) { case ID_SCE: tselem_draw_icon_uibut(&arg, ICON_SCENE_DATA); break; case ID_ME: @@ -1343,6 +1346,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break; case ID_GD: tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break; + default: + break; } } } diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 265a19b9e7e..f4089667b04 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -1092,7 +1092,7 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op)) te = outliner_find_id(so, &so->tree, &obact->id); - if (obact->type == OB_ARMATURE) { + if (te != NULL && obact->type == OB_ARMATURE) { /* traverse down the bone hierarchy in case of armature */ TreeElement *te_obact = te; diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 09a49f201d4..4b0b0e2e0f0 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -882,6 +882,8 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor } break; } + default: + break; } } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 70a6e6d83cb..97961501c6d 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -40,6 +40,7 @@ #include "DNA_scene_types.h" #include "DNA_mask_types.h" +#include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_userdef_types.h" @@ -1116,18 +1117,16 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; bool draw_metadata = false; - if (G.is_rendering == false && (scene->r.seq_flag & R_SEQ_GL_PREV) == 0) { + if (G.is_rendering == false && (scene->r.seq_prev_type) == OB_RENDER) { /* stop all running jobs, except screen one. currently previews frustrate Render * needed to make so sequencer's rendering doesn't conflict with compositor */ WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_COMPOSITE); - if ((scene->r.seq_flag & R_SEQ_GL_PREV) == 0) { - /* in case of final rendering used for preview, kill all previews, - * otherwise threading conflict will happen in rendering module - */ - WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_RENDER_PREVIEW); - } + /* in case of final rendering used for preview, kill all previews, + * otherwise threading conflict will happen in rendering module + */ + WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_RENDER_PREVIEW); } if ((!draw_overlay || sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE) && !draw_backdrop) { diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index e63569ac386..b22a158e151 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -727,7 +727,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) if (!skip_dup) { /* Duplicate AFTER the first change */ - seqn = BKE_sequence_dupli_recursive(scene, NULL, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); + seqn = BKE_sequence_dupli_recursive(scene, scene, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); } if (seqn) { @@ -820,7 +820,7 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) if (!skip_dup) { /* Duplicate AFTER the first change */ - seqn = BKE_sequence_dupli_recursive(scene, NULL, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); + seqn = BKE_sequence_dupli_recursive(scene, scene, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); } if (seqn) { @@ -2162,7 +2162,7 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) if (ed == NULL) return OPERATOR_CANCELLED; - BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT); + BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT, 0); if (nseqbase.first) { Sequence *seq = nseqbase.first; @@ -3200,7 +3200,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, ed->seqbasep, SEQ_DUPE_UNIQUE_NAME); + BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_UNIQUE_NAME, 0); /* To make sure the copied strips have unique names between each other add * them temporarily to the end of the original seqbase. (bug 25932) @@ -3267,7 +3267,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op)) ED_sequencer_deselect_all(scene); ofs = scene->r.cfra - seqbase_clipboard_frame; - BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, &seqbase_clipboard, SEQ_DUPE_UNIQUE_NAME); + BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, &seqbase_clipboard, SEQ_DUPE_UNIQUE_NAME, 0); /* transform pasted strips before adding */ if (ofs) { diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index a2a80297041..f1d0f23f8af 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -435,6 +435,7 @@ static void sequencer_dropboxes(void) /* ************* end drop *********** */ +/* DO NOT make this static, this hides the symbol and breaks API generation script. */ const char *sequencer_context_dir[] = {"edit_mask", NULL}; static int sequencer_context(const bContext *C, const char *member, bContextDataResult *result) diff --git a/source/blender/editors/space_text/text_format_pov.c b/source/blender/editors/space_text/text_format_pov.c index 0d19c503798..1ef3322711c 100644 --- a/source/blender/editors/space_text/text_format_pov.c +++ b/source/blender/editors/space_text/text_format_pov.c @@ -49,36 +49,38 @@ static int txtfmt_pov_find_keyword(const char *string) { int i, len; /* Language Directives */ - if (STR_LITERAL_STARTSWITH(string, "append", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "debug", len)) i = len; + if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "persistent", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "version", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "warning", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "declare", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "default", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "include", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "append", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "elseif", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "debug", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "end", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "error", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "fclose", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "fopen", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "ifndef", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "ifdef", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "include", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "patch", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "local", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "macro", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "range", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "read", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "render", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "switch", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "undef", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "version", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "warning", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "while", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "write", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "end", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len; else i = 0; /* If next source char is an identifier (eg. 'i' in "definate") no match */ @@ -92,221 +94,275 @@ static int txtfmt_pov_find_reserved_keywords(const char *string) * list is from... * http://www.povray.org/documentation/view/3.7.0/212/ */ + + /* Float Functions */ + if (STR_LITERAL_STARTSWITH(string, "conserve_energy", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_intersections", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dimension_size", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bitwise_and", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bitwise_or", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bitwise_xor", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "file_exists", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "precompute", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dimensions", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clipped_by", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "shadowless", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "turb_depth", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "reciprocal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "quaternion", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "phong_size", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tesselate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "save_file", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "load_file", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_trace", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "transform", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "translate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "direction", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "roughness", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "metallic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gts_load", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gts_save", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "location", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "altitude", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "function", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "evaluate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inverse", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "collect", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "target", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "albedo", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "rotate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "matrix", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "look_at", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "jitter", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "angle", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "right", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "scale", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "child", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "crand", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "blink", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "defined", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "degrees", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inside", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "radians", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vlength", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "select", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "floor", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "strcmp", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "strlen", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tessel", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sturm", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "abs", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "acosh", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "prod", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "with", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "acos", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "asc", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "asinh", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "asin", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "atan2", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "atand", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "atanh", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "atan", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ceil", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "warp", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cosh", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "log", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "min", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mod", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pow", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "rand", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "seed", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "form", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sinh", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sqrt", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tanh", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vdot", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sin", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sqr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sum", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pwr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tan", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "val", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cos", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "div", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "exp", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "int", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sky", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "up", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ln", len)) i = len; + /* Color Identifiers */ + else if (STR_LITERAL_STARTSWITH(string, "transmit", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "filter", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "srgbft", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "srgbf", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "srgbt", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "rgbft", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gamma", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "green", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "blue", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gray", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "srgb", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sRGB", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "SRGB", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "rgbf", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "rgbt", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "rgb", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "red", len)) i = len; + /* Color Spaces */ + else if (STR_LITERAL_STARTSWITH(string, "pov", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hsl", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hsv", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "xyl", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "xyv", len)) i = len; + /* Vector Functions */ + else if (STR_LITERAL_STARTSWITH(string, "vaxis_rotate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vturbulence", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "min_extent", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vnormalize", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_extent", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vrotate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vcross", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "trace", len)) i = len; + /* String Functions */ + else if (STR_LITERAL_STARTSWITH(string, "file_time", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "datetime", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "concat", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "strlwr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "strupr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "substr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vstr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "chr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "str", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "definate") no match */ + return (i == 0 || text_check_identifier(string[i])) ? -1 : i; +} + + +static int txtfmt_pov_find_reserved_builtins(const char *string) +{ + int i, len; + + /* POV-Ray Built-in Variables + * list is from... + * http://www.povray.org/documentation/view/3.7.0/212/ + */ /* Language Keywords */ - if (STR_LITERAL_STARTSWITH(string, "aa_level", len)) i = len; + if (STR_LITERAL_STARTSWITH(string, "reflection_exponent", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "area_illumination", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "all_intersections", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cutaway_textures", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "smooth_triangle", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "lommel_seeliger", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "falloff_angle", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "aa_threshold", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hypercomplex", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "major_radius", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_distance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_iteration", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "colour_space", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "color_space", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "iridescence", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "subsurface", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "scattering", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "absorption", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "accuracy", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "adc_bailout", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "albedo", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "all_intersections", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "translucency", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "all", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "alpha", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "altitude", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "always_sample", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ambient_light", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ambient", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "angle", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "aperture", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "water_level", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "reflection", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_extent", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "oren_nayar", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "refraction", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hierarchy", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "radiosity", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tolerance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "interior", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "toroidal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "emission", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "material", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "internal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "photons", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "arc_angle", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "area_light", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "area_illumination", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "minnaert", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "texture", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "array", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "assumed_gamma", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "autostop", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "black_hole", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "blur_samples", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "brightness", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "brilliance", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "caustics", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "charset", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "collect", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "component", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "composite", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "confidence", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "conserve_energy", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "contained_by", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "coords", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "count", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "crand", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "cube", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cutaway_textures", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "diffuse", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "direction", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "dispersion", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "dist_exp", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "distance", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "eccentricity", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "emission", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "error_bound", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "evaluate", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "expand_thresholds", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "exponent", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "exterior", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "extinction", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "face_indices", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "falloff_angle", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "falloff", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "file_gamma", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "flatness", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "planet", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "screw", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "keep", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "flip", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "focal_point", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fog_alt", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fog_offset", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fog_type", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "form", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fresnel", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "function", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "gamma", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "gather", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "global_settings", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "gray_threshold", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "hf_gray_16", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "hierarchy", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "hypercomplex", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "importance", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "inside_vector", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "internal", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "intervals", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ior", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "irid_wavelength", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "irid", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "load_file", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "location", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "move", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "roll", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "look_at", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "looks_like", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "low_error_factor", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "major_radius", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_distance", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_extent", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_gradient", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_intersections", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_iteration", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_sample", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_trace_level", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max_trace", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "maximum_reuse", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "metallic", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "method", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "metric", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "minimum_reuse", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "nearest_count", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "normal_indices", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "normal_vectors", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "now", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "number_of_waves", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "offset", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "open", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "orientation", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pass_through", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "pattern", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "phong_size", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "phong", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "point_at", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pot", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "precision", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "precompute", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pretrace_end", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pretrace_start", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "prod", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pwr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "quaternion", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "radiosity", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "radius", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ratio", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "reciprocal", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "recursion_limit", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "reflection_exponent", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "reflection", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "refraction", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "width", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "repeat", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "right", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "roughness", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "samples", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "save_file", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "scattering", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bend", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "size", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sky", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "alpha", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "slice", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "smooth", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "solid", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "spacing", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "specular", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "split_union", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "spotlight", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "strength", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sturm", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sum", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "target", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "texture_list", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "thickness", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "threshold", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tightness", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tolerance", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "toroidal", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ttf", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "turb_depth", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "all", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "now", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pot", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "type", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "u_steps", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "up", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "use_alpha", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "uv_indices", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "uv_vectors", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "v_steps", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "variance", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vertex_vectors", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "water_level", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "width", len)) i = len; - - else i = 0; - - /* If next source char is an identifier (eg. 'i' in "definate") no match */ - return (i == 0 || text_check_identifier(string[i])) ? -1 : i; -} - - -static int txtfmt_pov_find_reserved_builtins(const char *string) -{ - int i, len; - - /* POV-Ray Built-in Variables - * list is from... - * http://www.povray.org/documentation/view/3.7.0/212/ - */ - if (STR_LITERAL_STARTSWITH(string, "clock_delta", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "clock", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "clock_on", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "final_clock", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "final_frame", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "frame_number", len)) i = len; + /* Animation Options */ + else if (STR_LITERAL_STARTSWITH(string, "global_settings", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "input_file_name", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "initial_clock", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "initial_frame", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "frame_number", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "image_height", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "image_width", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "input_file_name", len)) i = len; - /* Color Identifiers */ - else if (STR_LITERAL_STARTSWITH(string, "blue", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "filter", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "gray", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "green", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "red", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "rgbft", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "rgbf", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "rgbt", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "rgb", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "srgb", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sRGB", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "SRGB", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "srgbft", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "srgbf", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "srgbt", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "transmit", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "final_clock", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "final_frame", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clock_delta", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clock_on", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clock", len)) i = len; + /* Spline Identifiers */ + else if (STR_LITERAL_STARTSWITH(string, "extended_x_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "general_x_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "quadratic_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "basic_x_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "natural_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "linear_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bezier_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "akima_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cubic_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sor_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tcb_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "linear_sweep", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "conic_sweep", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "b_spline", len)) i = len; /* Patterns */ - else if (STR_LITERAL_STARTSWITH(string, "agate", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "aoi", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pigment_pattern", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "image_pattern", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "density_file", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cylindrical", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "proportion", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "triangular", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "image_map", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "proximity", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "spherical", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bump_map", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "wrinkles", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "average", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "voronoi", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "masonry", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "binary", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "boxed", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "bozo", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "brick", len)) i = len; @@ -315,14 +371,11 @@ static int txtfmt_pov_find_reserved_builtins(const char *string) else if (STR_LITERAL_STARTSWITH(string, "checker", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "crackle", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cylindrical", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "density_file", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "dents", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "facets", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "gradient", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "granite", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "hexagon", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "image_pattern", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "julia", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "leopard", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "magnet", len)) i = len; @@ -330,13 +383,11 @@ static int txtfmt_pov_find_reserved_builtins(const char *string) else if (STR_LITERAL_STARTSWITH(string, "marble", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "onion", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "pavement", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pigment_pattern", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "planar", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "quilted", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "radial", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "ripples", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "slope", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "spherical", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "spiral1", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "spiral2", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "spotted", len)) i = len; @@ -344,97 +395,68 @@ static int txtfmt_pov_find_reserved_builtins(const char *string) else if (STR_LITERAL_STARTSWITH(string, "tile2", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "tiling", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "tiles", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "triangular", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "waves", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "wood", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "wrinkles", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "agate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "aoi", len)) i = len; /* Objects */ - else if (STR_LITERAL_STARTSWITH(string, "background", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "superellipsoid", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "bicubic_patch", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "blob", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "box", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "camera", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cone", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "julia_fractal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "height_field", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cubic_spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sphere_sweep", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "light_group", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "light_source", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "intersection", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "isosurface", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "background", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sky_sphere", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "cylinder", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "difference", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "brilliance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "parametric", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "interunion", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "intermerge", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "polynomial", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "displace", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "specular", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ambient", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "diffuse", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "polygon", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "quadric", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "quartic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "rainbow", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sphere", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "spline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "prism", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "galley", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "phong", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cone", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "blob", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "box", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "disc", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "fog", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "height_field", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "intersection", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "isosurface", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "julia_fractal", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "lathe", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "light_group", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "light_source", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "merge", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "mesh2", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "mesh", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "object", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "ovus", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "lemon", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "parametric", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "plane", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "poly", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "polygon", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "polynomial", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "prism", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "quadric", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "quartic", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "rainbow", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sky_sphere", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "smooth_triangle", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cubic_spline", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sphere_sweep", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sphere", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "spline", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "superellipsoid", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "irid", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "sor", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "text", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "torus", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "triangle", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "union", len)) i = len; - /* Filetypes */ - else if (STR_LITERAL_STARTSWITH(string, "df3", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "exr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "gif", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "hdr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "iff", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "jpeg", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pgm", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "png", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ppm", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sys", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tga", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tiff", len)) i = len; - /* Spline Identifiers */ - else if (STR_LITERAL_STARTSWITH(string, "b_spline", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "bezier_spline", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "conic_sweep", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cubic_spline", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "linear_spline", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "linear_sweep", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "natural_spline", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "quadratic_spline", len)) i = len; - /* Encodings */ - else if (STR_LITERAL_STARTSWITH(string, "ascii", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "utf8", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "uint8", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "uint16be", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "uint16le", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sint8", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sint16be", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sint16le", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sint32be", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sint32le", len)) i = len; - /* Camera Types */ - else if (STR_LITERAL_STARTSWITH(string, "fisheye", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "mesh_camera", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "omnimax", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "orthographic", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "panoramic", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "perspective", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ultra_wide_angle", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "colour", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "color", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "media", len)) i = len; /* Built-in Vectors */ else if (STR_LITERAL_STARTSWITH(string, "t", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "u", len)) i = len; @@ -442,7 +464,6 @@ static int txtfmt_pov_find_reserved_builtins(const char *string) else if (STR_LITERAL_STARTSWITH(string, "x", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "y", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "z", len)) i = len; - else i = 0; /* If next source char is an identifier (eg. 'i' in "definate") no match */ @@ -465,156 +486,201 @@ static int txtfmt_pov_find_specialvar(const char *string) { int i, len; /* Modifiers */ - if (STR_LITERAL_STARTSWITH(string, "interior_texture", len)) i = len; + if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "projected_through", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "double_illuminate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "expand_thresholds", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "media_interaction", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "media_attenuation", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "projected_through", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "low_error_factor", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "recursion_limit", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "interior_texture", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_trace_level", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gray_threshold", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pretrace_start", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "normal_indices", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "normal_vectors", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vertex_vectors", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "noise_generator", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "irid_wavelength", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "number_of_waves", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ambient_light", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inside_vector", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "face_indices", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "texture_list", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_gradient", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uv_indices", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uv_vectors", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fade_distance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "global_lights", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "no_bump_scale", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pretrace_end", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "no_radiosity", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "no_reflection", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "assumed_gamma", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "scallop_wave", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "triangle_wave", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "nearest_count", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "maximum_reuse", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "minimum_reuse", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "always_sample", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "translucency", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "eccentricity", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "contained_by", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inside_point", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "adc_bailout", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "density_map", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "split_union", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mm_per_unit", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "agate_turb", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "bounded_by", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "brick_size", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "bump_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "bump_size", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "circular", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "clipped_by", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hf_gray_16", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dispersion", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "extinction", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "thickness", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "color_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "color", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "colour_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "colour", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "control0", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "control1", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "cubic_wave", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "density_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "density", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fade_color", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "fade_colour", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fade_distance", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "fade_power", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "frequency", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "global_lights", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "hollow", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "image_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "adaptive", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "interior", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "interpolate", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "inverse", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "jitter", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "lambda", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "map_type", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "material_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "material", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "matrix", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "media", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "mm_per_unit", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "mortar", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "no_bump_scale", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "no_image", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "no_radiosity", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "no_reflection", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "no_shadow", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fade_color", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "normal_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "normal", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "octaves", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "omega", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "once", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "orient", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "parallel", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "phase", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "photons", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "pigment_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pigment", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "finish", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "poly_wave", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "quick_color", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "quick_colour", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ramp_wave", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "rotate", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "scale", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "scallop_wave", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "shadowless", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sine_wave", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "slope_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "subsurface", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "material_map", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pass_through", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "interpolate", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "texture_map", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "texture", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "transform", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "translate", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "triangle_wave", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "turbulence", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "error_bound", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "brightness", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "use_color", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "use_alpha", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "use_colour", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "use_index", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "uv_mapping", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "warp", len)) i = len; - - /* Vector Functions */ - else if (STR_LITERAL_STARTSWITH(string, "max_extent", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "min_extent", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "trace", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vaxis_rotate", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vcross", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vnormalize", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vrotate", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vturbulence", len)) i = len; - /* String Functions */ - else if (STR_LITERAL_STARTSWITH(string, "chr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "concat", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "datetime", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "str", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "strlwr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "strupr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "substr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vstr", len)) i = len; - /* Float Functions */ - else if (STR_LITERAL_STARTSWITH(string, "abs", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "acosh", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "acos", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "asc", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "asinh", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "asin", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "atan2", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "atand", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "atanh", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "atan", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "bitwise_and", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "bitwise_or", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "bitwise_xor", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ceil", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cosh", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "cos", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "defined", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "degrees", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "dimension_size", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "dimensions", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "div", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "exp", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "file_exists", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "floor", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "inside", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "int", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ln", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "log", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "max", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "min", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "mod", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pow", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "radians", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "rand", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "seed", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "select", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sinh", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sin", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sqrt", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "sqr", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "strcmp", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "strlen", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tanh", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tan", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "val", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vdot", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "vlength", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "importance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max_sample", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "intervals", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sine_wave", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "slope_map", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "poly_wave", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "no_shadow", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ramp_wave", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "precision", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "original", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "accuracy", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "map_type", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "no_image", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "distance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "autostop", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "caustics", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "octaves", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "aa_level", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "frequency", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fog_offset", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "modulation", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "outbound", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "no_cache", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pigment", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "charset", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inbound", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "outside", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inner", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "turbulence", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "threshold", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "accuracy", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "polarity", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bump_size", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "circular", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "control0", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "control1", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "maximal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "minimal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fog_type", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fog_alt", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "samples", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "origin", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "amount", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "adaptive", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "exponent", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "strength", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "density", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fresnel", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "albinos", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "finish", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "method", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "omega", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fixed", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "spacing", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "u_steps", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "v_steps", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "offset", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hollow", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gather", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "lambda", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mortar", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "count", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "once", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "orient", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "normal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "phase", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ratio", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "open", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ior", len)) i = len; + /* Light Types and options*/ + else if (STR_LITERAL_STARTSWITH(string, "area_light", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "looks_like", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fade_power", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tightness", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "spotlight", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "parallel", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "point_at", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "falloff", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "radius", len)) i = len; + /* Camera Types and options*/ + else if (STR_LITERAL_STARTSWITH(string, "omni_directional_stereo", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "lambert_cylindrical", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "miller_cylindrical", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "lambert_azimuthal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ultra_wide_angle", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_direction", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_location ", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "van_der_grinten", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "aitoff_hammer", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "smyth_craster", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "orthographic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_right", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "blur_samples", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "plate_carree", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_type", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "perspective", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mesh_camera", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "focal_point", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "balthasart", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "confidence", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "parallaxe", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hobo_dyer", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "camera_up", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "panoramic", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "eckert_vi", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "eckert_iv", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mollweide", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "aperture", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "behrmann", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "variance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "stereo", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "icosa", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tetra", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "octa", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mercator", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "omnimax", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fisheye", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "edwards", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "peters", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gall", len)) i = len; else i = 0; /* If next source char is an identifier (eg. 'i' in "definate") no match */ @@ -625,15 +691,43 @@ static int txtfmt_pov_find_bool(const char *string) { int i, len; /*Built-in Constants*/ - if (STR_LITERAL_STARTSWITH(string, "false", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "no", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "off", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "true", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "yes", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "on", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "pi", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "tau", len)) i = len; - else i = 0; + if (STR_LITERAL_STARTSWITH(string, "unofficial", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "false", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "no", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "off", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "true", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "yes", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "on", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pi", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tau", len)) i = len; + /* Encodings */ + else if (STR_LITERAL_STARTSWITH(string, "sint16be", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sint16le", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sint32be", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sint32le", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uint16be", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uint16le", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bt2020", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bt709", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sint8", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uint8", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ascii", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "utf8", len)) i = len; + /* Filetypes */ + else if (STR_LITERAL_STARTSWITH(string, "tiff", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "df3", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "exr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gif", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "hdr", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "iff", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "jpeg", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pgm", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "png", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ppm", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sys", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tga", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ttf", len)) i = len; + else i = 0; /* If next source char is an identifier (eg. 'i' in "Nonetheless") no match */ return (i == 0 || text_check_identifier(string[i])) ? -1 : i; @@ -645,7 +739,7 @@ static char txtfmt_pov_format_identifier(const char *str) if ((txtfmt_pov_find_specialvar(str)) != -1) fmt = FMT_TYPE_SPECIAL; else if ((txtfmt_pov_find_keyword(str)) != -1) fmt = FMT_TYPE_KEYWORD; else if ((txtfmt_pov_find_reserved_keywords(str)) != -1) fmt = FMT_TYPE_RESERVED; - else if ((txtfmt_pov_find_reserved_builtins(str)) != -1) fmt = FMT_TYPE_RESERVED; + else if ((txtfmt_pov_find_reserved_builtins(str)) != -1) fmt = FMT_TYPE_DIRECTIVE; else fmt = FMT_TYPE_DEFAULT; return fmt; } @@ -770,7 +864,7 @@ static void txtfmt_pov_format_line(SpaceText *st, TextLine *line, const bool do_ if ((i = txtfmt_pov_find_specialvar(str)) != -1) prev = FMT_TYPE_SPECIAL; else if ((i = txtfmt_pov_find_keyword(str)) != -1) prev = FMT_TYPE_KEYWORD; else if ((i = txtfmt_pov_find_reserved_keywords(str)) != -1) prev = FMT_TYPE_RESERVED; - else if ((i = txtfmt_pov_find_reserved_builtins(str)) != -1) prev = FMT_TYPE_RESERVED; + else if ((i = txtfmt_pov_find_reserved_builtins(str)) != -1) prev = FMT_TYPE_DIRECTIVE; if (i > 0) { text_format_fill_ascii(&str, &fmt, prev, i); diff --git a/source/blender/editors/space_text/text_format_pov_ini.c b/source/blender/editors/space_text/text_format_pov_ini.c index 719f4e3c036..453dd1d748c 100644 --- a/source/blender/editors/space_text/text_format_pov_ini.c +++ b/source/blender/editors/space_text/text_format_pov_ini.c @@ -49,36 +49,36 @@ static int txtfmt_ini_find_keyword(const char *string) { int i, len; /* Language Directives */ - if (STR_LITERAL_STARTSWITH(string, "append", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "debug", len)) i = len; + if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "declare", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "default", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "version", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "warning", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "include", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fclose", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ifndef", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "append", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "elseif", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "end", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "debug", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "error", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "fclose", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "fopen", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "ifdef", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ifndef", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "include", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "local", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "macro", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "range", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "read", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "render", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "switch", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "undef", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "version", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "warning", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "while", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "write", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "read", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "end", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "I", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "S", len)) i = len; @@ -104,29 +104,54 @@ static int txtfmt_ini_find_reserved(const char *string) * list is from... * http://www.povray.org/documentation/view/3.7.0/212/ */ - if (STR_LITERAL_STARTSWITH(string, "Antialias_Threshold", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Bounding_Method", len)) i = len; + if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSoundEnabled", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Create_Continue_Trace_Log", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSoundEnabled", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSoundEnabled", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "HideWhenMainMinimized", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Antialias_Confidence", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSound", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSound", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSound", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "UseExtensions", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ReadWriteSourceDir", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "NormalPositionLeft", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "NormalPositionTop", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "NormalPositionRight", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "NormalPositionBottom", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Pre_Scene_Command", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Pre_Frame_Command", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Post_Scene_Command", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Post_Frame_Command", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "User_Abort_Command", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Fatal_Error_Command", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "NormalPositionX", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "NormalPositionY", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Pre_Scene_Return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Pre_Frame_Return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Post_Scene_Return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Post_Frame_Return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "User_Abort_Return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Fatal_Error_Return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Antialias_Threshold", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Antialias_Gamma", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Antialias_Depth", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "clock_delta", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "clock_on", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "clock", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "final_clock", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "final_frame", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "frame_number", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "initial_clock", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "initial_frame", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "image_height", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "image_width", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "input_file_name", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Subset_Start_Frame", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Subset_End_Frame", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "UseToolbar", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "UseTooltips", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Frame_Step", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Cyclic_Animation", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Field_Render", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Odd_Field", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Height", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Width", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "final_clock", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "final_frame", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "frame_number", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "initial_clock", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "initial_frame", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "image_height", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "image_width", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Start_Column", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Start_Row", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "End_Column", len)) i = len; @@ -134,7 +159,7 @@ static int txtfmt_ini_find_reserved(const char *string) else if (STR_LITERAL_STARTSWITH(string, "Test_Abort_Count", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Test_Abort", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Continue_Trace", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Create_Continue_Trace_Log", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Bounding_Method", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Create_Ini", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Display_Gamma", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Display", len)) i = len; @@ -151,19 +176,6 @@ static int txtfmt_ini_find_reserved(const char *string) else if (STR_LITERAL_STARTSWITH(string, "Bits_Per_Color", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Compression", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Dither_Method", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Dither", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Pre_Scene_Command", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Pre_Frame_Command", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Post_Scene_Command", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Post_Frame_Command", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "User_Abort_Command", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Fatal_Error_Command", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Pre_Scene_Return", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Pre_Frame_Return", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Post_Scene_Return", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Post_Frame_Return", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "User_Abort_Return", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Fatal_Error_Return", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Include_Header", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Library_Path", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Debug_Console", len)) i = len; @@ -187,7 +199,9 @@ static int txtfmt_ini_find_reserved(const char *string) else if (STR_LITERAL_STARTSWITH(string, "Remove_Bounds", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Split_Unions", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Antialias", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Glare_Desaturation", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Sampling_Method", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Stochastic_Seed", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Jitter_Amount", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Jitter", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Antialias_Depth", len)) i = len; @@ -221,25 +235,14 @@ static int txtfmt_ini_find_reserved(const char *string) else if (STR_LITERAL_STARTSWITH(string, "Band3Width", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Band4Width", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "ShowCmd", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "NormalPositionLeft", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "NormalPositionTop", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "NormalPositionRight", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "NormalPositionBottom", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "UseToolbar", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "UseTooltips", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "NormalPositionX", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "NormalPositionY", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Flags", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Transparency", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Use8BitMode", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "MakeActive", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "KeepAboveMain", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "HideWhenMainMinimized", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "AutoClose", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "PreserveBitmap", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "FontSize", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "FontWeight", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "Font", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "KeepMessages", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "AlertSound", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Completion", len)) i = len; @@ -250,14 +253,6 @@ static int txtfmt_ini_find_reserved(const char *string) else if (STR_LITERAL_STARTSWITH(string, "PreventSleep", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "NoShelloutWait", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "SystemNoActive", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSoundEnabled", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSoundEnabled", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSoundEnabled", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSound", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSound", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSound", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "UseExtensions", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "ReadWriteSourceDir", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "NoShellOuts", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "VideoSource", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "SceneFile", len)) i = len; @@ -269,6 +264,14 @@ static int txtfmt_ini_find_reserved(const char *string) else if (STR_LITERAL_STARTSWITH(string, "RenderwinClose", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Append_File", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "Warning Level", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clock_delta", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clock_on", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clock", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Height", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Width", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Dither", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Flags", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "Font", len)) i = len; /* Filetypes */ else if (STR_LITERAL_STARTSWITH(string, "df3", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "exr", len)) i = len; diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index 15eb154c757..f29d2b30ffe 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -329,6 +329,8 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel) case ID_CF: cachefile_to_keylist(&ads, (CacheFile *)id, &keys, NULL); break; + default: + break; } /* build linked-list for searching */ diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 73fd77db477..5f01092f5b0 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -8457,8 +8457,8 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec else { Mesh *me = ob->data; if ((me->editflag & ME_EDIT_PAINT_VERT_SEL) && - /* currently vertex select only supports weight paint */ - (ob->mode & OB_MODE_WEIGHT_PAINT)) + /* currently vertex select supports weight paint and vertex paint*/ + ((ob->mode & OB_MODE_WEIGHT_PAINT) || (ob->mode & OB_MODE_VERTEX_PAINT))) { bbs_mesh_solid_verts(scene, ob); } diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index b8228c63209..996506a9cf7 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1412,33 +1412,31 @@ static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_i } } } - if ((ID *)v3d->ob_centre == old_id) { - v3d->ob_centre = (Object *)new_id; - if (new_id == NULL) { /* Otherwise, bonename may remain valid... We could be smart and check this, too? */ - v3d->ob_centre_bone[0] = '\0'; - } - } - if ((ID *)v3d->defmaterial == old_id) { - v3d->defmaterial = (Material *)new_id; - } -#if 0 /* XXX Deprecated? */ - if ((ID *)v3d->gpd == old_id) { - v3d->gpd = (bGPData *)new_id; - } -#endif + /* Values in local-view aren't used, see: T52663 */ + if (is_local == false) { + /* Skip 'v3d->defmaterial', it's not library data. */ - if (ELEM(GS(old_id->name), ID_IM, ID_MC)) { - for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { - if ((ID *)bgpic->ima == old_id) { - bgpic->ima = (Image *)new_id; - id_us_min(old_id); - id_us_plus(new_id); + if ((ID *)v3d->ob_centre == old_id) { + v3d->ob_centre = (Object *)new_id; + /* Otherwise, bonename may remain valid... We could be smart and check this, too? */ + if (new_id == NULL) { + v3d->ob_centre_bone[0] = '\0'; } - if ((ID *)bgpic->clip == old_id) { - bgpic->clip = (MovieClip *)new_id; - id_us_min(old_id); - id_us_plus(new_id); + } + + if (ELEM(GS(old_id->name), ID_IM, ID_MC)) { + for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { + if ((ID *)bgpic->ima == old_id) { + bgpic->ima = (Image *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + if ((ID *)bgpic->clip == old_id) { + bgpic->clip = (MovieClip *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } } } } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 250e6559b8f..56508ea989a 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -2471,6 +2471,7 @@ static void view3d_draw_depth_loop(Scene *scene, ARegion *ar, View3D *v3d) void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaoverride) { + struct bThemeState theme_state; RegionView3D *rv3d = ar->regiondata; short zbuf = v3d->zbuf; short flag = v3d->flag; @@ -2483,6 +2484,10 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; /* not that nice but means we wont zoom into billboards */ U.obcenter_dia = 0; + /* Tools may request depth outside of regular drawing code. */ + UI_Theme_Store(&theme_state); + UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); + /* Setup view matrix. */ ED_view3d_draw_setup_view(NULL, scene, ar, v3d, rv3d->viewmat, rv3d->winmat, NULL); @@ -2510,6 +2515,8 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover U.glalphaclip = glalphaclip; v3d->flag = flag; U.obcenter_dia = obcenter_dia; + + UI_Theme_Restore(&theme_state); } void ED_view3d_draw_select_loop( @@ -2592,7 +2599,7 @@ static void gpu_render_lamp_update(Scene *scene, View3D *v3d, if (layers && GPU_lamp_has_shadow_buffer(lamp) && /* keep last, may do string lookup */ - GPU_lamp_override_visible(lamp, srl, NULL)) + GPU_lamp_visible(lamp, srl, NULL)) { shadow = MEM_callocN(sizeof(View3DShadow), "View3DShadow"); shadow->lamp = lamp; diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 4e3f279e12e..97fcca11962 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -726,10 +726,15 @@ static enum eViewOpsOrbit viewops_orbit_mode(void) /** * Calculate the values for #ViewOpsData + * + * \param use_ensure_persp: When enabled run #view3d_ensure_persp this may switch out of + * camera view when orbiting or switch from ortho to perspective when auto-persp is enabled. + * Some operations don't require this (view zoom/pan or ndof where subtle rotation is common + * so we don't want it to trigger auto-perspective). */ static void viewops_data_create_ex( bContext *C, wmOperator *op, const wmEvent *event, - bool switch_from_camera, enum eViewOpsOrbit orbit_mode) + bool use_ensure_persp, enum eViewOpsOrbit orbit_mode) { ViewOpsData *vod = op->customdata; RegionView3D *rv3d = vod->rv3d; @@ -750,8 +755,7 @@ static void viewops_data_create_ex( vod->use_dyn_ofs = false; } - if (switch_from_camera) { - /* switch from camera view when: */ + if (use_ensure_persp) { if (view3d_ensure_persp(vod->v3d, vod->ar)) { /* If we're switching from camera view to the perspective one, * need to tag viewport update, so camera vuew and borders @@ -853,10 +857,10 @@ static void viewops_data_create_ex( rv3d->rflag |= RV3D_NAVIGATING; } -static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event, bool switch_from_camera) +static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event, bool use_ensure_persp) { enum eViewOpsOrbit orbit_mode = viewops_orbit_mode(); - viewops_data_create_ex(C, op, event, switch_from_camera, orbit_mode); + viewops_data_create_ex(C, op, event, use_ensure_persp, orbit_mode); } static void viewops_data_free(bContext *C, wmOperator *op) @@ -1673,7 +1677,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) viewops_data_alloc(C, op); viewops_data_create_ex( C, op, event, - viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false), false); + false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); vod = op->customdata; ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); @@ -1742,7 +1746,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev viewops_data_alloc(C, op); viewops_data_create_ex( C, op, event, - viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false), false); + false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); vod = op->customdata; @@ -4753,13 +4757,20 @@ void ED_view3d_cursor3d_update(bContext *C, const int mval[2]) ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = ar->regiondata; - float co_curr[2], co_prev[2]; + if (U.uiflag & USER_LOCK_CURSOR_ADJUST) { - if ((ED_view3d_project_float_global(ar, fp_prev, co_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) && - (ED_view3d_project_float_global(ar, fp_curr, co_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK)) - { - rv3d->ofs_lock[0] += (co_curr[0] - co_prev[0]) / (ar->winx * 0.5f); - rv3d->ofs_lock[1] += (co_curr[1] - co_prev[1]) / (ar->winy * 0.5f); + float co_curr[2], co_prev[2]; + + if ((ED_view3d_project_float_global(ar, fp_prev, co_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) && + (ED_view3d_project_float_global(ar, fp_curr, co_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK)) + { + rv3d->ofs_lock[0] += (co_curr[0] - co_prev[0]) / (ar->winx * 0.5f); + rv3d->ofs_lock[1] += (co_curr[1] - co_prev[1]) / (ar->winy * 0.5f); + } + } + else { + /* Cursor may be outside of the view, prevent it getting 'lost', see: T40353 & T45301 */ + zero_v2(rv3d->ofs_lock); } } diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index bf1bdf68619..70caee66b29 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -350,7 +350,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) PointerRNA meshptr; RNA_pointer_create(ob->data, &RNA_Mesh, ob->data, &meshptr); - if (ob->mode & (OB_MODE_TEXTURE_PAINT | OB_MODE_VERTEX_PAINT)) { + if (ob->mode & (OB_MODE_TEXTURE_PAINT)) { uiItemR(layout, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); } else { diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index aefe30bbe32..714db0db0ff 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -48,7 +48,6 @@ #include "ED_screen.h" #include "ED_view3d.h" -#include "ED_transform.h" #include "ED_transform_snap_object_context.h" #include "ED_space_api.h" diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 5c13fd37dda..16b626a5be4 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -54,6 +54,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "UI_resources.h" + #include "GPU_select.h" #include "WM_api.h" @@ -812,19 +814,108 @@ bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb) return view3d_boundbox_clip_m4(bb, rv3d->persmatob); } -float ED_view3d_depth_read_cached(const ViewContext *vc, int x, int y) +/* -------------------------------------------------------------------- */ + +/** \name Depth Utilities + * \{ */ + +float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2]) { ViewDepths *vd = vc->rv3d->depths; - x -= vc->ar->winrct.xmin; - y -= vc->ar->winrct.ymin; + int x = mval[0]; + int y = mval[1]; - if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) + if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) { return vd->depths[y * vd->w + x]; - else - return 1; + } + else { + BLI_assert(1.0 <= vd->depth_range[1]); + return 1.0f; + } +} + +bool ED_view3d_depth_read_cached_normal( + const ViewContext *vc, const bglMats *mats, const int mval[2], + float r_normal[3]) +{ + /* Note: we could support passing in a radius. + * For now just read 9 pixels. */ + + /* pixels surrounding */ + bool depths_valid[9] = {false}; + float coords[9][3] = {{0}}; + + ARegion *ar = vc->ar; + const ViewDepths *depths = vc->rv3d->depths; + + for (int x = 0, i = 0; x < 2; x++) { + for (int y = 0; y < 2; y++) { + const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)}; + + const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs); + if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { + if (ED_view3d_depth_unproject(ar, mats, mval_ofs, depth, coords[i])) { + depths_valid[i] = true; + } + } + i++; + } + } + + const int edges[2][6][2] = { + /* x edges */ + {{0, 1}, {1, 2}, + {3, 4}, {4, 5}, + {6, 7}, {7, 8}}, + /* y edges */ + {{0, 3}, {3, 6}, + {1, 4}, {4, 7}, + {2, 5}, {5, 8}}, + }; + + float cross[2][3] = {{0.0f}}; + + for (int i = 0; i < 6; i++) { + for (int axis = 0; axis < 2; axis++) { + if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) { + float delta[3]; + sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]); + add_v3_v3(cross[axis], delta); + } + } + } + + cross_v3_v3v3(r_normal, cross[0], cross[1]); + + if (normalize_v3(r_normal) != 0.0f) { + return true; + } + else { + return false; + } } +bool ED_view3d_depth_unproject( + const ARegion *ar, const bglMats *mats, + const int mval[2], const double depth, + float r_location_world[3]) +{ + double p[3]; + if (gluUnProject( + (double)ar->winrct.xmin + mval[0] + 0.5, + (double)ar->winrct.ymin + mval[1] + 0.5, + depth, mats->modelview, mats->projection, (const GLint *)mats->viewport, + &p[0], &p[1], &p[2])) + { + copy_v3fl_v3db(r_location_world, p); + return true; + } + return false; +} + +/** \} */ + void ED_view3d_depth_tag_update(RegionView3D *rv3d) { if (rv3d->depths) @@ -1117,6 +1208,7 @@ int view3d_opengl_select( ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, eV3DSelectMode select_mode) { + struct bThemeState theme_state; Scene *scene = vc->scene; View3D *v3d = vc->v3d; ARegion *ar = vc->ar; @@ -1161,6 +1253,10 @@ int view3d_opengl_select( } } + /* Tools may request depth outside of regular drawing code. */ + UI_Theme_Store(&theme_state); + UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); + /* Re-use cache (rect must be smaller then the cached) * other context is assumed to be unchanged */ if (GPU_select_is_cached()) { @@ -1213,6 +1309,8 @@ int view3d_opengl_select( finally: if (hits < 0) printf("Too many objects in select buffer\n"); /* XXX make error message */ + UI_Theme_Restore(&theme_state); + return hits; } diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 542dc410bc3..5248a260617 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -49,7 +49,6 @@ #include "ED_screen.h" #include "ED_space_api.h" -#include "ED_transform.h" #include "ED_transform_snap_object_context.h" #include "PIL_time.h" /* smoothview */ @@ -674,16 +673,6 @@ static int walkEnd(bContext *C, WalkInfo *walk) return OPERATOR_CANCELLED; } -static bool wm_event_is_last_mousemove(const wmEvent *event) -{ - while ((event = event->next)) { - if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { - return false; - } - } - return true; -} - static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent *event) { if (event->type == TIMER && event->customdata == walk->timer) { @@ -736,7 +725,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent } else #endif - if (wm_event_is_last_mousemove(event)) { + if (WM_event_is_last_mousemove(event)) { wmWindow *win = CTX_wm_window(C); #ifdef __APPLE__ diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index ca6e2267218..c2f04005e83 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -51,7 +51,7 @@ #include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_ghash.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_memarena.h" #include "BKE_nla.h" @@ -2878,7 +2878,9 @@ static void initBend(TransInfo *t) t->flag |= T_NO_CONSTRAINT; //copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view)); - calculateCenterCursor(t, t->center); + if ((t->flag & T_OVERRIDE_CENTER) == 0) { + calculateCenterCursor(t, t->center); + } calculateCenterGlobal(t, t->center, t->center_global); t->val = 0.0f; @@ -8360,8 +8362,15 @@ static void initTimeSlide(TransInfo *t) TransData *td = t->data; for (i = 0; i < t->total; i++, td++) { - if (min > *(td->val)) min = *(td->val); - if (max < *(td->val)) max = *(td->val); + AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; + float val = *(td->val); + + /* strip/action time to global (mapped) time */ + if (adt) + val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP); + + if (min > val) min = val; + if (max < val) max = val; } if (min == max) { @@ -8436,25 +8445,38 @@ static void applyTimeSlideValue(TransInfo *t, float sval) */ AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; float cval = t->values[0]; - - /* apply NLA-mapping to necessary values */ - if (adt) - cval = BKE_nla_tweakedit_remap(adt, cval, NLATIME_CONVERT_UNMAP); - + /* only apply to data if in range */ if ((sval > minx) && (sval < maxx)) { float cvalc = CLAMPIS(cval, minx, maxx); + float ival = td->ival; float timefac; - + + /* NLA mapping magic here works as follows: + * - "ival" goes from strip time to global time + * - calculation is performed into td->val in global time + * (since sval and min/max are all in global time) + * - "td->val" then gets put back into strip time + */ + if (adt) { + /* strip to global */ + ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP); + } + /* left half? */ - if (td->ival < sval) { - timefac = (sval - td->ival) / (sval - minx); + if (ival < sval) { + timefac = (sval - ival) / (sval - minx); *(td->val) = cvalc - timefac * (cvalc - minx); } else { - timefac = (td->ival - sval) / (maxx - sval); + timefac = (ival - sval) / (maxx - sval); *(td->val) = cvalc + timefac * (maxx - cvalc); } + + if (adt) { + /* global to strip */ + *(td->val) = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_UNMAP); + } } } } @@ -8513,9 +8535,11 @@ static void initTimeScale(TransInfo *t) /* recalculate center2d to use CFRA and mouse Y, since that's * what is used in time scale */ - t->center[0] = t->scene->r.cfra; - projectFloatView(t, t->center, center); - center[1] = t->mouse.imval[1]; + if ((t->flag & T_OVERRIDE_CENTER) == 0) { + t->center[0] = t->scene->r.cfra; + projectFloatView(t, t->center, center); + center[1] = t->mouse.imval[1]; + } /* force a reinit with the center2d used here */ initMouseInput(t, &t->mouse, center, t->mouse.imval, false); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index d60eb2f0778..06a60456cdb 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -533,6 +533,9 @@ typedef struct TransInfo { /* alternative transformation. used to add offset to tracking markers */ #define T_ALT_TRANSFORM (1 << 24) + /** #TransInfo.center has been set, don't change it. */ +#define T_OVERRIDE_CENTER (1 << 25) + /* TransInfo->modifiers */ #define MOD_CONSTRAINT_SELECT 0x01 #define MOD_PRECISION 0x02 diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index d7b670b6476..5621eede543 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -831,6 +831,13 @@ static void drawObjectConstraint(TransInfo *t) } } + if (t->options & CTX_GPENCIL_STROKES) { + /* only draw a constraint line for one point, otherwise we can't see anything */ + if ((options & DRAWLIGHT) == 0) { + break; + } + } + if (t->flag & T_OBJECT) { copy_v3_v3(co, td->ob->obmat[3]); axismtx = td->axismtx; diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 4429d19613a..9d63afeb85c 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -807,7 +807,6 @@ static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen) /* change the chain-length of auto-ik */ void transform_autoik_update(TransInfo *t, short mode) { - const short old_len = t->settings->autoik_chainlen; short *chainlen = &t->settings->autoik_chainlen; bPoseChannel *pchan; @@ -818,12 +817,13 @@ void transform_autoik_update(TransInfo *t, short mode) } else if (mode == -1) { /* mode==-1 is from WHEELMOUSEUP... decreases len */ - if (*chainlen > 0) (*chainlen)--; - } - - /* IK length did not change, skip any updates. */ - if (old_len == *chainlen) { - return; + if (*chainlen > 0) { + (*chainlen)--; + } + else { + /* IK length did not change, skip updates. */ + return; + } } /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */ @@ -2801,7 +2801,7 @@ void flushTransSeq(TransInfo *t) tdsq = (TransDataSeq *)td->extra; seq = tdsq->seq; old_start = seq->start; - new_frame = iroundf(td2d->loc[0]); + new_frame = round_fl_to_int(td2d->loc[0]); switch (tdsq->sel_flag) { case SELECT: @@ -2813,7 +2813,7 @@ void flushTransSeq(TransInfo *t) seq->start = new_frame - tdsq->start_offset; #endif if (seq->depth == 0) { - seq->machine = iroundf(td2d->loc[1]); + seq->machine = round_fl_to_int(td2d->loc[1]); CLAMP(seq->machine, 1, MAXSEQ); } break; @@ -3761,7 +3761,7 @@ void flushTransIntFrameActionData(TransInfo *t) /* flush data! */ for (i = 0; i < t->total; i++, tfd++) { - *(tfd->sdata) = iroundf(tfd->val); + *(tfd->sdata) = round_fl_to_int(tfd->val); } } @@ -4789,7 +4789,7 @@ void flushTransGraphData(TransInfo *t) /* if int-values only, truncate to integers */ if (td->flag & TD_INTVALUES) - td2d->loc2d[1] = floorf(td2d->loc[1] + 0.5f); + td2d->loc2d[1] = floorf(td2d->loc[1] * inv_unit_scale - tdg->offset + 0.5f); else td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset; @@ -5606,9 +5606,7 @@ static void set_trans_object_base_flags(TransInfo *t) } /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ -#ifdef WITH_LEGACY_DEPSGRAPH DAG_scene_flush_update(G.main, t->scene, -1, 0); -#endif /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ @@ -5687,9 +5685,7 @@ static int count_proportional_objects(TransInfo *t) /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ DAG_scene_relations_update(G.main, t->scene); -#ifdef WITH_LEGACY_DEPSGRAPH DAG_scene_flush_update(G.main, t->scene, -1, 0); -#endif /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ @@ -5976,27 +5972,23 @@ static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t) { SpaceClip *sc = t->sa->spacedata.first; MovieClip *clip = ED_space_clip_get_clip(sc); - MovieTrackingPlaneTrack *plane_track; ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); - int framenr = ED_space_clip_get_clip_frame_number(sc); - - for (plane_track = plane_tracks_base->first; + const int framenr = ED_space_clip_get_clip_frame_number(sc); + /* Update coordinates of modified plane tracks. */ + for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) { bool do_update = false; - if (plane_track->flag & PLANE_TRACK_HIDDEN) { continue; } - do_update |= PLANE_TRACK_VIEW_SELECTED(plane_track) != 0; if (do_update == false) { if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) { int i; for (i = 0; i < plane_track->point_tracksnr; i++) { MovieTrackingTrack *track = plane_track->point_tracks[i]; - if (TRACK_VIEW_SELECTED(sc, track)) { do_update = true; break; @@ -6004,15 +5996,14 @@ static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t) } } } - if (do_update) { BKE_tracking_track_plane_from_existing_motion(plane_track, framenr); } } - - if (t->scene->nodetree) { - /* tracks can be used for stabilization nodes, - * flush update for such nodes */ + if (t->scene->nodetree != NULL) { + /* Tracks can be used for stabilization nodes, + * flush update for such nodes. + */ nodeUpdateID(t->scene->nodetree, &clip->id); WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL); } @@ -7840,7 +7831,7 @@ static void createTransGPencil(bContext *C, TransInfo *t) float mtx[3][3], smtx[3][3]; const Scene *scene = CTX_data_scene(C); - const int cfra = CFRA; + const int cfra_scene = CFRA; const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0; @@ -7865,7 +7856,7 @@ static void createTransGPencil(bContext *C, TransInfo *t) if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf = gpl->actframe; bGPDstroke *gps; - + for (gps = gpf->strokes.first; gps; gps = gps->next) { /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) { @@ -7921,6 +7912,7 @@ static void createTransGPencil(bContext *C, TransInfo *t) for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* only editable and visible layers are considered */ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { + const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene; bGPDframe *gpf = gpl->actframe; bGPDstroke *gps; float diff_mat[4][4]; @@ -7937,7 +7929,6 @@ static void createTransGPencil(bContext *C, TransInfo *t) * - This is useful when animating as it saves that "uh-oh" moment when you realize you've * spent too much time editing the wrong frame... */ - // XXX: should this be allowed when framelock is enabled? if (gpf->framenum != cfra) { gpf = BKE_gpencil_frame_addcopy(gpl, cfra); /* in some weird situations (framelock enabled) return NULL */ diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index c23da19f830..179b68dd270 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1331,7 +1331,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->current_orientation = V3D_MANIP_GLOBAL; } } - + if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && RNA_property_is_set(op->ptr, prop))) { @@ -1435,6 +1435,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve #endif setTransformViewAspect(t, t->aspect); + + if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_get_array(op->ptr, prop, t->center); + mul_v3_v3(t->center, t->aspect); + t->flag |= T_OVERRIDE_CENTER; + } + setTransformViewMatrices(t); initNumInput(&t->num); } @@ -1835,7 +1842,9 @@ static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[ void calculateCenter(TransInfo *t) { - calculateCenter_FromAround(t, t->around, t->center); + if ((t->flag & T_OVERRIDE_CENTER) == 0) { + calculateCenter_FromAround(t, t->around, t->center); + } calculateCenterGlobal(t, t->center, t->center_global); /* avoid calculating again */ @@ -1849,7 +1858,7 @@ void calculateCenter(TransInfo *t) calculateCenter2D(t); /* for panning from cameraview */ - if (t->flag & T_OBJECT) { + if ((t->flag & T_OBJECT) && (t->flag & T_OVERRIDE_CENTER) == 0) { if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) { if (t->flag & T_CAMERA) { diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index ec066ba91a4..9a362ee609f 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -107,15 +107,16 @@ #define TW_AXIS_DOT_MIN 0.02f #define TW_AXIS_DOT_MAX 0.1f +struct TransformBounds { + float center[3]; /* Center for transform widget. */ + float min[3], max[3]; /* Boundbox of selection for transform widget. */ +}; + /* transform widget center calc helper for below */ -static void calc_tw_center(Scene *scene, const float co[3]) +static void calc_tw_center(struct TransformBounds *tbounds, const float co[3]) { - float *twcent = scene->twcent; - float *min = scene->twmin; - float *max = scene->twmax; - - minmax_v3v3_v3(min, max, co); - add_v3_v3(twcent, co); + minmax_v3v3_v3(tbounds->min, tbounds->max, co); + add_v3_v3(tbounds->center, co); } static void protectflag_to_drawflags(short protectflag, short *drawflags) @@ -260,7 +261,7 @@ bool gimbal_axis(Object *ob, float gmat[3][3]) /* centroid, boundbox, of selection */ /* returns total items selected */ -static int calc_manipulator_stats(const bContext *C) +static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbounds) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); @@ -280,9 +281,9 @@ static int calc_manipulator_stats(const bContext *C) rv3d->twdrawflag = 0xFFFF; /* transform widget centroid/center */ - INIT_MINMAX(scene->twmin, scene->twmax); - zero_v3(scene->twcent); - + INIT_MINMAX(tbounds->min, tbounds->max); + zero_v3(tbounds->center); + if (is_gp_edit) { float diff_mat[4][4]; float fpt[3]; @@ -311,12 +312,12 @@ static int calc_manipulator_stats(const bContext *C) for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (pt->flag & GP_SPOINT_SELECT) { if (gpl->parent == NULL) { - calc_tw_center(scene, &pt->x); + calc_tw_center(tbounds, &pt->x); totsel++; } else { mul_v3_m4v3(fpt, diff_mat, &pt->x); - calc_tw_center(scene, fpt); + calc_tw_center(tbounds, fpt); totsel++; } } @@ -329,7 +330,7 @@ static int calc_manipulator_stats(const bContext *C) /* selection center */ if (totsel) { - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); /* centroid! */ + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); } } else if (obedit) { @@ -344,7 +345,7 @@ static int calc_manipulator_stats(const bContext *C) /* USE LAST SELECTE WITH ACTIVE */ if ((v3d->around == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) { BM_editselection_center(&ese, vec); - calc_tw_center(scene, vec); + calc_tw_center(tbounds, vec); totsel = 1; } else { @@ -357,7 +358,7 @@ static int calc_manipulator_stats(const bContext *C) if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { totsel++; - calc_tw_center(scene, eve->co); + calc_tw_center(tbounds, eve->co); } } } @@ -370,13 +371,13 @@ static int calc_manipulator_stats(const bContext *C) if ((v3d->around == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) { /* doesn't check selection or visibility intentionally */ if (ebo->flag & BONE_TIPSEL) { - calc_tw_center(scene, ebo->tail); + calc_tw_center(tbounds, ebo->tail); totsel++; } if ((ebo->flag & BONE_ROOTSEL) || ((ebo->flag & BONE_TIPSEL) == false)) /* ensure we get at least one point */ { - calc_tw_center(scene, ebo->head); + calc_tw_center(tbounds, ebo->head); totsel++; } protectflag_to_drawflags_ebone(rv3d, ebo); @@ -385,7 +386,7 @@ static int calc_manipulator_stats(const bContext *C) for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { if (EBONE_VISIBLE(arm, ebo)) { if (ebo->flag & BONE_TIPSEL) { - calc_tw_center(scene, ebo->tail); + calc_tw_center(tbounds, ebo->tail); totsel++; } if ((ebo->flag & BONE_ROOTSEL) && @@ -395,7 +396,7 @@ static int calc_manipulator_stats(const bContext *C) (ebo->parent->flag & BONE_TIPSEL) && EBONE_VISIBLE(arm, ebo->parent)) == 0) { - calc_tw_center(scene, ebo->head); + calc_tw_center(tbounds, ebo->head); totsel++; } if (ebo->flag & BONE_SELECTED) { @@ -410,7 +411,7 @@ static int calc_manipulator_stats(const bContext *C) float center[3]; if (v3d->around == V3D_AROUND_ACTIVE && ED_curve_active_center(cu, center)) { - calc_tw_center(scene, center); + calc_tw_center(tbounds, center); totsel++; } else { @@ -431,21 +432,25 @@ static int calc_manipulator_stats(const bContext *C) */ if (cu->drawflag & CU_HIDE_HANDLES) { if (bezt->f2 & SELECT) { - calc_tw_center(scene, bezt->vec[1]); + calc_tw_center(tbounds, bezt->vec[1]); totsel++; } } else if (bezt->f2 & SELECT) { - calc_tw_center(scene, bezt->vec[1]); + calc_tw_center(tbounds, bezt->vec[1]); totsel++; } else { if (bezt->f1 & SELECT) { - calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]); + calc_tw_center( + tbounds, + bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]); totsel++; } if (bezt->f3 & SELECT) { - calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]); + calc_tw_center( + tbounds, + bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]); totsel++; } } @@ -457,7 +462,7 @@ static int calc_manipulator_stats(const bContext *C) a = nu->pntsu * nu->pntsv; while (a--) { if (bp->f1 & SELECT) { - calc_tw_center(scene, bp->vec); + calc_tw_center(tbounds, bp->vec); totsel++; } bp++; @@ -472,13 +477,13 @@ static int calc_manipulator_stats(const bContext *C) MetaElem *ml; if ((v3d->around == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) { - calc_tw_center(scene, &ml->x); + calc_tw_center(tbounds, &ml->x); totsel++; } else { for (ml = mb->editelems->first; ml; ml = ml->next) { if (ml->flag & SELECT) { - calc_tw_center(scene, &ml->x); + calc_tw_center(tbounds, &ml->x); totsel++; } } @@ -489,7 +494,7 @@ static int calc_manipulator_stats(const bContext *C) BPoint *bp; if ((v3d->around == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) { - calc_tw_center(scene, bp->vec); + calc_tw_center(tbounds, bp->vec); totsel++; } else { @@ -497,7 +502,7 @@ static int calc_manipulator_stats(const bContext *C) a = lt->pntsu * lt->pntsv * lt->pntsw; while (a--) { if (bp->f1 & SELECT) { - calc_tw_center(scene, bp->vec); + calc_tw_center(tbounds, bp->vec); totsel++; } bp++; @@ -507,10 +512,10 @@ static int calc_manipulator_stats(const bContext *C) /* selection center */ if (totsel) { - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid! - mul_m4_v3(obedit->obmat, scene->twcent); - mul_m4_v3(obedit->obmat, scene->twmin); - mul_m4_v3(obedit->obmat, scene->twmax); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); + mul_m4_v3(obedit->obmat, tbounds->center); + mul_m4_v3(obedit->obmat, tbounds->min); + mul_m4_v3(obedit->obmat, tbounds->max); } } else if (ob && (ob->mode & OB_MODE_POSE)) { @@ -524,7 +529,7 @@ static int calc_manipulator_stats(const bContext *C) /* doesn't check selection or visibility intentionally */ Bone *bone = pchan->bone; if (bone) { - calc_tw_center(scene, pchan->pose_head); + calc_tw_center(tbounds, pchan->pose_head); protectflag_to_drawflags_pchan(rv3d, pchan); totsel = 1; ok = true; @@ -538,7 +543,7 @@ 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)) { - calc_tw_center(scene, pchan->pose_head); + calc_tw_center(tbounds, pchan->pose_head); protectflag_to_drawflags_pchan(rv3d, pchan); } } @@ -547,10 +552,10 @@ static int calc_manipulator_stats(const bContext *C) } if (ok) { - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid! - mul_m4_v3(ob->obmat, scene->twcent); - mul_m4_v3(ob->obmat, scene->twmin); - mul_m4_v3(ob->obmat, scene->twmax); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); + mul_m4_v3(ob->obmat, tbounds->center); + mul_m4_v3(ob->obmat, tbounds->min); + mul_m4_v3(ob->obmat, tbounds->max); } } else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) { @@ -569,7 +574,7 @@ static int calc_manipulator_stats(const bContext *C) for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) { if (ek->flag & PEK_SELECT) { - calc_tw_center(scene, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co); + calc_tw_center(tbounds, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co); totsel++; } } @@ -577,7 +582,7 @@ static int calc_manipulator_stats(const bContext *C) /* selection center */ if (totsel) - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid! + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); } } else { @@ -590,7 +595,7 @@ static int calc_manipulator_stats(const bContext *C) if (TESTBASELIB(v3d, base)) { if (ob == NULL) ob = base->object; - calc_tw_center(scene, base->object->obmat[3]); + calc_tw_center(tbounds, base->object->obmat[3]); protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); totsel++; } @@ -598,7 +603,7 @@ static int calc_manipulator_stats(const bContext *C) /* selection center */ if (totsel) { - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid! + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); } } @@ -1643,9 +1648,10 @@ void BIF_draw_manipulator(const bContext *C) if ((v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE | V3D_MANIP_SCALE)) == 0) return; { + struct TransformBounds tbounds; v3d->twflag &= ~V3D_DRAW_MANIPULATOR; - totsel = calc_manipulator_stats(C); + totsel = calc_manipulator_stats(C, &tbounds); if (totsel == 0) return; v3d->twflag |= V3D_DRAW_MANIPULATOR; @@ -1665,13 +1671,13 @@ void BIF_draw_manipulator(const bContext *C) copy_v3_v3(rv3d->twmat[3], ob->obmat[3]); } else { - mid_v3_v3v3(rv3d->twmat[3], scene->twmin, scene->twmax); + mid_v3_v3v3(rv3d->twmat[3], tbounds.min, tbounds.max); } break; } case V3D_AROUND_LOCAL_ORIGINS: case V3D_AROUND_CENTER_MEAN: - copy_v3_v3(rv3d->twmat[3], scene->twcent); + copy_v3_v3(rv3d->twmat[3], tbounds.center); break; case V3D_AROUND_CURSOR: copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d)); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 2a97384cf7d..1aa800f9fb1 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -565,6 +565,14 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) RNA_def_boolean(ot->srna, "correct_uv", 0, "Correct UVs", "Correct UV coordinates when transforming"); } + if (flags & P_CENTER) { + /* For manipulators that define their own center. */ + prop = RNA_def_property(ot->srna, "center_override", PROP_FLOAT, PROP_XYZ); + RNA_def_property_array(prop, 3); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + RNA_def_property_ui_text(prop, "Center Override", "Force using this center value (when set)"); + } + if ((flags & P_NO_DEFAULTS) == 0) { // Add confirm method all the time. At the end because it's not really that important and should be hidden only in log, not in keymap edit /*prop =*/ RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "Always confirm operation when releasing button"); @@ -612,7 +620,8 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot) RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT); + Transform_Properties( + ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT | P_CENTER); } static int skin_resize_poll(bContext *C) @@ -663,7 +672,7 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot) /* Maybe we could use float_vector_xyz here too? */ RNA_def_float_rotation(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_rotate(struct wmOperatorType *ot) @@ -683,7 +692,8 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot) RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); - Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT); + Transform_Properties( + ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_tilt(struct wmOperatorType *ot) @@ -726,7 +736,7 @@ static void TRANSFORM_OT_bend(struct wmOperatorType *ot) RNA_def_float_rotation(ot->srna, "value", 1, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_shear(struct wmOperatorType *ot) @@ -767,7 +777,7 @@ static void TRANSFORM_OT_push_pull(struct wmOperatorType *ot) RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Distance", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_CENTER); } static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot) @@ -810,7 +820,7 @@ static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot) RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_mirror(struct wmOperatorType *ot) @@ -828,7 +838,7 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot) ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; - Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT); + Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot) @@ -991,7 +1001,8 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot) RNA_def_float_vector(ot->srna, "value", 4, NULL, -FLT_MAX, FLT_MAX, "Values", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_GPENCIL_EDIT); + Transform_Properties( + ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_GPENCIL_EDIT | P_CENTER); } void transform_operatortypes(void) diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 318d2718969..4a7c2decf95 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1017,7 +1017,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here char node_border; - if (snapNodesTransform(t, t->mval, t->tsnap.modeSelect, loc, &dist_px, &node_border)) { + if (snapNodesTransform(t, t->mval, loc, &dist_px, &node_border)) { copy_v2_v2(t->tsnap.snapPoint, loc); t->tsnap.snapNodeBorder = node_border; @@ -1413,22 +1413,11 @@ static bool snapNodes( } bool snapNodesTransform( - TransInfo *t, const int mval[2], SnapSelect snap_select, + TransInfo *t, const int mval[2], float r_loc[2], float *r_dist_px, char *r_node_border) { return snapNodes( - t->settings, t->sa->spacedata.first, t->ar, mval, snap_select, - r_loc, r_dist_px, r_node_border); -} - -bool snapNodesContext( - bContext *C, const int mval[2], SnapSelect snap_select, - float r_loc[2], float *r_dist_px, char *r_node_border) -{ - Scene *scene = CTX_data_scene(C); - ARegion *ar = CTX_wm_region(C); - return snapNodes( - scene->toolsettings, CTX_wm_space_node(C), ar, mval, snap_select, + t->settings, t->sa->spacedata.first, t->ar, mval, t->tsnap.modeSelect, r_loc, r_dist_px, r_node_border); } @@ -1478,7 +1467,7 @@ void snapSequenceBounds(TransInfo *t, const int mval[2]) /* convert to frame range */ UI_view2d_region_to_view(&t->ar->v2d, mval[0], mval[1], &xmouse, &ymouse); - mframe = iroundf(xmouse); + mframe = round_fl_to_int(xmouse); /* now find the closest sequence */ frame = BKE_sequencer_find_next_prev_edit(t->scene, mframe, SEQ_SIDE_BOTH, true, false, true); diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 85833f54da6..1fdf7c67cff 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -139,43 +139,55 @@ struct SnapObjectContext { * \{ */ -#define ITER_SNAP_OBJECTS(use_obedit, ob, obmat, sctx, snap_select, obedit, CODE) \ - Base *base_act = sctx->scene->basact;\ - /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA\ - * which makes the loop skip it, even the derived mesh will never change\ - *\ - * To solve that problem, we do it first as an exception.\ - * */\ - if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) {\ - use_obedit = false;\ - ob = base_act->object;\ - obmat = ob->obmat;\ - CODE\ - }\ - for (Base *base = sctx->scene->base.first; base != NULL; base = base->next) {\ - if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) &&\ - (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&\ - !((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL))) ||\ - (snap_select == SNAP_NOT_ACTIVE && base == base_act)))\ - {\ - Object *obj = base->object;\ - if (ob->transflag & OB_DUPLI) {\ - DupliObject *dupli_ob;\ - ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, obj);\ - for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {\ - use_obedit = obedit && dupli_ob->ob->data == obedit->data;;\ - ob = use_obedit ? obedit : dupli_ob->ob;\ - obmat = dupli_ob->mat;\ - CODE\ - }\ - free_object_duplilist(lb);\ - }\ - use_obedit = obedit && ob->data == obedit->data;\ - ob = use_obedit ? obedit : obj;\ - obmat = ob->obmat;\ - CODE\ - }\ - }\ +typedef void(*IterSnapObjsCallback)(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data); + +/** + * Walks through all objects in the scene to create the list of objets to snap. + * + * \param sctx: Snap context to store data. + * \param snap_select : from enum SnapSelect. + * \param obedit : Object Edited to use its coordinates of BMesh(if any) to do the snapping. + */ +static void iter_snap_objects( + SnapObjectContext *sctx, + const SnapSelect snap_select, + Object *obedit, + IterSnapObjsCallback sob_callback, + void *data) +{ + Base *base_act = sctx->scene->basact; + /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA + * which makes the loop skip it, even the derived mesh will never change + * + * To solve that problem, we do it first as an exception. + * */ + if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) { + sob_callback(sctx, false, base_act->object, base_act->object->obmat, data); + } + + for (Base *base = sctx->scene->base.first; base != NULL; base = base->next) { + if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) && + (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && + !((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL))) || + (snap_select == SNAP_NOT_ACTIVE && base == base_act))) + { + bool use_obedit; + Object *obj = base->object; + if (obj->transflag & OB_DUPLI) { + DupliObject *dupli_ob; + ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, obj); + for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { + use_obedit = obedit && dupli_ob->ob->data == obedit->data; + sob_callback(sctx, use_obedit, use_obedit ? obedit : dupli_ob->ob, dupli_ob->mat, data); + } + free_object_duplilist(lb); + } + + use_obedit = obedit && obj->data == obedit->data; + sob_callback(sctx, use_obedit, use_obedit ? obedit : obj, obj->obmat, data); + } + } +} /** @@ -353,7 +365,7 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH static bool raycastDerivedMesh( SnapObjectContext *sctx, - const float ray_orig[3], const float ray_start[3], const float ray_dir[3], const float depth_range[2], + const float ray_start[3], const float ray_dir[3], Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index, /* read/write args */ float *ray_depth, @@ -393,7 +405,7 @@ static bool raycastDerivedMesh( if (bb) { /* 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], &len_diff, NULL)) + ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], &len_diff, NULL)) { return retval; } @@ -424,21 +436,18 @@ static bool raycastDerivedMesh( free_bvhtree_from_mesh(treedata); } else { - if (!treedata->vert_allocated) { + if (treedata->vert == NULL) { treedata->vert = DM_get_vert_array(dm, &treedata->vert_allocated); } - if (!treedata->loop_allocated) { + if (treedata->loop == NULL) { treedata->loop = DM_get_loop_array(dm, &treedata->loop_allocated); } - if (!treedata->looptri_allocated) { - if (!sod->poly_allocated) { + if (treedata->looptri == NULL) { + if (sod->mpoly == NULL) { sod->mpoly = DM_get_poly_array(dm, &sod->poly_allocated); } - treedata->looptri = DM_get_looptri_array( - dm, treedata->vert, - sod->mpoly, dm->getNumPolys(dm), - treedata->loop, dm->getNumLoops(dm), - &treedata->looptri_allocated); + treedata->looptri = dm->getLoopTriArray(dm); + treedata->looptri_allocated = false; } } } @@ -462,8 +471,7 @@ static bool raycastDerivedMesh( if (len_diff == 0.0f) { /* do_ray_start_correction */ /* We *need* a reasonably valid len_diff in this case. * Get the distance to bvhtree root */ - if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) - { + if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) { return retval; } } @@ -471,18 +479,11 @@ static bool raycastDerivedMesh( * because even in the Orthografic view, in some cases, * the ray can start inside the object (see T50486) */ if (len_diff > 400.0f) { - float ray_org_local[3]; - - copy_v3_v3(ray_org_local, ray_orig); - mul_m4_v3(imat, ray_org_local); - /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with * very far away ray_start values (as returned in case of ortho view3d), see T38358. */ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl( - ray_start_local, ray_org_local, ray_normal_local, - len_diff + depth_range[0] * local_scale); + madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff); local_depth -= len_diff; } else { @@ -512,8 +513,8 @@ static bool raycastDerivedMesh( BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; if (BLI_bvhtree_ray_cast( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - &hit, treedata->raycast_callback, treedata) != -1) + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + &hit, treedata->raycast_callback, treedata) != -1) { hit.dist += len_diff; hit.dist /= local_scale; @@ -544,7 +545,7 @@ static bool raycastDerivedMesh( static bool raycastEditMesh( SnapObjectContext *sctx, - const float ray_orig[3], const float ray_start[3], const float ray_dir[3], const float depth_range[2], + const float ray_start[3], const float ray_dir[3], Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index, /* read/write args */ float *ray_depth, @@ -558,8 +559,7 @@ static bool raycastEditMesh( } SnapObjectData_EditMesh *sod = NULL; - - BVHTreeFromEditMesh *treedata; + BVHTreeFromEditMesh *treedata = NULL; void **sod_p; if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { @@ -627,26 +627,18 @@ static bool raycastEditMesh( if (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp) { /* do_ray_start_correction */ /* We *need* a reasonably valid len_diff in this case. * Get the distance to bvhtree root */ - if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) - { + if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) { return retval; } /* You need to make sure that ray_start is really far away, * because even in the Orthografic view, in some cases, * the ray can start inside the object (see T50486) */ if (len_diff > 400.0f) { - float ray_org_local[3]; - - copy_v3_v3(ray_org_local, ray_orig); - mul_m4_v3(imat, ray_org_local); - /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with * very far away ray_start values (as returned in case of ortho view3d), see T38358. */ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl( - ray_start_local, ray_org_local, ray_normal_local, - len_diff + depth_range[0] * local_scale); + madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff); local_depth -= len_diff; } else len_diff = 0.0f; @@ -713,7 +705,7 @@ static bool raycastEditMesh( */ static bool raycastObj( SnapObjectContext *sctx, - const float ray_orig[3], const float ray_start[3], const float ray_dir[3], const float depth_range[2], + const float ray_start[3], const float ray_dir[3], Object *ob, float obmat[4][4], const unsigned int ob_index, bool use_obedit, /* read/write args */ @@ -732,7 +724,7 @@ static bool raycastObj( em = BKE_editmesh_from_object(ob); retval = raycastEditMesh( sctx, - ray_orig, ray_start, ray_dir, depth_range, + ray_start, ray_dir, ob, em, obmat, ob_index, ray_depth, r_loc, r_no, r_index, r_hit_list); } @@ -749,11 +741,9 @@ static bool raycastObj( } retval = raycastDerivedMesh( sctx, - ray_orig, ray_start, ray_dir, depth_range, + ray_start, ray_dir, ob, dm, obmat, ob_index, ray_depth, r_loc, r_no, r_index, r_hit_list); - - dm->release(dm); } } @@ -768,6 +758,35 @@ static bool raycastObj( } +struct RaycastObjUserData { + const float *ray_start; + const float *ray_dir; + unsigned int ob_index; + /* read/write args */ + float *ray_depth; + /* return args */ + float *r_loc; + float *r_no; + int *r_index; + Object **r_ob; + float (*r_obmat)[4]; + ListBase *r_hit_list; + bool ret; +}; + +static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data) +{ + struct RaycastObjUserData *dt = data; + dt->ret |= raycastObj( + sctx, + dt->ray_start, dt->ray_dir, + ob, obmat, dt->ob_index++, is_obedit, + dt->ray_depth, + dt->r_loc, dt->r_no, dt->r_index, + dt->r_ob, dt->r_obmat, + dt->r_hit_list); +} + /** * Main RayCast Function * ====================== @@ -799,7 +818,7 @@ static bool raycastObj( */ static bool raycastObjects( SnapObjectContext *sctx, - const float ray_orig[3], const float ray_start[3], const float ray_dir[3], const float depth_range[2], + const float ray_start[3], const float ray_dir[3], const SnapSelect snap_select, const bool use_object_edit_cage, /* read/write args */ float *ray_depth, @@ -808,24 +827,25 @@ static bool raycastObjects( Object **r_ob, float r_obmat[4][4], ListBase *r_hit_list) { - bool retval = false; - bool use_obedit; - - unsigned int ob_index = 0; - - Object *ob, *obedit; - float (*obmat)[4]; + Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; + + struct RaycastObjUserData data = { + .ray_start = ray_start, + .ray_dir = ray_dir, + .ob_index = 0, + .ray_depth = ray_depth, + .r_loc = r_loc, + .r_no = r_no, + .r_index = r_index, + .r_ob = r_ob, + .r_obmat = r_obmat, + .r_hit_list = r_hit_list, + .ret = false, + }; - obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; - ITER_SNAP_OBJECTS(use_obedit, ob, obmat, sctx, snap_select, obedit, - retval |= raycastObj( - sctx, - ray_orig, ray_start, ray_dir, depth_range, - ob, obmat, ob_index++, use_obedit, - ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); - ) + iter_snap_objects(sctx, snap_select, obedit, raycast_obj_cb, &data); - return retval; + return data.ret; } @@ -1045,36 +1065,20 @@ static float dist_squared_to_projected_aabb( main_axis += 3; } - /* if rtmin < rtmax, ray intersect `AABB` */ - if (rtmin <= rtmax) { #define IGNORE_BEHIND_RAY #ifdef IGNORE_BEHIND_RAY - /* `if rtmax < depth_min`, the hit is behind us */ - if (rtmax < data->ray_min_dist) { - /* Test if the entire AABB is behind us */ - float depth = depth_get( - local_bvmax, data->ray_origin_local, data->ray_direction_local); - if (depth < (data->ray_min_dist)) { - return FLT_MAX; - } - } -#endif - const float proj = rtmin * data->ray_direction_local[main_axis]; - r_axis_closest[main_axis] = (proj - va[main_axis]) < (vb[main_axis] - proj); - return 0.0f; - } -#ifdef IGNORE_BEHIND_RAY - /* `if rtmin < depth_min`, the hit is behing us */ - else if (rtmin < data->ray_min_dist) { - /* Test if the entire AABB is behind us */ - float depth = depth_get( - local_bvmax, data->ray_origin_local, data->ray_direction_local); - if (depth < (data->ray_min_dist)) { - return FLT_MAX; - } + float depth_max = depth_get(local_bvmax, data->ray_origin_local, data->ray_direction_local); + if (depth_max < data->ray_min_dist) { + return FLT_MAX; } #endif #undef IGNORE_BEHIND_RAY + + /* if rtmin <= rtmax, ray intersect `AABB` */ + if (rtmin <= rtmax) { + return 0; + } + if (data->sign[main_axis]) { va[main_axis] = local_bvmax[main_axis]; vb[main_axis] = local_bvmin[main_axis]; @@ -1684,10 +1688,10 @@ static bool snapDerivedMesh( free_bvhtree_from_mesh(treedata); } else { - if (!treedata->vert_allocated) { + if (treedata->vert == NULL) { treedata->vert = DM_get_vert_array(dm, &treedata->vert_allocated); } - if ((tree_index == 1) && !treedata->edge_allocated) { + if ((tree_index == 1) && (treedata->edge == NULL)) { treedata->edge = DM_get_edge_array(dm, &treedata->edge_allocated); } } @@ -1794,8 +1798,7 @@ static bool snapEditMesh( float local_scale = normalize_v3(ray_normal_local); SnapObjectData_EditMesh *sod = NULL; - - BVHTreeFromEditMesh *treedata; + BVHTreeFromEditMesh *treedata = NULL; void **sod_p; if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { @@ -1998,6 +2001,33 @@ static bool snapObject( } +struct SnapObjUserData { + SnapData *snapdata; + /* read/write args */ + float *ray_depth; + float *dist_px; + /* return args */ + float *r_loc; + float *r_no; + Object **r_ob; + float (*r_obmat)[4]; + bool ret; +}; + +static void sanp_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data) +{ + struct SnapObjUserData *dt = data; + dt->ret |= snapObject( + sctx, dt->snapdata, + ob, obmat, is_obedit, + /* read/write args */ + dt->ray_depth, dt->dist_px, + /* return args */ + dt->r_loc, dt->r_no, + dt->r_ob, dt->r_obmat); +} + + /** * Main Snapping Function * ====================== @@ -2035,21 +2065,22 @@ static bool snapObjectsRay( float r_loc[3], float r_no[3], Object **r_ob, float r_obmat[4][4]) { - bool retval = false; - bool use_obedit; - - Object *ob, *obedit; - float (*obmat)[4]; + Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; + + struct SnapObjUserData data = { + .snapdata = snapdata, + .ray_depth = ray_depth, + .dist_px = dist_px, + .r_loc = r_loc, + .r_no = r_no, + .r_ob = r_ob, + .r_obmat = r_obmat, + .ret = false, + }; - obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; - ITER_SNAP_OBJECTS(use_obedit, ob, obmat, sctx, snap_select, obedit, - retval |= snapObject( - sctx, snapdata, ob, obmat, use_obedit, - ray_depth, dist_px, - r_loc, r_no, r_ob, r_obmat); - ) + iter_snap_objects(sctx, snap_select, obedit, sanp_obj_cb, &data); - return retval; + return data.ret; } /** \} */ @@ -2149,11 +2180,9 @@ bool ED_transform_snap_object_project_ray_ex( float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4]) { - const float depth_range[2] = {0.0f, FLT_MAX}; - return raycastObjects( sctx, - ray_start, ray_start, ray_normal, depth_range, + ray_start, ray_normal, params->snap_select, params->use_object_edit_cage, ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL); } @@ -2172,7 +2201,6 @@ bool ED_transform_snap_object_project_ray_all( float ray_depth, bool sort, ListBase *r_hit_list) { - const float depth_range[2] = {0.0f, FLT_MAX}; if (ray_depth == -1.0f) { ray_depth = BVH_RAYCAST_DIST_MAX; } @@ -2183,7 +2211,7 @@ bool ED_transform_snap_object_project_ray_all( bool retval = raycastObjects( sctx, - ray_start, ray_start, ray_normal, depth_range, + ray_start, ray_normal, params->snap_select, params->use_object_edit_cage, &ray_depth, NULL, NULL, NULL, NULL, NULL, r_hit_list); @@ -2366,7 +2394,7 @@ bool ED_transform_snap_object_project_view3d_ex( if (snap_to == SCE_SNAP_MODE_FACE) { return raycastObjects( sctx, - ray_origin, ray_start, ray_normal, depth_range, + ray_start, ray_normal, params->snap_select, params->use_object_edit_cage, ray_depth, r_loc, r_no, r_index, NULL, NULL, NULL); } diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 5125bb54dd4..9ae5145e53a 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -225,7 +225,7 @@ void ED_uvedit_assign_image(Main *UNUSED(bmain), Scene *scene, Object *obedit, I BM_data_layer_add(em->bm, &em->bm->pdata, CD_MTEXPOLY); BM_data_layer_add(em->bm, &em->bm->ldata, CD_MLOOPUV); /* make UVs all nice 0-1 */ - ED_mesh_uv_loop_reset_ex(obedit->data, CustomData_get_active_layer_index(&em->bm->pdata, CD_MTEXPOLY)); + ED_mesh_uv_loop_reset_ex(obedit->data, CustomData_get_active_layer(&em->bm->pdata, CD_MTEXPOLY)); update = true; } diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 1dbac1848b7..9c478c203e7 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -957,7 +957,7 @@ Render *BlenderStrokeRenderer::RenderScene(Render * /*re*/, bool render) } #endif - Render *freestyle_render = RE_NewRender(freestyle_scene->id.name); + Render *freestyle_render = RE_NewSceneRender(freestyle_scene); RE_RenderFreestyleStrokes(freestyle_render, freestyle_bmain, freestyle_scene, render && get_stroke_count() > 0); diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 6db23686832..dbfcd4d1ea4 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -226,7 +226,7 @@ void GPU_material_free(struct ListBase *gpumaterial); void GPU_materials_free(void); -bool GPU_lamp_override_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma); +bool GPU_lamp_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma); void GPU_material_bind( GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock); diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 9f1fe3a5a67..e288c74fee6 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -76,13 +76,13 @@ typedef struct { static size_t gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type); -const GPUBufferTypeSettings gpu_buffer_type_settings[] = { +static const GPUBufferTypeSettings gpu_buffer_type_settings[] = { /* vertex */ {GL_ARRAY_BUFFER, 3}, /* normal */ {GL_ARRAY_BUFFER, 4}, /* we copy 3 shorts per normal but we add a fourth for alignment */ /* mcol */ - {GL_ARRAY_BUFFER, 3}, + {GL_ARRAY_BUFFER, 4}, /* uv */ {GL_ARRAY_BUFFER, 2}, /* uv for texpaint */ @@ -690,7 +690,7 @@ void GPU_color_setup(DerivedMesh *dm, int colType) glEnableClientState(GL_COLOR_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->colors->id); - glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0); GLStates |= GPU_BUFFER_COLOR_STATE; } diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 1583d16ca27..2d7fa760e49 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -682,10 +682,10 @@ int GPU_verify_image( if (do_color_management) { srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(float) * 4, "floar_buf_col_cor"); gpu_verify_high_bit_srgb_buffer(srgb_frect, ibuf); - frect = srgb_frect + texwinsy * ibuf->x + texwinsx; + frect = srgb_frect + (4 * (texwinsy * ibuf->x + texwinsx)); } else { - frect = ibuf->rect_float + texwinsy * ibuf->x + texwinsx; + frect = ibuf->rect_float + (ibuf->channels * (texwinsy * ibuf->x + texwinsx)); } } else { diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 1f3ae7f708a..f39cad20b9b 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -312,9 +312,11 @@ void GPU_material_free(ListBase *gpumaterial) BLI_freelistN(gpumaterial); } -bool GPU_lamp_override_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma) +bool GPU_lamp_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma) { - if (srl && srl->light_override) + if (lamp->hide) + return false; + else if (srl && srl->light_override) return BKE_group_object_exists(srl->light_override, lamp->ob); else if (ma && ma->group) return BKE_group_object_exists(ma->group, lamp->ob); @@ -338,8 +340,8 @@ void GPU_material_bind( for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) { GPULamp *lamp = nlink->data; - if (!lamp->hide && (lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) && - GPU_lamp_override_visible(lamp, srl, material->ma)) + if ((lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) && + GPU_lamp_visible(lamp, srl, material->ma)) { lamp->dynenergy = lamp->energy; copy_v3_v3(lamp->dyncol, lamp->col); diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index f14db57a26a..3dbecc58a7e 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -3116,15 +3116,17 @@ void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha) } void node_tex_image_box(vec3 texco, - vec3 nob, + vec3 N, sampler2D ima, float blend, out vec4 color, out float alpha) { + vec3 signed_N = N; + /* project from direction vector to barycentric coordinates in triangles */ - nob = vec3(abs(nob.x), abs(nob.y), abs(nob.z)); - nob /= (nob.x + nob.y + nob.z); + N = vec3(abs(N.x), abs(N.y), abs(N.z)); + N /= (N.x + N.y + N.z); /* basic idea is to think of this as a triangle, each corner representing * one of the 3 faces of the cube. in the corners we have single textures, @@ -3140,37 +3142,37 @@ void node_tex_image_box(vec3 texco, float limit = 0.5 * (1.0 + blend); /* first test for corners with single texture */ - if (nob.x > limit * (nob.x + nob.y) && nob.x > limit * (nob.x + nob.z)) { + if (N.x > limit * (N.x + N.y) && N.x > limit * (N.x + N.z)) { weight.x = 1.0; } - else if (nob.y > limit * (nob.x + nob.y) && nob.y > limit * (nob.y + nob.z)) { + else if (N.y > limit * (N.x + N.y) && N.y > limit * (N.y + N.z)) { weight.y = 1.0; } - else if (nob.z > limit * (nob.x + nob.z) && nob.z > limit * (nob.y + nob.z)) { + else if (N.z > limit * (N.x + N.z) && N.z > limit * (N.y + N.z)) { weight.z = 1.0; } else if (blend > 0.0) { /* in case of blending, test for mixes between two textures */ - if (nob.z < (1.0 - limit) * (nob.y + nob.x)) { - weight.x = nob.x / (nob.x + nob.y); + if (N.z < (1.0 - limit) * (N.y + N.x)) { + weight.x = N.x / (N.x + N.y); weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); weight.y = 1.0 - weight.x; } - else if (nob.x < (1.0 - limit) * (nob.y + nob.z)) { - weight.y = nob.y / (nob.y + nob.z); + else if (N.x < (1.0 - limit) * (N.y + N.z)) { + weight.y = N.y / (N.y + N.z); weight.y = clamp((weight.y - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); weight.z = 1.0 - weight.y; } - else if (nob.y < (1.0 - limit) * (nob.x + nob.z)) { - weight.x = nob.x / (nob.x + nob.z); + else if (N.y < (1.0 - limit) * (N.x + N.z)) { + weight.x = N.x / (N.x + N.z); weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); weight.z = 1.0 - weight.x; } else { /* last case, we have a mix between three */ - weight.x = ((2.0 - limit) * nob.x + (limit - 1.0)) / (2.0 * limit - 1.0); - weight.y = ((2.0 - limit) * nob.y + (limit - 1.0)) / (2.0 * limit - 1.0); - weight.z = ((2.0 - limit) * nob.z + (limit - 1.0)) / (2.0 * limit - 1.0); + weight.x = ((2.0 - limit) * N.x + (limit - 1.0)) / (2.0 * limit - 1.0); + weight.y = ((2.0 - limit) * N.y + (limit - 1.0)) / (2.0 * limit - 1.0); + weight.z = ((2.0 - limit) * N.z + (limit - 1.0)) / (2.0 * limit - 1.0); } } else { @@ -3179,13 +3181,25 @@ void node_tex_image_box(vec3 texco, } color = vec4(0); if (weight.x > 0.0) { - color += weight.x * texture2D(ima, texco.yz); + vec2 uv = texco.yz; + if(signed_N.x < 0.0) { + uv.x = 1.0 - uv.x; + } + color += weight.x * texture2D(ima, uv); } if (weight.y > 0.0) { - color += weight.y * texture2D(ima, texco.xz); + vec2 uv = texco.xz; + if(signed_N.y > 0.0) { + uv.x = 1.0 - uv.x; + } + color += weight.y * texture2D(ima, uv); } if (weight.z > 0.0) { - color += weight.z * texture2D(ima, texco.yx); + vec2 uv = texco.yx; + if(signed_N.z > 0.0) { + uv.x = 1.0 - uv.x; + } + color += weight.z * texture2D(ima, uv); } alpha = color.a; diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c index 6ea311b2c7b..f837789914e 100644 --- a/source/blender/ikplugin/intern/iksolver_plugin.c +++ b/source/blender/ikplugin/intern/iksolver_plugin.c @@ -217,9 +217,27 @@ static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[3][3]) // nr = copy_m4_m3(ikmat, ik_mat); if (pchan->parent) - mul_m4_series(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat, ikmat); + mul_m4_m4m4(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat); else - mul_m4_m4m4(pchan->pose_mat, pchan->chan_mat, ikmat); + copy_m4_m4(pchan->pose_mat, pchan->chan_mat); + +#ifdef USE_NONUNIFORM_SCALE + /* apply IK mat, but as if the bones have uniform scale since the IK solver + * is not aware of non-uniform scale */ + float scale[3]; + mat4_to_size(scale, pchan->pose_mat); + normalize_v3_length(pchan->pose_mat[0], scale[1]); + normalize_v3_length(pchan->pose_mat[2], scale[1]); +#endif + + mul_m4_m4m4(pchan->pose_mat, pchan->pose_mat, ikmat); + +#ifdef USE_NONUNIFORM_SCALE + float ik_scale[3]; + mat3_to_size(ik_scale, ik_mat); + normalize_v3_length(pchan->pose_mat[0], scale[0] * ik_scale[0]); + normalize_v3_length(pchan->pose_mat[2], scale[2] * ik_scale[2]); +#endif /* calculate head */ copy_v3_v3(pchan->pose_head, pchan->pose_mat[3]); @@ -308,6 +326,10 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree) /* change length based on bone size */ length = bone->length * len_v3(R_bonemat[1]); + /* basis must be pure rotation */ + normalize_m3(R_bonemat); + normalize_m3(R_parmat); + /* compute rest basis and its inverse */ copy_m3_m3(rest_basis, bone->bone_mat); transpose_m3_m3(irest_basis, bone->bone_mat); @@ -317,11 +339,7 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree) mul_m3_m3m3(full_basis, iR_parmat, R_bonemat); mul_m3_m3m3(basis, irest_basis, full_basis); - /* basis must be pure rotation */ - normalize_m3(basis); - /* transform offset into local bone space */ - normalize_m3(iR_parmat); mul_m3_v3(iR_parmat, start); IK_SetTransform(seg, start, rest_basis, basis, length); @@ -545,18 +563,6 @@ void iksolver_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan tree->pchan[a]->flag |= POSE_CHAIN; } -#ifdef USE_NONUNIFORM_SCALE - float (*pchan_scale_data)[3] = MEM_mallocN(sizeof(float[3]) * tree->totchannel, __func__); - - for (a = 0; a < tree->totchannel; a++) { - mat4_to_size(pchan_scale_data[a], tree->pchan[a]->pose_mat); - - /* make uniform at y scale since this controls the length */ - normalize_v3_length(tree->pchan[a]->pose_mat[0], pchan_scale_data[a][1]); - normalize_v3_length(tree->pchan[a]->pose_mat[2], pchan_scale_data[a][1]); - } -#endif - /* 5. execute the IK solver */ execute_posetree(scene, ob, tree); @@ -571,14 +577,6 @@ void iksolver_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan where_is_ik_bone(tree->pchan[a], tree->basis_change[a]); } -#ifdef USE_NONUNIFORM_SCALE - for (a = 0; a < tree->totchannel; a++) { - normalize_v3_length(tree->pchan[a]->pose_mat[0], pchan_scale_data[a][0]); - normalize_v3_length(tree->pchan[a]->pose_mat[2], pchan_scale_data[a][2]); - } - MEM_freeN(pchan_scale_data); -#endif - /* 7. and free */ BLI_remlink(&pchan_root->iktree, tree); free_posetree(tree); diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt index b32f8c54cd6..c3950d8eb83 100644 --- a/source/blender/imbuf/CMakeLists.txt +++ b/source/blender/imbuf/CMakeLists.txt @@ -130,16 +130,6 @@ if(WITH_CODEC_AVI) add_definitions(-DWITH_AVI) endif() -if(WITH_CODEC_QUICKTIME) - list(APPEND INC - ../quicktime - ) - list(APPEND INC_SYS - ${QUICKTIME_INCLUDE_DIRS} - ) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_CODEC_FFMPEG) list(APPEND INC ../../../intern/ffmpeg diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index e7abfdc7d67..f1f36351e79 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -205,6 +205,7 @@ typedef enum IMB_BlendMode { IMB_BLEND_SATURATION = 21, IMB_BLEND_LUMINOSITY = 22, IMB_BLEND_COLOR = 23, + IMB_BLEND_INTERPOLATE = 24, IMB_BLEND_COPY = 1000, IMB_BLEND_COPY_RGB = 1001, diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 1701c2ba307..ee51854d7ed 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -295,7 +295,6 @@ typedef struct ImBuf { #endif /* DDS */ extern const char *imb_ext_image[]; -extern const char *imb_ext_image_qt[]; extern const char *imb_ext_movie[]; extern const char *imb_ext_audio[]; diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index 6d7ad7985f9..b10ae4f6fe9 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -63,12 +63,6 @@ # include "AVI_avi.h" #endif -#ifdef WITH_QUICKTIME -# if defined(_WIN32) || defined(__APPLE__) -# include "quicktime_import.h" -# endif /* _WIN32 || __APPLE__ */ -#endif /* WITH_QUICKTIME */ - #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -137,11 +131,6 @@ struct anim { PGETFRAME pgf; #endif -#ifdef WITH_QUICKTIME - /* quicktime */ - struct _QuicktimeMovie *qtime; -#endif /* WITH_QUICKTIME */ - #ifdef WITH_FFMPEG AVFormatContext *pFormatCtx; AVCodecContext *pCodecCtx; diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 9806ff006d7..25b0c0d7b1a 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -73,12 +73,6 @@ # include "AVI_avi.h" #endif -#ifdef WITH_QUICKTIME -#if defined(_WIN32) || defined(__APPLE__) -#include "quicktime_import.h" -#endif /* _WIN32 || __APPLE__ */ -#endif /* WITH_QUICKTIME */ - #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -221,9 +215,6 @@ void IMB_free_anim(struct anim *anim) free_anim_avi(anim); #endif -#ifdef WITH_QUICKTIME - free_anim_quicktime(anim); -#endif #ifdef WITH_FFMPEG free_anim_ffmpeg(anim); #endif @@ -513,6 +504,11 @@ static int startffmpeg(struct anim *anim) avformat_close_input(&pFormatCtx); return -1; } + if (pCodecCtx->pix_fmt == AV_PIX_FMT_NONE) { + avcodec_close(anim->pCodecCtx); + avformat_close_input(&pFormatCtx); + return -1; + } frame_rate = av_get_r_frame_rate_compat(pFormatCtx->streams[videoStream]); if (pFormatCtx->streams[videoStream]->nb_frames != 0) { @@ -1214,9 +1210,6 @@ static ImBuf *anim_getnew(struct anim *anim) free_anim_avi(anim); #endif -#ifdef WITH_QUICKTIME - free_anim_quicktime(anim); -#endif #ifdef WITH_FFMPEG free_anim_ffmpeg(anim); #endif @@ -1245,12 +1238,6 @@ static ImBuf *anim_getnew(struct anim *anim) ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0); break; #endif -#ifdef WITH_QUICKTIME - case ANIM_QTIME: - if (startquicktime(anim)) return (0); - ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0); - break; -#endif #ifdef WITH_FFMPEG case ANIM_FFMPEG: if (startffmpeg(anim)) return (0); @@ -1340,21 +1327,6 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim, int position, anim->curposition = position; break; #endif -#ifdef WITH_QUICKTIME - case ANIM_QTIME: - ibuf = qtime_fetchibuf(anim, position); - if (ibuf) { - if (ibuf->rect) { - /* OCIO_TODO: should happen in quicktime module, but it currently doesn't have access - * to color management's internals - */ - ibuf->rect_colorspace = colormanage_colorspace_get_named(anim->colorspace); - } - - anim->curposition = position; - } - break; -#endif #ifdef WITH_FFMPEG case ANIM_FFMPEG: ibuf = ffmpeg_fetchibuf(anim, position, tc); diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 03f71b5878c..863bce125c5 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -47,6 +47,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_filetype.h" +#include "IMB_filter.h" #include "IMB_moviecache.h" #include "MEM_guardedalloc.h" @@ -1521,6 +1522,10 @@ static bool is_ibuf_rect_in_display_space(ImBuf *ibuf, const ColorManagedViewSet { const char *from_colorspace = ibuf->rect_colorspace->name; const char *to_colorspace = IMB_colormanagement_get_display_colorspace_name(view_settings, display_settings); + ColorManagedLook *look_descr = colormanage_look_get_named(view_settings->look); + if (look_descr != NULL && !STREQ(look_descr->process_space, "")) { + return false; + } if (to_colorspace && STREQ(from_colorspace, to_colorspace)) return true; @@ -1635,12 +1640,13 @@ static void *do_processor_transform_thread(void *handle_v) if (float_from_byte) { IMB_buffer_float_from_byte(float_buffer, byte_buffer, IB_PROFILE_SRGB, IB_PROFILE_SRGB, - true, + false, width, height, width, width); - IMB_colormanagement_processor_apply(handle->cm_processor, - float_buffer, - width, height, channels, - predivide); + IMB_colormanagement_processor_apply(handle->cm_processor, + float_buffer, + width, height, channels, + predivide); + IMB_premultiply_rect_float(float_buffer, 4, width, height); } else { if (byte_buffer != NULL) { @@ -1776,14 +1782,15 @@ void IMB_colormanagement_transform_from_byte_threaded(float *float_buffer, unsig */ IMB_buffer_float_from_byte(float_buffer, byte_buffer, IB_PROFILE_SRGB, IB_PROFILE_SRGB, - true, + false, width, height, width, width); + IMB_premultiply_rect_float(float_buffer, 4, width, height); return; } cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace); processor_transform_apply_threaded(byte_buffer, float_buffer, width, height, channels, - cm_processor, true, true); + cm_processor, false, true); IMB_colormanagement_processor_free(cm_processor); } @@ -2565,6 +2572,14 @@ const char *IMB_colormanagement_colorspace_get_indexed_name(int index) void IMB_colormanagment_colorspace_from_ibuf_ftype(ColorManagedColorspaceSettings *colorspace_settings, ImBuf *ibuf) { + /* Don't modify non-color data space, it does not change with file type. */ + ColorSpace *colorspace = colormanage_colorspace_get_named(colorspace_settings->name); + + if (colorspace && colorspace->is_data) { + return; + } + + /* Get color space from file type. */ const ImFileType *type; for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) { diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c index 3d3e8a0646a..7ed5c8ffbcb 100644 --- a/source/blender/imbuf/intern/filetype.c +++ b/source/blender/imbuf/intern/filetype.c @@ -47,10 +47,6 @@ #include "dds/dds_api.h" #endif -#ifdef WITH_QUICKTIME -#include "quicktime_import.h" -#endif - static int imb_ftype_default(const ImFileType *type, ImBuf *ibuf) { return (ibuf->ftype == type->filetype); @@ -101,10 +97,6 @@ void imb_filetypes_init(void) for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) if (type->init) type->init(); - -#ifdef WITH_QUICKTIME - quicktime_init(); -#endif } void imb_filetypes_exit(void) @@ -114,9 +106,5 @@ void imb_filetypes_exit(void) for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) if (type->exit) type->exit(); - -#ifdef WITH_QUICKTIME - quicktime_exit(); -#endif } diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c index 7a9fa2b9768..6c0849358a5 100644 --- a/source/blender/imbuf/intern/iris.c +++ b/source/blender/imbuf/intern/iris.c @@ -48,36 +48,24 @@ #define IMAGIC 0732 typedef struct { - unsigned short imagic; /* stuff saved on disk . . */ - unsigned short type; - unsigned short dim; - unsigned short xsize; - unsigned short ysize; - unsigned short zsize; - unsigned int min; - unsigned int max; - unsigned int wastebytes; - char name[80]; - unsigned int colormap; - - int file; /* stuff used in core only */ - unsigned short flags; - short dorev; - short x; - short y; - short z; - short cnt; - unsigned short *ptr; - unsigned short *base; - unsigned short *tmpbuf; - unsigned int offset; - unsigned int rleend; /* for rle images */ - unsigned int *rowstart; /* for rle images */ - const int *rowsize; /* for rle images */ + ushort imagic; /* stuff saved on disk . . */ + ushort type; + ushort dim; + ushort xsize; + ushort ysize; + ushort zsize; + uint min; + uint max; + uchar _pad1[4]; + char name[80]; + uint colormap; + uchar _pad2[404]; } IMAGE; #define HEADER_SIZE 512 +BLI_STATIC_ASSERT(sizeof(IMAGE) == HEADER_SIZE, "Invalid header size"); + #define RINTLUM (79) #define GINTLUM (156) #define BINTLUM (21) @@ -106,68 +94,72 @@ typedef struct { /* local struct for mem access */ typedef struct MFileOffset { const uchar *_file_data; - unsigned int _file_offset; + uint _file_offset; } MFileOffset; -#define MFILE_DATA(inf) ((void)0, (inf)->_file_data + (inf)->_file_offset) +#define MFILE_DATA(inf) ((void)0, ((inf)->_file_data + (inf)->_file_offset)) #define MFILE_STEP(inf, step) { (inf)->_file_offset += step; } ((void)0) #define MFILE_SEEK(inf, pos) { (inf)->_file_offset = pos; } ((void)0) +/* error flags */ +#define DIRTY_FLAG_EOF (1 << 0) +#define DIRTY_FLAG_ENCODING (1 << 1) + /* funcs */ static void readheader(MFileOffset *inf, IMAGE *image); static int writeheader(FILE *outf, IMAGE *image); -static unsigned short getshort(MFileOffset *inf); -static unsigned int getlong(MFileOffset *inf); -static void putshort(FILE *outf, unsigned short val); -static int putlong(FILE *outf, unsigned int val); -static int writetab(FILE *outf, unsigned int *tab, int len); -static void readtab(MFileOffset *inf, unsigned int *tab, int len); +static ushort getshort(MFileOffset *inf); +static uint getlong(MFileOffset *inf); +static void putshort(FILE *outf, ushort val); +static int putlong(FILE *outf, uint val); +static int writetab(FILE *outf, uint *tab, int len); +static void readtab(MFileOffset *inf, uint *tab, int len); -static void expandrow(unsigned char *optr, const unsigned char *iptr, int z); -static void expandrow2(float *optr, const unsigned char *iptr, int z); -static void interleaverow(unsigned char *lptr, const unsigned char *cptr, int z, int n); -static void interleaverow2(float *lptr, const unsigned char *cptr, int z, int n); -static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cnt); -static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n); +static int expandrow(uchar *optr, const uchar *optr_end, const uchar *iptr, const uchar *iptr_end, int z); +static int expandrow2(float *optr, const float *optr_end, const uchar *iptr, const uchar *iptr_end, int z); +static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n); +static void interleaverow2(float *lptr, const uchar *cptr, int z, int n); +static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int cnt); +static void lumrow(uchar *rgbptr, uchar *lumptr, int n); /* * byte order independent read/write of shorts and ints. * */ -static unsigned short getshort(MFileOffset *inf) +static ushort getshort(MFileOffset *inf) { - const unsigned char *buf; + const uchar *buf; buf = MFILE_DATA(inf); MFILE_STEP(inf, 2); - - return (buf[0] << 8) + (buf[1] << 0); + + return ((ushort)buf[0] << 8) + ((ushort)buf[1] << 0); } -static unsigned int getlong(MFileOffset *mofs) +static uint getlong(MFileOffset *mofs) { - const unsigned char *buf; + const uchar *buf; buf = MFILE_DATA(mofs); MFILE_STEP(mofs, 4); - - return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3] << 0); + + return ((uint)buf[0] << 24) + ((uint)buf[1] << 16) + ((uint)buf[2] << 8) + ((uint)buf[3] << 0); } -static void putshort(FILE *outf, unsigned short val) +static void putshort(FILE *outf, ushort val) { - unsigned char buf[2]; + uchar buf[2]; buf[0] = (val >> 8); buf[1] = (val >> 0); fwrite(buf, 2, 1, outf); } -static int putlong(FILE *outf, unsigned int val) +static int putlong(FILE *outf, uint val) { - unsigned char buf[4]; + uchar buf[4]; buf[0] = (val >> 24); buf[1] = (val >> 16); @@ -205,7 +197,7 @@ static int writeheader(FILE *outf, IMAGE *image) return fwrite("no name", 8, 1, outf); } -static int writetab(FILE *outf, unsigned int *tab, int len) +static int writetab(FILE *outf, uint *tab, int len) { int r = 0; @@ -216,7 +208,7 @@ static int writetab(FILE *outf, unsigned int *tab, int len) return r; } -static void readtab(MFileOffset *inf, unsigned int *tab, int len) +static void readtab(MFileOffset *inf, uint *tab, int len) { while (len) { *tab++ = getlong(inf); @@ -242,12 +234,12 @@ static void test_endian_zbuf(struct ImBuf *ibuf) } /* from misc_util: flip the bytes from x */ -#define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) +#define GS(x) (((uchar *)(x))[0] << 8 | ((uchar *)(x))[1]) /* this one is only def-ed once, strangely... */ #define GSS(x) (((uchar *)(x))[1] << 8 | ((uchar *)(x))[0]) -int imb_is_a_iris(const unsigned char *mem) +int imb_is_a_iris(const uchar *mem) { return ((GS(mem) == IMAGIC) || (GSS(mem) == IMAGIC)); } @@ -259,46 +251,52 @@ int imb_is_a_iris(const unsigned char *mem) * */ -struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]) +struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]) { - unsigned int *base, *lptr = NULL; + uint *base, *lptr = NULL; float *fbase, *fptr = NULL; - unsigned int *zbase, *zptr; - const unsigned char *rledat; - unsigned int *starttab, *lengthtab; + uint *zbase, *zptr; + const uchar *rledat; + const uchar *mem_end = mem + size; MFileOffset _inf_data = {mem, 0}, *inf = &_inf_data; IMAGE image; int x, y, z, tablen; - int xsize, ysize, zsize; int bpp, rle, cur, badorder; ImBuf *ibuf; + uchar dirty_flag = 0; - (void)size; /* unused */ - - if (!imb_is_a_iris(mem)) return NULL; + if (size < HEADER_SIZE) { + return NULL; + } + + if (!imb_is_a_iris(mem)) { + return NULL; + } /* OCIO_TODO: only tested with 1 byte per pixel, not sure how to test with other settings */ colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE); - /*printf("new iris\n");*/ - readheader(inf, &image); if (image.imagic != IMAGIC) { fprintf(stderr, "longimagedata: bad magic number in image file\n"); return(NULL); } - + rle = ISRLE(image.type); bpp = BPP(image.type); if (bpp != 1 && bpp != 2) { fprintf(stderr, "longimagedata: image must have 1 or 2 byte per pix chan\n"); return(NULL); } - - xsize = image.xsize; - ysize = image.ysize; - zsize = image.zsize; - + if ((uint)image.zsize > 8) { + fprintf(stderr, "longimagedata: channels over 8 not supported\n"); + return(NULL); + } + + const int xsize = image.xsize; + const int ysize = image.ysize; + const int zsize = image.zsize; + if (flags & IB_test) { ibuf = IMB_allocImBuf(image.xsize, image.ysize, 8 * image.zsize, 0); if (ibuf) ibuf->ftype = IMB_FTYPE_IMAGIC; @@ -306,12 +304,17 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha } if (rle) { - tablen = ysize * zsize * sizeof(int); - starttab = (unsigned int *)MEM_mallocN(tablen, "iris starttab"); - lengthtab = (unsigned int *)MEM_mallocN(tablen, "iris endtab"); MFILE_SEEK(inf, HEADER_SIZE); - + + uint *starttab = MEM_mallocN(tablen, "iris starttab"); + uint *lengthtab = MEM_mallocN(tablen, "iris endtab"); + +#define MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(p) \ + if (UNLIKELY((p) > mem_end)) { dirty_flag |= DIRTY_FLAG_EOF; goto fail_rle; } ((void)0) + + MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(MFILE_DATA(inf) + ((4 * 2) * tablen)); + readtab(inf, starttab, tablen); readtab(inf, lengthtab, tablen); @@ -335,7 +338,7 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect); if (ibuf->planes > 32) ibuf->planes = 32; base = ibuf->rect; - zbase = (unsigned int *)ibuf->zbuf; + zbase = (uint *)ibuf->zbuf; if (badorder) { for (z = 0; z < zsize; z++) { @@ -344,9 +347,11 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha MFILE_SEEK(inf, starttab[y + z * ysize]); rledat = MFILE_DATA(inf); MFILE_STEP(inf, lengthtab[y + z * ysize]); - - expandrow((uchar *)lptr, rledat, 3 - z); - lptr += xsize; + const uchar *rledat_next = MFILE_DATA(inf); + uint *lptr_next = lptr + xsize; + MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next); + dirty_flag |= expandrow((uchar *)lptr, (uchar *)lptr_next, rledat, rledat_next, 3 - z); + lptr = lptr_next; } } } @@ -354,17 +359,25 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha lptr = base; zptr = zbase; for (y = 0; y < ysize; y++) { - + + uint *lptr_next = lptr + xsize; + uint *zptr_next = zptr + xsize; + for (z = 0; z < zsize; z++) { MFILE_SEEK(inf, starttab[y + z * ysize]); rledat = MFILE_DATA(inf); MFILE_STEP(inf, lengthtab[y + z * ysize]); - - if (z < 4) expandrow((uchar *)lptr, rledat, 3 - z); - else if (z < 8) expandrow((uchar *)zptr, rledat, 7 - z); + const uchar *rledat_next = MFILE_DATA(inf); + MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next); + if (z < 4) { + dirty_flag |= expandrow((uchar *)lptr, (uchar *)lptr_next, rledat, rledat_next, 3 - z); + } + else if (z < 8) { + dirty_flag |= expandrow((uchar *)zptr, (uchar *)zptr_next, rledat, rledat_next, 7 - z); + } } - lptr += xsize; - zptr += xsize; + lptr = lptr_next; + zptr = zptr_next; } } @@ -383,14 +396,17 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha MFILE_SEEK(inf, starttab[y + z * ysize]); rledat = MFILE_DATA(inf); MFILE_STEP(inf, lengthtab[y + z * ysize]); - - expandrow2(fptr, rledat, 3 - z); - fptr += xsize * 4; + const uchar *rledat_next = MFILE_DATA(inf); + MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next); + float *fptr_next = fptr + (xsize * 4); + dirty_flag |= expandrow2(fptr, fptr_next, rledat, rledat_next, 3 - z); + fptr = fptr_next; } } } else { fptr = fbase; + float *fptr_next = fptr + (xsize * 4); for (y = 0; y < ysize; y++) { @@ -398,27 +414,31 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha MFILE_SEEK(inf, starttab[y + z * ysize]); rledat = MFILE_DATA(inf); MFILE_STEP(inf, lengthtab[y + z * ysize]); - - expandrow2(fptr, rledat, 3 - z); - + const uchar *rledat_next = MFILE_DATA(inf); + MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next); + dirty_flag |= expandrow2(fptr, fptr_next, rledat, rledat_next, 3 - z); } - fptr += xsize * 4; + fptr = fptr_next; } } } - +#undef MFILE_CAPACITY_AT_PTR_OK_OR_FAIL +fail_rle: MEM_freeN(starttab); MEM_freeN(lengthtab); - } else { + +#define MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(p) \ + if (UNLIKELY((p) > mem_end)) { dirty_flag |= DIRTY_FLAG_EOF; goto fail_uncompressed; } ((void)0) + if (bpp == 1) { ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect); if (ibuf->planes > 32) ibuf->planes = 32; base = ibuf->rect; - zbase = (unsigned int *)ibuf->zbuf; + zbase = (uint *)ibuf->zbuf; MFILE_SEEK(inf, HEADER_SIZE); rledat = MFILE_DATA(inf); @@ -427,12 +447,13 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha if (z < 4) lptr = base; else if (z < 8) lptr = zbase; - - for (y = 0; y < ysize; y++) { - interleaverow((uchar *)lptr, rledat, 3 - z, xsize); - rledat += xsize; - + for (y = 0; y < ysize; y++) { + const uchar *rledat_next = rledat + xsize; + const int z_ofs = 3 - z; + MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next + z_ofs); + interleaverow((uchar *)lptr, rledat, z_ofs, xsize); + rledat = rledat_next; lptr += xsize; } } @@ -450,20 +471,23 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha for (z = 0; z < zsize; z++) { fptr = fbase; - - for (y = 0; y < ysize; y++) { - interleaverow2(fptr, rledat, 3 - z, xsize); - rledat += xsize * 2; - + for (y = 0; y < ysize; y++) { + const uchar *rledat_next = rledat + xsize * 2; + const int z_ofs = 3 - z; + MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next + z_ofs); + interleaverow2(fptr, rledat, z_ofs, xsize); + rledat = rledat_next; fptr += xsize * 4; } } } +#undef MFILE_CAPACITY_AT_PTR_OK_OR_FAIL +fail_uncompressed: + (void)0; } - - + if (bpp == 1) { uchar *rect; @@ -528,6 +552,9 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha } + if (dirty_flag) { + fprintf(stderr, "longimagedata: corrupt file content (%d)\n", dirty_flag); + } ibuf->ftype = IMB_FTYPE_IMAGIC; test_endian_zbuf(ibuf); @@ -541,7 +568,7 @@ struct ImBuf *imb_loadiris(const unsigned char *mem, size_t size, int flags, cha /* static utility functions for longimagedata */ -static void interleaverow(unsigned char *lptr, const unsigned char *cptr, int z, int n) +static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n) { lptr += z; while (n--) { @@ -550,7 +577,7 @@ static void interleaverow(unsigned char *lptr, const unsigned char *cptr, int z, } } -static void interleaverow2(float *lptr, const unsigned char *cptr, int z, int n) +static void interleaverow2(float *lptr, const uchar *cptr, int z, int n) { lptr += z; while (n--) { @@ -560,19 +587,34 @@ static void interleaverow2(float *lptr, const unsigned char *cptr, int z, int n) } } -static void expandrow2(float *optr, const unsigned char *iptr, int z) +static int expandrow2( + float *optr, const float *optr_end, + const uchar *iptr, const uchar *iptr_end, int z) { - unsigned short pixel, count; + ushort pixel, count; float pixel_f; +#define EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next) \ + if (UNLIKELY(iptr_next > iptr_end)) { goto fail; } + +#define EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next) \ + if (UNLIKELY(optr_next > optr_end)) { goto fail; } + optr += z; + optr_end += z; while (1) { + const uchar *iptr_next = iptr + 2; + EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next); pixel = (iptr[0] << 8) | (iptr[1] << 0); - iptr += 2; - + iptr = iptr_next; + if (!(count = (pixel & 0x7f)) ) - return; + return false; + const float *optr_next = optr + count; + EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next); if (pixel & 0x80) { + iptr_next = iptr + (count * 2); + EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next); while (count >= 8) { optr[0 * 4] = ((iptr[0] << 8) | (iptr[1] << 0)) / (float)0xFFFF; optr[1 * 4] = ((iptr[2] << 8) | (iptr[3] << 0)) / (float)0xFFFF; @@ -591,10 +633,13 @@ static void expandrow2(float *optr, const unsigned char *iptr, int z) iptr += 2; optr += 4; } + BLI_assert(iptr == iptr_next); } else { + iptr_next = iptr + 2; + EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next); pixel_f = ((iptr[0] << 8) | (iptr[1] << 0)) / (float)0xFFFF; - iptr += 2; + iptr = iptr_next; while (count >= 8) { optr[0 * 4] = pixel_f; @@ -612,20 +657,45 @@ static void expandrow2(float *optr, const unsigned char *iptr, int z) *optr = pixel_f; optr += 4; } + BLI_assert(iptr == iptr_next); } + BLI_assert(optr == optr_next); } + return false; + +#undef EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL +#undef EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL +fail: + return DIRTY_FLAG_ENCODING; } -static void expandrow(unsigned char *optr, const unsigned char *iptr, int z) +static int expandrow( + uchar *optr, const uchar *optr_end, + const uchar *iptr, const uchar *iptr_end, int z) { - unsigned char pixel, count; + uchar pixel, count; + +#define EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next) \ + if (UNLIKELY(iptr_next > iptr_end)) { goto fail; } + +#define EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next) \ + if (UNLIKELY(optr_next > optr_end)) { goto fail; } optr += z; + optr_end += z; while (1) { - pixel = *iptr++; + const uchar *iptr_next = iptr + 1; + EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next); + pixel = *iptr; + iptr = iptr_next; if (!(count = (pixel & 0x7f)) ) - return; + return false; + const uchar *optr_next = optr + ((int)count * 4); + EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next); + if (pixel & 0x80) { + iptr_next = iptr + count; + EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next); while (count >= 8) { optr[0 * 4] = iptr[0]; optr[1 * 4] = iptr[1]; @@ -643,8 +713,11 @@ static void expandrow(unsigned char *optr, const unsigned char *iptr, int z) *optr = *iptr++; optr += 4; } + BLI_assert(iptr == iptr_next); } else { + iptr_next = iptr + 1; + EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next); pixel = *iptr++; while (count >= 8) { optr[0 * 4] = pixel; @@ -662,8 +735,17 @@ static void expandrow(unsigned char *optr, const unsigned char *iptr, int z) *optr = pixel; optr += 4; } + BLI_assert(iptr == iptr_next); } + BLI_assert(optr == optr_next); } + + return false; + +#undef EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL +#undef EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL +fail: + return DIRTY_FLAG_ENCODING; } /* @@ -679,14 +761,14 @@ static void expandrow(unsigned char *optr, const unsigned char *iptr, int z) * Added: zbuf write */ -static int output_iris(unsigned int *lptr, int xsize, int ysize, int zsize, const char *name, int *zptr) +static int output_iris(uint *lptr, int xsize, int ysize, int zsize, const char *name, int *zptr) { FILE *outf; IMAGE *image; int tablen, y, z, pos, len = 0; - unsigned int *starttab, *lengthtab; - unsigned char *rlebuf; - unsigned int *lumbuf; + uint *starttab, *lengthtab; + uchar *rlebuf; + uint *lumbuf; int rlebuflen, goodwrite; goodwrite = 1; @@ -696,14 +778,14 @@ static int output_iris(unsigned int *lptr, int xsize, int ysize, int zsize, cons tablen = ysize * zsize * sizeof(int); image = (IMAGE *)MEM_mallocN(sizeof(IMAGE), "iris image"); - starttab = (unsigned int *)MEM_mallocN(tablen, "iris starttab"); - lengthtab = (unsigned int *)MEM_mallocN(tablen, "iris lengthtab"); + starttab = (uint *)MEM_mallocN(tablen, "iris starttab"); + lengthtab = (uint *)MEM_mallocN(tablen, "iris lengthtab"); rlebuflen = 1.05 * xsize + 10; - rlebuf = (unsigned char *)MEM_mallocN(rlebuflen, "iris rlebuf"); - lumbuf = (unsigned int *)MEM_mallocN(xsize * sizeof(int), "iris lumbuf"); + rlebuf = (uchar *)MEM_mallocN(rlebuflen, "iris rlebuf"); + lumbuf = (uint *)MEM_mallocN(xsize * sizeof(int), "iris lumbuf"); memset(image, 0, sizeof(IMAGE)); - image->imagic = IMB_FTYPE_IMAGIC; + image->imagic = IMAGIC; image->type = RLE(1); if (zsize > 1) image->dim = 3; @@ -765,7 +847,7 @@ static int output_iris(unsigned int *lptr, int xsize, int ysize, int zsize, cons /* static utility functions for output_iris */ -static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n) +static void lumrow(uchar *rgbptr, uchar *lumptr, int n) { lumptr += CHANOFFSET(0); while (n--) { @@ -775,9 +857,9 @@ static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n) } } -static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cnt) +static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int cnt) { - unsigned char *iptr, *ibufend, *sptr, *optr; + uchar *iptr, *ibufend, *sptr, *optr; short todo, cc; int count; @@ -830,7 +912,7 @@ static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cn } } *optr++ = 0; - return optr - (unsigned char *)rlebuf; + return optr - (uchar *)rlebuf; } int imb_saveiris(struct ImBuf *ibuf, const char *name, int flags) diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c index 390f2502ee7..388c2734fe9 100644 --- a/source/blender/imbuf/intern/jp2.c +++ b/source/blender/imbuf/intern/jp2.c @@ -588,7 +588,7 @@ static opj_image_t *ibuftoimage(ImBuf *ibuf, opj_cparameters_t *parameters) img_fol_t img_fol; /* only needed for cinema presets */ memset(&img_fol, 0, sizeof(img_fol_t)); - if (ibuf->float_colorspace) { + if (ibuf->float_colorspace || (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) { /* float buffer was managed already, no need in color space conversion */ chanel_colormanage_cb = channel_colormanage_noop; } diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c index 4b49076dcd6..89955711384 100644 --- a/source/blender/imbuf/intern/moviecache.c +++ b/source/blender/imbuf/intern/moviecache.c @@ -49,7 +49,7 @@ #include "IMB_imbuf.h" #ifdef DEBUG_MESSAGES -# if defined __GNUC__ || defined __sun +# if defined __GNUC__ # define PRINT(format, args ...) printf(format, ##args) # else # define PRINT(format, ...) printf(__VA_ARGS__) diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index ec544e65355..1fa3b943524 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -1104,7 +1104,7 @@ void IMB_exr_write_channels(void *handle) if (data->channels.first) { const size_t num_pixels = ((size_t)data->width) * data->height; - half *rect_half = NULL, *current_rect_half; + half *rect_half = NULL, *current_rect_half = NULL; /* We allocate teporary storage for half pixels for all the channels at once. */ if (data->num_half_channels != 0) { diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c index 503e63a3fb1..dded0f7aecf 100644 --- a/source/blender/imbuf/intern/png.c +++ b/source/blender/imbuf/intern/png.c @@ -152,7 +152,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) compression = (int)(((float)(ibuf->foptions.quality) / 11.1111f)); compression = compression < 0 ? 0 : (compression > 9 ? 9 : compression); - if (ibuf->float_colorspace) { + if (ibuf->float_colorspace || (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) { /* float buffer was managed already, no need in color space conversion */ chanel_colormanage_cb = channel_colormanage_noop; } diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c index 3360fd7548e..c4325caac91 100644 --- a/source/blender/imbuf/intern/rectop.c +++ b/source/blender/imbuf/intern/rectop.c @@ -301,8 +301,8 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, int destx, int desty, int origx, int origy, int srcx, int srcy, int width, int height, IMB_BlendMode mode, bool accumulate) { - unsigned int *drect = NULL, *orect, *srect = NULL, *dr, *or, *sr; - float *drectf = NULL, *orectf, *srectf = NULL, *drf, *orf, *srf; + unsigned int *drect = NULL, *orect = NULL, *srect = NULL, *dr, *or, *sr; + float *drectf = NULL, *orectf = NULL, *srectf = NULL, *drf, *orf, *srf; unsigned short *cmaskrect = curvemask, *cmr; unsigned short *dmaskrect = dmask, *dmr; unsigned short *texmaskrect = texmask, *tmr; @@ -424,6 +424,7 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, else { switch (mode) { case IMB_BLEND_MIX: + case IMB_BLEND_INTERPOLATE: func = blend_color_mix_byte; func_float = blend_color_mix_float; break; @@ -563,9 +564,15 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, mask_src[0] = src[0]; mask_src[1] = src[1]; mask_src[2] = src[2]; - mask_src[3] = divide_round_i(src[3] * mask, 65535); - func((unsigned char *)dr, (unsigned char *)or, mask_src); + if (mode == IMB_BLEND_INTERPOLATE) { + mask_src[3] = src[3]; + blend_color_interpolate_byte((unsigned char *)dr, (unsigned char *)or, mask_src, mask / 65535.0f); + } + else { + mask_src[3] = divide_round_i(src[3] * mask, 65535); + func((unsigned char *)dr, (unsigned char *)or, mask_src); + } } } } @@ -588,9 +595,15 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, mask_src[0] = src[0]; mask_src[1] = src[1]; mask_src[2] = src[2]; - mask_src[3] = divide_round_i(src[3] * mask, 65535); - func((unsigned char *)dr, (unsigned char *)or, mask_src); + if (mode == IMB_BLEND_INTERPOLATE) { + mask_src[3] = src[3]; + blend_color_interpolate_byte((unsigned char *)dr, (unsigned char *)or, mask_src, mask / 65535.0f); + } + else { + mask_src[3] = divide_round_i(src[3] * mask, 65535); + func((unsigned char *)dr, (unsigned char *)or, mask_src); + } } } } @@ -642,12 +655,16 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, mask = min_ff(mask, 65535.0); if (mask > *dmr) { - float mask_srf[4]; - *dmr = mask; - mul_v4_v4fl(mask_srf, srf, mask / 65535.0f); - func_float(drf, orf, mask_srf); + if (mode == IMB_BLEND_INTERPOLATE) { + blend_color_interpolate_float(drf, orf, srf, mask / 65535.0f); + } + else { + float mask_srf[4]; + mul_v4_v4fl(mask_srf, srf, mask / 65535.0f); + func_float(drf, orf, mask_srf); + } } } } @@ -664,11 +681,15 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, mask = min_ff(mask, 65535.0); if (srf[3] && (mask > 0.0f)) { - float mask_srf[4]; - - mul_v4_v4fl(mask_srf, srf, mask / 65535.0f); + if (mode == IMB_BLEND_INTERPOLATE) { + blend_color_interpolate_float(drf, orf, srf, mask / 65535.0f); + } + else { + float mask_srf[4]; + mul_v4_v4fl(mask_srf, srf, mask / 65535.0f); + func_float(drf, orf, mask_srf); + } - func_float(drf, orf, mask_srf); } } } diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c index 4368a428186..8e5cf80e013 100644 --- a/source/blender/imbuf/intern/tiff.c +++ b/source/blender/imbuf/intern/tiff.c @@ -822,7 +822,7 @@ int imb_savetiff(ImBuf *ibuf, const char *name, int flags) /* convert from float source */ float rgb[4]; - if (ibuf->float_colorspace) { + if (ibuf->float_colorspace || (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) { /* float buffer was managed already, no need in color space conversion */ copy_v3_v3(rgb, &fromf[from_i]); } diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index ba8480b636f..76a44aa81f7 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -52,10 +52,6 @@ #include "IMB_anim.h" -#ifdef WITH_QUICKTIME -#include "quicktime_import.h" -#endif - #ifdef WITH_FFMPEG #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> @@ -107,28 +103,6 @@ const char *imb_ext_image_filepath_only[] = { NULL }; -const char *imb_ext_image_qt[] = { - ".gif", - ".psd", - ".pct", ".pict", - ".pntg", - ".qtif", - NULL -}; - -#if 0 /* UNUSED */ -const char *imb_ext_movie_qt[] = { - ".avi", - ".flc", - ".dv", - ".r3d", - ".mov", - ".movie", - ".mv", - NULL -}; -#endif - const char *imb_ext_movie[] = { ".avi", ".flc", @@ -247,13 +221,6 @@ static int isavi(const char *name) #endif } -#ifdef WITH_QUICKTIME -static int isqtime(const char *name) -{ - return anim_is_quicktime(name); -} -#endif - #ifdef WITH_FFMPEG /* BLI_vsnprintf in ffmpeg_log_callback() causes invalid warning */ @@ -383,9 +350,6 @@ int imb_get_anim_type(const char *name) if (UTIL_DEBUG) printf("%s: %s\n", __func__, name); #ifndef _WIN32 -# ifdef WITH_QUICKTIME - if (isqtime(name)) return (ANIM_QTIME); -# endif # ifdef WITH_FFMPEG /* stat test below fails on large files > 4GB */ if (isffmpeg(name)) return (ANIM_FFMPEG); @@ -401,9 +365,6 @@ int imb_get_anim_type(const char *name) if (((st.st_mode) & S_IFMT) != S_IFREG) return(0); if (ismovie(name)) return (ANIM_MOVIE); -# ifdef WITH_QUICKTIME - if (isqtime(name)) return (ANIM_QTIME); -# endif # ifdef WITH_FFMPEG if (isffmpeg(name)) return (ANIM_FFMPEG); # endif diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index da0f505c4f3..b2a3cb4f9bc 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -127,8 +127,7 @@ typedef struct ID { /** * LIB_TAG_... tags (runtime only, cleared at read time). */ - short tag; - short pad_s1; + int tag; int us; int icon_id; IDProperty *properties; @@ -288,7 +287,7 @@ typedef enum ID_Type { #ifdef GS # undef GS #endif -#define GS(a) (CHECK_TYPE_ANY(a, char *, const char *, char [66], const char[66]), (*((const short *)(a)))) +#define GS(a) (CHECK_TYPE_ANY(a, char *, const char *, char [66], const char[66]), (ID_Type)(*((const short *)(a)))) #define ID_NEW_SET(_id, _idn) \ (((ID *)(_id))->newid = (ID *)(_idn), ((ID *)(_id))->newid->tag |= LIB_TAG_NEW, (void *)((ID *)(_id))->newid) @@ -350,6 +349,13 @@ enum { LIB_TAG_ID_RECALC_DATA = 1 << 13, LIB_TAG_ANIM_NO_RECALC = 1 << 14, LIB_TAG_ID_RECALC_ALL = (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA), + + /* RESET_NEVER tag datablock for freeing etc. behavior (usually set when copying real one into temp/runtime one). */ + LIB_TAG_NO_MAIN = 1 << 16, /* Datablock is not listed in Main database. */ + LIB_TAG_NO_USER_REFCOUNT = 1 << 17, /* Datablock does not refcount usages of other IDs. */ + /* Datablock was not allocated by standard system (BKE_libblock_alloc), do not free its memory + * (usual type-specific freeing is called though). */ + LIB_TAG_NOT_ALLOCATED = 1 << 18, }; /* To filter ID types (filter_id) */ diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 1083400ece2..d49960771d0 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -514,7 +514,7 @@ typedef enum eActionGroup_Flag { AGRP_MODIFIERS_OFF = (1 << 7), AGRP_TEMP = (1 << 30), - AGRP_MOVED = (1 << 31) + AGRP_MOVED = (1u << 31) } eActionGroup_Flag; @@ -757,7 +757,7 @@ typedef enum ACHAN_FLAG { ACHAN_EXPANDED = (1 << 4), ACHAN_SHOWIPO = (1 << 5), ACHAN_SHOWCONS = (1 << 6), - ACHAN_MOVED = (1 << 31) + ACHAN_MOVED = (1u << 31) } ACHAN_FLAG; #endif /* __DNA_ACTION_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index e50a2637fff..935a893f689 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -685,7 +685,7 @@ typedef enum eNlaStrip_Flag { /* temporary editing flags */ /* NLA-Strip is really just a temporary meta used to facilitate easier transform code */ NLASTRIP_FLAG_TEMP_META = (1<<30), - NLASTRIP_FLAG_EDIT_TOUCHED = (1<<31) + NLASTRIP_FLAG_EDIT_TOUCHED = (1u << 31) } eNlaStrip_Flag; /* NLA Strip Type */ diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index f4a1677efc4..67a35d4e207 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -210,7 +210,7 @@ typedef enum BrushFlags { BRUSH_CUSTOM_ICON = (1 << 28), BRUSH_LINE = (1 << 29), BRUSH_ABSOLUTE_JITTER = (1 << 30), - BRUSH_CURVE = (1 << 31) + BRUSH_CURVE = (1u << 31) } BrushFlags; typedef enum { @@ -315,7 +315,21 @@ enum { PAINT_BLEND_MUL = 3, PAINT_BLEND_BLUR = 4, PAINT_BLEND_LIGHTEN = 5, - PAINT_BLEND_DARKEN = 6 + PAINT_BLEND_DARKEN = 6, + PAINT_BLEND_AVERAGE = 7, + PAINT_BLEND_SMEAR = 8, + PAINT_BLEND_COLORDODGE = 9, + PAINT_BLEND_DIFFERENCE = 10, + PAINT_BLEND_SCREEN = 11, + PAINT_BLEND_HARDLIGHT = 12, + PAINT_BLEND_OVERLAY = 13, + PAINT_BLEND_SOFTLIGHT = 14, + PAINT_BLEND_EXCLUSION = 15, + PAINT_BLEND_LUMINOCITY = 16, + PAINT_BLEND_SATURATION = 17, + PAINT_BLEND_HUE = 18, + PAINT_BLEND_ALPHA_SUB = 19, + PAINT_BLEND_ALPHA_ADD = 20, }; typedef enum { diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 823a7f0812f..64856b2eb76 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -98,7 +98,7 @@ typedef enum ModifierMode { eModifierMode_Expanded = (1 << 4), eModifierMode_Virtual = (1 << 5), eModifierMode_ApplyOnSpline = (1 << 6), - eModifierMode_DisableTemporary = (1 << 31) + eModifierMode_DisableTemporary = (1u << 31) } ModifierMode; typedef struct ModifierData { @@ -278,6 +278,7 @@ typedef struct MirrorModifierData { short flag; float tolerance; float uv_offset[2]; + float uv_offset_copy[2]; struct Object *mirror_ob; } MirrorModifierData; @@ -654,7 +655,8 @@ typedef struct BooleanModifierData { struct Object *object; char operation; char solver; - char pad[2]; + char pad; + char bm_flag; float double_threshold; } BooleanModifierData; @@ -669,6 +671,13 @@ typedef enum { eBooleanModifierSolver_BMesh = 1, } BooleanSolver; +/* bm_flag (only used when G_DEBUG) */ +enum { + eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 0), + eBooleanModifierBMeshFlag_BMesh_NoDissolve = (1 << 1), + eBooleanModifierBMeshFlag_BMesh_NoConnectRegions = (1 << 2), +}; + typedef struct MDefInfluence { int vertex; float weight; @@ -924,9 +933,10 @@ typedef struct ScrewModifierData { unsigned int iter; float screw_ofs; float angle; - char axis; - char pad; + float merge_dist; short flag; + char axis; + char pad[5]; } ScrewModifierData; enum { @@ -937,6 +947,7 @@ enum { MOD_SCREW_SMOOTH_SHADING = (1 << 5), MOD_SCREW_UV_STRETCH_U = (1 << 6), MOD_SCREW_UV_STRETCH_V = (1 << 7), + MOD_SCREW_MERGE = (1 << 8), }; typedef struct OceanModifierData { @@ -1515,7 +1526,7 @@ enum { MOD_DATATRANSFER_USE_VERT = 1 << 28, MOD_DATATRANSFER_USE_EDGE = 1 << 29, MOD_DATATRANSFER_USE_LOOP = 1 << 30, - MOD_DATATRANSFER_USE_POLY = 1 << 31, + MOD_DATATRANSFER_USE_POLY = 1u << 31, }; /* Set Split Normals modifier */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index b922ac072b0..e6bc315b728 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -111,7 +111,7 @@ typedef struct bNodeSocket { short stack_index; /* local stack index */ /* XXX deprecated, kept for forward compatibility */ short stack_type DNA_DEPRECATED; - int pad; + char draw_shape, pad[3]; void *cache; /* cached data from execution */ @@ -143,6 +143,13 @@ typedef enum eNodeSocketDatatype { SOCK_STRING = 7 } eNodeSocketDatatype; +/* socket shape */ +typedef enum eNodeSocketDrawShape { + SOCK_DRAW_SHAPE_CIRCLE = 0, + SOCK_DRAW_SHAPE_SQUARE = 1, + SOCK_DRAW_SHAPE_DIAMOND = 2 +} eNodeSocketDrawShape; + /* socket side (input/output) */ typedef enum eNodeSocketInOut { SOCK_IN = 1, diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 6d79e6d49f8..0f341aa4001 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -683,6 +683,9 @@ typedef enum ObjectMode { /* any mode where the brush system is used */ #define OB_MODE_ALL_PAINT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT) +/* any mode that uses ob->sculpt */ +#define OB_MODE_ALL_SCULPT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) + #define MAX_DUPLI_RECUR 8 #ifdef __cplusplus diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 92c789f2feb..76cac158b5f 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -99,42 +99,6 @@ typedef struct AviCodecData { char avicodecname[128]; } AviCodecData; -typedef struct QuicktimeCodecData { - /*Old quicktime implementation compatibility fields, read only in 2.5 - deprecated*/ - void *cdParms; /* codec/compressor options */ - void *pad; /* padding */ - - unsigned int cdSize; /* size of cdParms buffer */ - unsigned int pad2; /* padding */ - - char qtcodecname[128]; -} QuicktimeCodecData; - -typedef struct QuicktimeCodecSettings { - /* Codec settings detailed for 2.5 implementation*/ - int codecType; /* Types defined in quicktime_export.h */ - int codecSpatialQuality; /* in 0-100 scale, to be translated in 0-1024 for qt use */ - - /* Settings not available in current QTKit API */ - int codec; - int codecFlags; - int colorDepth; - int codecTemporalQuality; /* in 0-100 scale, to be translated in 0-1024 for qt use */ - int minSpatialQuality; /* in 0-100 scale, to be translated in 0-1024 for qt use */ - int minTemporalQuality; /* in 0-100 scale, to be translated in 0-1024 for qt use */ - int keyFrameRate; - int bitRate; /* bitrate in bps */ - - /* Audio Codec settings */ - int audiocodecType; - int audioSampleRate; - short audioBitDepth; - short audioChannels; - int audioCodecFlags; - int audioBitRate; - int pad1; -} QuicktimeCodecSettings; - typedef enum FFMpegPreset { FFM_PRESET_NONE, FFM_PRESET_ULTRAFAST, @@ -456,7 +420,7 @@ typedef struct ImageFormatData { #define R_IMF_IMTYPE_AVIJPEG 16 #define R_IMF_IMTYPE_PNG 17 /* #define R_IMF_IMTYPE_AVICODEC 18 */ /* avicodec is nomore */ -#define R_IMF_IMTYPE_QUICKTIME 19 +/* #define R_IMF_IMTYPE_QUICKTIME 19 */ /* quicktime is nomore */ #define R_IMF_IMTYPE_BMP 20 #define R_IMF_IMTYPE_RADHDR 21 #define R_IMF_IMTYPE_TIFF 22 @@ -585,8 +549,6 @@ typedef struct RenderData { struct ImageFormatData im_format; struct AviCodecData *avicodecdata; - struct QuicktimeCodecData *qtcodecdata; - struct QuicktimeCodecSettings qtcodecsettings; struct FFMpegCodecData ffcodecdata; int cfra, sfra, efra; /* frames as in 'images' */ @@ -751,7 +713,7 @@ typedef struct RenderData { /* sequencer options */ char seq_prev_type; - char seq_rend_type; + char seq_rend_type; /* UNUSED! */ char seq_flag; /* flag use for sequence render/draw */ char pad5[5]; @@ -790,14 +752,13 @@ typedef struct RenderData { struct BakeData bake; int preview_start_resolution; + short preview_pixel_size; /* Type of the debug pass to use. * Only used when built with debug passes support. */ short debug_pass_type; - short pad; - /* MultiView */ ListBase views; /* SceneRenderView */ short actview; @@ -1156,13 +1117,8 @@ typedef struct UvSculpt { /* Vertex Paint */ typedef struct VPaint { Paint paint; - short flag, pad; - int tot; /* allocation size of prev buffers */ - unsigned int *vpaint_prev; /* previous mesh colors */ - struct MDeformVert *wpaint_prev; /* previous vertex weights */ - - void *paintcursor; /* wm handle */ + int radial_symm[3]; /* For mirrored painting */ } VPaint; /* VPaint.flag */ @@ -1668,8 +1624,7 @@ typedef struct Scene { struct Object *obedit; /* name replaces old G.obedit */ float cursor[3]; /* 3d cursor location */ - float twcent[3]; /* center for transform widget */ - float twmin[3], twmax[3]; /* boundbox of selection for transform widget */ + char _pad[4]; unsigned int lay; /* bitflags for layer visibility */ int layact; /* active layer */ @@ -1730,6 +1685,8 @@ typedef struct Scene { /* Movie Tracking */ struct MovieClip *clip; /* active movie clip */ + void *pad4; + uint64_t customdata_mask; /* XXX. runtime flag for drawing, actually belongs in the window, only used by BKE_object_handle_update() */ uint64_t customdata_mask_modal; /* XXX. same as above but for temp operator use (gl renders) */ @@ -1750,8 +1707,7 @@ typedef struct Scene { /* use preview range */ #define SCER_PRV_RANGE (1<<0) #define SCER_LOCK_FRAME_SELECTION (1<<1) - /* timeline/keyframe jumping - only selected items (on by default) */ -#define SCE_KEYS_NO_SELONLY (1<<2) + /* show/use subframes (for checking motion blur) */ #define SCER_SHOW_SUBFRAME (1<<3) /* mode (int now) */ @@ -1791,7 +1747,7 @@ typedef struct Scene { #define R_USE_WS_SHADING 0x8000000 /* use world space interpretation of lighting data */ /* seq_flag */ -#define R_SEQ_GL_PREV 1 +// #define R_SEQ_GL_PREV 1 // UNUSED, we just use setting from seq_prev_type now. // #define R_SEQ_GL_REND 2 // UNUSED, opengl render has its own operator now. #define R_SEQ_SOLID_TEX 4 @@ -1936,16 +1892,18 @@ extern const char *RE_engine_id_CYCLES; /* **************** SCENE ********************* */ /* note that much higher maxframes give imprecise sub-frames, see: T46859 */ +/* Current precision is 16 for the sub-frames closer to MAXFRAME. */ + /* for general use */ -#define MAXFRAME 500000 -#define MAXFRAMEF 500000.0f +#define MAXFRAME 1048574 +#define MAXFRAMEF 1048574.0f #define MINFRAME 0 #define MINFRAMEF 0.0f /* (minimum frame number for current-frame) */ -#define MINAFRAME -500000 -#define MINAFRAMEF -500000.0f +#define MINAFRAME -1048574 +#define MINAFRAMEF -1048574.0f /* depricate this! */ #define TESTBASE(v3d, base) ( \ @@ -2085,6 +2043,7 @@ typedef enum eVGroupSelect { #define SCE_DS_COLLAPSED (1<<1) #define SCE_NLA_EDIT_ON (1<<2) #define SCE_FRAME_DROP (1<<3) +#define SCE_KEYS_NO_SELONLY (1<<4) /* return flag BKE_scene_base_iter_next functions */ diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index e208ef39719..fd63d7c471c 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -366,7 +366,7 @@ enum { /* uiList filter orderby type */ enum { UILST_FLT_SORT_ALPHA = 1 << 0, - UILST_FLT_SORT_REVERSE = 1 << 31 /* Special value, bitflag used to reverse order! */ + UILST_FLT_SORT_REVERSE = 1u << 31 /* Special value, bitflag used to reverse order! */ }; #define UILST_FLT_SORT_MASK (((unsigned int)UILST_FLT_SORT_REVERSE) - 1) diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index 1f4e4df4660..74a1a13c2eb 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -442,7 +442,7 @@ enum { /* access scene strips directly (like a metastrip) */ SEQ_SCENE_STRIPS = (1 << 30), - SEQ_INVALID_EFFECT = (1 << 31), + SEQ_INVALID_EFFECT = (1u << 31), }; /* StripProxy->storage */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 0e5d9bd33e6..d6490d99016 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -741,7 +741,7 @@ typedef enum eFileSel_File_Types { FILE_TYPE_ALEMBIC = (1 << 16), FILE_TYPE_DIR = (1 << 30), /* An FS directory (i.e. S_ISDIR on its path is true). */ - FILE_TYPE_BLENDERLIB = (1 << 31), + FILE_TYPE_BLENDERLIB = (1u << 31), } eFileSel_File_Types; /* Selection Flags in filesel: struct direntry, unsigned char selflag */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 5e7e7366e35..cddb1e06b8c 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -48,7 +48,8 @@ struct ColorBand; #define MAX_STYLE_NAME 64 -/* default uifont_id offered by Blender */ +/* default offered by Blender. + * uiFont.uifont_id */ typedef enum eUIFont_ID { UIFONT_DEFAULT = 0, /* UIFONT_BITMAP = 1 */ /* UNUSED */ @@ -64,7 +65,7 @@ typedef struct uiFont { struct uiFont *next, *prev; char filename[1024];/* 1024 = FILE_MAX */ short blf_id; /* from blfont lib */ - short uifont_id; /* own id */ + short uifont_id; /* own id (eUIFont_ID) */ short r_to_l; /* fonts that read from left to right */ short hinting; } uiFont; @@ -84,7 +85,7 @@ typedef struct uiFontStyle { float shadowcolor; /* 1 value, typically white or black anyway */ } uiFontStyle; -/* uiFontStyle->align */ +/* uiFontStyle.align */ typedef enum eFontStyle_Align { UI_STYLE_TEXT_LEFT = 0, UI_STYLE_TEXT_CENTER = 1, @@ -354,11 +355,11 @@ typedef struct ThemeWireColor { char select[4]; char active[4]; - short flag; + short flag; /* eWireColor_Flags */ short pad; } ThemeWireColor; -/* flags for ThemeWireColor */ +/* ThemeWireColor.flag */ typedef enum eWireColor_Flags { TH_WIRECOLOR_CONSTCOLS = (1 << 0), TH_WIRECOLOR_TEXTCOLS = (1 << 1), @@ -434,7 +435,8 @@ typedef struct UserDef { /* UserDef has separate do-version handling, and can be read from other files */ int versionfile, subversionfile; - int flag, dupflag; + int flag; /* eUserPref_Flag */ + int dupflag; /* eDupli_ID_Flags */ int savetime; char tempdir[768]; /* FILE_MAXDIR length */ char fontdir[768]; @@ -450,14 +452,15 @@ typedef struct UserDef { int anim_player_preset; short v2d_min_gridsize; /* minimum spacing between gridlines in View2D grids */ - short timecode_style; /* style of timecode display */ + short timecode_style; /* eTimecodeStyles, style of timecode display */ short versions; short dbl_click_time; short gameflags; short wheellinescroll; - int uiflag, uiflag2; + int uiflag; /* eUserpref_UI_Flag */ + int uiflag2; /* eUserpref_UI_Flag2 */ int language; short userpref, viewzoom; @@ -470,10 +473,10 @@ typedef struct UserDef { int scrollback; /* console scrollback limit */ int dpi; /* range 48-128? */ float ui_scale; /* interface scale */ - int pad1; + int ui_line_width; /* interface line width */ char node_margin; /* node insert offset (aka auto-offset) margin, but might be useful for later stuff as well */ char pad2; - short transopts; + short transopts; /* eUserpref_Translation_Flags */ short menuthreshold1, menuthreshold2; /* startup template */ @@ -491,12 +494,12 @@ typedef struct UserDef { short undosteps; short undomemory; short gp_manhattendist, gp_euclideandist, gp_eraser; - short gp_settings; + short gp_settings; /* eGP_UserdefSettings */ short tb_leftmouse, tb_rightmouse; struct SolidLight light[3]; short tw_hotspot, tw_flag, tw_handlesize, tw_size; short textimeout, texcollectrate; - short wmdrawmethod; /* removed wmpad */ + short wmdrawmethod; /* eWM_DrawMethod */ short dragthreshold; int memcachelimit; int prefetchframes; @@ -509,13 +512,13 @@ typedef struct UserDef { short smooth_viewtx; /* miliseconds to spend spinning the view */ short glreslimit; short curssize; - short color_picker_type; + short color_picker_type; /* eColorPicker_Types */ char ipo_new; /* interpolation mode for newly added F-Curves */ char keyhandles_new; /* handle types for newly added keyframes */ char gpu_select_method; char gpu_select_pick_deph; char pad4; - char view_frame_type; + char view_frame_type; /* eZoomFrame_Mode */ int view_frame_keyframes; /* number of keyframes to zoom around current frame */ float view_frame_seconds; /* seconds to zoom around current frame */ @@ -530,15 +533,16 @@ typedef struct UserDef { float ndof_sensitivity; /* overall sensitivity of 3D mouse */ float ndof_orbit_sensitivity; float ndof_deadzone; /* deadzone of 3D mouse */ - int ndof_flag; /* flags for 3D mouse */ + int ndof_flag; /* eNdof_Flag, flags for 3D mouse */ - short ogl_multisamples; /* amount of samples for OpenGL FSA, if zero no FSA */ + short ogl_multisamples; /* eMultiSample_Type, amount of samples for OpenGL FSA, if zero no FSA */ - short image_draw_method; /* Method to be used to draw the images (AUTO, GLSL, Textures or DrawPixels) */ + /* eImageDrawMethod, Method to be used to draw the images (AUTO, GLSL, Textures or DrawPixels) */ + short image_draw_method; float glalphaclip; - short autokey_mode; /* autokeying mode */ + short autokey_mode; /* eAutokey_Mode, autokeying mode */ short autokey_flag; /* flags for autokeying */ short text_render, pad9; /* options for text rendering */ @@ -582,7 +586,7 @@ extern UserDef U; /* from blenkernel blender.c */ /* ***************** USERDEF ****************** */ -/* userpref/section */ +/* UserDef.userpref (UI active_section) */ typedef enum eUserPref_Section { USER_SECTION_INTERFACE = 0, USER_SECTION_EDIT = 1, @@ -593,19 +597,19 @@ typedef enum eUserPref_Section { USER_SECTION_ADDONS = 6, } eUserPref_Section; -/* flag */ +/* UserDef.flag */ typedef enum eUserPref_Flag { USER_AUTOSAVE = (1 << 0), -/* USER_AUTOGRABGRID = (1 << 1), deprecated */ -/* USER_AUTOROTGRID = (1 << 2), deprecated */ -/* USER_AUTOSIZEGRID = (1 << 3), deprecated */ + USER_FLAG_DEPRECATED_1 = (1 << 1), /* cleared */ + USER_FLAG_DEPRECATED_2 = (1 << 2), /* cleared */ + USER_FLAG_DEPRECATED_3 = (1 << 3), /* cleared */ USER_SCENEGLOBAL = (1 << 4), USER_TRACKBALL = (1 << 5), -/* USER_DUPLILINK = (1 << 6), deprecated */ -/* USER_FSCOLLUM = (1 << 7), deprecated */ + USER_FLAG_DEPRECATED_6 = (1 << 6), /* cleared */ + USER_FLAG_DEPRECATED_7 = (1 << 7), /* cleared */ USER_MAT_ON_OB = (1 << 8), -/* USER_NO_CAPSLOCK = (1 << 9), */ /* not used anywhere */ -/* USER_VIEWMOVE = (1 << 10), */ /* not used anywhere */ + USER_FLAG_DEPRECATED_9 = (1 << 9), /* cleared */ + USER_FLAG_DEPRECATED_10 = (1 << 10), /* cleared */ USER_TOOLTIPS = (1 << 11), USER_TWOBUTTONMOUSE = (1 << 12), USER_NONUMPAD = (1 << 13), @@ -624,7 +628,7 @@ typedef enum eUserPref_Flag { USER_TOOLTIPS_PYTHON = (1 << 26), } eUserPref_Flag; -/* flag */ +/* bPathCompare.flag */ typedef enum ePathCompare_Flag { USER_PATHCMP_GLOB = (1 << 0), } ePathCompare_Flag; @@ -635,33 +639,34 @@ typedef enum ePathCompare_Flag { cfra = 0; \ } (void)0 -/* viewzoom */ +/* UserDef.viewzoom */ typedef enum eViewZoom_Style { USER_ZOOM_CONT = 0, USER_ZOOM_SCALE = 1, USER_ZOOM_DOLLY = 2 } eViewZoom_Style; -/* navigation_mode */ +/* UserDef.navigation_mode */ typedef enum eViewNavigation_Method { VIEW_NAVIGATION_WALK = 0, VIEW_NAVIGATION_FLY = 1, } eViewNavigation_Method; -/* flag */ +/* UserDef.flag */ typedef enum eWalkNavigation_Flag { USER_WALK_GRAVITY = (1 << 0), USER_WALK_MOUSE_REVERSE = (1 << 1), } eWalkNavigation_Flag; -/* uiflag */ +/* UserDef.uiflag */ typedef enum eUserpref_UI_Flag { /* flags 0 and 1 were old flags (for autokeying) that aren't used anymore */ USER_WHEELZOOMDIR = (1 << 2), USER_FILTERFILEEXTS = (1 << 3), USER_DRAWVIEWINFO = (1 << 4), USER_PLAINMENUS = (1 << 5), - /* flags 6 and 7 were old flags that are no-longer used */ + USER_LOCK_CURSOR_ADJUST = (1 << 6), + USER_UIFLAG_DEPRECATED_7 = (1 << 7), /* cleared */ USER_ALLWINCODECS = (1 << 8), USER_MENUOPENAUTO = (1 << 9), USER_ZBUF_CURSOR = (1 << 10), @@ -685,17 +690,18 @@ typedef enum eUserpref_UI_Flag { USER_HIDE_RECENT = (1 << 28), USER_SHOW_THUMBNAILS = (1 << 29), USER_QUIT_PROMPT = (1 << 30), - USER_HIDE_SYSTEM_BOOKMARKS = (1 << 31) + USER_HIDE_SYSTEM_BOOKMARKS = (1u << 31) } eUserpref_UI_Flag; -/* uiflag2 */ +/* UserDef.uiflag2 */ typedef enum eUserpref_UI_Flag2 { USER_KEEP_SESSION = (1 << 0), USER_REGION_OVERLAP = (1 << 1), USER_TRACKPAD_NATURAL = (1 << 2), } eUserpref_UI_Flag2; -/* Auto-Keying mode */ +/* Auto-Keying mode. + * UserDef.autokey_mode */ typedef enum eAutokey_Mode { /* AUTOKEY_ON is a bitflag */ AUTOKEY_ON = 1, @@ -705,7 +711,8 @@ typedef enum eAutokey_Mode { AUTOKEY_MODE_EDITKEYS = 5 } eAutokey_Mode; -/* Zoom to frame mode */ +/* Zoom to frame mode. + * UserDef.view_frame_type */ typedef enum eZoomFrame_Mode { ZOOM_FRAME_MODE_KEEP_RANGE = 0, ZOOM_FRAME_MODE_SECONDS = 1, @@ -728,20 +735,20 @@ typedef enum eAutokey_Flag { ANIMRECORD_FLAG_WITHNLA = (1 << 10), } eAutokey_Flag; -/* transopts */ +/* UserDef.transopts */ typedef enum eUserpref_Translation_Flags { USER_TR_TOOLTIPS = (1 << 0), USER_TR_IFACE = (1 << 1), -/* USER_TR_MENUS = (1 << 2), deprecated */ -/* USER_TR_FILESELECT = (1 << 3), deprecated */ -/* USER_TR_TEXTEDIT = (1 << 4), deprecated */ + USER_TR_DEPRECATED_2 = (1 << 2), /* cleared */ + USER_TR_DEPRECATED_3 = (1 << 3), /* cleared */ + USER_TR_DEPRECATED_4 = (1 << 4), /* cleared */ USER_DOTRANSLATE = (1 << 5), - USER_USETEXTUREFONT = (1 << 6), -/* CONVERT_TO_UTF8 = (1 << 7), deprecated */ + USER_TR_DEPRECATED_6 = (1 << 6), /* cleared */ + USER_TR_DEPRECATED_7 = (1 << 7), /* cleared */ USER_TR_NEWDATANAME = (1 << 8), } eUserpref_Translation_Flags; -/* dupflag */ +/* UserDef.dupflag */ typedef enum eDupli_ID_Flags { USER_DUP_MESH = (1 << 0), USER_DUP_CURVE = (1 << 1), @@ -757,14 +764,13 @@ typedef enum eDupli_ID_Flags { USER_DUP_PSYS = (1 << 11) } eDupli_ID_Flags; -/* gameflags */ +/* UserDef.gameflags */ typedef enum eOpenGL_RenderingOptions { - /* USER_DEPRECATED_FLAG = (1 << 0), */ - /* USER_DISABLE_SOUND = (1 << 1), */ /* deprecated, don't use without checking for */ - /* backwards compatibilty in do_versions! */ - USER_DISABLE_MIPMAP = (1 << 2), - /* USER_DISABLE_VBO = (1 << 3), */ /* DEPRECATED we always use vertex buffers now */ - /* USER_DISABLE_AA = (1 << 4), */ /* DEPRECATED */ + USER_GL_RENDER_DEPRECATED_0 = (1 << 0), + USER_GL_RENDER_DEPRECATED_1 = (1 << 1), + USER_DISABLE_MIPMAP = (1 << 2), + USER_GL_RENDER_DEPRECATED_3 = (1 << 3), + USER_GL_RENDER_DEPRECATED_4 = (1 << 4), } eOpenGL_RenderingOptions; /* selection method for opengl gpu_select_method */ @@ -774,7 +780,8 @@ typedef enum eOpenGL_SelectOptions { USER_SELECT_USE_SELECT_RENDERMODE = 2 } eOpenGL_SelectOptions; -/* wm draw method */ +/* wm draw method. + * UserDef.wmdrawmethod */ typedef enum eWM_DrawMethod { USER_DRAW_TRIPLE = 0, USER_DRAW_OVERLAP = 1, @@ -783,20 +790,23 @@ typedef enum eWM_DrawMethod { USER_DRAW_OVERLAP_FLIP = 4, } eWM_DrawMethod; -/* text draw options */ +/* text draw options + * UserDef.text_render */ typedef enum eText_Draw_Options { USER_TEXT_DISABLE_AA = (1 << 0), } eText_Draw_Options; /* tw_flag (transform widget) */ -/* gp_settings (Grease Pencil Settings) */ +/* Grease Pencil Settings. + * UserDef.gp_settings */ typedef enum eGP_UserdefSettings { GP_PAINT_DOSMOOTH = (1 << 0), GP_PAINT_DOSIMPLIFY = (1 << 1), } eGP_UserdefSettings; -/* color picker types */ +/* Color Picker Types. + * UserDef.color_picker_type */ typedef enum eColorPicker_Types { USER_CP_CIRCLE_HSV = 0, USER_CP_SQUARE_SV = 1, @@ -805,7 +815,8 @@ typedef enum eColorPicker_Types { USER_CP_CIRCLE_HSL = 4, } eColorPicker_Types; -/* timecode display styles */ +/* timecode display styles + * UserDef.timecode_style */ typedef enum eTimecodeStyles { /* as little info as is necessary to show relevant info * with '+' to denote the frames @@ -840,7 +851,7 @@ typedef enum eTheme_DrawTypes { TH_SHADED = 4 } eTheme_DrawTypes; -/* ndof_flag (3D mouse options) */ +/* UserDef.ndof_flag (3D mouse options) */ typedef enum eNdof_Flag { NDOF_SHOW_GUIDE = (1 << 0), NDOF_FLY_HELICOPTER = (1 << 1), @@ -873,6 +884,7 @@ typedef enum eNdof_Flag { #define NDOF_PIXELS_PER_SECOND 600.0f +/* UserDef.ogl_multisamples */ typedef enum eMultiSample_Type { USER_MULTISAMPLE_NONE = 0, USER_MULTISAMPLE_2 = 2, @@ -880,7 +892,8 @@ typedef enum eMultiSample_Type { USER_MULTISAMPLE_8 = 8, USER_MULTISAMPLE_16 = 16, } eMultiSample_Type; - + +/* UserDef.image_draw_method */ typedef enum eImageDrawMethod { /* IMAGE_DRAW_METHOD_AUTO = 0, */ /* Currently unused */ IMAGE_DRAW_METHOD_GLSL = 1, @@ -888,6 +901,7 @@ typedef enum eImageDrawMethod { IMAGE_DRAW_METHOD_DRAWPIXELS = 3, } eImageDrawMethod; +/* UserDef.virtual_pixel */ typedef enum eUserpref_VirtualPixel { VIRTUAL_PIXEL_NATIVE = 0, VIRTUAL_PIXEL_DOUBLE = 1, diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 4c243507e82..b9894d46b5b 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -225,7 +225,8 @@ typedef struct View3D { struct GPUFXSettings fx_settings; void *properties_storage; /* Nkey panel stores stuff here (runtime only!) */ - struct Material *defmaterial; /* used by matcap now */ + /* Allocated per view, not library data (used by matcap). */ + struct Material *defmaterial; /* XXX deprecated? */ struct bGPdata *gpd DNA_DEPRECATED; /* Grease-Pencil Data (annotation layers) */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index a1af3f98274..178d2d398e9 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -488,7 +488,6 @@ extern StructRNA RNA_PropertyGroupItem; extern StructRNA RNA_PropertySensor; extern StructRNA RNA_PythonConstraint; extern StructRNA RNA_PythonController; -extern StructRNA RNA_QuickTimeSettings; extern StructRNA RNA_RadarSensor; extern StructRNA RNA_RandomSensor; extern StructRNA RNA_RaySensor; @@ -783,6 +782,9 @@ const struct ListBase *RNA_struct_type_functions(StructRNA *srna); char *RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, int *r_len); +bool RNA_struct_available_or_report(struct ReportList *reports, const char *identifier); +bool RNA_struct_bl_idname_ok_or_report(struct ReportList *reports, const char *identifier, const char *sep); + /* Properties * * Access to struct properties. All this works with RNA pointers rather than @@ -1197,7 +1199,7 @@ StructRNA *ID_code_to_RNA_type(short idcode); } (void)0 /* macro which inserts the function name */ -#if defined __GNUC__ || defined __sun +#if defined __GNUC__ # define RNA_warning(format, args ...) _RNA_warning("%s: " format "\n", __func__, ##args) #else # define RNA_warning(format, ...) _RNA_warning("%s: " format "\n", __FUNCTION__, __VA_ARGS__) diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index 6e62313b00a..42ffe774720 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -62,7 +62,8 @@ void RNA_def_struct_refine_func(StructRNA *srna, const char *refine); void RNA_def_struct_idprops_func(StructRNA *srna, const char *refine); void RNA_def_struct_register_funcs(StructRNA *srna, const char *reg, const char *unreg, const char *instance); void RNA_def_struct_path_func(StructRNA *srna, const char *path); -void RNA_def_struct_identifier(StructRNA *srna, const char *identifier); +void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier); +void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *identifier); void RNA_def_struct_ui_text(StructRNA *srna, const char *name, const char *description); void RNA_def_struct_ui_icon(StructRNA *srna, int icon); void RNA_struct_free_extension(StructRNA *srna, ExtensionRNA *ext); @@ -216,8 +217,8 @@ void RNA_enum_item_end(EnumPropertyItem **items, int *totitem); /* Memory management */ -void RNA_def_struct_duplicate_pointers(StructRNA *srna); -void RNA_def_struct_free_pointers(StructRNA *srna); +void RNA_def_struct_duplicate_pointers(BlenderRNA *brna, StructRNA *srna); +void RNA_def_struct_free_pointers(BlenderRNA *brna, StructRNA *srna); void RNA_def_func_duplicate_pointers(FunctionRNA *func); void RNA_def_func_free_pointers(FunctionRNA *func); void RNA_def_property_duplicate_pointers(StructOrFunctionRNA *cont_, PropertyRNA *prop); diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 1c9b3593d17..f8e240d57bf 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -114,6 +114,8 @@ extern EnumPropertyItem rna_enum_brush_image_tool_items[]; extern EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[]; +extern EnumPropertyItem rna_enum_uv_sculpt_tool_items[]; + extern EnumPropertyItem rna_enum_axis_xy_items[]; extern EnumPropertyItem rna_enum_axis_xyz_items[]; diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index cd04f9e8a6d..e119c49401e 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -178,7 +178,7 @@ typedef enum PropertyFlag { * after every typed char, instead of waiting final validation. Used e.g. for text searchbox. * It will also cause UI_BUT_VALUE_CLEAR to be set for text buttons. We could add an own flag * for search/filter properties, but this works just fine for now. */ - PROP_TEXTEDIT_UPDATE = (1 << 31), + PROP_TEXTEDIT_UPDATE = (1u << 31), /* icon */ PROP_ICONS_CONSECUTIVE = (1 << 12), @@ -436,6 +436,8 @@ typedef enum StructFlag { 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 */ + STRUCT_PUBLIC_NAMESPACE = (1 << 9), /* Added to type-map #BlenderRNA.structs_map */ + STRUCT_PUBLIC_NAMESPACE_INHERIT = (1 << 10), /* All subtypes are added too. */ } StructFlag; typedef int (*StructValidateFunc)(struct PointerRNA *ptr, void *data, int *have_function); diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 6a08d762920..743d192f0c5 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -140,6 +140,9 @@ set(GENSRC_CFLAGS) if(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang")) set(GENSRC_CFLAGS "-Wno-missing-prototypes") endif() +if(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(GENSRC_CFLAGS "${GENSRC_CFLAGS} -Wno-missing-variable-declarations") +endif() if(GENSRC_CFLAGS) set_source_files_properties(${GENSRC} PROPERTIES COMPILE_FLAGS "${GENSRC_CFLAGS}") @@ -229,13 +232,6 @@ if(WITH_AUDASPACE) ) endif() -if(WITH_CODEC_QUICKTIME) - list(APPEND INC - ../../quicktime - ) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_CODEC_FFMPEG) list(APPEND INC ../../../../intern/ffmpeg diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index de436172bfd..9471d0e3fcf 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -2583,17 +2583,23 @@ static void rna_generate_blender(BlenderRNA *brna, FILE *f) { StructRNA *srna; - fprintf(f, "BlenderRNA BLENDER_RNA = {"); - + fprintf(f, + "BlenderRNA BLENDER_RNA = {\n" + "\t.structs = {" + ); srna = brna->structs.first; - if (srna) fprintf(f, "{&RNA_%s, ", srna->identifier); - else fprintf(f, "{NULL, "); + if (srna) fprintf(f, "&RNA_%s, ", srna->identifier); + else fprintf(f, "NULL, "); srna = brna->structs.last; - if (srna) fprintf(f, "&RNA_%s}", srna->identifier); - else fprintf(f, "NULL}"); + if (srna) fprintf(f, "&RNA_%s},\n", srna->identifier); + else fprintf(f, "NULL},\n"); - fprintf(f, "};\n\n"); + fprintf(f, + "\t.structs_map = NULL,\n" + "\t.structs_len = 0,\n" + "};\n\n" + ); } static void rna_generate_property_prototypes(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE *f) diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index a74758a4f71..bf767d47994 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -250,9 +250,10 @@ void rna_PropertyGroup_unregister(Main *UNUSED(bmain), StructRNA *type) RNA_struct_free(&BLENDER_RNA, type); } -StructRNA *rna_PropertyGroup_register(Main *UNUSED(bmain), ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc UNUSED(call), - StructFreeFunc UNUSED(free)) +StructRNA *rna_PropertyGroup_register( + Main *UNUSED(bmain), ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc UNUSED(call), + StructFreeFunc UNUSED(free)) { PointerRNA dummyptr; diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 5a4db47d281..bfa1e7cef93 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -76,6 +76,9 @@ void RNA_init(void) StructRNA *srna; PropertyRNA *prop; + BLENDER_RNA.structs_map = BLI_ghash_str_new_ex(__func__, 2048); + BLENDER_RNA.structs_len = 0; + for (srna = BLENDER_RNA.structs.first; srna; srna = srna->cont.next) { if (!srna->cont.prophash) { srna->cont.prophash = BLI_ghash_str_new("RNA_init gh"); @@ -86,6 +89,9 @@ void RNA_init(void) } } } + BLI_assert(srna->flag & STRUCT_PUBLIC_NAMESPACE); + BLI_ghash_insert(BLENDER_RNA.structs_map, (void *)srna->identifier, srna); + BLENDER_RNA.structs_len += 1; } } @@ -513,13 +519,7 @@ static const char *rna_ensure_property_name(const PropertyRNA *prop) StructRNA *RNA_struct_find(const char *identifier) { - StructRNA *type; - if (identifier) { - for (type = BLENDER_RNA.structs.first; type; type = type->cont.next) - if (STREQ(type->identifier, identifier)) - return type; - } - return NULL; + return BLI_ghash_lookup(BLENDER_RNA.structs_map, identifier); } const char *RNA_struct_identifier(const StructRNA *type) @@ -815,6 +815,89 @@ char *RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, i return NULL; } +/** + * Use when registering structs with the #STRUCT_PUBLIC_NAMESPACE flag. + */ +bool RNA_struct_available_or_report(ReportList *reports, const char *identifier) +{ + const StructRNA *srna_exists = RNA_struct_find(identifier); + if (UNLIKELY(srna_exists != NULL)) { + /* Use comprehensive string construction since this is such a rare occurrence + * and information here may cut down time troubleshooting. */ + DynStr *dynstr = BLI_dynstr_new(); + BLI_dynstr_appendf(dynstr, "Type identifier '%s' is already in use: '", identifier); + BLI_dynstr_append(dynstr, srna_exists->identifier); + int i = 0; + if (srna_exists->base) { + for (const StructRNA *base = srna_exists->base; base; base = base->base) { + BLI_dynstr_append(dynstr, "("); + BLI_dynstr_append(dynstr, base->identifier); + i += 1; + } + while (i--) { + BLI_dynstr_append(dynstr, ")"); + } + } + BLI_dynstr_append(dynstr, "'."); + char *result = BLI_dynstr_get_cstring(dynstr); + BLI_dynstr_free(dynstr); + BKE_report(reports, RPT_ERROR, result); + MEM_freeN(result); + return false; + } + else { + return true; + } +} + +bool RNA_struct_bl_idname_ok_or_report(ReportList *reports, const char *identifier, const char *sep) +{ + const int len_sep = strlen(sep); + const int len_id = strlen(identifier); + const char *p = strstr(identifier, sep); + /* TODO: make error, for now warning until add-ons update. */ +#if 1 + const int report_level = RPT_WARNING; + const bool failure = true; +#else + const int report_level = RPT_ERROR; + const bool failure = false; +#endif + if (p == NULL || p == identifier || p + len_sep >= identifier + len_id) { + BKE_reportf(reports, report_level, "'%s' doesn't contain '%s' with prefix & suffix", identifier, sep); + return failure; + } + + const char *c, *start, *end, *last; + start = identifier; + end = p; + last = end - 1; + for (c = start; c != end; c++) { + if (((*c >= 'A' && *c <= 'Z') || + ((c != start) && (*c >= '0' && *c <= '9')) || + ((c != start) && (c != last) && (*c == '_'))) == 0) + { + BKE_reportf(reports, report_level, "'%s' doesn't have upper case alpha-numeric prefix", identifier); + return failure; + } + } + + start = p + len_sep; + end = identifier + len_id; + last = end - 1; + for (c = start; c != end; c++) { + if (((*c >= 'A' && *c <= 'Z') || + (*c >= 'a' && *c <= 'z') || + (*c >= '0' && *c <= '9') || + ((c != start) && (c != last) && (*c == '_'))) == 0) + { + BKE_reportf(reports, report_level, "'%s' doesn't have an alpha-numeric suffix", identifier); + return failure; + } + } + return true; +} + /* Property Information */ const char *RNA_property_identifier(PropertyRNA *prop) diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index f271bccd326..47b2c84a67f 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -246,8 +246,9 @@ static void rna_KeyingSetInfo_unregister(Main *bmain, StructRNA *type) ANIM_keyingset_info_unregister(bmain, ksi); } -static StructRNA *rna_KeyingSetInfo_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_KeyingSetInfo_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { KeyingSetInfo dummyksi = {NULL}; KeyingSetInfo *ksi; @@ -270,9 +271,10 @@ static StructRNA *rna_KeyingSetInfo_register(Main *bmain, ReportList *reports, v /* check if we have registered this info before, and remove it */ ksi = ANIM_keyingset_info_find_name(dummyksi.idname); - if (ksi && ksi->ext.srna) + if (ksi && ksi->ext.srna) { rna_KeyingSetInfo_unregister(bmain, ksi->ext.srna); - + } + /* create a new KeyingSetInfo type */ ksi = MEM_callocN(sizeof(KeyingSetInfo), "python keying set info"); memcpy(ksi, &dummyksi, sizeof(KeyingSetInfo)); diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 891f5c43ca6..ec700eb00de 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -480,7 +480,7 @@ static int rna_Armature_is_editmode_get(PointerRNA *ptr) static void rna_Armature_transform(struct bArmature *arm, float *mat) { - ED_armature_transform(arm, (float (*)[4])mat); + ED_armature_transform(arm, (float (*)[4])mat, true); } #else diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index ac348c1750c..fe8e1bb7e6e 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -94,6 +94,21 @@ EnumPropertyItem rna_enum_brush_vertex_tool_items[] = { {PAINT_BLEND_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", "Blur the color with surrounding values"}, {PAINT_BLEND_LIGHTEN, "LIGHTEN", ICON_BRUSH_LIGHTEN, "Lighten", "Use lighten blending mode while painting"}, {PAINT_BLEND_DARKEN, "DARKEN", ICON_BRUSH_DARKEN, "Darken", "Use darken blending mode while painting"}, + {PAINT_BLEND_AVERAGE, "AVERAGE", ICON_BRUSH_BLUR, "Average", "Use average blending mode while painting"}, + {PAINT_BLEND_SMEAR, "SMEAR", ICON_BRUSH_BLUR, "Smear", "Use smear blending mode while painting"}, + {PAINT_BLEND_COLORDODGE, "COLORDODGE", ICON_BRUSH_BLUR, "Color Dodge", "Use color dodge blending mode while painting" }, + {PAINT_BLEND_DIFFERENCE, "DIFFERENCE", ICON_BRUSH_BLUR, "Difference", "Use difference blending mode while painting"}, + {PAINT_BLEND_SCREEN, "SCREEN", ICON_BRUSH_BLUR, "Screen", "Use screen blending mode while painting"}, + {PAINT_BLEND_HARDLIGHT, "HARDLIGHT", ICON_BRUSH_BLUR, "Hardlight", "Use hardlight blending mode while painting"}, + {PAINT_BLEND_OVERLAY, "OVERLAY", ICON_BRUSH_BLUR, "Overlay", "Use overlay blending mode while painting"}, + {PAINT_BLEND_SOFTLIGHT, "SOFTLIGHT", ICON_BRUSH_BLUR, "Softlight", "Use softlight blending mode while painting"}, + {PAINT_BLEND_EXCLUSION, "EXCLUSION", ICON_BRUSH_BLUR, "Exclusion", "Use exclusion blending mode while painting"}, + {PAINT_BLEND_LUMINOCITY, "LUMINOCITY", ICON_BRUSH_BLUR, "Luminocity", "Use luminocity blending mode while painting"}, + {PAINT_BLEND_SATURATION, "SATURATION", ICON_BRUSH_BLUR, "Saturation", "Use saturation blending mode while painting"}, + {PAINT_BLEND_HUE, "HUE", ICON_BRUSH_BLUR, "Hue", "Use hue blending mode while painting"}, + {PAINT_BLEND_ALPHA_SUB, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"}, + {PAINT_BLEND_ALPHA_ADD, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"}, + {0, NULL, 0, NULL, NULL} }; @@ -1248,7 +1263,7 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Restore Mesh", "Allow a single dot to be carefully positioned"); RNA_def_property_update(prop, 0, "rna_Brush_update"); - /* only for projection paint, TODO, other paint modes */ + /* only for projection paint & vertex paint, TODO, other paint modes */ prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", BRUSH_LOCK_ALPHA); RNA_def_property_ui_text(prop, "Alpha", "When this is disabled, lock alpha while painting"); diff --git a/source/blender/makesrna/intern/rna_curve_api.c b/source/blender/makesrna/intern/rna_curve_api.c index b4b3aa84ec5..be6808567bb 100644 --- a/source/blender/makesrna/intern/rna_curve_api.c +++ b/source/blender/makesrna/intern/rna_curve_api.c @@ -45,7 +45,7 @@ #ifdef RNA_RUNTIME static void rna_Curve_transform(Curve *cu, float *mat, int shape_keys) { - BKE_curve_transform(cu, (float (*)[4])mat, shape_keys); + BKE_curve_transform(cu, (float (*)[4])mat, shape_keys, true); DAG_id_tag_update(&cu->id, 0); } diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 42c0344f46e..118dd0b15de 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -44,6 +44,8 @@ #include "BLT_translation.h" +#include "UI_interface.h" /* For things like UI_PRECISION_FLOAT_MAX... */ + #include "RNA_define.h" #include "rna_internal.h" @@ -135,6 +137,38 @@ void rna_freelistN(ListBase *listbase) listbase->first = listbase->last = NULL; } +static void rna_brna_structs_add(BlenderRNA *brna, StructRNA *srna) +{ + rna_addtail(&brna->structs, srna); + brna->structs_len += 1; + + /* This exception is only needed for pre-processing. + * otherwise we don't allow empty names. */ + if ((srna->flag & STRUCT_PUBLIC_NAMESPACE) && + (srna->identifier[0] != '\0')) + { + BLI_ghash_insert(brna->structs_map, (void *)srna->identifier, srna); + } +} + +#ifdef RNA_RUNTIME +static void rna_brna_structs_remove_and_free(BlenderRNA *brna, StructRNA *srna) +{ + if ((srna->flag & STRUCT_PUBLIC_NAMESPACE) && brna->structs_map) { + if (srna->identifier[0] != '\0') { + BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, NULL, NULL); + } + } + + RNA_def_struct_free_pointers(NULL, srna); + + if (srna->flag & STRUCT_RUNTIME) { + rna_freelinkN(&brna->structs, srna); + } + brna->structs_len -= 1; +} +#endif + StructDefRNA *rna_find_struct_def(StructRNA *srna) { StructDefRNA *dsrna; @@ -534,6 +568,8 @@ BlenderRNA *RNA_create(void) const char *error_message = NULL; BLI_listbase_clear(&DefRNA.structs); + brna->structs_map = BLI_ghash_str_new_ex(__func__, 2048); + DefRNA.error = 0; DefRNA.preprocess = 1; @@ -640,10 +676,8 @@ void RNA_struct_free(BlenderRNA *brna, StructRNA *srna) rna_freelinkN(&srna->functions, func); } - RNA_def_struct_free_pointers(srna); - if (srna->flag & STRUCT_RUNTIME) - rna_freelinkN(&brna->structs, srna); + rna_brna_structs_remove_and_free(brna, srna); #else UNUSED_VARS(brna, srna); #endif @@ -654,6 +688,9 @@ void RNA_free(BlenderRNA *brna) StructRNA *srna, *nextsrna; FunctionRNA *func; + BLI_ghash_free(brna->structs_map, NULL, NULL); + brna->structs_map = NULL; + if (DefRNA.preprocess) { RNA_define_free(brna); @@ -730,12 +767,19 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN BLI_listbase_clear(&srna->functions); srna->py_type = NULL; + srna->base = srnafrom; + if (DefRNA.preprocess) { - srna->base = srnafrom; dsfrom = rna_find_def_struct(srnafrom); } - else - srna->base = srnafrom; + else { + if (srnafrom->flag & STRUCT_PUBLIC_NAMESPACE_INHERIT) { + srna->flag |= STRUCT_PUBLIC_NAMESPACE | STRUCT_PUBLIC_NAMESPACE_INHERIT; + } + else { + srna->flag &= ~(STRUCT_PUBLIC_NAMESPACE | STRUCT_PUBLIC_NAMESPACE_INHERIT); + } + } } srna->identifier = identifier; @@ -747,7 +791,11 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN if (!srnafrom) srna->icon = ICON_DOT; - rna_addtail(&brna->structs, srna); + if (DefRNA.preprocess) { + srna->flag |= STRUCT_PUBLIC_NAMESPACE; + } + + rna_brna_structs_add(brna, srna); if (DefRNA.preprocess) { ds = MEM_callocN(sizeof(StructDefRNA), "StructDefRNA"); @@ -819,10 +867,8 @@ StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char * if (from) { /* find struct to derive from */ - for (srnafrom = brna->structs.first; srnafrom; srnafrom = srnafrom->cont.next) - if (STREQ(srnafrom->identifier, from)) - break; - + /* Inline RNA_struct_find(...) because it wont link from here. */ + srnafrom = BLI_ghash_lookup(brna->structs_map, from); if (!srnafrom) { fprintf(stderr, "%s: struct %s not found to define %s.\n", __func__, from, identifier); DefRNA.error = 1; @@ -901,10 +947,7 @@ void RNA_def_struct_nested(BlenderRNA *brna, StructRNA *srna, const char *struct StructRNA *srnafrom; /* find struct to derive from */ - for (srnafrom = brna->structs.first; srnafrom; srnafrom = srnafrom->cont.next) - if (STREQ(srnafrom->identifier, structname)) - break; - + srnafrom = BLI_ghash_lookup(brna->structs_map, structname); if (!srnafrom) { fprintf(stderr, "%s: struct %s not found for %s.\n", __func__, structname, srna->identifier); DefRNA.error = 1; @@ -965,7 +1008,32 @@ void RNA_def_struct_path_func(StructRNA *srna, const char *path) if (path) srna->path = (StructPathFunc)path; } -void RNA_def_struct_identifier(StructRNA *srna, const char *identifier) +void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *identifier) +{ + if (DefRNA.preprocess) { + fprintf(stderr, "%s: only at runtime.\n", __func__); + return; + } + + /* Operator registration may set twice, see: operator_properties_init */ + if (srna->flag & STRUCT_PUBLIC_NAMESPACE) { + if (identifier != srna->identifier) { + if (srna->identifier[0] != '\0') { + BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, NULL, NULL); + } + if (identifier[0] != '\0') { + BLI_ghash_insert(brna->structs_map, (void *)identifier, srna); + } + } + } + + srna->identifier = identifier; +} + +/** + * Only used in one case when we name the struct for the purpose of useful error messages. + */ +void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier) { if (DefRNA.preprocess) { fprintf(stderr, "%s: only at runtime.\n", __func__); @@ -1339,13 +1407,13 @@ void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, bool consecutive) * For ints, whole values are used. * * \param precision The number of zeros to show - * (as a whole number - common range is 1 - 6), see PRECISION_FLOAT_MAX + * (as a whole number - common range is 1 - 6), see UI_PRECISION_FLOAT_MAX */ void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision) { StructRNA *srna = DefRNA.laststruct; -#ifdef DEBUG +#ifndef NDEBUG if (min > max) { fprintf(stderr, "%s: \"%s.%s\", min > max.\n", __func__, srna->identifier, prop->identifier); @@ -1358,8 +1426,8 @@ void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double DefRNA.error = 1; } - if (precision < -1 || precision > 10) { - fprintf(stderr, "%s: \"%s.%s\", step outside range.\n", + if (precision < -1 || precision > UI_PRECISION_FLOAT_MAX) { + fprintf(stderr, "%s: \"%s.%s\", precision outside range.\n", __func__, srna->identifier, prop->identifier); DefRNA.error = 1; } @@ -1381,21 +1449,6 @@ void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double fprop->softmax = (float)max; fprop->step = (float)step; fprop->precision = (int)precision; -#if 0 /* handy but annoying */ - if (DefRNA.preprocess) { - /* check we're not over PRECISION_FLOAT_MAX */ - if (fprop->precision > 6) { - fprintf(stderr, "%s: \"%s.%s\", precision value over maximum.\n", - __func__, srna->identifier, prop->identifier); - DefRNA.error = 1; - } - else if (fprop->precision < 1) { - fprintf(stderr, "%s: \"%s.%s\", precision value under minimum.\n", - __func__, srna->identifier, prop->identifier); - DefRNA.error = 1; - } - } -#endif break; } default: @@ -3262,21 +3315,41 @@ void RNA_enum_item_end(EnumPropertyItem **items, int *totitem) /* Memory management */ #ifdef RNA_RUNTIME -void RNA_def_struct_duplicate_pointers(StructRNA *srna) +void RNA_def_struct_duplicate_pointers(BlenderRNA *brna, StructRNA *srna) { - if (srna->identifier) srna->identifier = BLI_strdup(srna->identifier); - if (srna->name) srna->name = BLI_strdup(srna->name); - if (srna->description) srna->description = BLI_strdup(srna->description); + if (srna->identifier) { + srna->identifier = BLI_strdup(srna->identifier); + if (srna->flag & STRUCT_PUBLIC_NAMESPACE) { + BLI_ghash_replace_key(brna->structs_map, (void *)srna->identifier); + } + } + if (srna->name) { + srna->name = BLI_strdup(srna->name); + } + if (srna->description) { + srna->description = BLI_strdup(srna->description); + } srna->flag |= STRUCT_FREE_POINTERS; } -void RNA_def_struct_free_pointers(StructRNA *srna) +void RNA_def_struct_free_pointers(BlenderRNA *brna, StructRNA *srna) { if (srna->flag & STRUCT_FREE_POINTERS) { - if (srna->identifier) MEM_freeN((void *)srna->identifier); - if (srna->name) MEM_freeN((void *)srna->name); - if (srna->description) MEM_freeN((void *)srna->description); + if (srna->identifier) { + if (srna->flag & STRUCT_PUBLIC_NAMESPACE) { + if (brna != NULL) { + BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, NULL, NULL); + } + } + MEM_freeN((void *)srna->identifier); + } + if (srna->name) { + MEM_freeN((void *)srna->name); + } + if (srna->description) { + MEM_freeN((void *)srna->description); + } } } diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 6e0d6ad2bcd..79e1e95b27a 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -74,7 +74,7 @@ static void rna_GPencil_editmode_update(Main *UNUSED(bmain), Scene *UNUSED(scene { /* Notify all places where GPencil data lives that the editing state is different */ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); - WM_main_add_notifier(NC_SCENE | ND_MODE, NULL); + WM_main_add_notifier(NC_SCENE | ND_MODE | NC_MOVIECLIP, NULL); } static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index b6e84cf8ac3..5ca7e624d88 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -192,6 +192,8 @@ static char *rna_ImageUser_path(PointerRNA *ptr) { return rna_Node_ImageUser_path(ptr); } + default: + break; } } diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index 344c1781b46..61f1edc0af5 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -67,7 +67,7 @@ static void rna_ImagePackedFile_save(ImagePackedFile *imapf, ReportList *reports) { if (writePackedFile(reports, imapf->filepath, imapf->packedfile, 0) != RET_OK) { - BKE_reportf(reports, RPT_ERROR, "Image could not save packed file to '%s'", + BKE_reportf(reports, RPT_ERROR, "Could not save packed file to disk as '%s'", imapf->filepath); } } @@ -291,7 +291,7 @@ static void rna_Image_filepath_from_user(Image *image, ImageUser *image_user, ch static void rna_Image_buffers_free(Image *image) { - BKE_image_free_buffers(image); + BKE_image_free_buffers_ex(image, true); } #else diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index df591659fdb..a470c807091 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -413,6 +413,11 @@ struct StructRNA { struct BlenderRNA { ListBase structs; + /* A map of structs: {StructRNA.identifier -> StructRNA} + * These are ensured to have unique names (with STRUCT_PUBLIC_NAMESPACE enabled). */ + struct GHash *structs_map; + /* Needed because types with an empty identifier aren't included in 'structs_map'. */ + unsigned int structs_len; }; #define CONTAINER_RNA_ID(cont) (*(const char **)(((ContainerRNA *)(cont))+1)) diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index a5abc8a3be2..b960890457b 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -178,6 +178,8 @@ static Mesh *rna_KeyBlock_normals_get_mesh(PointerRNA *ptr, ID *id) return ob->data; } } + default: + break; } } diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index c110dbff6c4..871f50e992e 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -123,7 +123,8 @@ static void rna_idname_validate(const char *name, char *r_name) } -static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, int do_unlink) +static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, + int do_unlink, int do_id_user, int do_ui_user) { ID *id = id_ptr->data; if (do_unlink) { @@ -131,7 +132,7 @@ static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ RNA_POINTER_INVALIDATE(id_ptr); } else if (ID_REAL_USERS(id) <= 0) { - BKE_libblock_free(bmain, id); + BKE_libblock_free_ex(bmain, id, do_id_user, do_ui_user); RNA_POINTER_INVALIDATE(id_ptr); } else { @@ -184,7 +185,7 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports } } - rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink); + rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink, true, true); } else { BKE_reportf(reports, RPT_ERROR, "Scene '%s' is the last, cannot be removed", scene->id.name + 2); @@ -661,6 +662,10 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this camera before deleting it " "(WARNING: will also delete objects instancing that camera data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this camera"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this camera"); func = RNA_def_function(srna, "tag", "rna_Main_cameras_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -739,6 +744,10 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this object before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this object"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this object"); func = RNA_def_function(srna, "tag", "rna_Main_objects_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -776,6 +785,10 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this material before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this material"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this material"); func = RNA_def_function(srna, "tag", "rna_Main_materials_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -820,6 +833,10 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this node tree before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this node tree"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this node tree"); func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -881,6 +898,10 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mesh before deleting it " "(WARNING: will also delete objects instancing that mesh data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this mesh data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this mesh data"); func = RNA_def_function(srna, "tag", "rna_Main_meshes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -921,6 +942,10 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this lamp before deleting it " "(WARNING: will also delete objects instancing that lamp data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this lamp data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this lamp data"); func = RNA_def_function(srna, "tag", "rna_Main_lamps_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1037,6 +1062,10 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this image before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this image"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this image"); func = RNA_def_function(srna, "tag", "rna_Main_images_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1076,6 +1105,10 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this lattice before deleting it " "(WARNING: will also delete objects instancing that lattice data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this lattice data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this lattice data"); func = RNA_def_function(srna, "tag", "rna_Main_lattices_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1116,6 +1149,10 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this curve before deleting it " "(WARNING: will also delete objects instancing that curve data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this curve data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this curve data"); func = RNA_def_function(srna, "tag", "rna_Main_curves_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1154,6 +1191,10 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this metaball before deleting it " "(WARNING: will also delete objects instancing that metaball data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this metaball data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this metaball data"); func = RNA_def_function(srna, "tag", "rna_Main_metaballs_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1192,6 +1233,10 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this font before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this font"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this font"); func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1230,6 +1275,10 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this texture before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this texture"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this texture"); func = RNA_def_function(srna, "tag", "rna_Main_textures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1267,6 +1316,10 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this brush before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this brush"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this brush"); func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1304,6 +1357,10 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this world before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this world"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this world"); func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1341,6 +1398,10 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this group before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this group"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this group"); func = RNA_def_function(srna, "tag", "rna_Main_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1380,6 +1441,10 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this speaker before deleting it " "(WARNING: will also delete objects instancing that speaker data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this speaker data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this speaker data"); func = RNA_def_function(srna, "tag", "rna_Main_speakers_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1417,6 +1482,10 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this text before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this text"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this text"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_texts_load"); @@ -1467,6 +1536,10 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this sound before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this sound"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this sound"); func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1506,6 +1579,10 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this armature before deleting it " "(WARNING: will also delete objects instancing that armature data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this armature data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this armature data"); func = RNA_def_function(srna, "tag", "rna_Main_armatures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1542,6 +1619,10 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this action before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this action"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this action"); func = RNA_def_function(srna, "tag", "rna_Main_actions_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1578,6 +1659,10 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of those particle settings before deleting them"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this particle settings"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this particle settings"); func = RNA_def_function(srna, "tag", "rna_Main_particles_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1614,6 +1699,10 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this palette before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this palette"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this palette"); func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1694,6 +1783,10 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this grease pencil before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this grease pencil"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this grease pencil"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1723,6 +1816,10 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this movie clip before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this movie clip"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this movie clip"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_movieclip_load"); @@ -1775,6 +1872,10 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mask before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this mask"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this mask"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1812,6 +1913,10 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this line style before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this line style"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this line style"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index ad5f320625c..650caf20093 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -46,6 +46,7 @@ #include "RNA_access.h" #include "RNA_define.h" #include "RNA_types.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -303,7 +304,7 @@ static float rna_MeshVertex_bevel_weight_get(PointerRNA *ptr) static void rna_MeshVertex_bevel_weight_set(PointerRNA *ptr, float value) { MVert *mvert = (MVert *)ptr->data; - mvert->bweight = (char)(CLAMPIS(value * 255.0f, 0, 255)); + mvert->bweight = round_fl_to_uchar_clamp(value * 255.0f); } static float rna_MEdge_bevel_weight_get(PointerRNA *ptr) @@ -315,7 +316,7 @@ static float rna_MEdge_bevel_weight_get(PointerRNA *ptr) static void rna_MEdge_bevel_weight_set(PointerRNA *ptr, float value) { MEdge *medge = (MEdge *)ptr->data; - medge->bweight = (char)(CLAMPIS(value * 255.0f, 0, 255)); + medge->bweight = round_fl_to_uchar_clamp(value * 255.0f); } static float rna_MEdge_crease_get(PointerRNA *ptr) @@ -327,7 +328,7 @@ static float rna_MEdge_crease_get(PointerRNA *ptr) static void rna_MEdge_crease_set(PointerRNA *ptr, float value) { MEdge *medge = (MEdge *)ptr->data; - medge->crease = (char)(CLAMPIS(value * 255.0f, 0, 255)); + medge->crease = round_fl_to_uchar_clamp(value * 255.0f); } static void rna_MeshLoop_normal_get(PointerRNA *ptr, float *values) @@ -585,15 +586,17 @@ static void rna_MeshColor_color1_set(PointerRNA *ptr, const float *values) { MCol *mcol = (MCol *)ptr->data; - (&mcol[0].r)[2] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255)); - (&mcol[0].r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255)); - (&mcol[0].r)[0] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255)); + (&mcol[0].r)[2] = round_fl_to_uchar_clamp(values[0] * 255.0f); + (&mcol[0].r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f); + (&mcol[0].r)[0] = round_fl_to_uchar_clamp(values[2] * 255.0f); + (&mcol[0].r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f); } static void rna_MeshColor_color2_get(PointerRNA *ptr, float *values) { MCol *mcol = (MCol *)ptr->data; + values[3] = (&mcol[1].r)[3] / 255.0f; values[2] = (&mcol[1].r)[0] / 255.0f; values[1] = (&mcol[1].r)[1] / 255.0f; values[0] = (&mcol[1].r)[2] / 255.0f; @@ -603,15 +606,17 @@ static void rna_MeshColor_color2_set(PointerRNA *ptr, const float *values) { MCol *mcol = (MCol *)ptr->data; - (&mcol[1].r)[2] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255)); - (&mcol[1].r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255)); - (&mcol[1].r)[0] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255)); + (&mcol[1].r)[2] = round_fl_to_uchar_clamp(values[0] * 255.0f); + (&mcol[1].r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f); + (&mcol[1].r)[0] = round_fl_to_uchar_clamp(values[2] * 255.0f); + (&mcol[1].r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f); } static void rna_MeshColor_color3_get(PointerRNA *ptr, float *values) { MCol *mcol = (MCol *)ptr->data; + values[3] = (&mcol[2].r)[3] / 255.0f; values[2] = (&mcol[2].r)[0] / 255.0f; values[1] = (&mcol[2].r)[1] / 255.0f; values[0] = (&mcol[2].r)[2] / 255.0f; @@ -621,9 +626,10 @@ static void rna_MeshColor_color3_set(PointerRNA *ptr, const float *values) { MCol *mcol = (MCol *)ptr->data; - (&mcol[2].r)[2] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255)); - (&mcol[2].r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255)); - (&mcol[2].r)[0] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255)); + (&mcol[2].r)[2] = round_fl_to_uchar_clamp(values[0] * 255.0f); + (&mcol[2].r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f); + (&mcol[2].r)[0] = round_fl_to_uchar_clamp(values[2] * 255.0f); + (&mcol[2].r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f); } static void rna_MeshColor_color4_get(PointerRNA *ptr, float *values) @@ -633,15 +639,17 @@ static void rna_MeshColor_color4_get(PointerRNA *ptr, float *values) values[2] = (&mcol[3].r)[0] / 255.0f; values[1] = (&mcol[3].r)[1] / 255.0f; values[0] = (&mcol[3].r)[2] / 255.0f; + values[3] = (&mcol[3].r)[3] / 255.0f; } static void rna_MeshColor_color4_set(PointerRNA *ptr, const float *values) { MCol *mcol = (MCol *)ptr->data; - (&mcol[3].r)[2] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255)); - (&mcol[3].r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255)); - (&mcol[3].r)[0] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255)); + (&mcol[3].r)[2] = round_fl_to_uchar_clamp(values[0] * 255.0f); + (&mcol[3].r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f); + (&mcol[3].r)[0] = round_fl_to_uchar_clamp(values[2] * 255.0f); + (&mcol[3].r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f); } static void rna_MeshLoopColor_color_get(PointerRNA *ptr, float *values) @@ -651,15 +659,17 @@ static void rna_MeshLoopColor_color_get(PointerRNA *ptr, float *values) values[0] = (&mcol->r)[0] / 255.0f; values[1] = (&mcol->r)[1] / 255.0f; values[2] = (&mcol->r)[2] / 255.0f; + values[3] = (&mcol->r)[3] / 255.0f; } static void rna_MeshLoopColor_color_set(PointerRNA *ptr, const float *values) { MLoopCol *mcol = (MLoopCol *)ptr->data; - (&mcol->r)[0] = (char)(CLAMPIS(values[0] * 255.0f, 0, 255)); - (&mcol->r)[1] = (char)(CLAMPIS(values[1] * 255.0f, 0, 255)); - (&mcol->r)[2] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255)); + (&mcol->r)[0] = round_fl_to_uchar_clamp(values[0] * 255.0f); + (&mcol->r)[1] = round_fl_to_uchar_clamp(values[1] * 255.0f); + (&mcol->r)[2] = round_fl_to_uchar_clamp(values[2] * 255.0f); + (&mcol->r)[3] = round_fl_to_uchar_clamp(values[3] * 255.0f); } static int rna_Mesh_texspace_editable(PointerRNA *ptr, const char **UNUSED(r_info)) @@ -2503,28 +2513,28 @@ static void rna_def_mcol(BlenderRNA *brna) RNA_def_struct_path_func(srna, "rna_MeshColor_path"); prop = RNA_def_property(srna, "color1", PROP_FLOAT, PROP_COLOR); - RNA_def_property_array(prop, 3); + RNA_def_property_array(prop, 4); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_float_funcs(prop, "rna_MeshColor_color1_get", "rna_MeshColor_color1_set", NULL); RNA_def_property_ui_text(prop, "Color 1", ""); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "color2", PROP_FLOAT, PROP_COLOR); - RNA_def_property_array(prop, 3); + RNA_def_property_array(prop, 4); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_float_funcs(prop, "rna_MeshColor_color2_get", "rna_MeshColor_color2_set", NULL); RNA_def_property_ui_text(prop, "Color 2", ""); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "color3", PROP_FLOAT, PROP_COLOR); - RNA_def_property_array(prop, 3); + RNA_def_property_array(prop, 4); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_float_funcs(prop, "rna_MeshColor_color3_get", "rna_MeshColor_color3_set", NULL); RNA_def_property_ui_text(prop, "Color 3", ""); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "color4", PROP_FLOAT, PROP_COLOR); - RNA_def_property_array(prop, 3); + RNA_def_property_array(prop, 4); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_float_funcs(prop, "rna_MeshColor_color4_get", "rna_MeshColor_color4_set", NULL); RNA_def_property_ui_text(prop, "Color 4", ""); @@ -2574,7 +2584,7 @@ static void rna_def_mloopcol(BlenderRNA *brna) RNA_def_struct_path_func(srna, "rna_MeshColor_path"); prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); - RNA_def_property_array(prop, 3); + RNA_def_property_array(prop, 4); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_float_funcs(prop, "rna_MeshLoopColor_color_get", "rna_MeshLoopColor_color_set", NULL); RNA_def_property_ui_text(prop, "Color", ""); diff --git a/source/blender/makesrna/intern/rna_meta_api.c b/source/blender/makesrna/intern/rna_meta_api.c index 3d8f375fd88..4c3fa787b94 100644 --- a/source/blender/makesrna/intern/rna_meta_api.c +++ b/source/blender/makesrna/intern/rna_meta_api.c @@ -45,7 +45,7 @@ #ifdef RNA_RUNTIME static void rna_Meta_transform(struct MetaBall *mb, float *mat) { - BKE_mball_transform(mb, (float (*)[4])mat); + BKE_mball_transform(mb, (float (*)[4])mat, true); DAG_id_tag_update(&mb->id, 0); } diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 1a8dd05a7b5..74aa3759d2d 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1518,26 +1518,40 @@ static void rna_def_modifier_mirror(BlenderRNA *brna) prop = RNA_def_property(srna, "use_mirror_u", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_MIRROR_U); - RNA_def_property_ui_text(prop, "Mirror U", "Mirror the U texture coordinate around the 0.5 point"); + RNA_def_property_ui_text(prop, "Mirror U", "Mirror the U texture coordinate around the flip offset point"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "use_mirror_v", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_MIRROR_V); - RNA_def_property_ui_text(prop, "Mirror V", "Mirror the V texture coordinate around the 0.5 point"); + RNA_def_property_ui_text(prop, "Mirror V", "Mirror the V texture coordinate around the flip offset 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_ui_text(prop, "Flip U Offset", "Amount to offset mirrored UVs flipping point from the 0.5 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_ui_text(prop, "Flip V Offset", "Amount to offset mirrored UVs flipping point from the 0.5 point on the V axis"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "offset_u", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "uv_offset_copy[0]"); + RNA_def_property_range(prop, -10000.0f, 10000.0f); + RNA_def_property_ui_range(prop, -1, 1, 2, 4); + RNA_def_property_ui_text(prop, "U Offset", "Mirrored UV offset on the U axis"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "offset_v", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "uv_offset_copy[1]"); + RNA_def_property_range(prop, -10000.0f, 10000.0f); + RNA_def_property_ui_range(prop, -1, 1, 2, 4); + RNA_def_property_ui_text(prop, "V Offset", "Mirrored UV offset on the V axis"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE); @@ -1974,9 +1988,26 @@ static void rna_def_modifier_boolean(BlenderRNA *brna) prop = RNA_def_property(srna, "double_threshold", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "double_threshold"); RNA_def_property_range(prop, 0, 1.0f); - RNA_def_property_ui_range(prop, 0, 1, 0.0001, 7); + RNA_def_property_ui_range(prop, 0, 1, 0.0001, 6); RNA_def_property_ui_text(prop, "Overlap Threshold", "Threshold for checking overlapping geometry"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + /* BMesh debugging options, only used when G_DEBUG is set */ + + /* BMesh intersection options */ + static EnumPropertyItem debug_items[] = { + {eBooleanModifierBMeshFlag_BMesh_Separate, "SEPARATE", 0, "Separate", ""}, + {eBooleanModifierBMeshFlag_BMesh_NoDissolve, "NO_DISSOLVE", 0, "NoDissolve", ""}, + {eBooleanModifierBMeshFlag_BMesh_NoConnectRegions, "NO_CONNECT_REGIONS", 0, "NoConnectRegions", ""}, + {0, NULL, 0, NULL, NULL} + }; + + prop = RNA_def_property(srna, "debug_options", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, debug_items); + RNA_def_property_enum_sdna(prop, NULL, "bm_flag"); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_ui_text(prop, "Debug", "Debugging options, only when started with '-d'"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_array(BlenderRNA *brna) @@ -3413,6 +3444,13 @@ static void rna_def_modifier_screw(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Screw", "Offset the revolution along its 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, "merge_dist"); + RNA_def_property_range(prop, 0, FLT_MAX); + RNA_def_property_ui_range(prop, 0, 1, 1, 4); + RNA_def_property_ui_text(prop, "Merge Distance", "Limit below which to merge vertices"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "use_normal_flip", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_NORMAL_FLIP); RNA_def_property_ui_text(prop, "Flip", "Flip normals of lathed faces"); @@ -3428,6 +3466,12 @@ static void rna_def_modifier_screw(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Object Screw", "Use the distance between the objects to make a screw"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + /* Vertex merging parameters */ + prop = RNA_def_property(srna, "use_merge_vertices", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_MERGE); + RNA_def_property_ui_text(prop, "Merge Vertices", "Merge adjacent vertices (screw offset must be zero)"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "use_smooth_shade", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_SMOOTH_SHADING); RNA_def_property_ui_text(prop, "Smooth Shading", "Output faces with smooth shading rather than flat shaded"); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 10422c85579..ee4608b550f 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -73,6 +73,13 @@ EnumPropertyItem rna_enum_node_socket_in_out_items[] = { }; #ifndef RNA_RUNTIME +static EnumPropertyItem rna_enum_node_socket_draw_shape_items[] = { + {SOCK_DRAW_SHAPE_CIRCLE, "CIRCLE", 0, "Circle", ""}, + {SOCK_DRAW_SHAPE_SQUARE, "SQUARE", 0, "Square", ""}, + {SOCK_DRAW_SHAPE_DIAMOND, "DIAMOND", 0, "Diamond", ""}, + {0, NULL, 0, NULL, NULL } +}; + static EnumPropertyItem node_socket_type_items[] = { {SOCK_CUSTOM, "CUSTOM", 0, "Custom", ""}, {SOCK_FLOAT, "VALUE", 0, "Value", ""}, @@ -238,10 +245,10 @@ bNodeTreeType *rna_node_tree_type_from_enum(int value) EnumPropertyItem *rna_node_tree_type_itemf(void *data, int (*poll)(void *data, bNodeTreeType *), bool *r_free) { - EnumPropertyItem tmp = {0, "", 0, "", ""}; + EnumPropertyItem tmp = {0}; EnumPropertyItem *item = NULL; int totitem = 0, i = 0; - + NODE_TREE_TYPES_BEGIN (nt) { if (poll && !poll(data, nt)) { @@ -261,9 +268,14 @@ EnumPropertyItem *rna_node_tree_type_itemf(void *data, int (*poll)(void *data, b } NODE_TREE_TYPES_END; + if (totitem == 0) { + *r_free = false; + return DummyRNA_NULL_items; + } + RNA_enum_item_end(&item, &totitem); *r_free = true; - + return item; } @@ -310,9 +322,9 @@ bNodeType *rna_node_type_from_enum(int value) EnumPropertyItem *rna_node_type_itemf(void *data, int (*poll)(void *data, bNodeType *), bool *r_free) { EnumPropertyItem *item = NULL; - EnumPropertyItem tmp = {0, "", 0, "", ""}; + EnumPropertyItem tmp = {0}; int totitem = 0, i = 0; - + NODE_TYPES_BEGIN(ntype) if (poll && !poll(data, ntype)) { ++i; @@ -329,9 +341,15 @@ EnumPropertyItem *rna_node_type_itemf(void *data, int (*poll)(void *data, bNodeT ++i; NODE_TYPES_END + + if (totitem == 0) { + *r_free = false; + return DummyRNA_NULL_items; + } + RNA_enum_item_end(&item, &totitem); *r_free = true; - + return item; } @@ -378,10 +396,10 @@ bNodeSocketType *rna_node_socket_type_from_enum(int value) EnumPropertyItem *rna_node_socket_type_itemf(void *data, int (*poll)(void *data, bNodeSocketType *), bool *r_free) { EnumPropertyItem *item = NULL; - EnumPropertyItem tmp = {0, "", 0, "", ""}; + EnumPropertyItem tmp = {0}; int totitem = 0, i = 0; StructRNA *srna; - + NODE_SOCKET_TYPES_BEGIN(stype) if (poll && !poll(data, stype)) { ++i; @@ -399,9 +417,15 @@ EnumPropertyItem *rna_node_socket_type_itemf(void *data, int (*poll)(void *data, ++i; NODE_SOCKET_TYPES_END + + if (totitem == 0) { + *r_free = false; + return DummyRNA_NULL_items; + } + RNA_enum_item_end(&item, &totitem); *r_free = true; - + return item; } @@ -410,25 +434,25 @@ static EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C), Pointer EnumPropertyItem *item = NULL; EnumPropertyItem tmp; int totitem = 0; - + /* hack, don't want to add include path to RNA just for this, since in the future RNA types * for nodes should be defined locally at runtime anyway ... */ - + tmp.value = NODE_CUSTOM; tmp.identifier = "CUSTOM"; tmp.name = "Custom"; tmp.description = "Custom Node"; tmp.icon = ICON_NONE; RNA_enum_item_add(&item, &totitem, &tmp); - + tmp.value = NODE_UNDEFINED; tmp.identifier = "UNDEFINED"; tmp.name = "UNDEFINED"; tmp.description = ""; tmp.icon = ICON_NONE; RNA_enum_item_add(&item, &totitem, &tmp); - + #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ if (STREQ(#Category, "Node")) { \ tmp.value = ID; \ @@ -440,7 +464,7 @@ static EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C), Pointer } #include "../../nodes/NOD_static_types.h" #undef DefNode - + if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) { #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ if (STREQ(#Category, "ShaderNode")) { \ @@ -468,7 +492,7 @@ static EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C), Pointer #include "../../nodes/NOD_static_types.h" #undef DefNode } - + if (RNA_struct_is_a(ptr->type, &RNA_TextureNode)) { #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ if (STREQ(#Category, "TextureNode")) { \ @@ -485,7 +509,7 @@ static EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C), Pointer RNA_enum_item_end(&item, &totitem); *r_free = true; - + return item; } @@ -578,11 +602,10 @@ static void rna_NodeTree_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &nt->ext); + RNA_struct_free(&BLENDER_RNA, type); ntreeTypeFreeLink(nt); - RNA_struct_free(&BLENDER_RNA, type); - /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); } @@ -614,9 +637,10 @@ static StructRNA *rna_NodeTree_register( /* check if we have registered this tree type before, and remove it */ nt = ntreeTypeFind(dummynt.idname); - if (nt) + if (nt) { rna_NodeTree_unregister(bmain, nt->ext.srna); - + } + /* create a new node tree type */ nt = MEM_callocN(sizeof(bNodeTreeType), "node tree type"); memcpy(nt, &dummynt, sizeof(dummynt)); @@ -1331,11 +1355,11 @@ static void rna_Node_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &nt->ext); + RNA_struct_free(&BLENDER_RNA, type); /* this also frees the allocated nt pointer, no MEM_free call needed! */ nodeUnregisterType(nt); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); @@ -1376,8 +1400,9 @@ static bNodeType *rna_Node_register_base(Main *bmain, ReportList *reports, Struc /* check if we have registered this node type before, and remove it */ nt = nodeTypeFind(dummynt.idname); - if (nt) + if (nt) { rna_Node_unregister(bmain, nt->ext.srna); + } /* create a new node type */ nt = MEM_callocN(sizeof(bNodeType), "node type"); @@ -1793,10 +1818,10 @@ static void rna_NodeSocket_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &st->ext_socket); + RNA_struct_free(&BLENDER_RNA, type); nodeUnregisterSocketType(st); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); @@ -2617,9 +2642,9 @@ static void rna_Node_image_layer_update(Main *bmain, Scene *scene, PointerRNA *p static EnumPropertyItem *renderresult_layers_add_enum(RenderLayer *rl) { EnumPropertyItem *item = NULL; - EnumPropertyItem tmp = {0, "", 0, "", ""}; + EnumPropertyItem tmp = {0}; int i = 0, totitem = 0; - + while (rl) { tmp.identifier = rl->name; /* little trick: using space char instead empty string makes the item selectable in the dropdown */ @@ -2631,7 +2656,7 @@ static EnumPropertyItem *renderresult_layers_add_enum(RenderLayer *rl) RNA_enum_item_add(&item, &totitem, &tmp); rl = rl->next; } - + RNA_enum_item_end(&item, &totitem); return item; @@ -2644,18 +2669,17 @@ static EnumPropertyItem *rna_Node_image_layer_itemf(bContext *UNUSED(C), Pointer Image *ima = (Image *)node->id; EnumPropertyItem *item = NULL; RenderLayer *rl; - - if (ima && ima->rr) { - rl = ima->rr->layers.first; - item = renderresult_layers_add_enum(rl); - } - else { - int totitem = 0; - RNA_enum_item_end(&item, &totitem); + + if (ima == NULL || ima->rr == NULL) { + *r_free = false; + return DummyRNA_NULL_items; } - + + rl = ima->rr->layers.first; + item = renderresult_layers_add_enum(rl); + *r_free = true; - + return item; } @@ -2706,19 +2730,22 @@ static EnumPropertyItem *renderresult_views_add_enum(RenderView *rv) } static EnumPropertyItem *rna_Node_image_view_itemf(bContext *UNUSED(C), PointerRNA *ptr, - PropertyRNA *UNUSED(prop), bool *free) + PropertyRNA *UNUSED(prop), bool *r_free) { bNode *node = (bNode *)ptr->data; Image *ima = (Image *)node->id; EnumPropertyItem *item = NULL; RenderView *rv; - if (!ima || !(ima->rr)) return NULL; + if (ima == NULL || ima->rr == NULL) { + *r_free = false; + return DummyRNA_NULL_items; + } rv = ima->rr->views.first; item = renderresult_views_add_enum(rv); - *free = true; + *r_free = true; return item; } @@ -2730,18 +2757,17 @@ static EnumPropertyItem *rna_Node_scene_layer_itemf(bContext *UNUSED(C), Pointer Scene *sce = (Scene *)node->id; EnumPropertyItem *item = NULL; RenderLayer *rl; - - if (sce) { - rl = sce->r.layers.first; - item = renderresult_layers_add_enum(rl); - } - else { - int totitem = 0; - RNA_enum_item_end(&item, &totitem); + + if (sce == NULL) { + *r_free = false; + return DummyRNA_NULL_items; } - + + rl = sce->r.layers.first; + item = renderresult_layers_add_enum(rl); + *r_free = true; - + return item; } @@ -2758,7 +2784,7 @@ static EnumPropertyItem *rna_Node_channel_itemf(bContext *UNUSED(C), PointerRNA { bNode *node = (bNode *)ptr->data; EnumPropertyItem *item = NULL; - EnumPropertyItem tmp = {0, "", 0, "", ""}; + EnumPropertyItem tmp = {0}; int totitem = 0; switch (node->custom1) { @@ -2795,7 +2821,7 @@ static EnumPropertyItem *rna_Node_channel_itemf(bContext *UNUSED(C), PointerRNA RNA_enum_item_add(&item, &totitem, &tmp); break; default: - break; + return DummyRNA_NULL_items; } RNA_enum_item_end(&item, &totitem); @@ -3339,7 +3365,7 @@ static void def_frame(StructRNA *srna) prop = RNA_def_property(srna, "text", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Text"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Text", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -3609,7 +3635,7 @@ static void def_sh_lamp(StructRNA *srna) prop = RNA_def_property(srna, "lamp_object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Object"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Lamp_object_poll"); RNA_def_property_ui_text(prop, "Lamp Object", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -3983,7 +4009,7 @@ static void def_sh_tex_coord(StructRNA *srna) prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Object"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Object", "Use coordinates from this object (for object texture coordinates output)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -4099,7 +4125,7 @@ static void def_sh_tex_pointdensity(StructRNA *srna) prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Object"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Object", "Object to take point data from"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -4796,7 +4822,7 @@ static void def_cmp_render_layers(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_pointer_funcs(prop, NULL, "rna_Node_scene_set", NULL, NULL); RNA_def_property_struct_type(prop, "Scene"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Scene", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_scene_layer_update"); @@ -5453,7 +5479,7 @@ static void def_cmp_defocus(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_pointer_funcs(prop, NULL, "rna_Node_scene_set", NULL, NULL); RNA_def_property_struct_type(prop, "Scene"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Scene", "Scene from which to select the active camera (render scene if undefined)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -6968,6 +6994,13 @@ static void rna_def_node_socket(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Type", "Data type"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocket_update"); + prop = RNA_def_property(srna, "draw_shape", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "draw_shape"); + RNA_def_property_enum_items(prop, rna_enum_node_socket_draw_shape_items); + RNA_def_property_enum_default(prop, SOCK_DRAW_SHAPE_CIRCLE); + RNA_def_property_ui_text(prop, "Shape", "Socket shape"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocket_update"); + /* registration */ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "typeinfo->idname"); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index a167ab03ba1..1f018a6ddfc 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2392,7 +2392,7 @@ static void rna_def_object(BlenderRNA *brna) /* only for the transform-panel and conflicts with animating scale */ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_float_funcs(prop, "rna_Object_dimensions_get", "rna_Object_dimensions_set", NULL); - RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3); + RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_ui_text(prop, "Dimensions", "Absolute bounding box dimensions of the object"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 44dcb72264a..034782cc818 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -33,6 +33,8 @@ #include "BLI_utildefines.h" #include "BLI_path_util.h" +#include "BKE_scene.h" + #include "RNA_define.h" #include "RNA_enum_types.h" @@ -41,6 +43,7 @@ #include "RE_engine.h" #include "RE_pipeline.h" +#include "ED_render.h" /* Deprecated, only provided for API compatibility. */ EnumPropertyItem rna_enum_render_pass_type_items[] = { @@ -123,6 +126,11 @@ static int engine_support_display_space_shader(RenderEngine *UNUSED(engine), Sce return IMB_colormanagement_support_glsl_draw(&scene->view_settings); } +static int engine_get_preview_pixel_size(RenderEngine *UNUSED(engine), Scene *scene) +{ + return BKE_render_preview_pixel_size(&scene->r); +} + static void engine_bind_display_space_shader(RenderEngine *UNUSED(engine), Scene *scene) { IMB_colormanagement_setup_glsl_draw(&scene->view_settings, @@ -271,7 +279,7 @@ static void engine_update_render_passes(RenderEngine *engine, struct Scene *scen /* RenderEngine registration */ -static void rna_RenderEngine_unregister(Main *UNUSED(bmain), StructRNA *type) +static void rna_RenderEngine_unregister(Main *bmain, StructRNA *type) { RenderEngineType *et = RNA_struct_blender_type_get(type); @@ -279,12 +287,16 @@ static void rna_RenderEngine_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &et->ext); - BLI_freelinkN(&R_engines, et); RNA_struct_free(&BLENDER_RNA, type); + BLI_freelinkN(&R_engines, et); + + /* Stop all renders in case we were using this one. */ + ED_render_engine_changed(bmain); } -static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_RenderEngine_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { RenderEngineType *et, dummyet = {NULL}; RenderEngine dummyengine = {NULL}; @@ -647,6 +659,13 @@ static void rna_def_render_engine(BlenderRNA *brna) parm = RNA_def_boolean(func, "supported", 0, "Supported", ""); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "get_preview_pixel_size", "engine_get_preview_pixel_size"); + RNA_def_function_ui_description(func, "Get the pixel size that should be used for preview rendering"); + parm = RNA_def_pointer(func, "scene", "Scene", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "pixel_size", 0, 1, 8, "Pixel Size", "", 1, 8); + RNA_def_function_return(func, parm); + RNA_define_verify_sdna(0); prop = RNA_def_property(srna, "is_animation", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index abded187b33..502a9c42363 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -610,6 +610,22 @@ static int rna_Property_array_length_get(PointerRNA *ptr) return prop->totarraylength; } +static void rna_Property_array_dimensions_get(PointerRNA *ptr, int dimensions[RNA_MAX_ARRAY_DIMENSION]) +{ + PropertyRNA *prop = (PropertyRNA *)ptr->data; + rna_idproperty_check(&prop, ptr); + + if (prop->arraydimension > 1) { + for (int i = RNA_MAX_ARRAY_DIMENSION; i--; ) { + dimensions[i] = (i >= prop->arraydimension) ? 0 : prop->arraylength[i]; + } + } + else { + memset(dimensions, 0, sizeof(*dimensions) * RNA_MAX_ARRAY_DIMENSION); + dimensions[0] = prop->totarraylength; + } +} + static int rna_Property_is_registered_get(PointerRNA *ptr) { PropertyRNA *prop = (PropertyRNA *)ptr->data; @@ -983,21 +999,32 @@ static int rna_Function_use_self_type_get(PointerRNA *ptr) /* Blender RNA */ +static int rna_struct_is_publc(CollectionPropertyIterator *UNUSED(iter), void *data) +{ + StructRNA *srna = data; + + return !(srna->flag & STRUCT_PUBLIC_NAMESPACE); +} + + static void rna_BlenderRNA_structs_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { - rna_iterator_listbase_begin(iter, &((BlenderRNA *)ptr->data)->structs, NULL); + BlenderRNA *brna = ptr->data; + rna_iterator_listbase_begin(iter, &brna->structs, rna_struct_is_publc); } /* optional, for faster lookups */ static int rna_BlenderRNA_structs_length(PointerRNA *ptr) { - return BLI_listbase_count(&((BlenderRNA *)ptr->data)->structs); + BlenderRNA *brna = ptr->data; + BLI_assert(brna->structs_len == BLI_listbase_count(&brna->structs)); + return brna->structs_len; } static int rna_BlenderRNA_structs_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr) { - StructRNA *srna = BLI_findlink(&((BlenderRNA *)ptr->data)->structs, index); - - if (srna) { + BlenderRNA *brna = ptr->data; + StructRNA *srna = index < brna->structs_len ? BLI_findlink(&brna->structs, index) : NULL; + if (srna != NULL) { RNA_pointer_create(NULL, &RNA_Struct, srna, r_ptr); return true; } @@ -1007,12 +1034,11 @@ static int rna_BlenderRNA_structs_lookup_int(PointerRNA *ptr, int index, Pointer } static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) { - StructRNA *srna = ((BlenderRNA *)ptr->data)->structs.first; - for (; srna; srna = srna->cont.next) { - if (key[0] == srna->identifier[0] && STREQ(key, srna->identifier)) { - RNA_pointer_create(NULL, &RNA_Struct, srna, r_ptr); - return true; - } + BlenderRNA *brna = ptr->data; + StructRNA *srna = BLI_ghash_lookup(brna->structs_map, (void *)key); + if (srna != NULL) { + RNA_pointer_create(NULL, &RNA_Struct, srna, r_ptr); + return true; } return false; @@ -1344,6 +1370,12 @@ static void rna_def_number_property(StructRNA *srna, PropertyType type) RNA_def_property_int_funcs(prop, "rna_Property_array_length_get", NULL, NULL); RNA_def_property_ui_text(prop, "Array Length", "Maximum length of the array, 0 means unlimited"); + prop = RNA_def_property(srna, "array_dimensions", PROP_INT, PROP_UNSIGNED); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_array(prop, RNA_MAX_ARRAY_DIMENSION); + RNA_def_property_int_funcs(prop, "rna_Property_array_dimensions_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Array Dimensions", "Length of each dimension of the array"); + prop = RNA_def_property(srna, "is_array", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_boolean_funcs(prop, "rna_NumberProperty_is_array_get", NULL); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index b9231574a24..cd0bcaf4cea 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -58,11 +58,6 @@ #include "RE_engine.h" #include "RE_pipeline.h" -#ifdef WITH_QUICKTIME -# include "quicktime_export.h" -# include AUD_TYPES_H -#endif - #ifdef WITH_FFMPEG # include "BKE_writeffmpeg.h" # include <libavcodec/avcodec.h> @@ -94,13 +89,15 @@ EnumPropertyItem rna_enum_exr_codec_items[] = { }; #endif -EnumPropertyItem uv_sculpt_relaxation_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem uv_sculpt_relaxation_items[] = { {UV_SCULPT_TOOL_RELAX_LAPLACIAN, "LAPLACIAN", 0, "Laplacian", "Use Laplacian method for relaxation"}, {UV_SCULPT_TOOL_RELAX_HC, "HC", 0, "HC", "Use HC method for relaxation"}, {0, NULL, 0, NULL, NULL} }; +#endif -EnumPropertyItem uv_sculpt_tool_items[] = { +EnumPropertyItem rna_enum_uv_sculpt_tool_items[] = { {UV_SCULPT_TOOL_PINCH, "PINCH", 0, "Pinch", "Pinch UVs"}, {UV_SCULPT_TOOL_RELAX, "RELAX", 0, "Relax", "Relax UVs"}, {UV_SCULPT_TOOL_GRAB, "GRAB", 0, "Grab", "Grab UVs"}, @@ -175,11 +172,13 @@ EnumPropertyItem rna_enum_snap_node_element_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem snap_uv_element_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem snap_uv_element_items[] = { {SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments of grid"}, {SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"}, {0, NULL, 0, NULL, NULL} }; +#endif EnumPropertyItem rna_enum_curve_fit_method_items[] = { {CURVE_PAINT_FIT_METHOD_REFIT, "REFIT", 0, "Refit", "Incrementally re-fit the curve (high quality)"}, @@ -265,12 +264,14 @@ EnumPropertyItem rna_enum_curve_fit_method_items[] = { R_IMF_ENUM_TIFF \ -EnumPropertyItem image_only_type_items[] = { +#ifdef RNA_RUNTIME +static EnumPropertyItem image_only_type_items[] = { IMAGE_TYPE_ITEMS_IMAGE_ONLY {0, NULL, 0, NULL, NULL} }; +#endif EnumPropertyItem rna_enum_image_type_items[] = { {0, "", 0, N_("Image"), NULL}, @@ -286,9 +287,6 @@ EnumPropertyItem rna_enum_image_type_items[] = { #ifdef WITH_FFMPEG {R_IMF_IMTYPE_FFMPEG, "FFMPEG", ICON_FILE_MOVIE, "FFmpeg video", "The most versatile way to output video files"}, #endif -#ifdef WITH_QUICKTIME - {R_IMF_IMTYPE_QUICKTIME, "QUICKTIME", ICON_FILE_MOVIE, "QuickTime", "Output video in Quicktime format"}, -#endif {0, NULL, 0, NULL, NULL} }; @@ -408,7 +406,8 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = { /* interpolation */ {0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"}, {GP_IPO_LINEAR, "LINEAR", ICON_IPO_LINEAR, "Linear", "Straight-line interpolation between A and B (i.e. no ease in/out)"}, @@ -431,6 +430,7 @@ EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = { {0, NULL, 0, NULL, NULL} }; +#endif #ifdef RNA_RUNTIME @@ -1118,9 +1118,6 @@ static void rna_ImageFormatSettings_file_format_set(PointerRNA *ptr, int value) #ifdef WITH_FFMPEG BKE_ffmpeg_image_type_verify(rd, imf); #endif -#ifdef WITH_QUICKTIME - quicktime_verify_image_type(rd, imf); -#endif (void)rd; } } @@ -1309,84 +1306,6 @@ static void rna_SceneRender_file_ext_get(PointerRNA *ptr, char *str) BKE_image_path_ensure_ext_from_imformat(str, &rd->im_format); } -#ifdef WITH_QUICKTIME -static int rna_RenderSettings_qtcodecsettings_codecType_get(PointerRNA *ptr) -{ - QuicktimeCodecSettings *settings = (QuicktimeCodecSettings *)ptr->data; - - return quicktime_rnatmpvalue_from_videocodectype(settings->codecType); -} - -static void rna_RenderSettings_qtcodecsettings_codecType_set(PointerRNA *ptr, int value) -{ - QuicktimeCodecSettings *settings = (QuicktimeCodecSettings *)ptr->data; - - settings->codecType = quicktime_videocodecType_from_rnatmpvalue(value); -} - -static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_codecType_itemf( - bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ - EnumPropertyItem *item = NULL; - EnumPropertyItem tmp = {0, "", 0, "", ""}; - QuicktimeCodecTypeDesc *codecTypeDesc; - int i = 1, totitem = 0; - - for (i = 0; i < quicktime_get_num_videocodecs(); i++) { - codecTypeDesc = quicktime_get_videocodecType_desc(i); - if (!codecTypeDesc) break; - - tmp.value = codecTypeDesc->rnatmpvalue; - tmp.identifier = codecTypeDesc->codecName; - tmp.name = codecTypeDesc->codecName; - RNA_enum_item_add(&item, &totitem, &tmp); - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; -} - -static int rna_RenderSettings_qtcodecsettings_audiocodecType_get(PointerRNA *ptr) -{ - QuicktimeCodecSettings *settings = (QuicktimeCodecSettings *)ptr->data; - - return quicktime_rnatmpvalue_from_audiocodectype(settings->audiocodecType); -} - -static void rna_RenderSettings_qtcodecsettings_audiocodecType_set(PointerRNA *ptr, int value) -{ - QuicktimeCodecSettings *settings = (QuicktimeCodecSettings *)ptr->data; - - settings->audiocodecType = quicktime_audiocodecType_from_rnatmpvalue(value); -} - -static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_audiocodecType_itemf( - bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ - EnumPropertyItem *item = NULL; - EnumPropertyItem tmp = {0, "", 0, "", ""}; - QuicktimeCodecTypeDesc *codecTypeDesc; - int i = 1, totitem = 0; - - for (i = 0; i < quicktime_get_num_audiocodecs(); i++) { - codecTypeDesc = quicktime_get_audiocodecType_desc(i); - if (!codecTypeDesc) break; - - tmp.value = codecTypeDesc->rnatmpvalue; - tmp.identifier = codecTypeDesc->codecName; - tmp.name = codecTypeDesc->codecName; - RNA_enum_item_add(&item, &totitem, &tmp); - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; -} -#endif - #ifdef WITH_FFMPEG static void rna_FFmpegSettings_lossless_output_set(PointerRNA *ptr, int value) { @@ -1838,6 +1757,13 @@ static void rna_Scene_simplify_update(Main *bmain, Scene *UNUSED(scene), Pointer rna_Scene_use_simplify_update(bmain, sce, ptr); } +static void rna_SceneRenderData_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + Scene *sce = ptr->id.data; + + DAG_id_tag_update(&sce->id, 0); +} + static void rna_Scene_use_persistent_data_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Scene *sce = ptr->id.data; @@ -2665,7 +2591,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "uv_sculpt_tool", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "uv_sculpt_tool"); - RNA_def_property_enum_items(prop, uv_sculpt_tool_items); + RNA_def_property_enum_items(prop, rna_enum_uv_sculpt_tool_items); RNA_def_property_ui_text(prop, "UV Sculpt Tools", "Select Tools for the UV sculpt brushes"); prop = RNA_def_property(srna, "uv_relax_method", PROP_ENUM, PROP_NONE); @@ -5723,106 +5649,6 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Audio Channels", "Audio channel count"); } -#ifdef WITH_QUICKTIME -static void rna_def_scene_quicktime_settings(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - static EnumPropertyItem quicktime_codec_type_items[] = { - {0, "codec", 0, "codec", ""}, - {0, NULL, 0, NULL, NULL} - }; - - static EnumPropertyItem quicktime_audio_samplerate_items[] = { - {22050, "22050", 0, "22kHz", ""}, - {44100, "44100", 0, "44.1kHz", ""}, - {48000, "48000", 0, "48kHz", ""}, - {88200, "88200", 0, "88.2kHz", ""}, - {96000, "96000", 0, "96kHz", ""}, - {192000, "192000", 0, "192kHz", ""}, - {0, NULL, 0, NULL, NULL} - }; - - static EnumPropertyItem quicktime_audio_bitdepth_items[] = { - {AUD_FORMAT_U8, "8BIT", 0, "8bit", ""}, - {AUD_FORMAT_S16, "16BIT", 0, "16bit", ""}, - {AUD_FORMAT_S24, "24BIT", 0, "24bit", ""}, - {AUD_FORMAT_S32, "32BIT", 0, "32bit", ""}, - {AUD_FORMAT_FLOAT32, "FLOAT32", 0, "float32", ""}, - {AUD_FORMAT_FLOAT64, "FLOAT64", 0, "float64", ""}, - {0, NULL, 0, NULL, NULL} - }; - - static EnumPropertyItem quicktime_audio_bitrate_items[] = { - {64000, "64000", 0, "64kbps", ""}, - {112000, "112000", 0, "112kpbs", ""}, - {128000, "128000", 0, "128kbps", ""}, - {192000, "192000", 0, "192kbps", ""}, - {256000, "256000", 0, "256kbps", ""}, - {320000, "320000", 0, "320kbps", ""}, - {0, NULL, 0, NULL, NULL} - }; - - /* QuickTime */ - srna = RNA_def_struct(brna, "QuickTimeSettings", NULL); - RNA_def_struct_sdna(srna, "QuicktimeCodecSettings"); - RNA_def_struct_ui_text(srna, "QuickTime Settings", "QuickTime related settings for the scene"); - - prop = RNA_def_property(srna, "codec_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "codecType"); - RNA_def_property_enum_items(prop, quicktime_codec_type_items); - RNA_def_property_enum_funcs(prop, "rna_RenderSettings_qtcodecsettings_codecType_get", - "rna_RenderSettings_qtcodecsettings_codecType_set", - "rna_RenderSettings_qtcodecsettings_codecType_itemf"); - RNA_def_property_ui_text(prop, "Codec", "QuickTime codec type"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "codec_spatial_quality", PROP_INT, PROP_PERCENTAGE); - RNA_def_property_int_sdna(prop, NULL, "codecSpatialQuality"); - RNA_def_property_range(prop, 0, 100); - RNA_def_property_ui_text(prop, "Spatial quality", "Intra-frame spatial quality level"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "audiocodec_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "audiocodecType"); - RNA_def_property_enum_items(prop, quicktime_codec_type_items); - RNA_def_property_enum_funcs(prop, "rna_RenderSettings_qtcodecsettings_audiocodecType_get", - "rna_RenderSettings_qtcodecsettings_audiocodecType_set", - "rna_RenderSettings_qtcodecsettings_audiocodecType_itemf"); - RNA_def_property_ui_text(prop, "Audio Codec", "QuickTime audio codec type"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "audio_samplerate", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "audioSampleRate"); - RNA_def_property_enum_items(prop, quicktime_audio_samplerate_items); - RNA_def_property_ui_text(prop, "Smp Rate", "Sample Rate"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "audio_bitdepth", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "audioBitDepth"); - RNA_def_property_enum_items(prop, quicktime_audio_bitdepth_items); - RNA_def_property_ui_text(prop, "Bit Depth", "Bit Depth"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "audio_resampling_hq", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "audioCodecFlags", QTAUDIO_FLAG_RESAMPLE_NOHQ); - RNA_def_property_ui_text(prop, "HQ", "Use High Quality resampling algorithm"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "audio_codec_isvbr", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "audioCodecFlags", QTAUDIO_FLAG_CODEC_ISCBR); - RNA_def_property_ui_text(prop, "VBR", "Use Variable Bit Rate compression (improves quality at same bitrate)"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "audio_bitrate", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "audioBitRate"); - RNA_def_property_enum_items(prop, quicktime_audio_bitrate_items); - RNA_def_property_ui_text(prop, "Bitrate", "Compressed audio bitrate"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); -} -#endif - static void rna_def_scene_render_data(BlenderRNA *brna) { StructRNA *srna; @@ -5887,6 +5713,15 @@ static void rna_def_scene_render_data(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem pixel_size_items[] = { + {0, "AUTO", 0, "Automatic", "Automatic pixel size, depends on the UI scale"}, + {1, "1", 0, "1x", "Render at full resolution"}, + {2, "2", 0, "2x", "Render at 50% resolution"}, + {4, "4", 0, "4x", "Render at 25% resolution"}, + {8, "8", 0, "8x", "Render at 12.5% resolution"}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem octree_resolution_items[] = { {64, "64", 0, "64", ""}, {128, "128", 0, "128", ""}, @@ -5947,9 +5782,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna) rna_def_scene_ffmpeg_settings(brna); -#ifdef WITH_QUICKTIME - rna_def_scene_quicktime_settings(brna); -#endif srna = RNA_def_struct(brna, "RenderSettings", NULL); RNA_def_struct_sdna(srna, "RenderData"); @@ -6010,6 +5842,12 @@ static void rna_def_scene_render_data(BlenderRNA *brna) "progressively increasing it to the full viewport size"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "preview_pixel_size", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "preview_pixel_size"); + RNA_def_property_enum_items(prop, pixel_size_items); + RNA_def_property_ui_text(prop, "Pixel Size", "Pixel size for viewport rendering"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderData_update"); + prop = RNA_def_property(srna, "pixel_aspect_x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "xasp"); RNA_def_property_flag(prop, PROP_PROPORTIONAL); @@ -6028,14 +5866,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna) "Vertical aspect ratio - for anamorphic or non-square pixel output"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneCamera_update"); -#ifdef WITH_QUICKTIME - prop = RNA_def_property(srna, "quicktime", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "QuickTimeSettings"); - RNA_def_property_pointer_sdna(prop, NULL, "qtcodecsettings"); - RNA_def_property_flag(prop, PROP_NEVER_UNLINK); - RNA_def_property_ui_text(prop, "QuickTime Settings", "QuickTime related settings for the scene"); -#endif - prop = RNA_def_property(srna, "ffmpeg", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "FFmpegSettings"); RNA_def_property_pointer_sdna(prop, NULL, "ffcodecdata"); @@ -6242,8 +6072,8 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "blurfac"); RNA_def_property_ui_range(prop, 0.01f, 2.0f, 1, 2); - RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close " + "(NOTE: Blender Internal does not support animated shutter)"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); prop = RNA_def_property(srna, "motion_blur_shutter_curve", PROP_POINTER, PROP_NONE); @@ -6605,11 +6435,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna) /* sequencer draw options */ - prop = RNA_def_property(srna, "use_sequencer_gl_preview", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "seq_flag", R_SEQ_GL_PREV); - RNA_def_property_ui_text(prop, "Sequencer OpenGL", ""); - RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SceneSequencer_update"); - #if 0 /* see R_SEQ_GL_REND comment */ prop = RNA_def_property(srna, "use_sequencer_gl_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "seq_flag", R_SEQ_GL_REND); @@ -6622,10 +6447,13 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Sequencer Preview Shading", "Method to draw in the sequencer view"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SceneSequencer_update"); +#if 0 /* UNUSED, see R_SEQ_GL_REND comment */ prop = RNA_def_property(srna, "sequencer_gl_render", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "seq_rend_type"); RNA_def_property_enum_items(prop, rna_enum_viewport_shade_items); + /* XXX Label and tooltips are obviously wrong! */ RNA_def_property_ui_text(prop, "Sequencer Preview Shading", "Method to draw in the sequencer view"); +#endif prop = RNA_def_property(srna, "use_sequencer_gl_textured_solid", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "seq_flag", R_SEQ_SOLID_TEX); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index ea7327cfa31..16d91a4964b 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -279,7 +279,7 @@ static void rna_Scene_collada_export( int include_shapekeys, int deform_bones_only, int active_uv_only, - int export_texture_type, + int export_texture_type, int use_texture_copies, int triangulate, int use_object_instantiation, diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 40aea37d9d2..09da34d59d8 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -28,6 +28,7 @@ #include <stdlib.h> #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -75,13 +76,15 @@ EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = { { 0, NULL, 0, NULL, NULL } }; -EnumPropertyItem rna_enum_gpencil_lockaxis_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem rna_enum_gpencil_lockaxis_items[] = { { GP_LOCKAXIS_NONE, "GP_LOCKAXIS_NONE", 0, "None", "" }, { GP_LOCKAXIS_X, "GP_LOCKAXIS_X", 0, "X", "Project strokes to plane locked to X" }, { GP_LOCKAXIS_Y, "GP_LOCKAXIS_Y", 0, "Y", "Project strokes to plane locked to Y" }, { GP_LOCKAXIS_Z, "GP_LOCKAXIS_Z", 0, "Z", "Project strokes to plane locked to Z" }, { 0, NULL, 0, NULL, NULL } }; +#endif EnumPropertyItem rna_enum_symmetrize_direction_items[] = { {BMO_SYMMETRIZE_NEGATIVE_X, "NEGATIVE_X", 0, "-X to +X", ""}, @@ -684,6 +687,15 @@ static void rna_def_vertex_paint(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_ONLYVGROUP); RNA_def_property_ui_text(prop, "Restrict", "Restrict painting to vertices in the group"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + /* Mirroring */ + prop = RNA_def_property(srna, "radial_symmetry", PROP_INT, PROP_XYZ); + RNA_def_property_int_sdna(prop, NULL, "radial_symm"); + RNA_def_property_int_default(prop, 1); + RNA_def_property_range(prop, 1, 64); + RNA_def_property_ui_range(prop, 1, 32, 1, 1); + RNA_def_property_ui_text(prop, "Radial Symmetry Count X Axis", + "Number of times to copy strokes across the surface"); } static void rna_def_image_paint(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index f628c5f14d9..520a1c2f730 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -725,8 +725,9 @@ static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), Poin static void rna_Sequence_sound_update(Main *bmain, Scene *scene, PointerRNA *ptr) { Sequence *seq = (Sequence *) ptr->data; - - BKE_sound_update_scene_sound(seq->scene_sound, seq->sound); + if (seq->sound != NULL) { + BKE_sound_update_scene_sound(seq->scene_sound, seq->sound); + } rna_Sequence_update(bmain, scene, ptr); } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index f2e856bf1ba..ed28b0d399b 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1045,6 +1045,8 @@ static void rna_SpaceProperties_pin_id_update(Main *UNUSED(bmain), Scene *UNUSED case ID_LA: WM_main_add_notifier(NC_LAMP, NULL); break; + default: + break; } } @@ -2836,6 +2838,16 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Is Perspective", ""); RNA_def_property_flag(prop, PROP_EDITABLE); + /* This isn't directly accessible from the UI, only an operator. */ + prop = RNA_def_property(srna, "use_clip_planes", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "rflag", RV3D_CLIPPING); + RNA_def_property_ui_text(prop, "Use Clip Planes", ""); + + prop = RNA_def_property(srna, "clip_planes", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "clip"); + RNA_def_property_multi_array(prop, 2, (int[]){6, 4}); + RNA_def_property_ui_text(prop, "Clipe Planes", ""); + prop = RNA_def_property(srna, "view_location", PROP_FLOAT, PROP_TRANSLATION); #if 0 RNA_def_property_float_sdna(prop, NULL, "ofs"); /* cant use because its negated */ @@ -4605,7 +4617,7 @@ static void rna_def_space_clip(BlenderRNA *brna) /* path length */ prop = RNA_def_property(srna, "path_length", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "path_length"); - RNA_def_property_range(prop, 0, 50); + RNA_def_property_range(prop, 0, INT_MAX); RNA_def_property_ui_text(prop, "Path Length", "Length of displaying path, in frames"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL); diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index 1e88585a286..4ad2832b953 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -267,6 +267,8 @@ void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL); break; } + default: + break; } } diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 54b82fc89d6..08038b0b1ff 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -177,16 +177,17 @@ static void rna_Panel_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &pt->ext); + RNA_struct_free(&BLENDER_RNA, type); BLI_freelinkN(&art->paneltypes, pt); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); } -static StructRNA *rna_Panel_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_Panel_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { ARegionType *art; PanelType *pt, dummypt = {NULL}; @@ -229,6 +230,12 @@ static StructRNA *rna_Panel_register(Main *bmain, ReportList *reports, void *dat break; } } + if (!RNA_struct_available_or_report(reports, dummypt.idname)) { + return NULL; + } + if (!RNA_struct_bl_idname_ok_or_report(reports, dummypt.idname, "_PT_")) { + return NULL; + } /* create a new panel type */ pt = MEM_callocN(sizeof(PanelType), "python buttons panel"); @@ -455,17 +462,17 @@ static void rna_UIList_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &ult->ext); + RNA_struct_free(&BLENDER_RNA, type); WM_uilisttype_freelink(ult); - RNA_struct_free(&BLENDER_RNA, type); - /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); } -static StructRNA *rna_UIList_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_UIList_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { uiListType *ult, dummyult = {NULL}; uiList dummyuilist = {NULL}; @@ -489,8 +496,15 @@ static StructRNA *rna_UIList_register(Main *bmain, ReportList *reports, void *da /* check if we have registered this uilist type before, and remove it */ ult = WM_uilisttype_find(dummyult.idname, true); - if (ult && ult->ext.srna) + if (ult && ult->ext.srna) { rna_UIList_unregister(bmain, ult->ext.srna); + } + if (!RNA_struct_available_or_report(reports, dummyult.idname)) { + return NULL; + } + if (!RNA_struct_bl_idname_ok_or_report(reports, dummyult.idname, "_UL_")) { + return NULL; + } /* create a new menu type */ ult = MEM_callocN(sizeof(uiListType) + over_alloc, "python uilist"); @@ -551,16 +565,17 @@ static void rna_Header_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &ht->ext); + RNA_struct_free(&BLENDER_RNA, type); BLI_freelinkN(&art->headertypes, ht); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); } -static StructRNA *rna_Header_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_Header_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { ARegionType *art; HeaderType *ht, dummyht = {NULL}; @@ -593,6 +608,12 @@ static StructRNA *rna_Header_register(Main *bmain, ReportList *reports, void *da break; } } + if (!RNA_struct_available_or_report(reports, dummyht.idname)) { + return NULL; + } + if (!RNA_struct_bl_idname_ok_or_report(reports, dummyht.idname, "_HT_")) { + return NULL; + } /* create a new header type */ ht = MEM_callocN(sizeof(HeaderType), "python buttons header"); @@ -673,17 +694,17 @@ static void rna_Menu_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &mt->ext); + RNA_struct_free(&BLENDER_RNA, type); WM_menutype_freelink(mt); - RNA_struct_free(&BLENDER_RNA, type); - /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); } -static StructRNA *rna_Menu_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_Menu_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { MenuType *mt, dummymt = {NULL}; Menu dummymenu = {NULL}; @@ -714,8 +735,15 @@ static StructRNA *rna_Menu_register(Main *bmain, ReportList *reports, void *data /* check if we have registered this menu type before, and remove it */ mt = WM_menutype_find(dummymt.idname, true); - if (mt && mt->ext.srna) + if (mt && mt->ext.srna) { rna_Menu_unregister(bmain, mt->ext.srna); + } + if (!RNA_struct_available_or_report(reports, dummymt.idname)) { + return NULL; + } + if (!RNA_struct_bl_idname_ok_or_report(reports, dummymt.idname, "_MT_")) { + return NULL; + } /* create a new menu type */ if (_menu_descr[0]) { @@ -937,6 +965,7 @@ static void rna_def_panel(BlenderRNA *brna) RNA_def_struct_refine_func(srna, "rna_Panel_refine"); RNA_def_struct_register_funcs(srna, "rna_Panel_register", "rna_Panel_unregister", NULL); RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT); /* poll */ func = RNA_def_function(srna, "poll", NULL); @@ -1039,7 +1068,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); + RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES | STRUCT_PUBLIC_NAMESPACE_INHERIT); /* Registration */ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); @@ -1161,6 +1190,7 @@ static void rna_def_header(BlenderRNA *brna) RNA_def_struct_sdna(srna, "Header"); RNA_def_struct_refine_func(srna, "rna_Header_refine"); RNA_def_struct_register_funcs(srna, "rna_Header_register", "rna_Header_unregister", NULL); + RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT); /* draw */ func = RNA_def_function(srna, "draw", NULL); @@ -1208,6 +1238,7 @@ static void rna_def_menu(BlenderRNA *brna) RNA_def_struct_refine_func(srna, "rna_Menu_refine"); RNA_def_struct_register_funcs(srna, "rna_Menu_register", "rna_Menu_unregister", NULL); RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT); /* poll */ func = RNA_def_function(srna, "poll", NULL); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index c0f2dbd0706..b50cbee4885 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -606,16 +606,17 @@ static void rna_AddonPref_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &apt->ext); + RNA_struct_free(&BLENDER_RNA, type); BKE_addon_pref_type_remove(apt); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); } -static StructRNA *rna_AddonPref_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_AddonPref_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bAddonPrefType *apt, dummyapt = {{'\0'}}; bAddon dummyaddon = {NULL}; @@ -638,10 +639,8 @@ static StructRNA *rna_AddonPref_register(Main *bmain, ReportList *reports, void /* check if we have registered this header type before, and remove it */ apt = BKE_addon_pref_type_find(dummyaddon.module, true); - if (apt) { - if (apt->ext.srna) { - rna_AddonPref_unregister(bmain, apt->ext.srna); - } + if (apt && apt->ext.srna) { + rna_AddonPref_unregister(bmain, apt->ext.srna); } /* create a new header type */ @@ -3304,6 +3303,13 @@ static void rna_def_userdef_view(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem line_width[] = { + {-1, "THIN", 0, "Thin", "Thinner lines than the default"}, + { 0, "AUTO", 0, "Auto", "Automatic line width based on UI scale"}, + { 1, "THICK", 0, "Thick", "Thicker lines than the default"}, + {0, NULL, 0, NULL, NULL} + }; + PropertyRNA *prop; StructRNA *srna; @@ -3321,6 +3327,12 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_float_default(prop, 1.0f); RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); + prop = RNA_def_property(srna, "ui_line_width", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, line_width); + RNA_def_property_ui_text(prop, "UI Line Width", + "Changes the thickness of lines and points in the interface"); + RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); + /* display */ prop = RNA_def_property(srna, "show_tooltips", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_TOOLTIPS); @@ -3445,6 +3457,11 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Cursor Depth", "Use the depth under the mouse when placing the cursor"); + prop = RNA_def_property(srna, "use_cursor_lock_adjust", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_LOCK_CURSOR_ADJUST); + RNA_def_property_ui_text(prop, "Cursor Lock Adjust", + "Place the cursor without 'jumping' to the new location (when lock-to-cursor is used)"); + prop = RNA_def_property(srna, "use_camera_lock_parent", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "uiflag", USER_CAM_LOCK_NO_PARENT); RNA_def_property_ui_text(prop, "Camera Parent Lock", @@ -3926,12 +3943,18 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop = RNA_def_property(srna, "dpi", PROP_INT, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "DPI", "Font size and resolution for display"); + RNA_def_property_ui_text(prop, "DPI", + "DPI for add-ons to use when drawing custom user interface elements, controlled by " + "operating system settings and Blender UI scale, with a reference value of 72 DPI " + "(note that since this value includes a user defined scale, it is not always the " + "actual monitor DPI)"); prop = RNA_def_property(srna, "pixel_size", PROP_FLOAT, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_float_sdna(prop, NULL, "pixelsize"); - RNA_def_property_ui_text(prop, "Pixel Size", ""); + RNA_def_property_ui_text(prop, "Pixel Size", + "Suggested line thickness and point size in pixels, for add-ons drawing custom user " + "interface elements, controlled by operating system settings and Blender UI scale"); prop = RNA_def_property(srna, "font_path_ui", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "font_path_ui"); @@ -3979,11 +4002,6 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Translate New Names", "Translate new data names (when adding/creating some)"); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop = RNA_def_property(srna, "use_textured_fonts", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_USETEXTUREFONT); - RNA_def_property_ui_text(prop, "Textured Fonts", "Use textures for drawing international fonts"); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - /* System & OpenGL */ prop = RNA_def_property(srna, "solid_lights", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index b5ecaf739c7..df3eae4f221 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -32,6 +32,7 @@ #include "DNA_windowmanager_types.h" #include "BLI_utildefines.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" @@ -1124,8 +1125,8 @@ static StructRNA *rna_Operator_register( struct { char idname[OP_MAX_TYPENAME]; char name[OP_MAX_TYPENAME]; - char descr[RNA_DYN_DESCR_MAX]; - char ctxt[RNA_DYN_DESCR_MAX]; + char description[RNA_DYN_DESCR_MAX]; + char translation_context[RNA_DYN_DESCR_MAX]; char undo_group[OP_MAX_TYPENAME]; } temp_buffers; @@ -1133,92 +1134,57 @@ static StructRNA *rna_Operator_register( dummyop.type = &dummyot; dummyot.idname = temp_buffers.idname; /* only assigne the pointer, string is NULL'd */ dummyot.name = temp_buffers.name; /* only assigne the pointer, string is NULL'd */ - dummyot.description = temp_buffers.descr; /* only assigne the pointer, string is NULL'd */ - dummyot.translation_context = temp_buffers.ctxt; /* only assigne the pointer, string is NULL'd */ + dummyot.description = temp_buffers.description; /* only assigne the pointer, string is NULL'd */ + dummyot.translation_context = temp_buffers.translation_context; /* only assigne the pointer, string is NULL'd */ dummyot.undo_group = temp_buffers.undo_group; /* only assigne the pointer, string is NULL'd */ RNA_pointer_create(NULL, &RNA_Operator, &dummyop, &dummyotr); /* clear in case they are left unset */ - temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.descr[0] = temp_buffers.undo_group[0] = '\0'; + temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.description[0] = temp_buffers.undo_group[0] = '\0'; /* We have to set default op context! */ - strcpy(temp_buffers.ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT); + strcpy(temp_buffers.translation_context, BLT_I18NCONTEXT_OPERATOR_DEFAULT); /* validate the python class */ if (validate(&dummyotr, data, have_function) != 0) return NULL; - { /* convert foo.bar to FOO_OT_bar - * allocate the description and the idname in 1 go */ - - /* inconveniently long name sanity check */ - { - char *ch = temp_buffers.idname; - int i; - int dot = 0; - for (i = 0; *ch; i++) { - if ((*ch >= 'a' && *ch <= 'z') || (*ch >= '0' && *ch <= '9') || *ch == '_') { - /* pass */ - } - else if (*ch == '.') { - dot++; - } - else { - BKE_reportf(reports, RPT_ERROR, - "Registering operator class: '%s', invalid bl_idname '%s', at position %d", - identifier, temp_buffers.idname, i); - return NULL; - } + /* check if we have registered this operator type before, and remove it */ + { + wmOperatorType *ot = WM_operatortype_find(dummyot.idname, true); + if (ot && ot->ext.srna) + rna_Operator_unregister(bmain, ot->ext.srna); + } - ch++; - } + if (!WM_operator_py_idname_ok_or_report(reports, identifier, dummyot.idname)) { + return NULL; + } - if (i > ((int)sizeof(dummyop.idname)) - 3) { - BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', " - "is too long, maximum length is %d", identifier, temp_buffers.idname, - (int)sizeof(dummyop.idname) - 3); - return NULL; - } + char idname_conv[sizeof(dummyop.idname)]; + WM_operator_bl_idname(idname_conv, dummyot.idname); /* convert the idname from python */ - if (dot != 1) { - BKE_reportf(reports, RPT_ERROR, - "Registering operator class: '%s', invalid bl_idname '%s', must contain 1 '.' character", - identifier, temp_buffers.idname); - return NULL; - } - } - /* end sanity check */ - - { - const uint idname_len = strlen(temp_buffers.idname) + 4; - const uint name_len = strlen(temp_buffers.name) + 1; - const uint desc_len = strlen(temp_buffers.descr) + 1; - const uint ctxt_len = strlen(temp_buffers.ctxt) + 1; - const uint undo_group_len = strlen(temp_buffers.undo_group) + 1; - /* 2 terminators and 3 to convert a.b -> A_OT_b */ - char *ch = MEM_mallocN( - sizeof(char) * (idname_len + name_len + desc_len + ctxt_len + undo_group_len), __func__); - WM_operator_bl_idname(ch, temp_buffers.idname); /* convert the idname from python */ - dummyot.idname = ch; - ch += idname_len; - memcpy(ch, temp_buffers.name, name_len); - dummyot.name = ch; - ch += name_len; - memcpy(ch, temp_buffers.descr, desc_len); - dummyot.description = ch; - ch += desc_len; - memcpy(ch, temp_buffers.ctxt, ctxt_len); - dummyot.translation_context = ch; - ch += ctxt_len; - memcpy(ch, temp_buffers.undo_group, undo_group_len); - dummyot.undo_group = ch; - } + if (!RNA_struct_available_or_report(reports, idname_conv)) { + return NULL; } - /* check if we have registered this operator type before, and remove it */ + /* Convert foo.bar to FOO_OT_bar + * allocate all strings at once. */ { - wmOperatorType *ot = WM_operatortype_find(dummyot.idname, true); - if (ot && ot->ext.srna) - rna_Operator_unregister(bmain, ot->ext.srna); + const char *strings[] = { + idname_conv, + temp_buffers.name, + temp_buffers.description, + temp_buffers.translation_context, + temp_buffers.undo_group, + }; + char *strings_table[ARRAY_SIZE(strings)]; + BLI_string_join_array_by_sep_char_with_tableN('\0', strings_table, strings, ARRAY_SIZE(strings)); + + dummyot.idname = strings_table[0]; /* allocated string stored here */ + dummyot.name = strings_table[1]; + dummyot.description = strings_table[2]; + dummyot.translation_context = strings_table[3]; + dummyot.undo_group = strings_table[4]; + BLI_assert(ARRAY_SIZE(strings) == 5); } /* XXX, this doubles up with the operator name [#29666] @@ -1269,10 +1235,11 @@ static void rna_Operator_unregister(struct Main *bmain, StructRNA *type) idname = ot->idname; WM_operatortype_remove_ptr(ot); - MEM_freeN((void *)idname); /* not to be confused with the RNA_struct_free that WM_operatortype_remove calls, they are 2 different srna's */ RNA_struct_free(&BLENDER_RNA, type); + + MEM_freeN((void *)idname); } static void **rna_Operator_instance(PointerRNA *ptr) @@ -1293,8 +1260,8 @@ static StructRNA *rna_MacroOperator_register( struct { char idname[OP_MAX_TYPENAME]; char name[OP_MAX_TYPENAME]; - char descr[RNA_DYN_DESCR_MAX]; - char ctxt[RNA_DYN_DESCR_MAX]; + char description[RNA_DYN_DESCR_MAX]; + char translation_context[RNA_DYN_DESCR_MAX]; char undo_group[OP_MAX_TYPENAME]; } temp_buffers; @@ -1302,15 +1269,15 @@ static StructRNA *rna_MacroOperator_register( dummyop.type = &dummyot; dummyot.idname = temp_buffers.idname; /* only assigne the pointer, string is NULL'd */ dummyot.name = temp_buffers.name; /* only assigne the pointer, string is NULL'd */ - dummyot.description = temp_buffers.descr; /* only assigne the pointer, string is NULL'd */ - dummyot.translation_context = temp_buffers.ctxt; /* only assigne the pointer, string is NULL'd */ + dummyot.description = temp_buffers.description; /* only assigne the pointer, string is NULL'd */ + dummyot.translation_context = temp_buffers.translation_context; /* only assigne the pointer, string is NULL'd */ dummyot.undo_group = temp_buffers.undo_group; /* only assigne the pointer, string is NULL'd */ RNA_pointer_create(NULL, &RNA_Macro, &dummyop, &dummyotr); /* clear in case they are left unset */ - temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.descr[0] = temp_buffers.undo_group[0] = '\0'; + temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.description[0] = temp_buffers.undo_group[0] = '\0'; /* We have to set default op context! */ - strcpy(temp_buffers.ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT); + strcpy(temp_buffers.translation_context, BLT_I18NCONTEXT_OPERATOR_DEFAULT); /* validate the python class */ if (validate(&dummyotr, data, have_function) != 0) @@ -1322,32 +1289,6 @@ static StructRNA *rna_MacroOperator_register( return NULL; } - { /* convert foo.bar to FOO_OT_bar - * allocate the description and the idname in 1 go */ - const uint idname_len = strlen(temp_buffers.idname) + 4; - const uint name_len = strlen(temp_buffers.name) + 1; - const uint desc_len = strlen(temp_buffers.descr) + 1; - const uint ctxt_len = strlen(temp_buffers.ctxt) + 1; - const uint undo_group_len = strlen(temp_buffers.undo_group) + 1; - /* 2 terminators and 3 to convert a.b -> A_OT_b */ - char *ch = MEM_mallocN( - sizeof(char) * (idname_len + name_len + desc_len + ctxt_len + undo_group_len), __func__); - WM_operator_bl_idname(ch, temp_buffers.idname); /* convert the idname from python */ - dummyot.idname = ch; - ch += idname_len; - memcpy(ch, temp_buffers.name, name_len); - dummyot.name = ch; - ch += name_len; - memcpy(ch, temp_buffers.descr, desc_len); - dummyot.description = ch; - ch += desc_len; - memcpy(ch, temp_buffers.ctxt, ctxt_len); - dummyot.translation_context = ch; - ch += ctxt_len; - memcpy(ch, temp_buffers.undo_group, undo_group_len); - dummyot.undo_group = ch; - } - /* check if we have registered this operator type before, and remove it */ { wmOperatorType *ot = WM_operatortype_find(dummyot.idname, true); @@ -1355,6 +1296,38 @@ static StructRNA *rna_MacroOperator_register( rna_Operator_unregister(bmain, ot->ext.srna); } + if (!WM_operator_py_idname_ok_or_report(reports, identifier, dummyot.idname)) { + return NULL; + } + + char idname_conv[sizeof(dummyop.idname)]; + WM_operator_bl_idname(idname_conv, dummyot.idname); /* convert the idname from python */ + + if (!RNA_struct_available_or_report(reports, idname_conv)) { + return NULL; + } + + /* Convert foo.bar to FOO_OT_bar + * allocate all strings at once. */ + { + const char *strings[] = { + idname_conv, + temp_buffers.name, + temp_buffers.description, + temp_buffers.translation_context, + temp_buffers.undo_group, + }; + char *strings_table[ARRAY_SIZE(strings)]; + BLI_string_join_array_by_sep_char_with_tableN('\0', strings_table, strings, ARRAY_SIZE(strings)); + + dummyot.idname = strings_table[0]; /* allocated string stored here */ + dummyot.name = strings_table[1]; + dummyot.description = strings_table[2]; + dummyot.translation_context = strings_table[3]; + dummyot.undo_group = strings_table[4]; + BLI_assert(ARRAY_SIZE(strings) == 5); + } + /* XXX, this doubles up with the operator name [#29666] * for now just remove from dir(bpy.types) */ @@ -1488,6 +1461,7 @@ static void rna_def_operator(BlenderRNA *brna) RNA_def_struct_register_funcs(srna, "rna_Operator_register", "rna_Operator_unregister", "rna_Operator_instance"); #endif RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT); + RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1591,6 +1565,7 @@ static void rna_def_macro_operator(BlenderRNA *brna) "rna_Operator_instance"); #endif RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT); + RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index 2400dbcb898..f2f76f13883 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -64,13 +64,13 @@ static void initData(ModifierData *md) static void copyData(ModifierData *md, ModifierData *target) { +#if 0 ArmatureModifierData *amd = (ArmatureModifierData *) md; +#endif ArmatureModifierData *tamd = (ArmatureModifierData *) target; - tamd->object = amd->object; - tamd->deformflag = amd->deformflag; - tamd->multi = amd->multi; - BLI_strncpy(tamd->defgrp_name, amd->defgrp_name, sizeof(tamd->defgrp_name)); + modifier_copyData_generic(md, target); + tamd->prevCos = NULL; } static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md)) diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 5874029ae08..93dc0203f83 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -65,19 +65,11 @@ static void initData(ModifierData *md) static void copyData(ModifierData *md, ModifierData *target) { +#if 0 BevelModifierData *bmd = (BevelModifierData *) md; BevelModifierData *tbmd = (BevelModifierData *) target; - - tbmd->value = bmd->value; - tbmd->res = bmd->res; - tbmd->flags = bmd->flags; - tbmd->val_flags = bmd->val_flags; - tbmd->lim_flags = bmd->lim_flags; - tbmd->e_flags = bmd->e_flags; - tbmd->mat = bmd->mat; - tbmd->profile = bmd->profile; - tbmd->bevel_angle = bmd->bevel_angle; - BLI_strncpy(tbmd->defgrp_name, bmd->defgrp_name, sizeof(tbmd->defgrp_name)); +#endif + modifier_copyData_generic(md, target); } static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index f86d8b99f3c..1140460161f 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -59,6 +59,7 @@ #include "BLI_alloca.h" #include "BLI_math_geom.h" #include "BKE_material.h" +#include "BKE_global.h" /* only to check G.debug */ #include "MEM_guardedalloc.h" #include "bmesh.h" @@ -224,6 +225,8 @@ static DerivedMesh *applyModifier_bmesh( result = get_quick_derivedMesh(ob, dm, bmd->object, dm_other, bmd->operation); if (result == NULL) { + const bool is_flip = (is_negative_m4(ob->obmat) != is_negative_m4(bmd->object->obmat)); + BMesh *bm; const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm, dm_other); @@ -235,6 +238,16 @@ static DerivedMesh *applyModifier_bmesh( &((struct BMeshCreateParams){.use_toolflags = false,})); DM_to_bmesh_ex(dm_other, bm, true); + + if (UNLIKELY(is_flip)) { + const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); + BMIter iter; + BMFace *efa; + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + BM_face_normal_flip_ex(bm, efa, cd_loop_mdisp_offset, true); + } + } + DM_to_bmesh_ex(dm, bm, true); /* main bmesh intersection setup */ @@ -246,7 +259,7 @@ static DerivedMesh *applyModifier_bmesh( looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__); - BM_mesh_calc_tessellation(bm, looptris, &tottri); + BM_mesh_calc_tessellation_beauty(bm, looptris, &tottri); /* postpone this until after tessellating * so we can use the original normals before the vertex are moved */ @@ -262,7 +275,6 @@ static DerivedMesh *applyModifier_bmesh( invert_m4_m4(imat, ob->obmat); mul_m4_m4m4(omat, imat, bmd->object->obmat); - BMVert *eve; i = 0; BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { @@ -275,8 +287,13 @@ static DerivedMesh *applyModifier_bmesh( /* we need face normals because of 'BM_face_split_edgenet' * we could calculate on the fly too (before calling split). */ { - float nmat[4][4]; - invert_m4_m4(nmat, omat); + float nmat[3][3]; + copy_m3_m4(nmat, omat); + invert_m3(nmat); + + if (UNLIKELY(is_flip)) { + negate_m3(nmat); + } const short ob_src_totcol = bmd->object->totcol; short *material_remap = BLI_array_alloca(material_remap, ob_src_totcol ? ob_src_totcol : 1); @@ -286,7 +303,7 @@ static DerivedMesh *applyModifier_bmesh( BMFace *efa; i = 0; BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - mul_transposed_mat3_m4_v3(nmat, efa->no); + mul_transposed_m3_v3(nmat, efa->no); normalize_v3(efa->no); BM_elem_flag_enable(efa, BM_FACE_TAG); /* temp tag to test which side split faces are from */ @@ -306,11 +323,17 @@ static DerivedMesh *applyModifier_bmesh( * currently this is ok for 'BM_mesh_intersect' */ // BM_mesh_normals_update(bm); - /* change for testing */ bool use_separate = false; bool use_dissolve = true; bool use_island_connect = true; + /* change for testing */ + if (G.debug & G_DEBUG) { + use_separate = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_Separate) != 0; + use_dissolve = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoDissolve) == 0; + use_island_connect = (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoConnectRegions) == 0; + } + BM_mesh_intersect( bm, looptris, tottri, diff --git a/source/blender/modifiers/intern/MOD_boolean_util.c b/source/blender/modifiers/intern/MOD_boolean_util.c index 061b1198f7e..49010664aa8 100644 --- a/source/blender/modifiers/intern/MOD_boolean_util.c +++ b/source/blender/modifiers/intern/MOD_boolean_util.c @@ -390,6 +390,9 @@ static void exporter_InitGeomArrays(ExportMeshData *export_data, * the operand. Data for those layers will not be allocated or initialized. */ + CustomData_merge(&dm_left->vertData, &dm->vertData, merge_mask, CD_DEFAULT, num_verts); + CustomData_merge(&dm_right->vertData, &dm->vertData, merge_mask, CD_DEFAULT, num_verts); + CustomData_merge(&dm_left->loopData, &dm->loopData, merge_mask, CD_DEFAULT, num_loops); CustomData_merge(&dm_right->loopData, &dm->loopData, merge_mask, CD_DEFAULT, num_loops); diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c index a364eef2974..56a274b9ac9 100644 --- a/source/blender/modifiers/intern/MOD_build.c +++ b/source/blender/modifiers/intern/MOD_build.c @@ -47,6 +47,8 @@ #include "BKE_particle.h" #include "BKE_scene.h" + + #ifdef _OPENMP # include "BKE_mesh.h" /* BKE_MESH_OMP_LIMIT */ #endif diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index e7ff0a90fbc..74e49dda074 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -40,7 +40,6 @@ #include "BLI_math.h" #include "BLI_utildefines.h" - #include "BKE_collision.h" #include "BKE_cdderivedmesh.h" #include "BKE_global.h" @@ -48,6 +47,8 @@ #include "BKE_pointcache.h" #include "BKE_scene.h" +#include "MOD_modifiertypes.h" + static void initData(ModifierData *md) { CollisionModifierData *collmd = (CollisionModifierData *) md; @@ -152,8 +153,6 @@ static void deformVerts(ModifierData *md, Object *ob, collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame collmd->mvert_num = mvert_num; - - DM_ensure_looptri(dm); collmd->tri_num = dm->getNumLoopTri(dm); { diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c index 3c6ba7acc88..c9a910d769b 100644 --- a/source/blender/modifiers/intern/MOD_curve.c +++ b/source/blender/modifiers/intern/MOD_curve.c @@ -39,7 +39,6 @@ #include "BLI_utildefines.h" - #include "BKE_cdderivedmesh.h" #include "BKE_lattice.h" #include "BKE_library_query.h" @@ -48,6 +47,7 @@ #include "depsgraph_private.h" #include "DEG_depsgraph_build.h" +#include "MOD_modifiertypes.h" static void initData(ModifierData *md) { diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index 3325f05025f..fb8c0dd05a5 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -75,14 +75,10 @@ static void copyData(ModifierData *md, ModifierData *target) { #if 0 DisplaceModifierData *dmd = (DisplaceModifierData *) md; -#endif DisplaceModifierData *tdmd = (DisplaceModifierData *) target; +#endif modifier_copyData_generic(md, target); - - if (tdmd->texture) { - id_us_plus(&tdmd->texture->id); - } } static void freeData(ModifierData *md) diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index 83a42504180..eec97828091 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -43,6 +43,7 @@ #include "depsgraph_private.h" #include "DEG_depsgraph_build.h" +#include "MOD_modifiertypes.h" static void initData(ModifierData *md) { diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c index 4441edb299b..a17870f2bf4 100644 --- a/source/blender/modifiers/intern/MOD_edgesplit.c +++ b/source/blender/modifiers/intern/MOD_edgesplit.c @@ -48,6 +48,7 @@ #include "DNA_object_types.h" +#include "MOD_modifiertypes.h" static DerivedMesh *doEdgeSplit(DerivedMesh *dm, EdgeSplitModifierData *emd) { diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index ca7b3ce8039..72bc046b440 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -51,9 +51,9 @@ #include "BKE_particle.h" #include "BKE_scene.h" - #include "MEM_guardedalloc.h" +#include "MOD_modifiertypes.h" static void initData(ModifierData *md) { diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c index 1964e940cb2..53f955b15f0 100644 --- a/source/blender/modifiers/intern/MOD_fluidsim.c +++ b/source/blender/modifiers/intern/MOD_fluidsim.c @@ -47,6 +47,8 @@ #include "DEG_depsgraph_build.h" #include "MOD_fluidsim_util.h" +#include "MOD_modifiertypes.h" + #include "MEM_guardedalloc.h" /* Fluidsim */ diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c index ce3fdc4bbe8..c2896e83a0b 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.c +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c @@ -29,7 +29,7 @@ */ #include "BLI_utildefines.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_math.h" #include "BLI_string.h" @@ -539,7 +539,7 @@ static void initSystem(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh STACK_PUSH(index_anchors, i); } } - DM_ensure_looptri(dm); + total_anchors = STACK_SIZE(index_anchors); lmd->cache_system = initLaplacianSystem(numVerts, dm->getNumEdges(dm), dm->getNumLoopTri(dm), total_anchors, lmd->anchor_grp_name, lmd->repeat); diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c index dcc7fe4d4f1..18caf4a39f4 100644 --- a/source/blender/modifiers/intern/MOD_mask.c +++ b/source/blender/modifiers/intern/MOD_mask.c @@ -53,6 +53,8 @@ #include "depsgraph_private.h" #include "DEG_depsgraph_build.h" +#include "MOD_modifiertypes.h" + #include "BLI_strict_flags.h" static void copyData(ModifierData *md, ModifierData *target) diff --git a/source/blender/modifiers/intern/MOD_meshcache_pc2.c b/source/blender/modifiers/intern/MOD_meshcache_pc2.c index 8360c8ffda7..4b2b3f17d18 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_pc2.c +++ b/source/blender/modifiers/intern/MOD_meshcache_pc2.c @@ -146,7 +146,7 @@ bool MOD_meshcache_read_pc2_index(FILE *fp, return false; } - if (fseek(fp, sizeof(float) * 3 * index * pc2_head.verts_tot , SEEK_CUR) != 0) { + if (fseek(fp, sizeof(float) * 3 * index * pc2_head.verts_tot, SEEK_CUR) != 0) { *err_str = "Failed to seek frame"; return false; } diff --git a/source/blender/modifiers/intern/MOD_meshcache_util.c b/source/blender/modifiers/intern/MOD_meshcache_util.c index c263c4810e4..10861f5b02b 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_util.c +++ b/source/blender/modifiers/intern/MOD_meshcache_util.c @@ -36,7 +36,7 @@ void MOD_meshcache_calc_range(const float frame, const char interp, int r_index_range[2], float *r_factor) { if (interp == MOD_MESHCACHE_INTERP_NONE) { - r_index_range[0] = r_index_range[1] = max_ii(0, min_ii(frame_tot - 1, iroundf(frame))); + r_index_range[0] = r_index_range[1] = max_ii(0, min_ii(frame_tot - 1, round_fl_to_int(frame))); *r_factor = 1.0f; /* dummy */ } else { diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index f0edcc31a10..5b059ef89d2 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -25,12 +25,14 @@ */ #include "DNA_cachefile_types.h" +#include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BKE_cachefile.h" #include "BKE_DerivedMesh.h" +#include "BKE_cdderivedmesh.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -95,11 +97,15 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams)) static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, - ModifierApplyFlag flag) + ModifierApplyFlag UNUSED(flag)) { #ifdef WITH_ALEMBIC MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; + /* Only used to check whether we are operating on org data or not... */ + Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; + DerivedMesh *org_dm = dm; + Scene *scene = md->scene; const float frame = BKE_scene_frame_get(scene); const float time = BKE_cachefile_time_offset(mcmd->cache_file, frame, FPS); @@ -121,6 +127,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, } } + if (me != NULL) { + MVert *mvert = dm->getVertArray(dm); + MEdge *medge = dm->getEdgeArray(dm); + MPoly *mpoly = dm->getPolyArray(dm); + if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) { + /* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */ + dm = CDDM_copy(dm); + } + } + DerivedMesh *result = ABC_read_mesh(mcmd->reader, ob, dm, @@ -132,11 +148,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, modifier_setError(md, "%s", err_str); } + if (!ELEM(result, NULL, dm) && (dm != org_dm)) { + dm->release(dm); + dm = org_dm; + } + return result ? result : dm; - UNUSED_VARS(flag); #else return dm; - UNUSED_VARS(md, ob, flag); + UNUSED_VARS(md, ob); #endif } diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index 9705edc580c..157f37e973c 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -48,6 +48,8 @@ #include "depsgraph_private.h" #include "DEG_depsgraph_build.h" +#include "MOD_modifiertypes.h" + static void initData(ModifierData *md) { MirrorModifierData *mmd = (MirrorModifierData *) md; @@ -263,7 +265,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, /* handle uvs, * let tessface recalc handle updating the MTFace data */ - if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) { + if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) || (is_zero_v2(mmd->uv_offset_copy) == false)) { const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0; const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0; @@ -276,6 +278,8 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, for (; j-- > 0; dmloopuv++) { 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]; + dmloopuv->uv[0] += mmd->uv_offset_copy[0]; + dmloopuv->uv[1] += mmd->uv_offset_copy[1]; } } } diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index 90ad1bdfdc2..f9f17b88fa4 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -46,6 +46,8 @@ #include "BKE_modifier.h" #include "BKE_subsurf.h" +#include "MOD_modifiertypes.h" + static void initData(ModifierData *md) { MultiresModifierData *mmd = (MultiresModifierData *)md; diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index 2c0bfc86e7d..8d8565e7e62 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -44,6 +44,8 @@ #include "BKE_modifier.h" #include "BKE_ocean.h" +#include "MOD_modifiertypes.h" + #ifdef WITH_OCEANSIM static void init_cache_data(Object *ob, struct OceanModifierData *omd) { diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index fbf5a958254..0c91cb08da7 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -54,6 +54,8 @@ #include "depsgraph_private.h" #include "DEG_depsgraph_build.h" +#include "MOD_modifiertypes.h" + static void initData(ModifierData *md) { ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 87859cd240a..2c3d7f394bb 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -112,6 +112,56 @@ static void screwvert_iter_step(ScrewVertIter *iter) } } +static DerivedMesh *dm_remove_doubles_on_axis( + DerivedMesh *result, MVert *mvert_new, const uint totvert, const uint step_tot, + const float axis_vec[3], const float axis_offset[3], const float merge_threshold) +{ + const float merge_threshold_sq = SQUARE(merge_threshold); + const bool use_offset = axis_offset != NULL; + uint tot_doubles = 0; + for (uint i = 0; i < totvert; i += 1) { + float axis_co[3]; + if (use_offset) { + float offset_co[3]; + sub_v3_v3v3(offset_co, mvert_new[i].co, axis_offset); + project_v3_v3v3_normalized(axis_co, offset_co, axis_vec); + add_v3_v3(axis_co, axis_offset); + } + else { + project_v3_v3v3_normalized(axis_co, mvert_new[i].co, axis_vec); + } + const float dist_sq = len_squared_v3v3(axis_co, mvert_new[i].co); + if (dist_sq <= merge_threshold_sq) { + mvert_new[i].flag |= ME_VERT_TMP_TAG; + tot_doubles += 1; + copy_v3_v3(mvert_new[i].co, axis_co); + } + } + + if (tot_doubles != 0) { + uint tot = totvert * step_tot; + int *full_doubles_map = MEM_mallocN(sizeof(int) * tot, __func__); + copy_vn_i(full_doubles_map, (int)tot, -1); + + uint tot_doubles_left = tot_doubles; + for (uint i = 0; i < totvert; i += 1) { + if (mvert_new[i].flag & ME_VERT_TMP_TAG) { + int *doubles_map = &full_doubles_map[totvert + i] ; + for (uint step = 1; step < step_tot; step += 1) { + *doubles_map = (int)i; + doubles_map += totvert; + } + tot_doubles_left -= 1; + if (tot_doubles_left == 0) { + break; + } + } + } + result = CDDM_merge_verts(result, full_doubles_map, (int)(tot_doubles * (step_tot - 1)), CDDM_MERGE_VERTS_DUMP_IF_MAPPED); + MEM_freeN(full_doubles_map); + } + return result; +} static void initData(ModifierData *md) { @@ -123,6 +173,7 @@ static void initData(ModifierData *md) ltmd->steps = 16; ltmd->render_steps = 16; ltmd->iter = 1; + ltmd->merge_dist = 0.01f; } static void copyData(ModifierData *md, ModifierData *target) @@ -1050,6 +1101,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, MEM_freeN(vert_loop_map); } + if ((ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f)) { + DerivedMesh *result_prev = result; + result = dm_remove_doubles_on_axis( + result, mvert_new, totvert, step_tot, + axis_vec, ltmd->ob_axis ? mtx_tx[3] : NULL, ltmd->merge_dist); + if (result != result_prev) { + result->dirty |= DM_DIRTY_NORMALS; + } + } + if ((ltmd->flag & MOD_SCREW_NORMAL_CALC) == 0) { result->dirty |= DM_DIRTY_NORMALS; } diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index 8ed623734be..ad1e4badd3e 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -77,6 +77,8 @@ #include "BKE_mesh_mapping.h" #include "BKE_modifier.h" +#include "MOD_modifiertypes.h" + #include "bmesh.h" typedef struct { diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c index c105a3ab3a7..7f2d9e42fe6 100644 --- a/source/blender/modifiers/intern/MOD_smoke.c +++ b/source/blender/modifiers/intern/MOD_smoke.c @@ -45,7 +45,6 @@ #include "BLI_utildefines.h" - #include "BKE_cdderivedmesh.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -56,6 +55,8 @@ #include "depsgraph_private.h" #include "DEG_depsgraph_build.h" +#include "MOD_modifiertypes.h" + static void initData(ModifierData *md) { SmokeModifierData *smd = (SmokeModifierData *) md; diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index 911b6997058..e96771e0665 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -36,7 +36,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_bitmap.h" #include "BLI_math.h" diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c index 6fad2756f82..b057d6d5a86 100644 --- a/source/blender/modifiers/intern/MOD_triangulate.c +++ b/source/blender/modifiers/intern/MOD_triangulate.c @@ -35,6 +35,8 @@ #include "bmesh.h" #include "bmesh_tools.h" +#include "MOD_modifiertypes.h" + static DerivedMesh *triangulate_dm(DerivedMesh *dm, const int quad_method, const int ngon_method) { DerivedMesh *result; diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index f0c4940816e..b4990c5250e 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -90,14 +90,10 @@ static void copyData(ModifierData *md, ModifierData *target) { #if 0 WaveModifierData *wmd = (WaveModifierData *) md; -#endif WaveModifierData *twmd = (WaveModifierData *) target; +#endif modifier_copyData_generic(md, target); - - if (twmd->texture) { - id_us_plus(&twmd->texture->id); - } } static bool dependsOnTime(ModifierData *UNUSED(md)) diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index cd30b54350c..13a97c1c13d 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -50,7 +50,9 @@ #include "DEG_depsgraph_build.h" #include "MEM_guardedalloc.h" + #include "MOD_weightvg_util.h" +#include "MOD_modifiertypes.h" /************************************** * Modifiers functions. * @@ -91,10 +93,6 @@ static void copyData(ModifierData *md, ModifierData *target) modifier_copyData_generic(md, target); twmd->cmap_curve = curvemapping_copy(wmd->cmap_curve); - - if (twmd->mask_texture) { - id_us_plus(&twmd->mask_texture->id); - } } static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index 1b3188c83b3..392f42040b0 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -47,7 +47,9 @@ #include "DEG_depsgraph_build.h" #include "MEM_guardedalloc.h" + #include "MOD_weightvg_util.h" +#include "MOD_modifiertypes.h" /** @@ -136,14 +138,10 @@ static void copyData(ModifierData *md, ModifierData *target) { #if 0 WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md; -#endif WeightVGMixModifierData *twmd = (WeightVGMixModifierData *) target; +#endif modifier_copyData_generic(md, target); - - if (twmd->mask_texture) { - id_us_plus(&twmd->mask_texture->id); - } } static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 2c87838aeab..2ca380ba5c2 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -51,7 +51,9 @@ #include "DEG_depsgraph_build.h" #include "MEM_guardedalloc.h" + #include "MOD_weightvg_util.h" +#include "MOD_modifiertypes.h" //#define USE_TIMEIT @@ -286,14 +288,10 @@ static void copyData(ModifierData *md, ModifierData *target) { #if 0 WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; -#endif WeightVGProximityModifierData *twmd = (WeightVGProximityModifierData *) target; +#endif modifier_copyData_generic(md, target); - - if (twmd->mask_texture) { - id_us_plus(&twmd->mask_texture->id); - } } static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index 8139e29bade..a95c3233132 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -178,6 +178,9 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node, LinkNod cmp_node_image_add_pass_output(ntree, node, "Alpha", RE_PASSNAME_COMBINED, -1, SOCK_FLOAT, false, available_sockets, &prev_index); if (ima) { + if (!ima->rr) { + cmp_node_image_add_pass_output(ntree, node, RE_PASSNAME_Z, RE_PASSNAME_Z, -1, SOCK_FLOAT, false, available_sockets, &prev_index); + } BKE_image_release_ibuf(ima, ibuf, NULL); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.c index 5a9e33a4053..8262b70fc44 100644 --- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c +++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.c @@ -51,14 +51,23 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat, bNode *UNUSED(node), bNodeE return GPU_stack_link(mat, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION)); } -static void node_shader_exec_fresnel(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) +static void node_shader_exec_fresnel(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) { ShadeInput *shi = ((ShaderCallData *)data)->shi; - float eta = max_ff(in[0]->vec[0], 0.00001); + + /* Compute IOR. */ + float eta; + nodestack_get_vec(&eta, SOCK_FLOAT, in[0]); + eta = max_ff(eta, 0.00001); + eta = shi->flippednor ? 1 / eta : eta; + + /* Get normal from socket, but only if linked. */ + bNodeSocket *sock_normal = node->inputs.first; + sock_normal = sock_normal->next; float n[3]; - if (in[1]->hasinput) { - copy_v3_v3(n, in[1]->vec); + if (sock_normal->link) { + nodestack_get_vec(n, SOCK_VECTOR, in[1]); } else { copy_v3_v3(n, shi->vn); @@ -68,7 +77,7 @@ static void node_shader_exec_fresnel(void *data, int UNUSED(thread), bNode *UNUS mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), n); } - out[0]->vec[0] = RE_fresnel_dielectric(shi->view, n, shi->flippednor ? 1 / eta : eta); + out[0]->vec[0] = RE_fresnel_dielectric(shi->view, n, eta); } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c index a0b2408a7bb..998e1a5687e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c +++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c @@ -52,24 +52,33 @@ static int node_shader_gpu_layer_weight(GPUMaterial *mat, bNode *UNUSED(node), b return GPU_stack_link(mat, "node_layer_weight", in, out, GPU_builtin(GPU_VIEW_POSITION)); } -static void node_shader_exec_layer_weight(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) +static void node_shader_exec_layer_weight(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) { ShadeInput *shi = ((ShaderCallData *)data)->shi; - float blend = in[0]->vec[0]; + + /* Compute IOR. */ + float blend; + nodestack_get_vec(&blend, SOCK_FLOAT, in[0]); float eta = max_ff(1 - blend, 0.00001); + eta = shi->flippednor ? eta : 1 / eta; + + /* Get normal from socket, but only if linked. */ + bNodeSocket *sock_normal = node->inputs.first; + sock_normal = sock_normal->next; float n[3]; - if (in[1]->hasinput) { - copy_v3_v3(n, in[1]->vec); + if (sock_normal->link) { + nodestack_get_vec(n, SOCK_VECTOR, in[1]); } else { copy_v3_v3(n, shi->vn); } + if (shi->use_world_space_shading) mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), n); - out[0]->vec[0] = RE_fresnel_dielectric(shi->view, n, shi->flippednor ? eta : 1 / eta); + out[0]->vec[0] = RE_fresnel_dielectric(shi->view, n, eta); float facing = fabs(dot_v3v3(shi->view, n)); if (blend != 0.5) { diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c index 8f287918a4a..6598d402f72 100644 --- a/source/blender/python/bmesh/bmesh_py_ops_call.c +++ b/source/blender/python/bmesh/bmesh_py_ops_call.c @@ -44,6 +44,7 @@ #include "bmesh_py_types.h" #include "../generic/python_utildefines.h" +#include "../generic/py_capi_utils.h" static int bpy_bm_op_as_py_error(BMesh *bm) { @@ -152,11 +153,9 @@ static int bpy_slot_from_py( switch (slot->slot_type) { case BMO_OP_SLOT_BOOL: { - int param; + const int param = PyC_Long_AsBool(value); - param = PyLong_AsLong(value); - - if (param < 0) { + if (param == -1) { PyErr_Format(PyExc_TypeError, "%.200s: keyword \"%.200s\" expected True/False or 0/1, not %.200s", opname, slot_name, Py_TYPE(value)->tp_name); @@ -170,23 +169,16 @@ static int bpy_slot_from_py( } case BMO_OP_SLOT_INT: { - int overflow; - long param = PyLong_AsLongAndOverflow(value, &overflow); - if (overflow || (param > INT_MAX) || (param < INT_MIN)) { - PyErr_Format(PyExc_ValueError, - "%.200s: keyword \"%.200s\" value not in 'int' range " - "(" STRINGIFY(INT_MIN) ", " STRINGIFY(INT_MAX) ")", - opname, slot_name, Py_TYPE(value)->tp_name); - return -1; - } - else if (param == -1 && PyErr_Occurred()) { + const int param = PyC_Long_AsI32(value); + + if (param == -1 && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "%.200s: keyword \"%.200s\" expected an int, not %.200s", opname, slot_name, Py_TYPE(value)->tp_name); return -1; } else { - BMO_SLOT_AS_INT(slot) = (int)param; + BMO_SLOT_AS_INT(slot) = param; } break; } @@ -208,26 +200,19 @@ static int bpy_slot_from_py( { /* XXX - BMesh operator design is crappy here, operator slot should define matrix size, * not the caller! */ - unsigned short size; - if (!MatrixObject_Check(value)) { - PyErr_Format(PyExc_TypeError, - "%.200s: keyword \"%.200s\" expected a Matrix, not %.200s", - opname, slot_name, Py_TYPE(value)->tp_name); + MatrixObject *pymat; + if (!Matrix_ParseAny(value, &pymat)) { return -1; } - else if (BaseMath_ReadCallback((MatrixObject *)value) == -1) { - return -1; - } - else if (((size = ((MatrixObject *)value)->num_col) != ((MatrixObject *)value)->num_row) || - (ELEM(size, 3, 4) == false)) - { + const ushort size = pymat->num_col; + if ((size != pymat->num_row) || (!ELEM(size, 3, 4))) { PyErr_Format(PyExc_TypeError, "%.200s: keyword \"%.200s\" expected a 3x3 or 4x4 matrix Matrix", opname, slot_name); return -1; } - BMO_slot_mat_set(bmop, bmop->slots_in, slot_name, ((MatrixObject *)value)->matrix, size); + BMO_slot_mat_set(bmop, bmop->slots_in, slot_name, pymat->matrix, size); break; } case BMO_OP_SLOT_VEC: @@ -436,7 +421,7 @@ static int bpy_slot_from_py( return -1; /* error is set in bpy_slot_from_py_elem_check() */ } - value_i = PyLong_AsLong(arg_value); + value_i = PyC_Long_AsI32(arg_value); if (value_i == -1 && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, @@ -466,7 +451,7 @@ static int bpy_slot_from_py( return -1; /* error is set in bpy_slot_from_py_elem_check() */ } - value_i = PyLong_AsLong(arg_value); + value_i = PyC_Long_AsI32(arg_value); if (value_i == -1 && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index b20c03bee28..52ca475297d 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -124,25 +124,19 @@ static int bpy_bm_elem_hflag_set(BPy_BMElem *self, PyObject *value, void *flag) BPY_BM_CHECK_INT(self); - param = PyLong_AsLong(value); - - if ((unsigned int)param <= 1) { - if (hflag == BM_ELEM_SELECT) - BM_elem_select_set(self->bm, self->ele, param); - else - BM_elem_flag_set(self->ele, hflag, param); + if ((param = PyC_Long_AsBool(value)) == -1) { + return -1; + } - return 0; + if (hflag == BM_ELEM_SELECT) { + BM_elem_select_set(self->bm, self->ele, param); } else { - PyErr_Format(PyExc_TypeError, - "expected True/False or 0/1, not %.200s", - Py_TYPE(value)->tp_name); - return -1; + BM_elem_flag_set(self->ele, hflag, param); } + return 0; } - PyDoc_STRVAR(bpy_bm_elem_index_doc, "Index of this element.\n" "\n" @@ -169,21 +163,17 @@ static int bpy_bm_elem_index_set(BPy_BMElem *self, PyObject *value, void *UNUSED BPY_BM_CHECK_INT(self); - param = PyLong_AsLong(value); - - if (param == -1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "expected an int type"); + if (((param = PyC_Long_AsI32(value)) == -1) && PyErr_Occurred()) { + /* error is set */ return -1; } - else { - BM_elem_index_set(self->ele, param); /* set_dirty! */ - /* when setting the index assume its set invalid */ - self->bm->elem_index_dirty |= self->ele->head.htype; + BM_elem_index_set(self->ele, param); /* set_dirty! */ - return 0; - } + /* when setting the index assume its set invalid */ + self->bm->elem_index_dirty |= self->ele->head.htype; + + return 0; } /* type specific get/sets @@ -506,14 +496,12 @@ static int bpy_bmface_material_index_set(BPy_BMFace *self, PyObject *value) BPY_BM_CHECK_INT(self); - param = PyLong_AsLong(value); - - if (param == -1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "expected an int type"); + if (((param = PyC_Long_AsI32(value)) == -1) && PyErr_Occurred()) { + /* error is set */ return -1; } - else if ((param < 0) || (param > MAXMAT)) { + + if ((param < 0) || (param > MAXMAT)) { /* normally we clamp but in this case raise an error */ PyErr_SetString(PyExc_ValueError, "material index outside of usable range (0 - 32766)"); @@ -1049,6 +1037,13 @@ PyDoc_STRVAR(bpy_bmesh_from_mesh_doc, " :type use_shape_key: boolean\n" " :arg shape_key_index: The shape key index to use.\n" " :type shape_key_index: int\n" +"\n" +" .. note::\n" +"\n" +" Multiple calls can be used to join multiple meshes.\n" +"\n" +" Custom-data layers are only copied from ``mesh`` on initialization.\n" +" Further calls will copy custom-data to matching layers, layers missing on the target mesh wont be added.\n" ); static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw) { @@ -1113,15 +1108,16 @@ static PyObject *bpy_bmesh_select_flush(BPy_BMesh *self, PyObject *value) BPY_BM_CHECK_OBJ(self); - param = PyLong_AsLong(value); - if (param != false && param != true) { - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + if ((param = PyC_Long_AsBool(value)) == -1) { return NULL; } - if (param) BM_mesh_select_flush(self->bm); - else BM_mesh_deselect_flush(self->bm); + if (param) { + BM_mesh_select_flush(self->bm); + } + else { + BM_mesh_deselect_flush(self->bm); + } Py_RETURN_NONE; } @@ -1301,10 +1297,7 @@ static PyObject *bpy_bm_elem_select_set(BPy_BMElem *self, PyObject *value) BPY_BM_CHECK_OBJ(self); - param = PyLong_AsLong(value); - if (param != false && param != true) { - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + if ((param = PyC_Long_AsBool(value)) == -1) { return NULL; } @@ -1329,10 +1322,7 @@ static PyObject *bpy_bm_elem_hide_set(BPy_BMElem *self, PyObject *value) BPY_BM_CHECK_OBJ(self); - param = PyLong_AsLong(value); - if (param != false && param != true) { - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + if ((param = PyC_Long_AsBool(value)) == -1) { return NULL; } diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c index 908f6b5a734..cb95ded4f0d 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c @@ -43,6 +43,7 @@ #include "../mathutils/mathutils.h" #include "../generic/python_utildefines.h" +#include "../generic/py_capi_utils.h" #include "BKE_customdata.h" @@ -1074,9 +1075,9 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj } case CD_PROP_INT: { - int tmp_val = PyLong_AsLong(py_value); + int tmp_val = PyC_Long_AsI32(py_value); if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) { - PyErr_Format(PyExc_TypeError, "expected an int, not a %.200s", Py_TYPE(py_value)->tp_name); + /* error is set */ ret = -1; } else { diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c index 92c11a03433..b01d3f89d4e 100644 --- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c @@ -45,6 +45,7 @@ #include "bmesh_py_types_meshdata.h" +#include "../generic/py_capi_utils.h" #include "../generic/python_utildefines.h" @@ -188,7 +189,7 @@ static int bpy_bmloopuv_flag_set(BPy_BMLoopUV *self, PyObject *value, void *flag { const int flag = GET_INT_FROM_POINTER(flag_p); - switch (PyLong_AsLong(value)) { + switch (PyC_Long_AsBool(value)) { case true: self->data->flag |= flag; return 0; @@ -196,8 +197,7 @@ static int bpy_bmloopuv_flag_set(BPy_BMLoopUV *self, PyObject *value, void *flag self->data->flag &= ~flag; return 0; default: - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + /* error is set */ return -1; } } @@ -297,7 +297,7 @@ static int bpy_bmvertskin_flag_set(BPy_BMVertSkin *self, PyObject *value, void * { const int flag = GET_INT_FROM_POINTER(flag_p); - switch (PyLong_AsLong(value)) { + switch (PyC_Long_AsBool(value)) { case true: self->data->flag |= flag; return 0; @@ -305,8 +305,7 @@ static int bpy_bmvertskin_flag_set(BPy_BMVertSkin *self, PyObject *value, void * self->data->flag &= ~flag; return 0; default: - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + /* error is set */ return -1; } } diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index 3ea10228ad4..9cf00192db5 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -472,6 +472,49 @@ int BGL_typeSize(int type) return -1; } +static int gl_buffer_type_from_py_format_char(char *typestr) +{ + if (ELEM(typestr[0], '<', '>', '|')) { + typestr += 1; + } + char format = typestr[0]; + char byte_num = typestr[1]; + + switch (format) { + case 't': + case 'b': + case 'h': + if (!byte_num) return GL_BYTE; + ATTR_FALLTHROUGH; + case 'i': + if (!byte_num) return GL_SHORT; + ATTR_FALLTHROUGH; + case 'l': + if (!byte_num || byte_num == '4') return GL_INT; + if (byte_num == '1') return GL_BYTE; + if (byte_num == '2') return GL_SHORT; + break; + case 'f': + if (!byte_num) return GL_FLOAT; + ATTR_FALLTHROUGH; + case 'd': + if (!byte_num || byte_num == '8') return GL_DOUBLE; + if (byte_num == '4') return GL_FLOAT; + break; + } + return -1; /* UNKNOWN */ +} + +static bool compare_dimensions(int ndim, int *dim1, Py_ssize_t *dim2) +{ + for (int i = 0; i < ndim; i++) { + if (dim1[i] != dim2[i]) { + return false; + } + } + return true; +} + /** \} */ @@ -630,6 +673,22 @@ PyTypeObject BGL_bufferType = { NULL /*tp_del*/ }; + +static Buffer *BGL_MakeBuffer_FromData(PyObject *parent, int type, int ndimensions, int *dimensions, void *buf) +{ + Buffer *buffer = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType); + + Py_XINCREF(parent); + buffer->parent = parent; + buffer->ndimensions = ndimensions; + buffer->dimensions = MEM_mallocN(ndimensions * sizeof(int), "Buffer dimensions"); + memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int)); + buffer->type = type; + buffer->buf.asvoid = buf; + + return buffer; +} + /** * Create a buffer object * @@ -641,30 +700,21 @@ Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuf { Buffer *buffer; void *buf = NULL; - int i, size, length; + int i, size = BGL_typeSize(type); - length = 1; for (i = 0; i < ndimensions; i++) { - length *= dimensions[i]; + size *= dimensions[i]; } - size = BGL_typeSize(type); + buf = MEM_mallocN(size, "Buffer buffer"); - buf = MEM_mallocN(length * size, "Buffer buffer"); - - buffer = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType); - buffer->parent = NULL; - buffer->ndimensions = ndimensions; - buffer->dimensions = MEM_mallocN(ndimensions * sizeof(int), "Buffer dimensions"); - memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int)); - buffer->type = type; - buffer->buf.asvoid = buf; + buffer = BGL_MakeBuffer_FromData(NULL, type, ndimensions, dimensions, buf); if (initbuffer) { - memcpy(buffer->buf.asvoid, initbuffer, length * size); + memcpy(buffer->buf.asvoid, initbuffer, size); } else { - memset(buffer->buf.asvoid, 0, length * size); + memset(buffer->buf.asvoid, 0, size); } return buffer; } @@ -674,7 +724,7 @@ Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuf static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) { PyObject *length_ob = NULL, *init = NULL; - Buffer *buffer; + Buffer *buffer = NULL; int dimensions[MAX_DIMENSIONS]; int type; @@ -739,9 +789,32 @@ static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject return NULL; } - buffer = BGL_MakeBuffer(type, ndimensions, dimensions, NULL); - if (init && ndimensions) { - if (Buffer_ass_slice(buffer, 0, dimensions[0], init)) { + if (init && PyObject_CheckBuffer(init)) { + Py_buffer pybuffer; + + if (PyObject_GetBuffer(init, &pybuffer, PyBUF_ND | PyBUF_FORMAT) == -1) { + /* PyObject_GetBuffer raise a PyExc_BufferError */ + return NULL; + } + + if (type != gl_buffer_type_from_py_format_char(pybuffer.format)) { + PyErr_Format(PyExc_TypeError, + "`GL_TYPE` and `typestr` of object with buffer interface do not match. '%s'", pybuffer.format); + } + else if (ndimensions != pybuffer.ndim || + !compare_dimensions(ndimensions, dimensions, pybuffer.shape)) + { + PyErr_Format(PyExc_TypeError, "array size does not match"); + } + else { + buffer = BGL_MakeBuffer_FromData(init, type, pybuffer.ndim, dimensions, pybuffer.buf); + } + + PyBuffer_Release(&pybuffer); + } + else { + buffer = BGL_MakeBuffer(type, ndimensions, dimensions, NULL); + if (init && Buffer_ass_slice(buffer, 0, dimensions[0], init)) { Py_DECREF(buffer); return NULL; } @@ -774,27 +847,17 @@ static PyObject *Buffer_item(Buffer *self, int i) } } else { - Buffer *newbuf; - int j, length, size; + int j, offset = i * BGL_typeSize(self->type); - length = 1; for (j = 1; j < self->ndimensions; j++) { - length *= self->dimensions[j]; + offset *= self->dimensions[j]; } - size = BGL_typeSize(self->type); - - newbuf = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType); - - Py_INCREF(self); - newbuf->parent = (PyObject *)self; - - newbuf->ndimensions = self->ndimensions - 1; - newbuf->type = self->type; - newbuf->buf.asvoid = self->buf.asbyte + i * length * size; - newbuf->dimensions = MEM_mallocN(newbuf->ndimensions * sizeof(int), "Buffer dimensions"); - memcpy(newbuf->dimensions, self->dimensions + 1, newbuf->ndimensions * sizeof(int)); - return (PyObject *)newbuf; + return (PyObject *)BGL_MakeBuffer_FromData( + (PyObject *)self, self->type, + self->ndimensions - 1, + self->dimensions + 1, + self->buf.asbyte + offset); } return NULL; diff --git a/source/blender/python/generic/bpy_internal_import.c b/source/blender/python/generic/bpy_internal_import.c index ed2752d8372..7ab6447d21a 100644 --- a/source/blender/python/generic/bpy_internal_import.c +++ b/source/blender/python/generic/bpy_internal_import.c @@ -248,8 +248,17 @@ PyObject *bpy_text_reimport(PyObject *module, int *found) if ((name = PyModule_GetName(module)) == NULL) return NULL; - if ((filepath = (char *)PyModule_GetFilename(module)) == NULL) - return NULL; + { + PyObject *module_file = PyModule_GetFilenameObject(module); + if (module_file == NULL) { + return NULL; + } + filepath = (char *)_PyUnicode_AsString(module_file); + Py_DECREF(module_file); + if (filepath == NULL) { + return NULL; + } + } /* look up the text object */ text = BLI_findstring(&maggie->text, BLI_path_basename(filepath), offsetof(ID, name) + 2); diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index 5d6a7c578a2..1153e0176df 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -386,7 +386,7 @@ static IDProperty *idp_from_PyFloat(const char *name, PyObject *ob) static IDProperty *idp_from_PyLong(const char *name, PyObject *ob) { IDPropertyTemplate val = {0}; - val.i = _PyLong_AsInt(ob); + val.i = PyC_Long_AsI32(ob); if (val.i == -1 && PyErr_Occurred()) { return NULL; } @@ -499,7 +499,7 @@ static IDProperty *idp_from_PySequence_Fast(const char *name, PyObject *ob) 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()) { + if (((prop_data[i] = PyC_Long_AsI32(item)) == -1) && PyErr_Occurred()) { return NULL; } } @@ -1337,7 +1337,7 @@ static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value) } case IDP_INT: { - const int i = _PyLong_AsInt(value); + const int i = PyC_Long_AsI32(value); if (i == -1 && PyErr_Occurred()) { return -1; } diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index 2e789d6d4b3..d49f9514b8c 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -85,7 +85,7 @@ int PyC_AsArray_FAST( /* could use is_double for 'long int' but no use now */ int *array_int = array; for (i = 0; i < length; i++) { - array_int[i] = PyLong_AsLong(value_fast_items[i]); + array_int[i] = PyC_Long_AsI32(value_fast_items[i]); } } else if (type == &PyBool_Type) { @@ -127,54 +127,52 @@ int PyC_AsArray( return ret; } +/* -------------------------------------------------------------------- */ +/** \name Typed Tuple Packing + * + * \note See #PyC_Tuple_Pack_* macros that take multiple arguments. + * + * \{ */ + /* array utility function */ -PyObject *PyC_FromArray(const void *array, int length, const PyTypeObject *type, - const bool is_double, const char *error_prefix) +PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len) { - PyObject *tuple; - int i; - - tuple = PyTuple_New(length); - - /* for each type */ - if (type == &PyFloat_Type) { - if (is_double) { - const double *array_double = array; - for (i = 0; i < length; ++i) { - PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array_double[i])); - } - } - else { - const float *array_float = array; - for (i = 0; i < length; ++i) { - PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array_float[i])); - } - } - } - else if (type == &PyLong_Type) { - /* could use is_double for 'long int' but no use now */ - const int *array_int = array; - for (i = 0; i < length; ++i) { - PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(array_int[i])); - } + PyObject *tuple = PyTuple_New(len); + for (uint i = 0; i < len; i++) { + PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array[i])); } - else if (type == &PyBool_Type) { - const int *array_bool = array; - for (i = 0; i < length; ++i) { - PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array_bool[i])); - } + return tuple; +} + +PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len) +{ + PyObject *tuple = PyTuple_New(len); + for (uint i = 0; i < len; i++) { + PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(array[i])); } - else { - Py_DECREF(tuple); - PyErr_Format(PyExc_TypeError, - "%s: internal error %s is invalid", - error_prefix, type->tp_name); - return NULL; + return tuple; +} + +PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len) +{ + PyObject *tuple = PyTuple_New(len); + for (uint i = 0; i < len; i++) { + PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array[i])); } + return tuple; +} +PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len) +{ + PyObject *tuple = PyTuple_New(len); + for (uint i = 0; i < len; i++) { + PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array[i])); + } return tuple; } +/** \} */ + /** * Caller needs to ensure tuple is uninitialized. * Handy for filling a tuple with None for eg. @@ -203,6 +201,8 @@ void PyC_List_Fill(PyObject *list, PyObject *value) /** * Use with PyArg_ParseTuple's "O&" formatting. + * + * \see #PyC_Long_AsBool for a similar function to use outside of argument parsing. */ int PyC_ParseBool(PyObject *o, void *p) { @@ -300,7 +300,14 @@ void PyC_FileAndNum(const char **filename, int *lineno) if (mod_name) { PyObject *mod = PyDict_GetItem(PyImport_GetModuleDict(), mod_name); if (mod) { - *filename = PyModule_GetFilename(mod); + PyObject *mod_file = PyModule_GetFilenameObject(mod); + if (mod_file) { + *filename = _PyUnicode_AsString(mod_name); + Py_DECREF(mod_file); + } + else { + PyErr_Clear(); + } } /* unlikely, fallback */ @@ -1108,3 +1115,101 @@ bool PyC_RunString_AsString(const char *expr, const char *filename, char **r_val } #endif /* #ifndef MATH_STANDALONE */ + +/* -------------------------------------------------------------------- */ + +/** \name Int Conversion + * + * \note Python doesn't provide overflow checks for specific bit-widths. + * + * \{ */ + +/* Compiler optimizes out redundant checks. */ +#ifdef __GNUC__ +# pragma warning(push) +# pragma GCC diagnostic ignored "-Wtype-limits" +#endif + +/** + * Don't use `bool` return type, so -1 can be used as an error value. + */ +int PyC_Long_AsBool(PyObject *value) +{ + int test = _PyLong_AsInt(value); + if (UNLIKELY((uint)test > 1)) { + PyErr_SetString(PyExc_TypeError, + "Python number not a bool (0/1)"); + return -1; + } + return test; +} + +int8_t PyC_Long_AsI8(PyObject *value) +{ + int test = _PyLong_AsInt(value); + if (UNLIKELY(test < INT8_MIN || test > INT8_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C int8"); + return -1; + } + return (int8_t)test; +} + +int16_t PyC_Long_AsI16(PyObject *value) +{ + int test = _PyLong_AsInt(value); + if (UNLIKELY(test < INT16_MIN || test > INT16_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C int16"); + return -1; + } + return (int16_t)test; +} + +/* Inlined in header: + * PyC_Long_AsI32 + * PyC_Long_AsI64 + */ + +uint8_t PyC_Long_AsU8(PyObject *value) +{ + ulong test = PyLong_AsUnsignedLong(value); + if (UNLIKELY(test > UINT8_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C uint8"); + return (uint8_t)-1; + } + return (uint8_t)test; +} + +uint16_t PyC_Long_AsU16(PyObject *value) +{ + ulong test = PyLong_AsUnsignedLong(value); + if (UNLIKELY(test > UINT16_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C uint16"); + return (uint16_t)-1; + } + return (uint16_t)test; +} + +uint32_t PyC_Long_AsU32(PyObject *value) +{ + ulong test = PyLong_AsUnsignedLong(value); + if (UNLIKELY(test > UINT32_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C uint32"); + return (uint32_t)-1; + } + return (uint32_t)test; +} + +/* Inlined in header: + * PyC_Long_AsU64 + */ + +#ifdef __GNUC__ +# pragma warning(pop) +#endif + +/** \} */ diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h index 3f89e1d82a0..327d4e60954 100644 --- a/source/blender/python/generic/py_capi_utils.h +++ b/source/blender/python/generic/py_capi_utils.h @@ -24,10 +24,12 @@ * \ingroup pygen */ - #ifndef __PY_CAPI_UTILS_H__ #define __PY_CAPI_UTILS_H__ +#include "BLI_sys_types.h" +#include "BLI_utildefines_variadic.h" + void PyC_ObSpit(const char *name, PyObject *var); void PyC_LineSpit(void); void PyC_StackSpit(void); @@ -44,8 +46,21 @@ int PyC_AsArray_FAST( int PyC_AsArray( void *array, PyObject *value, const Py_ssize_t length, const PyTypeObject *type, const bool is_double, const char *error_prefix); -PyObject * PyC_FromArray(const void *array, int length, const PyTypeObject *type, - const bool is_double, const char *error_prefix); + +PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len); +PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len); +PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len); +PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len); + +#define PyC_Tuple_Pack_F32(...) \ + PyC_Tuple_PackArray_F32(((const float []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) +#define PyC_Tuple_Pack_I32(...) \ + PyC_Tuple_PackArray_I32(((const int []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) +#define PyC_Tuple_Pack_I32FromBool(...) \ + PyC_Tuple_PackArray_I32FromBool(((const int []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) +#define PyC_Tuple_Pack_Bool(...) \ + PyC_Tuple_PackArray_Bool(((const bool []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) + void PyC_Tuple_Fill(PyObject *tuple, PyObject *value); void PyC_List_Fill(PyObject *list, PyObject *value); @@ -85,4 +100,26 @@ bool PyC_RunString_AsString(const char *expr, const char *filename, char **r_val int PyC_ParseBool(PyObject *o, void *p); + +/* Integer parsing (with overflow checks), -1 on error. */ +int PyC_Long_AsBool(PyObject *value); +int8_t PyC_Long_AsI8(PyObject *value); +int16_t PyC_Long_AsI16(PyObject *value); +#if 0 /* inline */ +int32_t PyC_Long_AsI32(PyObject *value); +int64_t PyC_Long_AsI64(PyObject *value); +#endif + +uint8_t PyC_Long_AsU8(PyObject *value); +uint16_t PyC_Long_AsU16(PyObject *value); +uint32_t PyC_Long_AsU32(PyObject *value); +#if 0 /* inline */ +uint64_t PyC_Long_AsU64(PyObject *value); +#endif + +/* inline so type signatures match as expected */ +Py_LOCAL_INLINE(int32_t) PyC_Long_AsI32(PyObject *value) { return (int32_t)_PyLong_AsInt(value); } +Py_LOCAL_INLINE(int64_t) PyC_Long_AsI64(PyObject *value) { return (int64_t)PyLong_AsLongLong(value); } +Py_LOCAL_INLINE(uint64_t) PyC_Long_AsU64(PyObject *value) { return (uint64_t)PyLong_AsUnsignedLongLong(value); } + #endif /* __PY_CAPI_UTILS_H__ */ diff --git a/source/blender/python/generic/python_utildefines.h b/source/blender/python/generic/python_utildefines.h index f7d3e7a8b4a..2d2d19c05f5 100644 --- a/source/blender/python/generic/python_utildefines.h +++ b/source/blender/python/generic/python_utildefines.h @@ -36,16 +36,16 @@ extern "C" { PyTupleObject *op = (PyTupleObject *)op_arg; \ PyObject **ob_items = op->ob_item; \ CHECK_TYPE_ANY(op_arg, PyObject *, PyTupleObject *); \ - BLI_assert(_VA_NARGS_COUNT(__VA_ARGS__) == PyTuple_GET_SIZE(op)); \ + BLI_assert(VA_NARGS_COUNT(__VA_ARGS__) == PyTuple_GET_SIZE(op)); \ ARRAY_SET_ITEMS(ob_items, __VA_ARGS__); \ } (void)0 /* wrap Py_INCREF & return the result, * use sparingly to avoid comma operator or temp var assignment */ -BLI_INLINE PyObject *Py_INCREF_RET(PyObject *op) { Py_INCREF(op); return op; } +Py_LOCAL_INLINE(PyObject *)Py_INCREF_RET(PyObject *op) { Py_INCREF(op); return op; } /* append & transfer ownership to the list, avoids inline Py_DECREF all over (which is quite a large macro) */ -BLI_INLINE int PyList_APPEND(PyObject *op, PyObject *v) +Py_LOCAL_INLINE(int) PyList_APPEND(PyObject *op, PyObject *v) { int ret = PyList_Append(op, v); Py_DecRef(v); diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index be4db6477fe..dd84ce0ebe1 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -147,10 +147,6 @@ if(WITH_CODEC_FFMPEG) add_definitions(-DWITH_FFMPEG) endif() -if(WITH_CODEC_QUICKTIME) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_CODEC_SNDFILE) add_definitions(-DWITH_SNDFILE) endif() diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index 8b3464173d2..f44401afd7d 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -89,6 +89,7 @@ static PyStructSequence_Field app_info_fields[] = { {(char *)"version_cycle", (char *)"The release status of this build alpha/beta/rc/release"}, {(char *)"binary_path", (char *)"The location of blenders executable, useful for utilities that spawn new instances"}, {(char *)"background", (char *)"Boolean, True when blender is running without a user interface (started with -b)"}, + {(char *)"factory_startup", (char *)"Boolean, True when blender is running with --factory-startup)"}, /* buildinfo */ {(char *)"build_date", (char *)"The date this blender instance was built"}, @@ -156,8 +157,7 @@ static PyObject *make_app_info(void) #define SetObjItem(obj) \ PyStructSequence_SET_ITEM(app_info, pos++, obj) - SetObjItem(Py_BuildValue("(iii)", - BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); + SetObjItem(PyC_Tuple_Pack_I32(BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); SetObjItem(PyUnicode_FromFormat("%d.%02d (sub %d)", BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); @@ -165,6 +165,7 @@ static PyObject *make_app_info(void) SetStrItem(STRINGIFY(BLENDER_VERSION_CYCLE)); SetStrItem(BKE_appdir_program_path()); SetObjItem(PyBool_FromLong(G.background)); + SetObjItem(PyBool_FromLong(G.factory_startup)); /* build info, use bytes since we can't assume _any_ encoding: * see patch [#30154] for issue */ @@ -290,7 +291,7 @@ static PyObject *bpy_app_debug_value_get(PyObject *UNUSED(self), void *UNUSED(cl static int bpy_app_debug_value_set(PyObject *UNUSED(self), PyObject *value, void *UNUSED(closure)) { - int param = PyLong_AsLong(value); + int param = PyC_Long_AsI32(value); if (param == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "bpy.app.debug_value can only be set to a whole number"); diff --git a/source/blender/python/intern/bpy_app_alembic.c b/source/blender/python/intern/bpy_app_alembic.c index 90e6a02b418..2a1a031a629 100644 --- a/source/blender/python/intern/bpy_app_alembic.c +++ b/source/blender/python/intern/bpy_app_alembic.c @@ -34,6 +34,8 @@ #include "bpy_app_alembic.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_ALEMBIC # include "ABC_alembic.h" #endif @@ -79,11 +81,11 @@ static PyObject *make_alembic_info(void) const int patch = curversion - ((curversion / 100 ) * 100); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", major, minor, patch)); + SetObjItem(PyC_Tuple_Pack_I32(major, minor, patch)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", major, minor, patch)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c index a6b98567a9a..501e09dd6ad 100644 --- a/source/blender/python/intern/bpy_app_build_options.c +++ b/source/blender/python/intern/bpy_app_build_options.c @@ -37,7 +37,6 @@ static PyStructSequence_Field app_builtopts_info_fields[] = { {(char *)"bullet", NULL}, {(char *)"codec_avi", NULL}, {(char *)"codec_ffmpeg", NULL}, - {(char *)"codec_quicktime", NULL}, {(char *)"codec_sndfile", NULL}, {(char *)"compositor", NULL}, {(char *)"cycles", NULL}, @@ -112,12 +111,6 @@ static PyObject *make_builtopts_info(void) SetObjIncref(Py_False); #endif -#ifdef WITH_QUICKTIME - SetObjIncref(Py_True); -#else - SetObjIncref(Py_False); -#endif - #ifdef WITH_SNDFILE SetObjIncref(Py_True); #else diff --git a/source/blender/python/intern/bpy_app_ffmpeg.c b/source/blender/python/intern/bpy_app_ffmpeg.c index fd516e4547f..9f8355db72b 100644 --- a/source/blender/python/intern/bpy_app_ffmpeg.c +++ b/source/blender/python/intern/bpy_app_ffmpeg.c @@ -29,6 +29,8 @@ #include "bpy_app_ffmpeg.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_FFMPEG #include <libavcodec/avcodec.h> #include <libavdevice/avdevice.h> @@ -91,8 +93,7 @@ static PyObject *make_ffmpeg_info(void) #ifdef WITH_FFMPEG # define FFMPEG_LIB_VERSION(lib) { \ curversion = lib ## _version(); \ - SetObjItem(Py_BuildValue("(iii)", \ - curversion >> 16, (curversion >> 8) % 256, curversion % 256)); \ + SetObjItem(PyC_Tuple_Pack_I32(curversion >> 16, (curversion >> 8) % 256, curversion % 256)); \ SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", \ curversion >> 16, (curversion >> 8) % 256, curversion % 256)); \ } (void)0 diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c index fdc2371c259..90aa22de5bf 100644 --- a/source/blender/python/intern/bpy_app_handlers.c +++ b/source/blender/python/intern/bpy_app_handlers.c @@ -59,8 +59,12 @@ static PyStructSequence_Field app_cb_info_fields[] = { {(char *)"load_post", (char *)"on loading a new blend file (after)"}, {(char *)"save_pre", (char *)"on saving a blend file (before)"}, {(char *)"save_post", (char *)"on saving a blend file (after)"}, - {(char *)"scene_update_pre", (char *)"on updating the scenes data (before)"}, - {(char *)"scene_update_post", (char *)"on updating the scenes data (after)"}, + {(char *)"scene_update_pre", (char *)"on every scene data update. Does not imply that anything changed in the " + "scene, just that the dependency graph is about to be reevaluated, and the " + "scene is about to be updated by Blender's animation system."}, + {(char *)"scene_update_post", (char *)"on every scene data update. Does not imply that anything changed in the " + "scene, just that the dependency graph was reevaluated, and the scene was " + "possibly updated by Blender's animation system."}, {(char *)"game_pre", (char *)"on starting the game engine"}, {(char *)"game_post", (char *)"on ending the game engine"}, {(char *)"version_update", (char *)"on ending the versioning code"}, diff --git a/source/blender/python/intern/bpy_app_ocio.c b/source/blender/python/intern/bpy_app_ocio.c index 02e4044219a..9997e6b87f1 100644 --- a/source/blender/python/intern/bpy_app_ocio.c +++ b/source/blender/python/intern/bpy_app_ocio.c @@ -29,6 +29,8 @@ #include "bpy_app_ocio.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_OCIO # include "ocio_capi.h" #endif @@ -74,13 +76,12 @@ static PyObject *make_ocio_info(void) #ifdef WITH_OCIO curversion = OCIO_getVersionHex(); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", - curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); + SetObjItem(PyC_Tuple_Pack_I32(curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_oiio.c b/source/blender/python/intern/bpy_app_oiio.c index 60daf3ddd8b..e14b48ff7cf 100644 --- a/source/blender/python/intern/bpy_app_oiio.c +++ b/source/blender/python/intern/bpy_app_oiio.c @@ -29,6 +29,8 @@ #include "bpy_app_oiio.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_OPENIMAGEIO # include "openimageio_api.h" #endif @@ -74,13 +76,12 @@ static PyObject *make_oiio_info(void) #ifdef WITH_OPENIMAGEIO curversion = OIIO_getVersionHex(); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", - curversion / 10000, (curversion / 100) % 100, curversion % 100)); + SetObjItem(PyC_Tuple_Pack_I32(curversion / 10000, (curversion / 100) % 100, curversion % 100)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", curversion / 10000, (curversion / 100) % 100, curversion % 100)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_opensubdiv.c b/source/blender/python/intern/bpy_app_opensubdiv.c index 7f269baf2b0..096374794c9 100644 --- a/source/blender/python/intern/bpy_app_opensubdiv.c +++ b/source/blender/python/intern/bpy_app_opensubdiv.c @@ -29,6 +29,8 @@ #include "bpy_app_opensubdiv.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_OPENSUBDIV # include "opensubdiv_capi.h" #endif @@ -70,13 +72,12 @@ static PyObject *make_opensubdiv_info(void) #ifdef WITH_OPENSUBDIV int curversion = openSubdiv_getVersionHex(); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", - curversion / 10000, (curversion / 100) % 100, curversion % 100)); + SetObjItem(PyC_Tuple_Pack_I32(curversion / 10000, (curversion / 100) % 100, curversion % 100)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", curversion / 10000, (curversion / 100) % 100, curversion % 100)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_openvdb.c b/source/blender/python/intern/bpy_app_openvdb.c index 8a24aaf0555..0b385206d7b 100644 --- a/source/blender/python/intern/bpy_app_openvdb.c +++ b/source/blender/python/intern/bpy_app_openvdb.c @@ -34,6 +34,8 @@ #include "bpy_app_openvdb.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_OPENVDB # include "openvdb_capi.h" #endif @@ -79,13 +81,12 @@ static PyObject *make_openvdb_info(void) #ifdef WITH_OPENVDB curversion = OpenVDB_getVersionHex(); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", - curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); + SetObjItem(PyC_Tuple_Pack_I32(curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_sdl.c b/source/blender/python/intern/bpy_app_sdl.c index 76dab775953..816ad2833cc 100644 --- a/source/blender/python/intern/bpy_app_sdl.c +++ b/source/blender/python/intern/bpy_app_sdl.c @@ -29,6 +29,8 @@ #include "bpy_app_sdl.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_SDL /* SDL force defines __SSE__ and __SSE2__ flags, which generates warnings * because we pass those defines via command line as well. For until there's @@ -103,7 +105,7 @@ static PyObject *make_sdl_info(void) # endif # endif - SetObjItem(Py_BuildValue("(iii)", version.major, version.minor, version.patch)); + SetObjItem(PyC_Tuple_Pack_I32(version.major, version.minor, version.patch)); if (sdl_available) { SetObjItem(PyUnicode_FromFormat("%d.%d.%d", version.major, version.minor, version.patch)); } @@ -114,7 +116,7 @@ static PyObject *make_sdl_info(void) #else // WITH_SDL=OFF SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); SetObjItem(PyBool_FromLong(0)); #endif diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 7b0daa91523..20cfd364a0c 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -869,6 +869,7 @@ static void bpy_module_delay_init(PyObject *bpy_proxy) BLI_strncpy(filename_abs, filename_rel, sizeof(filename_abs)); BLI_path_cwd(filename_abs, sizeof(filename_abs)); + Py_DECREF(filename_obj); argv[0] = filename_abs; argv[1] = NULL; diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 15f3c665fcf..cb6a7147368 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -73,7 +73,7 @@ typedef struct { } BPy_Library; static PyObject *bpy_lib_load(PyObject *self, PyObject *args, PyObject *kwds); -static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *args); +static PyObject *bpy_lib_enter(BPy_Library *self); static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *args); static PyObject *bpy_lib_dir(BPy_Library *self); @@ -237,7 +237,7 @@ static PyObject *_bpy_names(BPy_Library *self, int blocktype) return list; } -static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *UNUSED(args)) +static PyObject *bpy_lib_enter(BPy_Library *self) { PyObject *ret; BPy_Library *self_from; diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index 90719905a79..9d57adca946 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -48,10 +48,12 @@ static void operator_properties_init(wmOperatorType *ot) PyTypeObject *py_class = ot->ext.data; RNA_struct_blender_type_set(ot->ext.srna, ot); - /* only call this so pyrna_deferred_register_class gives a useful error - * WM_operatortype_append_ptr will call RNA_def_struct_identifier - * later */ - RNA_def_struct_identifier(ot->srna, ot->idname); + /* Only call this so pyrna_deferred_register_class gives a useful error + * WM_operatortype_append_ptr will call RNA_def_struct_identifier later. + * + * Note the 'no_struct_map' function is used since the actual struct name is already used by the operator. + */ + RNA_def_struct_identifier_no_struct_map(ot->srna, ot->idname); if (pyrna_deferred_register_class(ot->srna, py_class) != 0) { PyErr_Print(); /* failed to register operator props */ diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index c7787ba9682..9ef8f9aa046 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -320,7 +320,7 @@ static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p value = false; } else { - value = PyLong_AsLong(ret); + value = PyC_Long_AsI32(ret); if (value == -1 && PyErr_Occurred()) { printf_func_error(py_func); @@ -530,12 +530,8 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct Propert self = pyrna_struct_as_instance(ptr); PyTuple_SET_ITEM(args, 0, self); - py_values = PyC_FromArray(values, len, &PyBool_Type, false, "BoolVectorProperty set"); - if (!py_values) { - printf_func_error(py_func); - } - else - PyTuple_SET_ITEM(args, 1, py_values); + py_values = PyC_Tuple_PackArray_I32FromBool(values, len); + PyTuple_SET_ITEM(args, 1, py_values); ret = PyObject_CallObject(py_func, args); @@ -599,7 +595,7 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop) value = 0.0f; } else { - value = PyLong_AsLong(ret); + value = PyC_Long_AsI32(ret); if (value == -1 && PyErr_Occurred()) { printf_func_error(py_func); @@ -764,12 +760,8 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA self = pyrna_struct_as_instance(ptr); PyTuple_SET_ITEM(args, 0, self); - py_values = PyC_FromArray(values, len, &PyLong_Type, false, "IntVectorProperty set"); - if (!py_values) { - printf_func_error(py_func); - } - else - PyTuple_SET_ITEM(args, 1, py_values); + py_values = PyC_Tuple_PackArray_I32(values, len); + PyTuple_SET_ITEM(args, 1, py_values); ret = PyObject_CallObject(py_func, args); @@ -998,12 +990,8 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyR self = pyrna_struct_as_instance(ptr); PyTuple_SET_ITEM(args, 0, self); - py_values = PyC_FromArray(values, len, &PyFloat_Type, false, "FloatVectorProperty set"); - if (!py_values) { - printf_func_error(py_func); - } - else - PyTuple_SET_ITEM(args, 1, py_values); + py_values = PyC_Tuple_PackArray_F32(values, len); + PyTuple_SET_ITEM(args, 1, py_values); ret = PyObject_CallObject(py_func, args); @@ -1249,7 +1237,7 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop value = RNA_property_enum_get_default(ptr, prop); } else { - value = PyLong_AsLong(ret); + value = PyC_Long_AsI32(ret); if (value == -1 && PyErr_Occurred()) { printf_func_error(py_func); @@ -2697,7 +2685,8 @@ PyDoc_STRVAR(BPy_EnumProperty_doc, " :icon: An icon string identifier or integer icon value\n" " (e.g. returned by :class:`bpy.types.UILayout.icon`)\n" " :number: Unique value used as the identifier for this item (stored in file data).\n" -" Use when the identifier may need to change.\n" +" Use when the identifier may need to change. If the *ENUM_FLAG* option is used,\n" +" the values are bitmasks and should be powers of two.\n" "\n" " When an item only contains 4 items they define ``(identifier, name, description, number)``.\n" "\n" @@ -2891,7 +2880,7 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) PyObject *update_cb = NULL, *poll_cb = NULL; if (!PyArg_ParseTupleAndKeywords(args, kw, - "s#O|ssO!OOO:PointerProperty", + "s#O|ssO!OO:PointerProperty", (char **)kwlist, &id, &id_len, &type, &name, &description, &PySet_Type, &pyopts, diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index eda880d4dce..398d2631f6c 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -70,6 +70,8 @@ #include "BKE_report.h" #include "BKE_idprop.h" +/* only for types */ +#include "BKE_node.h" #include "../generic/idprop_py_api.h" /* for IDprop lookups */ #include "../generic/py_capi_utils.h" @@ -1395,7 +1397,7 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val) } else { EnumPropertyItem *enum_item; - bool free = false; + bool free; /* don't throw error here, can't trust blender 100% to give the * right values, python code should not generate error for that */ @@ -1404,6 +1406,9 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val) ret = PyUnicode_FromString(enum_item->identifier); } else { + if (free) { + MEM_freeN(enum_item); + } RNA_property_enum_items(NULL, ptr, prop, &enum_item, NULL, &free); /* Do not print warning in case of DummyRNA_NULL_items, this one will never match any value... */ @@ -1640,7 +1645,7 @@ static int pyrna_py_to_prop( param = PyObject_IsTrue(value); } else { - param = PyLong_AsLong(value); + param = PyC_Long_AsI32(value); if (UNLIKELY(param & ~1)) { /* only accept 0/1 */ param = -1; /* error out below */ @@ -2076,10 +2081,10 @@ static int pyrna_py_to_prop_array_index(BPy_PropertyArrayRNA *self, int index, P switch (RNA_property_type(prop)) { case PROP_BOOLEAN: { - int param = PyLong_AsLong(value); + int param = PyC_Long_AsBool(value); - if (param < 0 || param > 1) { - PyErr_SetString(PyExc_TypeError, "expected True/False or 0/1"); + if (param == -1) { + /* error is set */ ret = -1; } else { @@ -2089,7 +2094,7 @@ static int pyrna_py_to_prop_array_index(BPy_PropertyArrayRNA *self, int index, P } case PROP_INT: { - int param = PyLong_AsLong(value); + int param = PyC_Long_AsI32(value); if (param == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "expected an int type"); ret = -1; @@ -2709,7 +2714,7 @@ static PyObject *pyrna_prop_array_subscript(BPy_PropertyArrayRNA *self, PyObject Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; - return pyrna_prop_array_subscript_int(self, PyLong_AsLong(key)); + return pyrna_prop_array_subscript_int(self, i); } else if (PySlice_Check(key)) { Py_ssize_t step = 1; @@ -3704,6 +3709,110 @@ static PyObject *pyrna_struct_type_recast(BPy_StructRNA *self) return pyrna_struct_CreatePyObject(&r_ptr); } +/** + * \note Return value is borrowed, caller must incref. + */ +static PyObject *pyrna_struct_bl_rna_find_subclass_recursive(PyObject *cls, const char *id) +{ + PyObject *ret_test = NULL; + PyObject *subclasses = ((PyTypeObject *)cls)->tp_subclasses; + if (subclasses) { + /* Unfortunately we can't use the dict key because Python class names + * don't match the bl_idname used internally. */ + BLI_assert(PyDict_CheckExact(subclasses)); + PyObject *key = NULL; + Py_ssize_t pos = 0; + PyObject *value = NULL; + while (PyDict_Next(subclasses, &pos, &key, &value)) { + BLI_assert(PyWeakref_CheckRef(value)); + PyObject *subcls = PyWeakref_GET_OBJECT(value); + if (subcls != Py_None) { + BPy_StructRNA *py_srna = (BPy_StructRNA *)PyDict_GetItem( + ((PyTypeObject *)subcls)->tp_dict, bpy_intern_str_bl_rna); + if (py_srna) { + StructRNA *srna = py_srna->ptr.data; + if (STREQ(id, RNA_struct_identifier(srna))) { + ret_test = subcls; + break; + } + } + ret_test = pyrna_struct_bl_rna_find_subclass_recursive(subcls, id); + if (ret_test) { + break; + } + } + } + } + return ret_test; +} + +PyDoc_STRVAR(pyrna_struct_bl_rna_get_subclass_py_doc, +".. classmethod:: bl_rna_get_subclass_py(id, default=None)\n" +"\n" +" :arg id: The RNA type identifier.\n" +" :type id: string\n" +" :return: The class or default when not found.\n" +" :rtype: type\n" +); +static PyObject *pyrna_struct_bl_rna_get_subclass_py(PyObject *cls, PyObject *args) +{ + char *id; + PyObject *ret_default = Py_None; + + if (!PyArg_ParseTuple(args, "s|O:bl_rna_get_subclass_py", &id, &ret_default)) { + return NULL; + } + PyObject *ret = pyrna_struct_bl_rna_find_subclass_recursive(cls, id); + if (ret == NULL) { + ret = ret_default; + } + return Py_INCREF_RET(ret); +} + +PyDoc_STRVAR(pyrna_struct_bl_rna_get_subclass_doc, +".. classmethod:: bl_rna_get_subclass(id, default=None)\n" +"\n" +" :arg id: The RNA type identifier.\n" +" :type id: string\n" +" :return: The RNA type or default when not found.\n" +" :rtype: :class:`bpy.types.Struct` subclass\n" +); +static PyObject *pyrna_struct_bl_rna_get_subclass(PyObject *cls, PyObject *args) +{ + char *id; + PyObject *ret_default = Py_None; + + if (!PyArg_ParseTuple(args, "s|O:bl_rna_get_subclass", &id, &ret_default)) { + return NULL; + } + + + const BPy_StructRNA *py_srna = (BPy_StructRNA *)PyDict_GetItem(((PyTypeObject *)cls)->tp_dict, bpy_intern_str_bl_rna); + if (py_srna == NULL) { + PyErr_SetString(PyExc_ValueError, "Not a registered class"); + return NULL; + + } + const StructRNA *srna_base = py_srna->ptr.data; + + PointerRNA ptr; + if (srna_base == &RNA_Node) { + bNodeType *nt = nodeTypeFind(id); + if (nt) { + RNA_pointer_create(NULL, &RNA_Struct, nt->ext.srna, &ptr); + return pyrna_struct_CreatePyObject(&ptr); + } + } + else { + /* TODO, panels, menus etc. */ + PyErr_Format(PyExc_ValueError, "Class type \"%.200s\" not supported", + RNA_struct_identifier(srna_base)); + return NULL; + } + + return Py_INCREF_RET(ret_default); +} + static void pyrna_dir_members_py__add_keys(PyObject *list, PyObject *dict) { PyObject *list_tmp; @@ -5002,6 +5111,8 @@ static struct PyMethodDef pyrna_struct_methods[] = { {"path_resolve", (PyCFunction)pyrna_struct_path_resolve, METH_VARARGS, pyrna_struct_path_resolve_doc}, {"path_from_id", (PyCFunction)pyrna_struct_path_from_id, METH_VARARGS, pyrna_struct_path_from_id_doc}, {"type_recast", (PyCFunction)pyrna_struct_type_recast, METH_NOARGS, pyrna_struct_type_recast_doc}, + {"bl_rna_get_subclass_py", (PyCFunction) pyrna_struct_bl_rna_get_subclass_py, METH_VARARGS | METH_CLASS, pyrna_struct_bl_rna_get_subclass_py_doc}, + {"bl_rna_get_subclass", (PyCFunction) pyrna_struct_bl_rna_get_subclass, METH_VARARGS | METH_CLASS, pyrna_struct_bl_rna_get_subclass_doc}, {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, NULL}, /* experimental */ @@ -6924,15 +7035,7 @@ static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self) RNA_PROP_BEGIN (&self->ptr, itemptr, self->prop) { StructRNA *srna = itemptr.data; - StructRNA *srna_base = RNA_struct_base(itemptr.data); - /* skip own operators, these double up [#29666] */ - if (srna_base == &RNA_Operator) { - /* do nothing */ - } - else { - /* add to python list */ - PyList_APPEND(ret, PyUnicode_FromString(RNA_struct_identifier(srna))); - } + PyList_APPEND(ret, PyUnicode_FromString(RNA_struct_identifier(srna))); } RNA_PROP_END; diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c index 38931cd85de..3e147d29c90 100644 --- a/source/blender/python/intern/bpy_rna_array.c +++ b/source/blender/python/intern/bpy_rna_array.c @@ -38,6 +38,8 @@ #include "RNA_access.h" +#include "../generic/py_capi_utils.h" + #define USE_MATHUTILS #ifdef USE_MATHUTILS @@ -550,7 +552,7 @@ static void py_to_float(const struct ItemConvertArgData *arg, PyObject *py, char static void py_to_int(const struct ItemConvertArgData *arg, PyObject *py, char *data) { const int *range = arg->int_data.range; - int value = (int)PyLong_AsLong(py); + int value = PyC_Long_AsI32(py); CLAMP(value, range[0], range[1]); *(int *)data = value; } diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c index b4c0de51c04..1135ba121e3 100644 --- a/source/blender/python/intern/bpy_rna_driver.c +++ b/source/blender/python/intern/bpy_rna_driver.c @@ -63,7 +63,15 @@ PyObject *pyrna_driver_get_variable_value( } else { /* object & property */ - driver_arg = pyrna_prop_to_py(&ptr, prop); + PropertyType type = RNA_property_type(prop); + if (type == PROP_ENUM) { + /* Note that enum's are converted to strings by default, + * we want to avoid that, see: T52213 */ + driver_arg = PyLong_FromLong(RNA_property_enum_get(&ptr, prop)); + } + else { + driver_arg = pyrna_prop_to_py(&ptr, prop); + } } } else { diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c index 7711ce18bd0..3c340d14e3f 100644 --- a/source/blender/python/intern/gpu_offscreen.c +++ b/source/blender/python/intern/gpu_offscreen.c @@ -144,36 +144,6 @@ static PyObject *pygpu_offscreen_unbind(BPy_GPUOffScreen *self, PyObject *args, Py_RETURN_NONE; } -/** - * Use with PyArg_ParseTuple's "O&" formatting. - */ -static int pygpu_offscreen_check_matrix(PyObject *o, void *p) -{ - MatrixObject **pymat_p = p; - MatrixObject *pymat = (MatrixObject *)o; - - if (!MatrixObject_Check(pymat)) { - PyErr_Format(PyExc_TypeError, - "expected a mathutils.Matrix, not a %.200s", - Py_TYPE(o)->tp_name); - return 0; - } - - if (BaseMath_ReadCallback(pymat) == -1) { - return 0; - } - - if ((pymat->num_col != 4) || - (pymat->num_row != 4)) - { - PyErr_SetString(PyExc_ValueError, "matrix must be 4x4"); - return 0; - } - - *pymat_p = pymat; - return 1; -} - PyDoc_STRVAR(pygpu_offscreen_draw_view3d_doc, "draw_view3d(scene, view3d, region, modelview_matrix, projection_matrix)\n" "\n" @@ -209,8 +179,8 @@ static PyObject *pygpu_offscreen_draw_view3d(BPy_GPUOffScreen *self, PyObject *a if (!PyArg_ParseTupleAndKeywords( args, kwds, "OOOO&O&:draw_view3d", (char **)(kwlist), &py_scene, &py_view3d, &py_region, - pygpu_offscreen_check_matrix, &py_mat_projection, - pygpu_offscreen_check_matrix, &py_mat_modelview) || + Matrix_Parse4x4, &py_mat_projection, + Matrix_Parse4x4, &py_mat_modelview) || (!(scene = PyC_RNA_AsPointer(py_scene, "Scene")) || !(v3d = PyC_RNA_AsPointer(py_view3d, "SpaceView3D")) || !(ar = PyC_RNA_AsPointer(py_region, "Region")))) diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c index 1afb1d7be90..96ae0a9e50f 100644 --- a/source/blender/python/mathutils/mathutils.c +++ b/source/blender/python/mathutils/mathutils.c @@ -554,8 +554,8 @@ char BaseMathObject_freeze_doc[] = ; PyObject *BaseMathObject_freeze(BaseMathObject *self) { - if (self->flag & BASE_MATH_FLAG_IS_WRAP) { - PyErr_SetString(PyExc_TypeError, "Cannot freeze wrapped data"); + if ((self->flag & BASE_MATH_FLAG_IS_WRAP) || (self->cb_user != NULL)) { + PyErr_SetString(PyExc_TypeError, "Cannot freeze wrapped/owned data"); return NULL; } diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h index 6ac75565c66..d1fb6dcdb82 100644 --- a/source/blender/python/mathutils/mathutils.h +++ b/source/blender/python/mathutils/mathutils.h @@ -41,9 +41,18 @@ extern char BaseMathObject_owner_doc[]; (struct_name *)((base_type ? (base_type)->tp_alloc(base_type, 0) : _PyObject_GC_New(&(root_type)))); -/* BaseMathObject.flag */ +/** BaseMathObject.flag */ enum { + /** + * Do not own the memory used in this vector, + * \note This is error prone if the memory may be freed while this vector is in use. + * Prefer using callbacks where possible, see: #Mathutils_RegisterCallback + */ BASE_MATH_FLAG_IS_WRAP = (1 << 0), + /** + * Prevent changes to the vector so it can be used as a set or dictionary key for example. + * (typical use cases for tuple). + */ BASE_MATH_FLAG_IS_FROZEN = (1 << 1), }; #define BASE_MATH_FLAG_DEFAULT 0 diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index e368e8871f3..2578b19d5ec 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -2914,6 +2914,73 @@ PyObject *Matrix_CreatePyObject_cb(PyObject *cb_user, return (PyObject *) self; } +/** + * Use with PyArg_ParseTuple's "O&" formatting. + */ +static bool Matrix_ParseCheck(MatrixObject *pymat) +{ + if (!MatrixObject_Check(pymat)) { + PyErr_Format(PyExc_TypeError, + "expected a mathutils.Matrix, not a %.200s", + Py_TYPE(pymat)->tp_name); + return 0; + } + /* sets error */ + if (BaseMath_ReadCallback(pymat) == -1) { + return 0; + } + return 1; +} + +int Matrix_ParseAny(PyObject *o, void *p) +{ + MatrixObject **pymat_p = p; + MatrixObject *pymat = (MatrixObject *)o; + + if (!Matrix_ParseCheck(pymat)) { + return 0; + } + *pymat_p = pymat; + return 1; +} + +int Matrix_Parse3x3(PyObject *o, void *p) +{ + MatrixObject **pymat_p = p; + MatrixObject *pymat = (MatrixObject *)o; + + if (!Matrix_ParseCheck(pymat)) { + return 0; + } + if ((pymat->num_col != 3) || + (pymat->num_row != 3)) + { + PyErr_SetString(PyExc_ValueError, "matrix must be 3x3"); + return 0; + } + + *pymat_p = pymat; + return 1; +} + +int Matrix_Parse4x4(PyObject *o, void *p) +{ + MatrixObject **pymat_p = p; + MatrixObject *pymat = (MatrixObject *)o; + + if (!Matrix_ParseCheck(pymat)) { + return 0; + } + if ((pymat->num_col != 4) || + (pymat->num_row != 4)) + { + PyErr_SetString(PyExc_ValueError, "matrix must be 4x4"); + return 0; + } + + *pymat_p = pymat; + return 1; +} /* ---------------------------------------------------------------------------- * special type for alternate access */ diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h index 542a0e349c7..9c84716d307 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.h +++ b/source/blender/python/mathutils/mathutils_Matrix.h @@ -77,6 +77,11 @@ PyObject *Matrix_CreatePyObject_cb( unsigned char cb_type, unsigned char cb_subtype ) ATTR_WARN_UNUSED_RESULT; +/* PyArg_ParseTuple's "O&" formatting helpers. */ +int Matrix_ParseAny(PyObject *o, void *p); +int Matrix_Parse3x3(PyObject *o, void *p); +int Matrix_Parse4x4(PyObject *o, void *p); + extern unsigned char mathutils_matrix_row_cb_index; /* default */ extern unsigned char mathutils_matrix_col_cb_index; extern unsigned char mathutils_matrix_translation_cb_index; diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index afc8a30a6b5..65450505e08 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -32,10 +32,17 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "../generic/py_capi_utils.h" + #ifndef MATH_STANDALONE # include "BLI_dynstr.h" #endif +/** + * Higher dimensions are supported, for many common operations + * (dealing with vector/matrix multiply or handling as 3D locations) + * stack memory is used with a fixed size - defined here. + */ #define MAX_DIMENSIONS 4 /* Swizzle axes get packed into a single value that is used as a closure. Each @@ -50,7 +57,8 @@ static PyObject *Vector_deepcopy(VectorObject *self, PyObject *args); static PyObject *Vector_to_tuple_ext(VectorObject *self, int ndigits); static int row_vector_multiplication(float rvec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat); -/* Supports 2D, 3D, and 4D vector objects both int and float values +/** + * Supports 2D, 3D, and 4D vector objects both int and float values * accepted. Mixed float and int values accepted. Ints are parsed to float */ static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds) @@ -403,7 +411,7 @@ static PyObject *Vector_resize(VectorObject *self, PyObject *value) return NULL; } - if ((size = PyLong_AsLong(value)) == -1) { + if ((size = PyC_Long_AsI32(value)) == -1) { PyErr_SetString(PyExc_TypeError, "Vector.resize(size): " "expected size argument to be an integer"); @@ -836,9 +844,11 @@ static PyObject *Vector_orthogonal(VectorObject *self) } -/* - * Vector.reflect(mirror): return a reflected vector on the mirror normal - * vec - ((2 * DotVecs(vec, mirror)) * mirror) +/** + * Vector.reflect(mirror): return a reflected vector on the mirror normal. + * <pre> + * vec - ((2 * dot(vec, mirror)) * mirror) + * </pre> */ PyDoc_STRVAR(Vector_reflect_doc, ".. method:: reflect(mirror)\n" @@ -1644,13 +1654,16 @@ static PyObject *Vector_isub(PyObject *v1, PyObject *v2) * multiplication */ -/* COLUMN VECTOR Multiplication (Matrix X Vector) +/** + * column vector multiplication (Matrix * Vector) + * <pre> * [1][4][7] [a] * [2][5][8] * [b] * [3][6][9] [c] + * </pre> * - * note: vector/matrix multiplication IS NOT COMMUTATIVE!!!! - * note: assume read callbacks have been done first. + * \note Vector/Matrix multiplication is not commutative. + * \note Assume read callbacks have been done first. */ int column_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat) { @@ -2199,9 +2212,67 @@ static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(clos return PyFloat_FromDouble(dot_vn_vn(self->vec, self->vec, self->size)); } -/* Get a new Vector according to the provided swizzle. This function has little - * error checking, as we are in control of the inputs: the closure is set by us - * in Vector_createSwizzleGetSeter. */ + +/** + * Python script used to make swizzle array: + * + * \code{.py} + * SWIZZLE_BITS_PER_AXIS = 3 + * SWIZZLE_VALID_AXIS = 0x4 + * + * axis_dict = {} + * axis_pos = {'x': 0, 'y': 1, 'z': 2, 'w': 3} + * axises = 'xyzw' + * while len(axises) >= 2: + * for axis_0 in axises: + * axis_0_pos = axis_pos[axis_0] + * for axis_1 in axises: + * axis_1_pos = axis_pos[axis_1] + * axis_dict[axis_0 + axis_1] = ( + * '((%s | SWIZZLE_VALID_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS))' % + * (axis_0_pos, axis_1_pos)) + * if len(axises) > 2: + * for axis_2 in axises: + * axis_2_pos = axis_pos[axis_2] + * axis_dict[axis_0 + axis_1 + axis_2] = ( + * '((%s | SWIZZLE_VALID_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))' % + * (axis_0_pos, axis_1_pos, axis_2_pos)) + * if len(axises) > 3: + * for axis_3 in axises: + * axis_3_pos = axis_pos[axis_3] + * axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = ( + * '((%s | SWIZZLE_VALID_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ' + * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) ' % + * (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos)) + * + * axises = axises[:-1] + * + * + * items = list(axis_dict.items()) + * items.sort(key=lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3')) + * + * unique = set() + * for key, val in items: + * num = eval(val) + * set_str = 'Vector_swizzle_set' if (len(set(key)) == len(key)) else 'NULL' + * key_args = ', '.join(["'%s'" % c for c in key.upper()]) + * print('\t{(char *)"%s", %s(getter)Vector_swizzle_get, (setter)%s, NULL, SWIZZLE%d(%s)},' % + * (key, (' ' * (4 - len(key))), set_str, len(key), key_args)) + * unique.add(num) + * + * if len(unique) != len(items): + * print("ERROR, duplicate values found") + * \endcode + */ + +/** + * Get a new Vector according to the provided swizzle bits. + */ static PyObject *Vector_swizzle_get(VectorObject *self, void *closure) { size_t axis_to; @@ -2232,7 +2303,8 @@ static PyObject *Vector_swizzle_get(VectorObject *self, void *closure) return Vector_CreatePyObject(vec, axis_to, Py_TYPE(self)); } -/* Set the items of this vector using a swizzle. +/** + * Set the items of this vector using a swizzle. * - If value is a vector or list this operates like an array copy, except that * the destination is effectively re-ordered as defined by the swizzle. At * most min(len(source), len(dest)) values will be copied. @@ -2240,8 +2312,8 @@ static PyObject *Vector_swizzle_get(VectorObject *self, void *closure) * - If an axis appears more than once in the swizzle, the final occurrence is * the one that determines its value. * - * Returns 0 on success and -1 on failure. On failure, the vector will be - * unchanged. */ + * \return 0 on success and -1 on failure. On failure, the vector will be unchanged. + */ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure) { size_t size_from; @@ -2324,19 +2396,14 @@ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure return 0; } -/* XYZW -> 0123 */ -#define AXIS_FROM_CHAR(a) (((a) != 'W') ? ((a) - 'X') : 3) - -#define _VA_SWIZZLE_1(a) ( \ - ((AXIS_FROM_CHAR(a) | SWIZZLE_VALID_AXIS))) -#define _VA_SWIZZLE_2(a, b) (_VA_SWIZZLE_1(a) | \ - ((AXIS_FROM_CHAR(b) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS))) -#define _VA_SWIZZLE_3(a, b, c) (_VA_SWIZZLE_2(a, b) | \ - ((AXIS_FROM_CHAR(c) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))) -#define _VA_SWIZZLE_4(a, b, c, d) (_VA_SWIZZLE_3(a, b, c) | \ - ((AXIS_FROM_CHAR(d) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) +#define _SWIZZLE1(a) ((a) | SWIZZLE_VALID_AXIS) +#define _SWIZZLE2(a, b) (_SWIZZLE1(a) | (((b) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS))) +#define _SWIZZLE3(a, b, c) (_SWIZZLE2(a, b) | (((c) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))) +#define _SWIZZLE4(a, b, c, d) (_SWIZZLE3(a, b, c) | (((d) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) -#define SWIZZLE(...) SET_INT_IN_POINTER(VA_NARGS_CALL_OVERLOAD(_VA_SWIZZLE_, __VA_ARGS__)) +#define SWIZZLE2(a, b) SET_INT_IN_POINTER(_SWIZZLE2(a, b)) +#define SWIZZLE3(a, b, c) SET_INT_IN_POINTER(_SWIZZLE3(a, b, c)) +#define SWIZZLE4(a, b, c, d) SET_INT_IN_POINTER(_SWIZZLE4(a, b, c, d)) /*****************************************************************************/ /* Python attributes get/set structure: */ @@ -2353,416 +2420,366 @@ static PyGetSetDef Vector_getseters[] = { {(char *)"is_frozen", (getter)BaseMathObject_is_frozen_get, (setter)NULL, BaseMathObject_is_frozen_doc, NULL}, {(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL}, - /* autogenerated swizzle attrs, see python script below */ - {(char *)"xx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X')}, - {(char *)"xxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X')}, - {(char *)"xxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'X')}, - {(char *)"xxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'Y')}, - {(char *)"xxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'Z')}, - {(char *)"xxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'W')}, - {(char *)"xxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y')}, - {(char *)"xxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'X')}, - {(char *)"xxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'Y')}, - {(char *)"xxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'Z')}, - {(char *)"xxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'W')}, - {(char *)"xxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z')}, - {(char *)"xxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'X')}, - {(char *)"xxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'Y')}, - {(char *)"xxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'Z')}, - {(char *)"xxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'W')}, - {(char *)"xxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W')}, - {(char *)"xxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'X')}, - {(char *)"xxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'Y')}, - {(char *)"xxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'Z')}, - {(char *)"xxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'W')}, - {(char *)"xy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y')}, - {(char *)"xyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X')}, - {(char *)"xyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'X')}, - {(char *)"xyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'Y')}, - {(char *)"xyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'Z')}, - {(char *)"xyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'W')}, - {(char *)"xyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y')}, - {(char *)"xyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'X')}, - {(char *)"xyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'Y')}, - {(char *)"xyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'Z')}, - {(char *)"xyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'W')}, - {(char *)"xyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'Z')}, - {(char *)"xyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'X')}, - {(char *)"xyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'Y')}, - {(char *)"xyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'Z')}, - {(char *)"xyzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'Z', 'W')}, - {(char *)"xyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'W')}, - {(char *)"xywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'X')}, - {(char *)"xywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'Y')}, - {(char *)"xywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'W', 'Z')}, - {(char *)"xyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'W')}, - {(char *)"xz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z')}, - {(char *)"xzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X')}, - {(char *)"xzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'X')}, - {(char *)"xzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'Y')}, - {(char *)"xzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'Z')}, - {(char *)"xzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'W')}, - {(char *)"xzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'Y')}, - {(char *)"xzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'X')}, - {(char *)"xzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'Y')}, - {(char *)"xzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'Z')}, - {(char *)"xzyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'Y', 'W')}, - {(char *)"xzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z')}, - {(char *)"xzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'X')}, - {(char *)"xzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'Y')}, - {(char *)"xzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'Z')}, - {(char *)"xzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'W')}, - {(char *)"xzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'W')}, - {(char *)"xzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'X')}, - {(char *)"xzwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'W', 'Y')}, - {(char *)"xzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'Z')}, - {(char *)"xzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'W')}, - {(char *)"xw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W')}, - {(char *)"xwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X')}, - {(char *)"xwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'X')}, - {(char *)"xwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'Y')}, - {(char *)"xwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'Z')}, - {(char *)"xwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'W')}, - {(char *)"xwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Y')}, - {(char *)"xwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'X')}, - {(char *)"xwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'Y')}, - {(char *)"xwyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Y', 'Z')}, - {(char *)"xwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'W')}, - {(char *)"xwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Z')}, - {(char *)"xwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'X')}, - {(char *)"xwzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Z', 'Y')}, - {(char *)"xwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'Z')}, - {(char *)"xwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'W')}, - {(char *)"xww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W')}, - {(char *)"xwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'X')}, - {(char *)"xwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'Y')}, - {(char *)"xwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'Z')}, - {(char *)"xwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'W')}, - {(char *)"yx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X')}, - {(char *)"yxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X')}, - {(char *)"yxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'X')}, - {(char *)"yxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'Y')}, - {(char *)"yxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'Z')}, - {(char *)"yxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'W')}, - {(char *)"yxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y')}, - {(char *)"yxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'X')}, - {(char *)"yxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'Y')}, - {(char *)"yxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'Z')}, - {(char *)"yxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'W')}, - {(char *)"yxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'Z')}, - {(char *)"yxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'X')}, - {(char *)"yxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'Y')}, - {(char *)"yxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'Z')}, - {(char *)"yxzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'Z', 'W')}, - {(char *)"yxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'W')}, - {(char *)"yxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'X')}, - {(char *)"yxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'Y')}, - {(char *)"yxwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'W', 'Z')}, - {(char *)"yxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'W')}, - {(char *)"yy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y')}, - {(char *)"yyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X')}, - {(char *)"yyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'X')}, - {(char *)"yyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'Y')}, - {(char *)"yyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'Z')}, - {(char *)"yyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'W')}, - {(char *)"yyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y')}, - {(char *)"yyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'X')}, - {(char *)"yyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'Y')}, - {(char *)"yyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'Z')}, - {(char *)"yyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'W')}, - {(char *)"yyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z')}, - {(char *)"yyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'X')}, - {(char *)"yyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'Y')}, - {(char *)"yyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'Z')}, - {(char *)"yyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'W')}, - {(char *)"yyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W')}, - {(char *)"yywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'X')}, - {(char *)"yywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'Y')}, - {(char *)"yywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'Z')}, - {(char *)"yyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'W')}, - {(char *)"yz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z')}, - {(char *)"yzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'X')}, - {(char *)"yzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'X')}, - {(char *)"yzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'Y')}, - {(char *)"yzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'Z')}, - {(char *)"yzxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'X', 'W')}, - {(char *)"yzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y')}, - {(char *)"yzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'X')}, - {(char *)"yzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'Y')}, - {(char *)"yzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'Z')}, - {(char *)"yzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'W')}, - {(char *)"yzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z')}, - {(char *)"yzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'X')}, - {(char *)"yzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'Y')}, - {(char *)"yzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'Z')}, - {(char *)"yzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'W')}, - {(char *)"yzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'W')}, - {(char *)"yzwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'W', 'X')}, - {(char *)"yzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'Y')}, - {(char *)"yzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'Z')}, - {(char *)"yzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'W')}, - {(char *)"yw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W')}, - {(char *)"ywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'X')}, - {(char *)"ywxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'X')}, - {(char *)"ywxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'Y')}, - {(char *)"ywxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'X', 'Z')}, - {(char *)"ywxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'W')}, - {(char *)"ywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y')}, - {(char *)"ywyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'X')}, - {(char *)"ywyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'Y')}, - {(char *)"ywyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'Z')}, - {(char *)"ywyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'W')}, - {(char *)"ywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'Z')}, - {(char *)"ywzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'Z', 'X')}, - {(char *)"ywzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'Y')}, - {(char *)"ywzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'Z')}, - {(char *)"ywzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'W')}, - {(char *)"yww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W')}, - {(char *)"ywwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'X')}, - {(char *)"ywwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'Y')}, - {(char *)"ywwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'Z')}, - {(char *)"ywww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'W')}, - {(char *)"zx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X')}, - {(char *)"zxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X')}, - {(char *)"zxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'X')}, - {(char *)"zxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'Y')}, - {(char *)"zxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'Z')}, - {(char *)"zxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'W')}, - {(char *)"zxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'Y')}, - {(char *)"zxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'X')}, - {(char *)"zxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'Y')}, - {(char *)"zxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'Z')}, - {(char *)"zxyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'Y', 'W')}, - {(char *)"zxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z')}, - {(char *)"zxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'X')}, - {(char *)"zxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'Y')}, - {(char *)"zxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'Z')}, - {(char *)"zxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'W')}, - {(char *)"zxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'W')}, - {(char *)"zxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'X')}, - {(char *)"zxwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'W', 'Y')}, - {(char *)"zxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'Z')}, - {(char *)"zxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'W')}, - {(char *)"zy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y')}, - {(char *)"zyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'X')}, - {(char *)"zyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'X')}, - {(char *)"zyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'Y')}, - {(char *)"zyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'Z')}, - {(char *)"zyxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'X', 'W')}, - {(char *)"zyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y')}, - {(char *)"zyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'X')}, - {(char *)"zyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'Y')}, - {(char *)"zyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'Z')}, - {(char *)"zyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'W')}, - {(char *)"zyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z')}, - {(char *)"zyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'X')}, - {(char *)"zyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'Y')}, - {(char *)"zyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'Z')}, - {(char *)"zyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'W')}, - {(char *)"zyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'W')}, - {(char *)"zywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'W', 'X')}, - {(char *)"zywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'Y')}, - {(char *)"zywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'Z')}, - {(char *)"zyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'W')}, - {(char *)"zz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z')}, - {(char *)"zzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X')}, - {(char *)"zzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'X')}, - {(char *)"zzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'Y')}, - {(char *)"zzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'Z')}, - {(char *)"zzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'W')}, - {(char *)"zzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y')}, - {(char *)"zzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'X')}, - {(char *)"zzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'Y')}, - {(char *)"zzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'Z')}, - {(char *)"zzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'W')}, - {(char *)"zzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z')}, - {(char *)"zzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'X')}, - {(char *)"zzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'Y')}, - {(char *)"zzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'Z')}, - {(char *)"zzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'W')}, - {(char *)"zzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W')}, - {(char *)"zzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'X')}, - {(char *)"zzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'Y')}, - {(char *)"zzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'Z')}, - {(char *)"zzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'W')}, - {(char *)"zw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W')}, - {(char *)"zwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'X')}, - {(char *)"zwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'X')}, - {(char *)"zwxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'X', 'Y')}, - {(char *)"zwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'Z')}, - {(char *)"zwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'W')}, - {(char *)"zwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'Y')}, - {(char *)"zwyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'Y', 'X')}, - {(char *)"zwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'Y')}, - {(char *)"zwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'Z')}, - {(char *)"zwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'W')}, - {(char *)"zwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z')}, - {(char *)"zwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'X')}, - {(char *)"zwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'Y')}, - {(char *)"zwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'Z')}, - {(char *)"zwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'W')}, - {(char *)"zww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W')}, - {(char *)"zwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'X')}, - {(char *)"zwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'Y')}, - {(char *)"zwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'Z')}, - {(char *)"zwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'W')}, - {(char *)"wx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X')}, - {(char *)"wxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X')}, - {(char *)"wxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'X')}, - {(char *)"wxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'Y')}, - {(char *)"wxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'Z')}, - {(char *)"wxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'W')}, - {(char *)"wxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Y')}, - {(char *)"wxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'X')}, - {(char *)"wxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'Y')}, - {(char *)"wxyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Y', 'Z')}, - {(char *)"wxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'W')}, - {(char *)"wxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Z')}, - {(char *)"wxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'X')}, - {(char *)"wxzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Z', 'Y')}, - {(char *)"wxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'Z')}, - {(char *)"wxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'W')}, - {(char *)"wxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W')}, - {(char *)"wxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'X')}, - {(char *)"wxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'Y')}, - {(char *)"wxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'Z')}, - {(char *)"wxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'W')}, - {(char *)"wy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y')}, - {(char *)"wyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'X')}, - {(char *)"wyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'X')}, - {(char *)"wyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'Y')}, - {(char *)"wyxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'X', 'Z')}, - {(char *)"wyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'W')}, - {(char *)"wyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y')}, - {(char *)"wyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'X')}, - {(char *)"wyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'Y')}, - {(char *)"wyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'Z')}, - {(char *)"wyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'W')}, - {(char *)"wyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'Z')}, - {(char *)"wyzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'Z', 'X')}, - {(char *)"wyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'Y')}, - {(char *)"wyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'Z')}, - {(char *)"wyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'W')}, - {(char *)"wyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W')}, - {(char *)"wywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'X')}, - {(char *)"wywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'Y')}, - {(char *)"wywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'Z')}, - {(char *)"wyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'W')}, - {(char *)"wz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z')}, - {(char *)"wzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'X')}, - {(char *)"wzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'X')}, - {(char *)"wzxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'X', 'Y')}, - {(char *)"wzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'Z')}, - {(char *)"wzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'W')}, - {(char *)"wzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'Y')}, - {(char *)"wzyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'Y', 'X')}, - {(char *)"wzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'Y')}, - {(char *)"wzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'Z')}, - {(char *)"wzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'W')}, - {(char *)"wzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z')}, - {(char *)"wzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'X')}, - {(char *)"wzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'Y')}, - {(char *)"wzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'Z')}, - {(char *)"wzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'W')}, - {(char *)"wzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W')}, - {(char *)"wzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'X')}, - {(char *)"wzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'Y')}, - {(char *)"wzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'Z')}, - {(char *)"wzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'W')}, - {(char *)"ww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W')}, - {(char *)"wwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X')}, - {(char *)"wwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'X')}, - {(char *)"wwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'Y')}, - {(char *)"wwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'Z')}, - {(char *)"wwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'W')}, - {(char *)"wwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y')}, - {(char *)"wwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'X')}, - {(char *)"wwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'Y')}, - {(char *)"wwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'Z')}, - {(char *)"wwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'W')}, - {(char *)"wwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z')}, - {(char *)"wwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'X')}, - {(char *)"wwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'Y')}, - {(char *)"wwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'Z')}, - {(char *)"wwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'W')}, - {(char *)"www", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W')}, - {(char *)"wwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'X')}, - {(char *)"wwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'Y')}, - {(char *)"wwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'Z')}, - {(char *)"wwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'W')}, + /* autogenerated swizzle attrs, see Python script above */ + {(char *)"xx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(0, 0)}, + {(char *)"xxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 0)}, + {(char *)"xxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 0)}, + {(char *)"xxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 1)}, + {(char *)"xxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 2)}, + {(char *)"xxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 3)}, + {(char *)"xxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 1)}, + {(char *)"xxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 0)}, + {(char *)"xxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 1)}, + {(char *)"xxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 2)}, + {(char *)"xxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 3)}, + {(char *)"xxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 2)}, + {(char *)"xxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 0)}, + {(char *)"xxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 1)}, + {(char *)"xxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 2)}, + {(char *)"xxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 3)}, + {(char *)"xxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 3)}, + {(char *)"xxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 0)}, + {(char *)"xxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 1)}, + {(char *)"xxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 2)}, + {(char *)"xxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 3)}, + {(char *)"xy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 1)}, + {(char *)"xyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 1, 0)}, + {(char *)"xyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 0)}, + {(char *)"xyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 1)}, + {(char *)"xyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 2)}, + {(char *)"xyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 3)}, + {(char *)"xyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 1, 1)}, + {(char *)"xyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 0)}, + {(char *)"xyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 1)}, + {(char *)"xyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 2)}, + {(char *)"xyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 3)}, + {(char *)"xyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 1, 2)}, + {(char *)"xyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 0)}, + {(char *)"xyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 1)}, + {(char *)"xyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 2)}, + {(char *)"xyzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 1, 2, 3)}, + {(char *)"xyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 1, 3)}, + {(char *)"xywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 0)}, + {(char *)"xywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 1)}, + {(char *)"xywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 1, 3, 2)}, + {(char *)"xyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 3)}, + {(char *)"xz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 2)}, + {(char *)"xzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 2, 0)}, + {(char *)"xzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 0)}, + {(char *)"xzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 1)}, + {(char *)"xzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 2)}, + {(char *)"xzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 3)}, + {(char *)"xzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 2, 1)}, + {(char *)"xzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 0)}, + {(char *)"xzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 1)}, + {(char *)"xzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 2)}, + {(char *)"xzyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 2, 1, 3)}, + {(char *)"xzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 2, 2)}, + {(char *)"xzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 0)}, + {(char *)"xzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 1)}, + {(char *)"xzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 2)}, + {(char *)"xzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 3)}, + {(char *)"xzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 2, 3)}, + {(char *)"xzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 0)}, + {(char *)"xzwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 2, 3, 1)}, + {(char *)"xzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 2)}, + {(char *)"xzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 3)}, + {(char *)"xw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 3)}, + {(char *)"xwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 3, 0)}, + {(char *)"xwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 0)}, + {(char *)"xwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 1)}, + {(char *)"xwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 2)}, + {(char *)"xwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 3)}, + {(char *)"xwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 3, 1)}, + {(char *)"xwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 0)}, + {(char *)"xwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 1)}, + {(char *)"xwyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 3, 1, 2)}, + {(char *)"xwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 3)}, + {(char *)"xwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 3, 2)}, + {(char *)"xwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 0)}, + {(char *)"xwzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 3, 2, 1)}, + {(char *)"xwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 2)}, + {(char *)"xwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 3)}, + {(char *)"xww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 3, 3)}, + {(char *)"xwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 0)}, + {(char *)"xwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 1)}, + {(char *)"xwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 2)}, + {(char *)"xwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 3)}, + {(char *)"yx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 0)}, + {(char *)"yxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 0, 0)}, + {(char *)"yxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 0)}, + {(char *)"yxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 1)}, + {(char *)"yxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 2)}, + {(char *)"yxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 3)}, + {(char *)"yxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 0, 1)}, + {(char *)"yxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 0)}, + {(char *)"yxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 1)}, + {(char *)"yxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 2)}, + {(char *)"yxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 3)}, + {(char *)"yxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 0, 2)}, + {(char *)"yxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 0)}, + {(char *)"yxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 1)}, + {(char *)"yxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 2)}, + {(char *)"yxzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 0, 2, 3)}, + {(char *)"yxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 0, 3)}, + {(char *)"yxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 0)}, + {(char *)"yxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 1)}, + {(char *)"yxwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 0, 3, 2)}, + {(char *)"yxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 3)}, + {(char *)"yy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(1, 1)}, + {(char *)"yyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 0)}, + {(char *)"yyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 0)}, + {(char *)"yyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 1)}, + {(char *)"yyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 2)}, + {(char *)"yyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 3)}, + {(char *)"yyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 1)}, + {(char *)"yyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 0)}, + {(char *)"yyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 1)}, + {(char *)"yyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 2)}, + {(char *)"yyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 3)}, + {(char *)"yyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 2)}, + {(char *)"yyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 0)}, + {(char *)"yyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 1)}, + {(char *)"yyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 2)}, + {(char *)"yyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 3)}, + {(char *)"yyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 3)}, + {(char *)"yywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 0)}, + {(char *)"yywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 1)}, + {(char *)"yywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 2)}, + {(char *)"yyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 3)}, + {(char *)"yz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 2)}, + {(char *)"yzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 2, 0)}, + {(char *)"yzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 0)}, + {(char *)"yzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 1)}, + {(char *)"yzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 2)}, + {(char *)"yzxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 2, 0, 3)}, + {(char *)"yzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 2, 1)}, + {(char *)"yzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 0)}, + {(char *)"yzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 1)}, + {(char *)"yzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 2)}, + {(char *)"yzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 3)}, + {(char *)"yzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 2, 2)}, + {(char *)"yzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 0)}, + {(char *)"yzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 1)}, + {(char *)"yzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 2)}, + {(char *)"yzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 3)}, + {(char *)"yzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 2, 3)}, + {(char *)"yzwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 2, 3, 0)}, + {(char *)"yzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 1)}, + {(char *)"yzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 2)}, + {(char *)"yzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 3)}, + {(char *)"yw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 3)}, + {(char *)"ywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 3, 0)}, + {(char *)"ywxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 0)}, + {(char *)"ywxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 1)}, + {(char *)"ywxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 3, 0, 2)}, + {(char *)"ywxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 3)}, + {(char *)"ywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 3, 1)}, + {(char *)"ywyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 0)}, + {(char *)"ywyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 1)}, + {(char *)"ywyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 2)}, + {(char *)"ywyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 3)}, + {(char *)"ywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 3, 2)}, + {(char *)"ywzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 3, 2, 0)}, + {(char *)"ywzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 1)}, + {(char *)"ywzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 2)}, + {(char *)"ywzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 3)}, + {(char *)"yww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 3, 3)}, + {(char *)"ywwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 0)}, + {(char *)"ywwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 1)}, + {(char *)"ywwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 2)}, + {(char *)"ywww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 3)}, + {(char *)"zx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 0)}, + {(char *)"zxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 0, 0)}, + {(char *)"zxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 0)}, + {(char *)"zxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 1)}, + {(char *)"zxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 2)}, + {(char *)"zxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 3)}, + {(char *)"zxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 0, 1)}, + {(char *)"zxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 0)}, + {(char *)"zxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 1)}, + {(char *)"zxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 2)}, + {(char *)"zxyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 0, 1, 3)}, + {(char *)"zxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 0, 2)}, + {(char *)"zxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 0)}, + {(char *)"zxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 1)}, + {(char *)"zxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 2)}, + {(char *)"zxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 3)}, + {(char *)"zxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 0, 3)}, + {(char *)"zxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 0)}, + {(char *)"zxwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 0, 3, 1)}, + {(char *)"zxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 2)}, + {(char *)"zxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 3)}, + {(char *)"zy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 1)}, + {(char *)"zyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 1, 0)}, + {(char *)"zyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 0)}, + {(char *)"zyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 1)}, + {(char *)"zyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 2)}, + {(char *)"zyxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 1, 0, 3)}, + {(char *)"zyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 1, 1)}, + {(char *)"zyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 0)}, + {(char *)"zyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 1)}, + {(char *)"zyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 2)}, + {(char *)"zyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 3)}, + {(char *)"zyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 1, 2)}, + {(char *)"zyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 0)}, + {(char *)"zyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 1)}, + {(char *)"zyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 2)}, + {(char *)"zyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 3)}, + {(char *)"zyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 1, 3)}, + {(char *)"zywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 1, 3, 0)}, + {(char *)"zywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 1)}, + {(char *)"zywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 2)}, + {(char *)"zyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 3)}, + {(char *)"zz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(2, 2)}, + {(char *)"zzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 0)}, + {(char *)"zzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 0)}, + {(char *)"zzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 1)}, + {(char *)"zzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 2)}, + {(char *)"zzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 3)}, + {(char *)"zzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 1)}, + {(char *)"zzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 0)}, + {(char *)"zzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 1)}, + {(char *)"zzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 2)}, + {(char *)"zzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 3)}, + {(char *)"zzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 2)}, + {(char *)"zzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 0)}, + {(char *)"zzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 1)}, + {(char *)"zzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 2)}, + {(char *)"zzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 3)}, + {(char *)"zzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 3)}, + {(char *)"zzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 0)}, + {(char *)"zzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 1)}, + {(char *)"zzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 2)}, + {(char *)"zzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 3)}, + {(char *)"zw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 3)}, + {(char *)"zwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 3, 0)}, + {(char *)"zwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 0)}, + {(char *)"zwxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 3, 0, 1)}, + {(char *)"zwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 2)}, + {(char *)"zwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 3)}, + {(char *)"zwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 3, 1)}, + {(char *)"zwyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 3, 1, 0)}, + {(char *)"zwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 1)}, + {(char *)"zwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 2)}, + {(char *)"zwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 3)}, + {(char *)"zwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 3, 2)}, + {(char *)"zwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 0)}, + {(char *)"zwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 1)}, + {(char *)"zwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 2)}, + {(char *)"zwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 3)}, + {(char *)"zww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 3, 3)}, + {(char *)"zwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 0)}, + {(char *)"zwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 1)}, + {(char *)"zwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 2)}, + {(char *)"zwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 3)}, + {(char *)"wx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 0)}, + {(char *)"wxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 0, 0)}, + {(char *)"wxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 0)}, + {(char *)"wxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 1)}, + {(char *)"wxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 2)}, + {(char *)"wxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 3)}, + {(char *)"wxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 0, 1)}, + {(char *)"wxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 0)}, + {(char *)"wxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 1)}, + {(char *)"wxyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 0, 1, 2)}, + {(char *)"wxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 3)}, + {(char *)"wxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 0, 2)}, + {(char *)"wxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 0)}, + {(char *)"wxzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 0, 2, 1)}, + {(char *)"wxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 2)}, + {(char *)"wxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 3)}, + {(char *)"wxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 0, 3)}, + {(char *)"wxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 0)}, + {(char *)"wxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 1)}, + {(char *)"wxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 2)}, + {(char *)"wxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 3)}, + {(char *)"wy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 1)}, + {(char *)"wyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 1, 0)}, + {(char *)"wyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 0)}, + {(char *)"wyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 1)}, + {(char *)"wyxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 1, 0, 2)}, + {(char *)"wyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 3)}, + {(char *)"wyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 1, 1)}, + {(char *)"wyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 0)}, + {(char *)"wyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 1)}, + {(char *)"wyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 2)}, + {(char *)"wyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 3)}, + {(char *)"wyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 1, 2)}, + {(char *)"wyzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 1, 2, 0)}, + {(char *)"wyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 1)}, + {(char *)"wyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 2)}, + {(char *)"wyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 3)}, + {(char *)"wyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 1, 3)}, + {(char *)"wywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 0)}, + {(char *)"wywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 1)}, + {(char *)"wywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 2)}, + {(char *)"wyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 3)}, + {(char *)"wz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 2)}, + {(char *)"wzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 2, 0)}, + {(char *)"wzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 0)}, + {(char *)"wzxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 2, 0, 1)}, + {(char *)"wzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 2)}, + {(char *)"wzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 3)}, + {(char *)"wzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 2, 1)}, + {(char *)"wzyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 2, 1, 0)}, + {(char *)"wzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 1)}, + {(char *)"wzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 2)}, + {(char *)"wzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 3)}, + {(char *)"wzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 2, 2)}, + {(char *)"wzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 0)}, + {(char *)"wzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 1)}, + {(char *)"wzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 2)}, + {(char *)"wzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 3)}, + {(char *)"wzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 2, 3)}, + {(char *)"wzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 0)}, + {(char *)"wzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 1)}, + {(char *)"wzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 2)}, + {(char *)"wzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 3)}, + {(char *)"ww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(3, 3)}, + {(char *)"wwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 0)}, + {(char *)"wwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 0)}, + {(char *)"wwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 1)}, + {(char *)"wwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 2)}, + {(char *)"wwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 3)}, + {(char *)"wwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 1)}, + {(char *)"wwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 0)}, + {(char *)"wwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 1)}, + {(char *)"wwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 2)}, + {(char *)"wwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 3)}, + {(char *)"wwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 2)}, + {(char *)"wwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 0)}, + {(char *)"wwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 1)}, + {(char *)"wwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 2)}, + {(char *)"wwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 3)}, + {(char *)"www", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 3)}, + {(char *)"wwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 0)}, + {(char *)"wwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 1)}, + {(char *)"wwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 2)}, + {(char *)"wwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 3)}, #undef AXIS_FROM_CHAR -#undef SWIZZLE -#undef _VA_SWIZZLE_1 -#undef _VA_SWIZZLE_2 -#undef _VA_SWIZZLE_3 -#undef _VA_SWIZZLE_4 +#undef SWIZZLE1 +#undef SWIZZLE2 +#undef SWIZZLE3 +#undef SWIZZLE4 +#undef _SWIZZLE1 +#undef _SWIZZLE2 +#undef _SWIZZLE3 +#undef _SWIZZLE4 {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; /** - * Python script used to make swizzle array: - * - * \code{.py} - * SWIZZLE_BITS_PER_AXIS = 3 - * SWIZZLE_VALID_AXIS = 0x4 - * - * axis_dict = {} - * axis_pos = {'x': 0, 'y': 1, 'z': 2, 'w': 3} - * axises = 'xyzw' - * while len(axises) >= 2: - * for axis_0 in axises: - * axis_0_pos = axis_pos[axis_0] - * for axis_1 in axises: - * axis_1_pos = axis_pos[axis_1] - * axis_dict[axis_0 + axis_1] = ( - * '((%s | SWIZZLE_VALID_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS))' % - * (axis_0_pos, axis_1_pos)) - * if len(axises) > 2: - * for axis_2 in axises: - * axis_2_pos = axis_pos[axis_2] - * axis_dict[axis_0 + axis_1 + axis_2] = ( - * '((%s | SWIZZLE_VALID_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))' % - * (axis_0_pos, axis_1_pos, axis_2_pos)) - * if len(axises) > 3: - * for axis_3 in axises: - * axis_3_pos = axis_pos[axis_3] - * axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = ( - * '((%s | SWIZZLE_VALID_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ' - * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) ' % - * (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos)) - * - * axises = axises[:-1] - * - * - * items = list(axis_dict.items()) - * items.sort(key=lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3')) - * - * unique = set() - * for key, val in items: - * num = eval(val) - * set_str = 'Vector_swizzle_set' if (len(set(key)) == len(key)) else 'NULL' - * key_args = ', '.join(["'%s'" % c for c in key.upper()]) - * print('\t{(char *)"%s", %s(getter)Vector_swizzle_get, (setter)%s, NULL, SWIZZLE(%s)},' % - * (key, (' ' * (4 - len(key))), set_str, key_args)) - * unique.add(num) - * - * if len(unique) != len(items): - * print("ERROR, duplicate values found") - * \endcode - */ - -/* ROW VECTOR Multiplication - Vector X Matrix + * Row vector multiplication - (Vector * Matrix) + * <pre> * [x][y][z] * [1][4][7] * [2][5][8] * [3][6][9] - * vector/matrix multiplication IS NOT COMMUTATIVE!!!! */ + * </pre> + * \note vector/matrix multiplication is not commutative. + */ static int row_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat) { float vec_cpy[MAX_DIMENSIONS]; @@ -2863,10 +2880,11 @@ static struct PyMethodDef Vector_methods[] = { }; -/* Note - * Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing - * but this means for eg that - * (vec * mat) and (mat * vec) both get sent to Vector_mul and it needs to sort out the order +/** + * Note: + * #Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing + * but this means for eg that (vec * mat) and (mat * vec) + * both get sent to Vector_mul and it needs to sort out the order */ PyDoc_STRVAR(vector_doc, @@ -3010,6 +3028,11 @@ PyObject *Vector_CreatePyObject( return (PyObject *)self; } +/** + * Create a vector that wraps existing memory. + * + * \param vec: Use this vector in-place. + */ PyObject *Vector_CreatePyObject_wrap( float *vec, const int size, PyTypeObject *base_type) @@ -3036,6 +3059,10 @@ PyObject *Vector_CreatePyObject_wrap( return (PyObject *) self; } +/** + * Create a vector where the value is defined by registered callbacks, + * see: #Mathutils_RegisterCallback + */ PyObject *Vector_CreatePyObject_cb( PyObject *cb_user, int size, unsigned char cb_type, unsigned char cb_subtype) @@ -3052,6 +3079,9 @@ PyObject *Vector_CreatePyObject_cb( return (PyObject *)self; } +/** + * \param vec: Initialized vector value to use in-place, allocated with: PyMem_Malloc + */ PyObject *Vector_CreatePyObject_alloc( float *vec, const int size, PyTypeObject *base_type) diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c index 1eb8644a9a6..42771d93b4e 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.c +++ b/source/blender/python/mathutils/mathutils_bvhtree.c @@ -761,7 +761,7 @@ static PyObject *C_BVHTree_FromPolygons(PyObject *UNUSED(cls), PyObject *args, P py_tricoords_fast_items = PySequence_Fast_ITEMS(py_tricoords_fast); for (j = 0; j < 3; j++) { - tri[j] = (unsigned int)_PyLong_AsInt(py_tricoords_fast_items[j]); + tri[j] = PyC_Long_AsU32(py_tricoords_fast_items[j]); if (UNLIKELY(tri[j] >= (unsigned int)coords_len)) { PyErr_Format(PyExc_ValueError, "%s: index %d must be less than %d", @@ -812,7 +812,7 @@ static PyObject *C_BVHTree_FromPolygons(PyObject *UNUSED(cls), PyObject *args, P p_plink_prev = &plink->next; for (j = 0; j < py_tricoords_len; j++) { - plink->poly[j] = (unsigned int)_PyLong_AsInt(py_tricoords_fast_items[j]); + plink->poly[j] = PyC_Long_AsU32(py_tricoords_fast_items[j]); if (UNLIKELY(plink->poly[j] >= (unsigned int)coords_len)) { PyErr_Format(PyExc_ValueError, "%s: index %d must be less than %d", @@ -1156,7 +1156,6 @@ static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyO /* Get data for tessellation */ { - DM_ensure_looptri(dm); lt = dm->getLoopTriArray(dm); tris_len = (unsigned int)dm->getNumLoopTri(dm); diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c index 868e4b38408..1dc18dbe509 100644 --- a/source/blender/python/mathutils/mathutils_geometry.c +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -1279,7 +1279,7 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject index = 0; dl_face = dl->index; while (index < dl->parts) { - PyList_SET_ITEM(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2])); + PyList_SET_ITEM(tri_list, index, PyC_Tuple_Pack_I32(dl_face[0], dl_face[1], dl_face[2])); dl_face += 3; index++; } diff --git a/source/blender/quicktime/CMakeLists.txt b/source/blender/quicktime/CMakeLists.txt deleted file mode 100644 index f853c35457f..00000000000 --- a/source/blender/quicktime/CMakeLists.txt +++ /dev/null @@ -1,62 +0,0 @@ -# ***** 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. -# -# The Original Code is Copyright (C) 2006, Blender Foundation -# All rights reserved. -# -# The Original Code is: all of this file. -# -# Contributor(s): Jacques Beaurain. -# -# ***** END GPL LICENSE BLOCK ***** - -set(INC - . - ../avi - ../blenkernel - ../blenlib - ../imbuf - ../imbuf/intern - ../makesdna - ../makesrna - ../render/extern/include - ../windowmanager - ../../../intern/guardedalloc -) - -set(INC_SYS - ${QUICKTIME_INCLUDE_DIRS} -) - -set(SRC - apple/qtkit_import.m - apple/qtkit_export.m - - quicktime_export.h - quicktime_import.h -) - -add_definitions(-DWITH_QUICKTIME) - -if(WITH_AUDASPACE) - add_definitions(${AUDASPACE_DEFINITIONS}) - - list(APPEND INC_SYS - ${AUDASPACE_C_INCLUDE_DIRS} - ) -endif() - -blender_add_lib(bf_quicktime "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/quicktime/apple/qtkit_export.m b/source/blender/quicktime/apple/qtkit_export.m deleted file mode 100644 index 1ac3c58f888..00000000000 --- a/source/blender/quicktime/apple/qtkit_export.m +++ /dev/null @@ -1,884 +0,0 @@ -/* - * Code to create QuickTime Movies with Blender - * - * ***** 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. - * - * - * The Original Code is written by Rob Haarsma (phase) - * - * Contributor(s): Stefan Gartner (sgefant) - * Damien Plisson 11/2009 - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifdef WITH_QUICKTIME -#if defined(_WIN32) || defined(__APPLE__) - -#include <stdio.h> -#include <string.h> - -#include "DNA_scene_types.h" -#include "DNA_userdef_types.h" - -#ifdef WITH_AUDASPACE -# include AUD_DEVICE_H -#endif - -#include "BLI_utildefines.h" -#include "BKE_global.h" -#include "BKE_main.h" -#include "BKE_scene.h" -#include "BKE_report.h" - -#include "BLI_blenlib.h" - -#include "BLI_sys_types.h" - -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - -#include "MEM_guardedalloc.h" - -#ifdef __APPLE__ -/* evil */ -#ifndef __AIFF__ -#define __AIFF__ -#endif -#import <Cocoa/Cocoa.h> -#import <QTKit/QTKit.h> -#include <AudioToolbox/AudioToolbox.h> - -#include "quicktime_import.h" -#include "quicktime_export.h" - -#endif /* __APPLE__ */ - -typedef struct QuicktimeExport { - QTMovie *movie; - - NSString *filename; - - QTTime frameDuration; - NSDictionary *frameAttributes; - - NSString *videoTempFileName; - /* Audio section */ - AUD_Device *audioInputDevice; - AudioFileID audioFile; - NSString *audioFileName; - AudioConverterRef audioConverter; - AudioBufferList audioBufferList; - AudioStreamBasicDescription audioInputFormat, audioOutputFormat; - AudioStreamPacketDescription *audioOutputPktDesc; - SInt64 audioFilePos; - char *audioInputBuffer; - char *audioOutputBuffer; - UInt32 audioCodecMaxOutputPacketSize; - UInt64 audioTotalExportedFrames, audioTotalSavedFrames; - UInt64 audioLastFrame; - SInt64 audioOutputPktPos; - -} QuicktimeExport; - -#define AUDIOOUTPUTBUFFERSIZE 65536 - -#pragma mark rna helper functions - -/* Video codec */ -static QuicktimeCodecTypeDesc qtVideoCodecList[] = { - {kRawCodecType, 1, "Uncompressed"}, - {k422YpCbCr8CodecType, 2, "Uncompressed 8-bit 4:2:2"}, - {k422YpCbCr10CodecType, 3, "Uncompressed 10-bit 4:2:2"}, - {kComponentVideoCodecType, 4, "Component Video"}, - {kPixletCodecType, 5, "Pixlet"}, - {kPNGCodecType, 6, "PNG"}, - {kJPEGCodecType, 7, "JPEG"}, - {kMotionJPEGACodecType, 8, "M-JPEG A"}, - {kMotionJPEGBCodecType, 9, "M-JPEG B"}, - {kDVCPALCodecType, 10, "DV PAL"}, - {kDVCNTSCCodecType, 11, "DV/DVCPRO NTSC"}, - {kDVCPROHD720pCodecType, 12, "DVCPRO HD 720p"}, - {kDVCPROHD1080i50CodecType, 13, "DVCPRO HD 1080i50"}, - {kDVCPROHD1080i60CodecType, 14, "DVCPRO HD 1080i60"}, - {kMPEG4VisualCodecType, 15, "MPEG4"}, - {kH263CodecType, 16, "H.263"}, - {kH264CodecType, 17, "H.264"}, - {kAnimationCodecType, 18, "Animation"}, - {0,0,NULL}}; - -static int qtVideoCodecCount = 18; - -int quicktime_get_num_videocodecs() -{ - return qtVideoCodecCount; -} - -QuicktimeCodecTypeDesc* quicktime_get_videocodecType_desc(int indexValue) -{ - if ((indexValue>=0) && (indexValue < qtVideoCodecCount)) - return &qtVideoCodecList[indexValue]; - else - return NULL; -} - -int quicktime_rnatmpvalue_from_videocodectype(int codecType) -{ - int i; - for (i = 0; i < qtVideoCodecCount; i++) { - if (qtVideoCodecList[i].codecType == codecType) - return qtVideoCodecList[i].rnatmpvalue; - } - - return 0; -} - -int quicktime_videocodecType_from_rnatmpvalue(int rnatmpvalue) -{ - int i; - for (i = 0; i < qtVideoCodecCount; i++) { - if (qtVideoCodecList[i].rnatmpvalue == rnatmpvalue) - return qtVideoCodecList[i].codecType; - } - - return 0; -} - -/* Audio codec */ -static QuicktimeCodecTypeDesc qtAudioCodecList[] = { - {0, 0, "No audio"}, - {kAudioFormatLinearPCM, 1, "LPCM"}, - {kAudioFormatAppleLossless, 2, "Apple Lossless"}, - {kAudioFormatMPEG4AAC, 3, "AAC"}, - {0,0,NULL}}; - -static int qtAudioCodecCount = 4; - -int quicktime_get_num_audiocodecs() -{ - return qtAudioCodecCount; -} - -QuicktimeCodecTypeDesc* quicktime_get_audiocodecType_desc(int indexValue) -{ - if ((indexValue>=0) && (indexValue < qtAudioCodecCount)) - return &qtAudioCodecList[indexValue]; - else - return NULL; -} - -int quicktime_rnatmpvalue_from_audiocodectype(int codecType) -{ - int i; - for (i = 0; i < qtAudioCodecCount; i++) { - if (qtAudioCodecList[i].codecType == codecType) - return qtAudioCodecList[i].rnatmpvalue; - } - - return 0; -} - -int quicktime_audiocodecType_from_rnatmpvalue(int rnatmpvalue) -{ - int i; - for (i = 0; i < qtAudioCodecCount; i++) { - if (qtAudioCodecList[i].rnatmpvalue == rnatmpvalue) - return qtAudioCodecList[i].codecType; - } - - return 0; -} - - -static NSString *stringWithCodecType(int codecType) -{ - char str[5]; - - *((int *)str) = EndianU32_NtoB(codecType); - str[4] = 0; - - return [NSString stringWithCString:str encoding:NSASCIIStringEncoding]; -} - -void makeqtstring(RenderData *rd, char *string, bool preview) -{ - int sfra, efra; - - char txt[64]; - - if (preview) { - sfra = rd->psfra; - efra = rd->pefra; - } - else { - sfra = rd->sfra; - efra = rd->efra; - } - - strcpy(string, rd->pic); - BLI_path_abs(string, G.main->name); - - BLI_make_existing_file(string); - - if (BLI_strcasecmp(string + strlen(string) - 4, ".mov")) { - sprintf(txt, "%04d-%04d.mov", (rd->sfra) , (rd->efra) ); - strcat(string, txt); - } -} - -void filepath_qt(char *string, RenderData *rd, bool preview, const char *suffix) -{ - int sfra, efra; - - if (string == NULL) return; - - if (preview) { - sfra = rd->psfra; - efra = rd->pefra; - } - else { - sfra = rd->sfra; - efra = rd->efra; - } - - strcpy(string, rd->pic); - BLI_path_abs(string, G.main->name); - - BLI_make_existing_file(string); - - if (rd->scemode & R_EXTENSION) { - if (!BLI_testextensie(string, ".mov")) { - BLI_path_frame_range(string, sfra, efra, 4); - strcat(string, ".mov"); - } - } - else { - if (BLI_path_frame_check_chars(string)) { - BLI_path_frame_range(string, sfra, efra, 4); - } - } - - BLI_path_suffix(string, FILE_MAX, suffix, ""); -} - -void *context_create_qt(void) -{ - QuicktimeExport *qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport"); - return qtexport; -} - -void context_free_qt(void *context_v) -{ - QuicktimeExport *qtexport = context_v; - if (qtexport) { - MEM_freeN(qtexport); - } -} - -#pragma mark audio export functions - -static OSStatus write_cookie(AudioConverterRef converter, AudioFileID outfile) -{ - // grab the cookie from the converter and write it to the file - UInt32 cookieSize = 0; - OSStatus err = AudioConverterGetPropertyInfo(converter, kAudioConverterCompressionMagicCookie, &cookieSize, NULL); - // if there is an error here, then the format doesn't have a cookie, so on we go - if (!err && cookieSize) { - char* cookie = malloc(cookieSize); - - err = AudioConverterGetProperty(converter, kAudioConverterCompressionMagicCookie, &cookieSize, cookie); - - if (!err) - err = AudioFileSetProperty (outfile, kAudioFilePropertyMagicCookieData, cookieSize, cookie); - // even though some formats have cookies, some files don't take them - - free(cookie); - } - return err; -} - -/* AudioConverter input stream callback */ -static OSStatus AudioConverterInputCallback(AudioConverterRef inAudioConverter, - UInt32* ioNumberDataPackets, - AudioBufferList* ioData, - AudioStreamPacketDescription** outDataPacketDescription, - void* inUserData) -{ - QuicktimeExport *qtexport = inUserData; - if (qtexport->audioTotalExportedFrames >= qtexport->audioLastFrame) { /* EOF */ - *ioNumberDataPackets = 0; - return noErr; - } - - if (qtexport->audioInputFormat.mBytesPerPacket * *ioNumberDataPackets > AUDIOOUTPUTBUFFERSIZE) - *ioNumberDataPackets = AUDIOOUTPUTBUFFERSIZE / qtexport->audioInputFormat.mBytesPerPacket; - - if ((qtexport->audioTotalExportedFrames + *ioNumberDataPackets) > qtexport->audioLastFrame) - *ioNumberDataPackets = (qtexport->audioLastFrame - qtexport->audioTotalExportedFrames) / qtexport->audioInputFormat.mFramesPerPacket; - - qtexport->audioTotalExportedFrames += *ioNumberDataPackets; - - AUD_Device_read(qtexport->audioInputDevice, (UInt8 *)qtexport->audioInputBuffer, - qtexport->audioInputFormat.mFramesPerPacket * *ioNumberDataPackets); - - ioData->mBuffers[0].mDataByteSize = qtexport->audioInputFormat.mBytesPerPacket * *ioNumberDataPackets; - ioData->mBuffers[0].mData = qtexport->audioInputBuffer; - ioData->mBuffers[0].mNumberChannels = qtexport->audioInputFormat.mChannelsPerFrame; - - return noErr; -} - - -#pragma mark export functions - -int start_qt( - void *context_v, struct Scene *scene, struct RenderData *rd, int UNUSED(rectx), int UNUSED(recty), - ReportList *reports, bool preview, const char *UNUSED(suffix)) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSError *error; - char name[1024]; - int success = 1; - OSStatus err = noErr; - int sfra, efra; - QuicktimeExport *qtexport = context_v; - - if (preview) { - sfra = rd->psfra; - efra = rd->pefra; - } - else { - sfra = rd->sfra; - efra = rd->efra; - } - - [QTMovie enterQTKitOnThread]; - - /* Check first if the QuickTime 7.2.1 initToWritableFile: method is available */ - if ([[[[QTMovie alloc] init] autorelease] respondsToSelector:@selector(initToWritableFile:error:)] != YES) { - BKE_report(reports, RPT_ERROR, "\nUnable to create quicktime movie, need Quicktime rev 7.2.1 or later"); - success = 0; - } - else { - makeqtstring(rd, name, preview); - qtexport->filename = [[NSString alloc] initWithUTF8String:name]; - qtexport->movie = nil; - qtexport->audioFile = NULL; - - if (rd->qtcodecsettings.audiocodecType) { - // generate a name for our video & audio files - /* Init audio file */ - CFURLRef outputFileURL; - char extension[32]; - AudioFileTypeID audioFileType; - - switch (rd->qtcodecsettings.audiocodecType) { - case kAudioFormatLinearPCM: - audioFileType = kAudioFileWAVEType; - strcpy(extension,".wav"); - break; - case kAudioFormatMPEG4AAC: - case kAudioFormatAppleLossless: - audioFileType = kAudioFileM4AType; - strcpy(extension, ".m4a"); - break; - default: - audioFileType = kAudioFileAIFFType; - strcpy(extension,".aiff"); - break; - } - - tmpnam(name); - strcat(name, extension); - outputFileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,(UInt8 *)name, strlen(name), false); - - if (outputFileURL) { - - qtexport->audioFileName = [[NSString alloc] initWithCString:name - encoding:[NSString defaultCStringEncoding]]; - - qtexport->audioInputFormat.mSampleRate = U.audiorate; - qtexport->audioInputFormat.mFormatID = kAudioFormatLinearPCM; - qtexport->audioInputFormat.mChannelsPerFrame = U.audiochannels; - switch (U.audioformat) { - case AUD_FORMAT_U8: - qtexport->audioInputFormat.mBitsPerChannel = 8; - qtexport->audioInputFormat.mFormatFlags = 0; - break; - case AUD_FORMAT_S24: - qtexport->audioInputFormat.mBitsPerChannel = 24; - qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - break; - case AUD_FORMAT_S32: - qtexport->audioInputFormat.mBitsPerChannel = 32; - qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - break; - case AUD_FORMAT_FLOAT32: - qtexport->audioInputFormat.mBitsPerChannel = 32; - qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; - break; - case AUD_FORMAT_FLOAT64: - qtexport->audioInputFormat.mBitsPerChannel = 64; - qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; - break; - case AUD_FORMAT_S16: - default: - qtexport->audioInputFormat.mBitsPerChannel = 16; - qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - break; - } - qtexport->audioInputFormat.mBytesPerFrame = qtexport->audioInputFormat.mChannelsPerFrame * qtexport->audioInputFormat.mBitsPerChannel / 8; - qtexport->audioInputFormat.mFramesPerPacket = 1; /*If not ==1, then need to check input callback for "rounding" issues"*/ - qtexport->audioInputFormat.mBytesPerPacket = qtexport->audioInputFormat.mBytesPerFrame; - qtexport->audioInputFormat.mFormatFlags |= kLinearPCMFormatFlagIsPacked; - - - /*Output format*/ - qtexport->audioOutputFormat.mFormatID = rd->qtcodecsettings.audiocodecType; - //TODO: set audio channels - qtexport->audioOutputFormat.mChannelsPerFrame = 2; - qtexport->audioOutputFormat.mSampleRate = rd->qtcodecsettings.audioSampleRate; - - /* Default value for compressed formats, overridden after if not the case */ - qtexport->audioOutputFormat.mFramesPerPacket = 0; - qtexport->audioOutputFormat.mBytesPerFrame = 0; - qtexport->audioOutputFormat.mBytesPerPacket = 0; - qtexport->audioOutputFormat.mBitsPerChannel = 0; - - switch (rd->qtcodecsettings.audiocodecType) { - case kAudioFormatMPEG4AAC: - qtexport->audioOutputFormat.mFormatFlags = kMPEG4Object_AAC_Main; - /* AAC codec does not handle sample rates above 48kHz, force this limit instead of getting an error afterwards */ - if (qtexport->audioOutputFormat.mSampleRate > 48000) qtexport->audioOutputFormat.mSampleRate = 48000; - break; - case kAudioFormatAppleLossless: - switch (U.audioformat) { - case AUD_FORMAT_S16: - qtexport->audioOutputFormat.mFormatFlags = kAppleLosslessFormatFlag_16BitSourceData; - break; - case AUD_FORMAT_S24: - qtexport->audioOutputFormat.mFormatFlags = kAppleLosslessFormatFlag_24BitSourceData; - break; - case AUD_FORMAT_S32: - qtexport->audioOutputFormat.mFormatFlags = kAppleLosslessFormatFlag_32BitSourceData; - break; - case AUD_FORMAT_U8: - case AUD_FORMAT_FLOAT32: - case AUD_FORMAT_FLOAT64: - default: - break; - } - break; - case kAudioFormatLinearPCM: - default: - switch (rd->qtcodecsettings.audioBitDepth) { - case AUD_FORMAT_U8: - qtexport->audioOutputFormat.mBitsPerChannel = 8; - qtexport->audioOutputFormat.mFormatFlags = 0; - break; - case AUD_FORMAT_S24: - qtexport->audioOutputFormat.mBitsPerChannel = 24; - qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - break; - case AUD_FORMAT_S32: - qtexport->audioOutputFormat.mBitsPerChannel = 32; - qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - break; - case AUD_FORMAT_FLOAT32: - qtexport->audioOutputFormat.mBitsPerChannel = 32; - qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; - break; - case AUD_FORMAT_FLOAT64: - qtexport->audioOutputFormat.mBitsPerChannel = 64; - qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; - break; - case AUD_FORMAT_S16: - default: - qtexport->audioOutputFormat.mBitsPerChannel = 16; - qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - break; - } - qtexport->audioOutputFormat.mFormatFlags |= kLinearPCMFormatFlagIsPacked; - qtexport->audioOutputFormat.mBytesPerPacket = qtexport->audioOutputFormat.mChannelsPerFrame * (qtexport->audioOutputFormat.mBitsPerChannel / 8); - qtexport->audioOutputFormat.mFramesPerPacket = 1; - qtexport->audioOutputFormat.mBytesPerFrame = qtexport->audioOutputFormat.mBytesPerPacket; - break; - } - - err = AudioFileCreateWithURL(outputFileURL, audioFileType, &qtexport->audioOutputFormat, kAudioFileFlags_EraseFile, &qtexport->audioFile); - CFRelease(outputFileURL); - - if (err) - BKE_report(reports, RPT_ERROR, "\nQuicktime: unable to create temporary audio file. Format error ?"); - else { - err = AudioConverterNew(&qtexport->audioInputFormat, &qtexport->audioOutputFormat, &qtexport->audioConverter); - if (err) { - BKE_report(reports, RPT_ERROR, "\nQuicktime: unable to initialize audio codec converter. Format error ?"); - AudioFileClose(qtexport->audioFile); - qtexport->audioFile = NULL; - [qtexport->audioFileName release]; - qtexport->audioFileName = nil; - } - else { - UInt32 prop,propSize; - /* Set up codec properties */ - if (rd->qtcodecsettings.audiocodecType == kAudioFormatMPEG4AAC) { /* Lossy compressed format */ - prop = rd->qtcodecsettings.audioBitRate; - AudioConverterSetProperty(qtexport->audioConverter, kAudioConverterEncodeBitRate, - sizeof(prop), &prop); - - if (rd->qtcodecsettings.audioCodecFlags & QTAUDIO_FLAG_CODEC_ISCBR) - prop = kAudioCodecBitRateControlMode_Constant; - else - prop = kAudioCodecBitRateControlMode_LongTermAverage; - AudioConverterSetProperty(qtexport->audioConverter, kAudioCodecPropertyBitRateControlMode, - sizeof(prop), &prop); - } - /* Conversion quality : if performance impact then offer degraded option */ - if ((rd->qtcodecsettings.audioCodecFlags & QTAUDIO_FLAG_RESAMPLE_NOHQ) == 0) { - prop = kAudioConverterSampleRateConverterComplexity_Mastering; - AudioConverterSetProperty(qtexport->audioConverter, kAudioConverterSampleRateConverterComplexity, - sizeof(prop), &prop); - - prop = kAudioConverterQuality_Max; - AudioConverterSetProperty(qtexport->audioConverter, kAudioConverterSampleRateConverterQuality, - sizeof(prop), &prop); - } - - write_cookie(qtexport->audioConverter, qtexport->audioFile); - - /* Allocate output buffer */ - if (qtexport->audioOutputFormat.mBytesPerPacket ==0) /* VBR */ - AudioConverterGetProperty(qtexport->audioConverter, kAudioConverterPropertyMaximumOutputPacketSize, - &propSize, &qtexport->audioCodecMaxOutputPacketSize); - else - qtexport->audioCodecMaxOutputPacketSize = qtexport->audioOutputFormat.mBytesPerPacket; - - qtexport->audioInputBuffer = MEM_mallocN(AUDIOOUTPUTBUFFERSIZE, "qt_audio_inputPacket"); - qtexport->audioOutputBuffer = MEM_mallocN(AUDIOOUTPUTBUFFERSIZE, "qt_audio_outputPacket"); - qtexport->audioOutputPktDesc = MEM_mallocN(sizeof(AudioStreamPacketDescription) * AUDIOOUTPUTBUFFERSIZE / qtexport->audioCodecMaxOutputPacketSize, - "qt_audio_pktdesc"); - } - } - } - - if (err == noErr) { - qtexport->videoTempFileName = [[NSString alloc] initWithCString:tmpnam(nil) - encoding:[NSString defaultCStringEncoding]]; - if (qtexport->videoTempFileName) { - qtexport->movie = [[QTMovie alloc] initToWritableFile:qtexport->videoTempFileName error:&error]; - } - - } - } - else - qtexport->movie = [[QTMovie alloc] initToWritableFile:qtexport->filename error:&error]; - - if (qtexport->movie == nil) { - BKE_report(reports, RPT_ERROR, "Unable to create quicktime movie."); - success = 0; - if (qtexport->filename) [qtexport->filename release]; - qtexport->filename = nil; - if (qtexport->audioFileName) [qtexport->audioFileName release]; - qtexport->audioFileName = nil; - if (qtexport->videoTempFileName) [qtexport->videoTempFileName release]; - qtexport->videoTempFileName = nil; - [QTMovie exitQTKitOnThread]; - } - else { - [qtexport->movie retain]; - [qtexport->movie setAttribute:[NSNumber numberWithBool:YES] forKey:QTMovieEditableAttribute]; - [qtexport->movie setAttribute:@"Made with Blender" forKey:QTMovieCopyrightAttribute]; - - qtexport->frameDuration = QTMakeTime(rd->frs_sec_base * 1000, rd->frs_sec * 1000); - - /* specifying the codec attributes : try to retrieve them from render data first*/ - if (rd->qtcodecsettings.codecType) { - qtexport->frameAttributes = [ - NSDictionary dictionaryWithObjectsAndKeys: - stringWithCodecType(rd->qtcodecsettings.codecType), - QTAddImageCodecType, - [NSNumber numberWithLong:((rd->qtcodecsettings.codecSpatialQuality)*codecLosslessQuality)/100], - QTAddImageCodecQuality, - nil]; - } - else { - qtexport->frameAttributes = [ - NSDictionary dictionaryWithObjectsAndKeys:@"jpeg", - QTAddImageCodecType, - [NSNumber numberWithLong:codecHighQuality], - QTAddImageCodecQuality, - nil]; - } - [qtexport->frameAttributes retain]; - - if (qtexport->audioFile) { - /* Init audio input stream */ - AUD_DeviceSpecs specs; - - specs.channels = U.audiochannels; - specs.format = U.audioformat; - specs.rate = U.audiorate; - qtexport->audioInputDevice = AUD_openReadDevice(specs); - AUD_playDevice(qtexport->audioInputDevice, scene->sound_scene, sfra * rd->frs_sec_base / rd->frs_sec); - - qtexport->audioOutputPktPos = 0; - qtexport->audioTotalExportedFrames = 0; - qtexport->audioTotalSavedFrames = 0; - - qtexport->audioLastFrame = (efra - sfra) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec; - } - } - } - - [pool drain]; - - return success; -} - -int append_qt( - void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, - const char *UNUSED(suffix), ReportList *reports) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSBitmapImageRep *blBitmapFormatImage; - NSImage *frameImage; - OSStatus err = noErr; - unsigned char *from_Ptr,*to_Ptr; - int y,from_i,to_i; - QuicktimeExport *qtexport = context_v; - - /* Create bitmap image rep in blender format (32bit RGBA) */ - blBitmapFormatImage = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:rectx - pixelsHigh:recty - bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO - colorSpaceName:NSCalibratedRGBColorSpace - bitmapFormat:NSAlphaNonpremultipliedBitmapFormat - bytesPerRow:rectx*4 - bitsPerPixel:32]; - if (!blBitmapFormatImage) { - [pool drain]; - return 0; - } - - from_Ptr = (unsigned char *)pixels; - to_Ptr = (unsigned char *)[blBitmapFormatImage bitmapData]; - for (y = 0; y < recty; y++) { - to_i = (recty-y-1)*rectx; - from_i = y*rectx; - memcpy(to_Ptr+4*to_i, from_Ptr+4*from_i, 4*rectx); - } - - frameImage = [[NSImage alloc] initWithSize:NSMakeSize(rectx, recty)]; - [frameImage addRepresentation:blBitmapFormatImage]; - - /* Add the image to the movie clip */ - [qtexport->movie addImage:frameImage - forDuration:qtexport->frameDuration - withAttributes:qtexport->frameAttributes]; - - [blBitmapFormatImage release]; - [frameImage release]; - - - if (qtexport->audioFile) { - UInt32 audioPacketsConverted; - - // Upper limit on total exported audio frames for this particular video frame - const UInt64 exportedAudioFrameLimit = (frame - start_frame) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec; - - /* Append audio */ - while (qtexport->audioTotalExportedFrames < exportedAudioFrameLimit) { - - qtexport->audioBufferList.mNumberBuffers = 1; - qtexport->audioBufferList.mBuffers[0].mNumberChannels = qtexport->audioOutputFormat.mChannelsPerFrame; - qtexport->audioBufferList.mBuffers[0].mDataByteSize = AUDIOOUTPUTBUFFERSIZE; - qtexport->audioBufferList.mBuffers[0].mData = qtexport->audioOutputBuffer; - - // Convert one audio packet at a time so that enclosing while loop can - // keep audio processing in sync with video frames. - // Previously, this was set to (AUDIOOUTPUTBUFFERSIZE / qtexport->audioCodecMaxOutputPacketSize), - // however this may cause AudioConverterFillComplexBuffer to convert audio spanning multiple - // video frames, which breaks animation of audio parameters such as volume for fade-in/out. - audioPacketsConverted = 1; - - err = AudioConverterFillComplexBuffer(qtexport->audioConverter, AudioConverterInputCallback, - qtexport, &audioPacketsConverted, &qtexport->audioBufferList, qtexport->audioOutputPktDesc); - if (audioPacketsConverted) { - AudioFileWritePackets(qtexport->audioFile, false, qtexport->audioBufferList.mBuffers[0].mDataByteSize, - qtexport->audioOutputPktDesc, qtexport->audioOutputPktPos, &audioPacketsConverted, qtexport->audioOutputBuffer); - qtexport->audioOutputPktPos += audioPacketsConverted; - - if (qtexport->audioOutputFormat.mFramesPerPacket) { - // this is the common case: format has constant frames per packet - qtexport->audioTotalSavedFrames += (audioPacketsConverted * qtexport->audioOutputFormat.mFramesPerPacket); - } - else { - unsigned int i; - // if there are variable frames per packet, then we have to do this for each packeet - for (i = 0; i < audioPacketsConverted; ++i) - qtexport->audioTotalSavedFrames += qtexport->audioOutputPktDesc[i].mVariableFramesInPacket; - } - - - } - else { - //Error getting audio packets - BKE_reportf(reports, RPT_ERROR, "Unable to get further audio packets from frame %i, error = 0x%x",(int)qtexport->audioTotalExportedFrames,err); - break; - } - - } - } - [pool drain]; - - return 1; -} - - -void end_qt(void *context_v) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - QuicktimeExport *qtexport = context_v; - - if (qtexport->movie) { - - if (qtexport->audioFile) - { - NSDictionary *dict = nil; - QTMovie *audioTmpMovie = nil; - NSError *error; - NSFileManager *fileManager; - - /* Mux video and audio then save file */ - - /* Write last frames for VBR files */ - if (qtexport->audioOutputFormat.mBitsPerChannel == 0) { - OSStatus err = noErr; - AudioConverterPrimeInfo primeInfo; - UInt32 primeSize = sizeof(primeInfo); - - err = AudioConverterGetProperty(qtexport->audioConverter, kAudioConverterPrimeInfo, &primeSize, &primeInfo); - if (err == noErr) { - // there's priming to write out to the file - AudioFilePacketTableInfo pti; - pti.mPrimingFrames = primeInfo.leadingFrames; - pti.mRemainderFrames = primeInfo.trailingFrames; - pti.mNumberValidFrames = qtexport->audioTotalSavedFrames - pti.mPrimingFrames - pti.mRemainderFrames; - AudioFileSetProperty(qtexport->audioFile, kAudioFilePropertyPacketTableInfo, sizeof(pti), &pti); - } - - } - - write_cookie(qtexport->audioConverter, qtexport->audioFile); - AudioConverterDispose(qtexport->audioConverter); - AudioFileClose(qtexport->audioFile); - AUD_Device_free(qtexport->audioInputDevice); - qtexport->audioFile = NULL; - qtexport->audioInputDevice = NULL; - MEM_freeN(qtexport->audioInputBuffer); - MEM_freeN(qtexport->audioOutputBuffer); - MEM_freeN(qtexport->audioOutputPktDesc); - - /* Reopen audio file and merge it */ - audioTmpMovie = [QTMovie movieWithFile:qtexport->audioFileName error:&error]; - if (audioTmpMovie) { - NSArray *audioTracks = [audioTmpMovie tracksOfMediaType:QTMediaTypeSound]; - QTTrack *audioTrack = nil; - if ( [audioTracks count] > 0 ) { - audioTrack = [audioTracks objectAtIndex:0]; - } - - if (audioTrack) { - QTTimeRange totalRange; - totalRange.time = QTZeroTime; - totalRange.duration = [[audioTmpMovie attributeForKey:QTMovieDurationAttribute] QTTimeValue]; - - [qtexport->movie insertSegmentOfTrack:audioTrack timeRange:totalRange atTime:QTZeroTime]; - } - } - - /* Save file */ - dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] - forKey:QTMovieFlatten]; - - if (dict) { - [qtexport->movie writeToFile:qtexport->filename withAttributes:dict]; - } - - /* Delete temp files */ - fileManager = [[NSFileManager alloc] init]; - [fileManager removeItemAtPath:qtexport->audioFileName error:&error]; - [fileManager removeItemAtPath:qtexport->videoTempFileName error:&error]; - [fileManager release]; - } - else { - /* Flush update of the movie file */ - [qtexport->movie updateMovieFile]; - - [qtexport->movie invalidate]; - } - - /* Clean up movie structure */ - if (qtexport->filename) [qtexport->filename release]; - qtexport->filename = nil; - if (qtexport->audioFileName) [qtexport->audioFileName release]; - qtexport->audioFileName = nil; - if (qtexport->videoTempFileName) [qtexport->videoTempFileName release]; - qtexport->videoTempFileName = nil; - [qtexport->frameAttributes release]; - [qtexport->movie release]; - } - - [QTMovie exitQTKitOnThread]; - [pool drain]; -} - - -void free_qtcomponentdata(void) -{ -} - -void quicktime_verify_image_type(RenderData *rd, ImageFormatData *imf) -{ - if (imf->imtype == R_IMF_IMTYPE_QUICKTIME) { - if ((rd->qtcodecsettings.codecType <= 0) || - (rd->qtcodecsettings.codecSpatialQuality < 0) || - (rd->qtcodecsettings.codecSpatialQuality > 100)) - { - rd->qtcodecsettings.codecType = kJPEGCodecType; - rd->qtcodecsettings.codecSpatialQuality = (codecHighQuality * 100) / codecLosslessQuality; - } - if ((rd->qtcodecsettings.audioSampleRate < 21000) || - (rd->qtcodecsettings.audioSampleRate > 193000)) - { - rd->qtcodecsettings.audioSampleRate = 48000; - } - - if (rd->qtcodecsettings.audioBitDepth == 0) { - rd->qtcodecsettings.audioBitDepth = AUD_FORMAT_S16; - } - - if (rd->qtcodecsettings.audioBitRate == 0) { - rd->qtcodecsettings.audioBitRate = 256000; - } - } -} - -#endif /* _WIN32 || __APPLE__ */ -#endif /* WITH_QUICKTIME */ - diff --git a/source/blender/quicktime/apple/qtkit_import.m b/source/blender/quicktime/apple/qtkit_import.m deleted file mode 100644 index ba7ee0a8936..00000000000 --- a/source/blender/quicktime/apple/qtkit_import.m +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Code to use Quicktime to load images/movies as texture. - * - * ***** 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. - * - * - * The Original Code is written by Rob Haarsma (phase) - * - * Contributor(s): Stefan Gartner (sgefant) - * Damien Plisson 11/2009 - * - * ***** END GPL LICENSE BLOCK ***** - */ -#ifdef WITH_QUICKTIME - -#include "MEM_guardedalloc.h" - -#include "IMB_anim.h" -#include "BLI_sys_types.h" -#include "BLI_utildefines.h" -#include "BKE_global.h" - -#include "BLI_dynstr.h" -#include "BLI_path_util.h" - -#import <Cocoa/Cocoa.h> -#import <QTKit/QTKit.h> - -#include "quicktime_import.h" -#include "quicktime_export.h" - -// quicktime structure definition -// this structure is part of the anim struct - -typedef struct _QuicktimeMovie { - QTMovie *movie; - QTMedia *media; - - long durationTime; - long durationScale; - long framecount; - - - ImBuf *ibuf; - - long previousPosition; - -} QuicktimeMovie; - - -#define QTIME_DEBUG 0 - - -void quicktime_init(void) -{ - G.have_quicktime = true; -} - -void quicktime_exit(void) -{ - if (G.have_quicktime) { - free_qtcomponentdata(); - } -} - - -int anim_is_quicktime(const char *name) -{ - NSAutoreleasePool *pool; - - // don't let quicktime movie import handle these - - if (BLI_testextensie_n( - name, - ".swf", - ".txt", - ".mpg", - ".vob", /* disabled, vob is essential .mpg, don't handle */ - ".avi", /* wouldn't be appropriate ;) */ - ".mov", /* disabled, suboptimal decoding speed */ - ".mp4", /* disabled, suboptimal decoding speed */ - ".m4v", /* disabled, suboptimal decoding speed */ - ".tga", - ".png", - ".bmp", - ".jpg", - ".tif", - ".exr", - ".wav", - ".zip", - ".mp3", - NULL)) - { - return 0; - } - - if (QTIME_DEBUG) printf("qt: checking as movie: %s\n", name); - - pool = [[NSAutoreleasePool alloc] init]; - - if ([QTMovie canInitWithFile:[NSString stringWithCString:name - encoding:[NSString defaultCStringEncoding]]]) - { - [pool drain]; - return true; - } - else - { - [pool drain]; - return false; - } -} - - -void free_anim_quicktime(struct anim *anim) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - if (anim == NULL) return; - if (anim->qtime == NULL) return; - - if (anim->qtime->ibuf) - IMB_freeImBuf(anim->qtime->ibuf); - - [anim->qtime->media release]; - [anim->qtime->movie release]; - - [QTMovie exitQTKitOnThread]; - - if (anim->qtime) MEM_freeN (anim->qtime); - - anim->qtime = NULL; - - anim->duration = 0; - - [pool drain]; -} - -static ImBuf *nsImageToiBuf(NSImage *sourceImage, int width, int height) -{ - ImBuf *ibuf = NULL; - uchar *rasterRGB = NULL; - uchar *rasterRGBA = NULL; - uchar *toIBuf = NULL; - int x, y, to_i, from_i; - NSSize bitmapSize; - NSBitmapImageRep *blBitmapFormatImageRGB,*blBitmapFormatImageRGBA, *bitmapImage = nil; - NSEnumerator *enumerator; - NSImageRep *representation; - - ibuf = IMB_allocImBuf(width, height, 32, IB_rect); - if (!ibuf) { - if (QTIME_DEBUG) { - printf("quicktime_import: could not allocate memory for the image.\n"); - } - return NULL; - } - - /*Get the bitmap of the image*/ - enumerator = [[sourceImage representations] objectEnumerator]; - while ((representation = [enumerator nextObject])) { - if ([representation isKindOfClass:[NSBitmapImageRep class]]) { - bitmapImage = (NSBitmapImageRep *)representation; - break; - } - } - if (bitmapImage == nil) return NULL; - - if (([bitmapImage bitsPerPixel] == 32) && (([bitmapImage bitmapFormat] & 0x5) == 0) - && ![bitmapImage isPlanar]) { - /* Try a fast copy if the image is a meshed RGBA 32bit bitmap*/ - toIBuf = (uchar *)ibuf->rect; - rasterRGB = (uchar *)[bitmapImage bitmapData]; - for (y = 0; y < height; y++) { - to_i = (height-y-1)*width; - from_i = y*width; - memcpy(toIBuf+4*to_i, rasterRGB+4*from_i, 4*width); - } - } - else { - - bitmapSize.width = width; - bitmapSize.height = height; - - /* Tell cocoa image resolution is same as current system one */ - [bitmapImage setSize:bitmapSize]; - - /* Convert the image in a RGBA 32bit format */ - /* As Core Graphics does not support contextes with non premutliplied alpha, - * we need to get alpha key values in a separate batch */ - - /* First get RGB values w/o Alpha to avoid pre-multiplication, 32bit but last byte is unused */ - blBitmapFormatImageRGB = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:width - pixelsHigh:height - bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bitmapFormat:0 - bytesPerRow:4*width - bitsPerPixel:32/*RGB format padded to 32bits*/]; - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGB]]; - [bitmapImage draw]; - [NSGraphicsContext restoreGraphicsState]; - - rasterRGB = (uchar *)[blBitmapFormatImageRGB bitmapData]; - if (rasterRGB == NULL) { - [blBitmapFormatImageRGB release]; - return NULL; - } - - /* Then get Alpha values by getting the RGBA image (that is premultiplied btw) */ - blBitmapFormatImageRGBA = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:width - pixelsHigh:height - bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bitmapFormat:0 - bytesPerRow:4*width - bitsPerPixel:32/* RGBA */]; - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]]; - [bitmapImage draw]; - [NSGraphicsContext restoreGraphicsState]; - - rasterRGBA = (uchar *)[blBitmapFormatImageRGBA bitmapData]; - if (rasterRGBA == NULL) { - [blBitmapFormatImageRGB release]; - [blBitmapFormatImageRGBA release]; - return NULL; - } - - /*Copy the image to ibuf, flipping it vertically*/ - toIBuf = (uchar *)ibuf->rect; - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - to_i = (height-y-1)*width + x; - from_i = y*width + x; - - toIBuf[4*to_i] = rasterRGB[4*from_i]; /* R */ - toIBuf[4*to_i+1] = rasterRGB[4*from_i+1]; /* G */ - toIBuf[4*to_i+2] = rasterRGB[4*from_i+2]; /* B */ - toIBuf[4*to_i+3] = rasterRGBA[4*from_i+3]; /* A */ - } - } - - [blBitmapFormatImageRGB release]; - [blBitmapFormatImageRGBA release]; - } - - return ibuf; -} - -ImBuf *qtime_fetchibuf (struct anim *anim, int position) -{ - NSImage *frameImage; - QTTime time; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - ImBuf *ibuf; - - if (anim == NULL) { - return (NULL); - } - - if (position == anim->qtime->previousPosition+1) { //Optimize sequential read - [anim->qtime->movie stepForward]; - frameImage = [anim->qtime->movie currentFrameImage]; - anim->qtime->previousPosition++; - } - else { - time.timeScale = anim->qtime->durationScale; - time.timeValue = (anim->qtime->durationTime * position) / anim->qtime->framecount; - - [anim->qtime->movie setCurrentTime:time]; - frameImage = [anim->qtime->movie currentFrameImage]; - - anim->qtime->previousPosition = position; - } - - if (frameImage == nil) { - if (QTIME_DEBUG) printf ("Error reading frame from Quicktime"); - [pool drain]; - return NULL; - } - - ibuf = nsImageToiBuf(frameImage,anim->x, anim->y); - [pool drain]; - - return ibuf; -} - - -int startquicktime(struct anim *anim) -{ - NSAutoreleasePool *pool; - NSArray* videoTracks; - NSSize frameSize; - QTTime qtTimeDuration; - NSDictionary *attributes; - - anim->qtime = MEM_callocN(sizeof(QuicktimeMovie),"animqt"); - - if (anim->qtime == NULL) { - if (QTIME_DEBUG) printf("Can't alloc qtime: %s\n", anim->name); - return -1; - } - - pool = [[NSAutoreleasePool alloc] init]; - - [QTMovie enterQTKitOnThread]; - - attributes = [NSDictionary dictionaryWithObjectsAndKeys: - [NSString stringWithCString:anim->name - encoding:[NSString defaultCStringEncoding]], QTMovieFileNameAttribute, - [NSNumber numberWithBool:NO], QTMovieEditableAttribute, - nil]; - - anim->qtime->movie = [QTMovie movieWithAttributes:attributes error:NULL]; - - if (!anim->qtime->movie) { - if (QTIME_DEBUG) printf("qt: bad movie %s\n", anim->name); - MEM_freeN(anim->qtime); - if (QTIME_DEBUG) printf("qt: can't load %s\n", anim->name); - [QTMovie exitQTKitOnThread]; - [pool drain]; - return -1; - } - [anim->qtime->movie retain]; - - // sets Media and Track! - - videoTracks = [anim->qtime->movie tracksOfMediaType:QTMediaTypeVideo]; - - if ([videoTracks count] == 0) { - if (QTIME_DEBUG) printf("qt: no video tracks for movie %s\n", anim->name); - [anim->qtime->movie release]; - MEM_freeN(anim->qtime); - if (QTIME_DEBUG) printf("qt: can't load %s\n", anim->name); - [QTMovie exitQTKitOnThread]; - [pool drain]; - return -1; - } - - anim->qtime->media = [[videoTracks objectAtIndex:0] media]; - [anim->qtime->media retain]; - - - frameSize = [[anim->qtime->movie attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]; - anim->x = frameSize.width; - anim->y = frameSize.height; - - if (anim->x == 0 && anim->y == 0) { - if (QTIME_DEBUG) printf("qt: error, no dimensions\n"); - free_anim_quicktime(anim); - [pool drain]; - return -1; - } - - anim->qtime->ibuf = IMB_allocImBuf(anim->x, anim->y, 32, IB_rect); - - qtTimeDuration = [[anim->qtime->media attributeForKey:QTMediaDurationAttribute] QTTimeValue]; - anim->qtime->durationTime = qtTimeDuration.timeValue; - anim->qtime->durationScale = qtTimeDuration.timeScale; - - anim->qtime->framecount = [[anim->qtime->media attributeForKey:QTMediaSampleCountAttribute] longValue]; - anim->qtime->previousPosition = -2; //Force seeking for first read - - //fill blender's anim struct - - anim->duration = anim->qtime->framecount; - anim->params = 0; - - anim->interlacing = 0; - anim->orientation = 0; - anim->framesize = anim->x * anim->y * 4; - - anim->curposition = 0; - - [pool drain]; - - return 0; -} - -#endif /* WITH_QUICKTIME */ - diff --git a/source/blender/quicktime/quicktime_export.h b/source/blender/quicktime/quicktime_export.h deleted file mode 100644 index aaa3f5c9070..00000000000 --- a/source/blender/quicktime/quicktime_export.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * ***** 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. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/quicktime/quicktime_export.h - * \ingroup quicktime - */ - - -#ifndef __QUICKTIME_EXPORT_H__ -#define __QUICKTIME_EXPORT_H__ - -#if defined (_WIN32) || (__APPLE__) - -#define __AIFF__ - - -#define QTAUDIO_FLAG_RESAMPLE_NOHQ 1 -#define QTAUDIO_FLAG_CODEC_ISCBR 2 - - -/*Codec list*/ -typedef struct QuicktimeCodecTypeDesc { - int codecType; - int rnatmpvalue; - const char *codecName; -} QuicktimeCodecTypeDesc; - -// quicktime movie output functions -struct ImageFormatData; -struct RenderData; -struct ReportList; -struct Scene; - -int start_qt(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview, const char *suffix); //for movie handle (BKE writeavi.c now) -int append_qt(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, const char *suffix, struct ReportList *reports); -void end_qt(void *context_v); -void filepath_qt(char *string, struct RenderData *rd, bool preview, const char *suffix); -void *context_create_qt(void); -void context_free_qt(void *context_v); - -/*RNA helper functions */ -void quicktime_verify_image_type(struct RenderData *rd, struct ImageFormatData *imf); //used by RNA for defaults values init, if needed -/*Video codec type*/ -int quicktime_get_num_videocodecs(void); -QuicktimeCodecTypeDesc *quicktime_get_videocodecType_desc(int indexValue); -int quicktime_rnatmpvalue_from_videocodectype(int codecType); -int quicktime_videocodecType_from_rnatmpvalue(int rnatmpvalue); - -/*Audio codec type*/ -int quicktime_get_num_audiocodecs(void); -QuicktimeCodecTypeDesc *quicktime_get_audiocodecType_desc(int indexValue); -int quicktime_rnatmpvalue_from_audiocodectype(int codecType); -int quicktime_audiocodecType_from_rnatmpvalue(int rnatmpvalue); - -void free_qtcomponentdata(void); -void makeqtstring(struct RenderData *rd, char *string, bool preview); //for playanim.c - - -#ifdef __APPLE__ -//Include the quicktime codec types constants that are missing in QTKitDefines.h -enum { - kRawCodecType = 'raw ', - kCinepakCodecType = 'cvid', - kGraphicsCodecType = 'smc ', - kAnimationCodecType = 'rle ', - kVideoCodecType = 'rpza', - kComponentVideoCodecType = 'yuv2', - kJPEGCodecType = 'jpeg', - kMotionJPEGACodecType = 'mjpa', - kMotionJPEGBCodecType = 'mjpb', - kSGICodecType = '.SGI', - kPlanarRGBCodecType = '8BPS', - kMacPaintCodecType = 'PNTG', - kGIFCodecType = 'gif ', - kPhotoCDCodecType = 'kpcd', - kQuickDrawGXCodecType = 'qdgx', - kAVRJPEGCodecType = 'avr ', - kOpenDMLJPEGCodecType = 'dmb1', - kBMPCodecType = 'WRLE', - kWindowsRawCodecType = 'WRAW', - kVectorCodecType = 'path', - kQuickDrawCodecType = 'qdrw', - kWaterRippleCodecType = 'ripl', - kFireCodecType = 'fire', - kCloudCodecType = 'clou', - kH261CodecType = 'h261', - kH263CodecType = 'h263', - kDVCNTSCCodecType = 'dvc ', /* DV - NTSC and DVCPRO NTSC (available in QuickTime 6.0 or later)*/ - /* NOTE: kDVCProNTSCCodecType is deprecated. */ - /* Use kDVCNTSCCodecType instead -- as far as the codecs are concerned, */ - /* the two data formats are identical.*/ - kDVCPALCodecType = 'dvcp', - kDVCProPALCodecType = 'dvpp', /* available in QuickTime 6.0 or later*/ - kDVCPro50NTSCCodecType = 'dv5n', - kDVCPro50PALCodecType = 'dv5p', - kDVCPro100NTSCCodecType = 'dv1n', - kDVCPro100PALCodecType = 'dv1p', - kDVCPROHD720pCodecType = 'dvhp', - kDVCPROHD1080i60CodecType = 'dvh6', - kDVCPROHD1080i50CodecType = 'dvh5', - kBaseCodecType = 'base', - kFLCCodecType = 'flic', - kTargaCodecType = 'tga ', - kPNGCodecType = 'png ', - kTIFFCodecType = 'tiff', /* NOTE: despite what might seem obvious from the two constants*/ - /* below and their names, they really are correct. 'yuvu' really */ - /* does mean signed, and 'yuvs' really does mean unsigned. Really. */ - kComponentVideoSigned = 'yuvu', - kComponentVideoUnsigned = 'yuvs', - kCMYKCodecType = 'cmyk', - kMicrosoftVideo1CodecType = 'msvc', - kSorensonCodecType = 'SVQ1', - kSorenson3CodecType = 'SVQ3', /* available in QuickTime 5 and later*/ - kIndeo4CodecType = 'IV41', - kMPEG4VisualCodecType = 'mp4v', - k64ARGBCodecType = 'b64a', - k48RGBCodecType = 'b48r', - k32AlphaGrayCodecType = 'b32a', - k16GrayCodecType = 'b16g', - kMpegYUV420CodecType = 'myuv', - kYUV420CodecType = 'y420', - kSorensonYUV9CodecType = 'syv9', - k422YpCbCr8CodecType = '2vuy', /* Component Y'CbCr 8-bit 4:2:2 */ - k444YpCbCr8CodecType = 'v308', /* Component Y'CbCr 8-bit 4:4:4 */ - k4444YpCbCrA8CodecType = 'v408', /* Component Y'CbCrA 8-bit 4:4:4:4 */ - k422YpCbCr16CodecType = 'v216', /* Component Y'CbCr 10,12,14,16-bit 4:2:2*/ - k422YpCbCr10CodecType = 'v210', /* Component Y'CbCr 10-bit 4:2:2 */ - k444YpCbCr10CodecType = 'v410', /* Component Y'CbCr 10-bit 4:4:4 */ - k4444YpCbCrA8RCodecType = 'r408', /* Component Y'CbCrA 8-bit 4:4:4:4, rendering format. full range alpha, zero biased yuv*/ - kJPEG2000CodecType = 'mjp2', - kPixletCodecType = 'pxlt', - kH264CodecType = 'avc1' -}; -#endif - -#endif /* (_WIN32) || (__APPLE__) */ - -#endif /* __QUICKTIME_IMP_H__ */ diff --git a/source/blender/quicktime/quicktime_import.h b/source/blender/quicktime/quicktime_import.h deleted file mode 100644 index 3c6b2028031..00000000000 --- a/source/blender/quicktime/quicktime_import.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Quicktime_import.h - * - * - * ***** 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. - * - * The Original Code is Copyright (C) 2002-2003 by TNCCI Inc. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/quicktime/quicktime_import.h - * \ingroup quicktime - */ - - - -#ifndef __QUICKTIME_IMPORT_H__ -#define __QUICKTIME_IMPORT_H__ - -#define __AIFF__ - -#include "../imbuf/IMB_imbuf.h" -#include "../imbuf/IMB_imbuf_types.h" - -#ifdef _WIN32 -# ifndef __FIXMATH__ -# include <FixMath.h> -# endif /* __FIXMATH__ */ -#endif /* _WIN32 _ */ - -/* init/exit */ - -void quicktime_init(void); -void quicktime_exit(void); - -/* quicktime movie import functions */ - -int anim_is_quicktime(const char *name); -int startquicktime(struct anim *anim); -void free_anim_quicktime(struct anim *anim); -ImBuf *qtime_fetchibuf(struct anim *anim, int position); - -#endif /* __QUICKTIME_IMPORT_H__ */ diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index a12bdd910c3..27ec6bf8ba6 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -148,16 +148,6 @@ if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() -if(WITH_CODEC_QUICKTIME) - list(APPEND INC - ../quicktime - ) - list(APPEND INC_SYS - ${QUICKTIME_INCLUDE_DIRS} - ) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_GAMEENGINE) add_definitions(-DWITH_GAMEENGINE) endif() diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index 0d2e29ba4c8..cf9298bdb9e 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -194,6 +194,10 @@ typedef struct RenderStats { struct Render *RE_NewRender(const char *name); struct Render *RE_GetRender(const char *name); +struct Scene; +struct Render *RE_NewSceneRender(const struct Scene *scene); +struct Render *RE_GetSceneRender(const struct Scene *scene); + /* assign default dummy callbacks */ void RE_InitRenderCB(struct Render *re); diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h index 13f16ce0bd7..3ef6e9d7476 100644 --- a/source/blender/render/intern/include/shading.h +++ b/source/blender/render/intern/include/shading.h @@ -57,7 +57,7 @@ typedef struct ShadeSample { void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr); void shade_input_set_triangle_i(struct ShadeInput *shi, struct ObjectInstanceRen *obi, struct VlakRen *vlr, short i1, short i2, short i3); -void shade_input_set_triangle(struct ShadeInput *shi, volatile int obi, volatile int facenr, int normal_flip); +void shade_input_set_triangle(struct ShadeInput *shi, int obi, int facenr, int normal_flip); void shade_input_copy_triangle(struct ShadeInput *shi, struct ShadeInput *from); void shade_input_calc_viewco(struct ShadeInput *shi, float x, float y, float z, float view[3], float dxyview[2], float co[3], float dxco[3], float dyco[3]); void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float sx, float sy, float z); diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp index 81e41a20f2e..103fa3e6034 100644 --- a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp +++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp @@ -59,6 +59,7 @@ static void rtbuild_init(RTBuilder *b) b->primitives.begin = NULL; b->primitives.end = NULL; b->primitives.maxsize = 0; + b->depth = 0; for (int i = 0; i < RTBUILD_MAX_CHILDS; i++) b->child_offset[i] = 0; @@ -178,6 +179,8 @@ RTBuilder *rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp) { rtbuild_init(tmp); + tmp->depth = b->depth + 1; + for (int i = 0; i < 3; i++) if (b->sorted_begin[i]) { tmp->sorted_begin[i] = b->sorted_begin[i] + b->child_offset[child]; @@ -336,6 +339,15 @@ int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds) int baxis = -1, boffset = 0; if (size > nchilds) { + if (b->depth > RTBUILD_MAX_SAH_DEPTH) { + // for degenerate cases we avoid running out of stack space + // by simply splitting the children in the middle + b->child_offset[0] = 0; + b->child_offset[1] = (size+1)/2; + b->child_offset[2] = size; + return 2; + } + float bcost = FLT_MAX; baxis = -1; boffset = size / 2; diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.h b/source/blender/render/intern/raytrace/rayobject_rtbuild.h index 9e296da144b..83042ef3d7e 100644 --- a/source/blender/render/intern/raytrace/rayobject_rtbuild.h +++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.h @@ -49,7 +49,8 @@ extern "C" { * generate with simple calls, and then convert to the theirs * specific structure on the fly. */ -#define RTBUILD_MAX_CHILDS 32 +#define RTBUILD_MAX_CHILDS 32 +#define RTBUILD_MAX_SAH_DEPTH 256 typedef struct RTBuilder { @@ -79,6 +80,8 @@ typedef struct RTBuilder { float bb[6]; + /* current depth */ + int depth; } RTBuilder; /* used during creation */ diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c index 04010522c12..ae02cf56b88 100644 --- a/source/blender/render/intern/source/imagetexture.c +++ b/source/blender/render/intern/source/imagetexture.c @@ -1172,7 +1172,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex a = max_ff(a, 1.0f); b = max_ff(b, 1.0f); fProbes = 2.f*(a / b) - 1.f; - AFD.iProbes = iroundf(fProbes); + AFD.iProbes = round_fl_to_int(fProbes); AFD.iProbes = MIN2(AFD.iProbes, tex->afmax); if (AFD.iProbes < fProbes) b = 2.f*a / (float)(AFD.iProbes + 1); @@ -1277,7 +1277,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex b = max_ff(b, 1.0f); fProbes = 2.f*(a / b) - 1.f; /* no limit to number of Probes here */ - AFD.iProbes = iroundf(fProbes); + AFD.iProbes = round_fl_to_int(fProbes); if (AFD.iProbes < fProbes) b = 2.f*a / (float)(AFD.iProbes + 1); AFD.majrad = a/ff; AFD.minrad = b/ff; diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c index 970a3937657..fbf18405093 100644 --- a/source/blender/render/intern/source/initrender.c +++ b/source/blender/render/intern/source/initrender.c @@ -48,10 +48,6 @@ #include "BKE_camera.h" -#ifdef WITH_QUICKTIME -#include "quicktime_export.h" -#endif - /* this module */ #include "renderpipeline.h" #include "render_types.h" diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index e078365e1ed..a0ebe241569 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -307,7 +307,6 @@ Render *RE_GetRender(const char *name) return re; } - /* if you want to know exactly what has been done */ RenderResult *RE_AcquireResultRead(Render *re) { @@ -514,6 +513,36 @@ Render *RE_NewRender(const char *name) return re; } +/* MAX_ID_NAME + sizeof(Library->name) + space + null-terminator. */ +#define MAX_SCENE_RENDER_NAME (MAX_ID_NAME + 1024 + 2) + +static void scene_render_name_get(const Scene *scene, + const size_t max_size, + char *render_name) +{ + if (ID_IS_LINKED_DATABLOCK(scene)) { + BLI_snprintf(render_name, max_size, "%s %s", + scene->id.lib->id.name, scene->id.name); + } + else { + BLI_snprintf(render_name, max_size, "%s", scene->id.name); + } +} + +Render *RE_GetSceneRender(const Scene *scene) +{ + char render_name[MAX_SCENE_RENDER_NAME]; + scene_render_name_get(scene, sizeof(render_name), render_name); + return RE_GetRender(render_name); +} + +Render *RE_NewSceneRender(const Scene *scene) +{ + char render_name[MAX_SCENE_RENDER_NAME]; + scene_render_name_get(scene, sizeof(render_name), render_name); + return RE_NewRender(render_name); +} + /* called for new renders and when finishing rendering so * we always have valid callbacks on a render */ void RE_InitRenderCB(Render *re) @@ -1913,7 +1942,7 @@ static void do_render_fields_blur_3d(Render *re) */ static void render_scene(Render *re, Scene *sce, int cfra) { - Render *resc = RE_NewRender(sce->id.name); + Render *resc = RE_NewSceneRender(sce); int winx = re->winx, winy = re->winy; sce->r.cfra = cfra; @@ -2348,7 +2377,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) tag_scenes_for_render(re); for (sce = re->main->scene.first; sce; sce = sce->id.next) { if (sce->id.tag & LIB_TAG_DOIT) { - re1 = RE_GetRender(sce->id.name); + re1 = RE_GetSceneRender(sce); if (re1 && (re1->r.scemode & R_FULL_SAMPLE)) { if (sample) { @@ -3858,9 +3887,9 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode) scene = scenode; /* get render: it can be called from UI with draw callbacks */ - re = RE_GetRender(scene->id.name); + re = RE_GetSceneRender(scene); if (re == NULL) - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); RE_InitState(re, NULL, &scene->r, NULL, winx, winy, &disprect); re->scene = scene; re->scene_color_manage = BKE_scene_check_color_management_enabled(scene); diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index 20602314526..b4ff5f52fcf 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -292,12 +292,8 @@ void shade_input_set_triangle_i(ShadeInput *shi, ObjectInstanceRen *obi, VlakRen } } -/* note, facenr declared volatile due to over-eager -O2 optimization's - * on cygwin (particularly -frerun-cse-after-loop) - */ - /* copy data from face to ShadeInput, scanline case */ -void shade_input_set_triangle(ShadeInput *shi, volatile int obi, volatile int facenr, int UNUSED(normal_flip)) +void shade_input_set_triangle(ShadeInput *shi, int obi, int facenr, int UNUSED(normal_flip)) { if (facenr > 0) { shi->obi = &R.objectinstance[obi]; diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index 68707f163af..1481e7a8059 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -393,7 +393,7 @@ static void zbuffillAc4(ZSpan *zspan, int obi, int zvlnr, zverg-= zspan->polygon_offset; while (x>=0) { - intzverg= (int)CLAMPIS(zverg, INT_MIN, INT_MAX); + intzverg = round_db_to_int_clamp(zverg); if ( intzverg < *rz) { if (!zspan->rectmask || intzverg > *rm) { @@ -1137,7 +1137,7 @@ static void zbuffillGLinv4(ZSpan *zspan, int obi, int zvlnr, x= sn2-sn1; while (x>=0) { - intzverg= (int)CLAMPIS(zverg, INT_MIN, INT_MAX); + intzverg = round_db_to_int_clamp(zverg); if ( intzverg > *rz || *rz==0x7FFFFFFF) { /* UNIQUE LINE: see comment above */ if (!zspan->rectmask || intzverg > *rm) { @@ -1260,7 +1260,7 @@ static void zbuffillGL4(ZSpan *zspan, int obi, int zvlnr, x= sn2-sn1; while (x>=0) { - intzverg= (int)CLAMPIS(zverg, INT_MIN, INT_MAX); + intzverg = round_db_to_int_clamp(zverg); if (intzverg < *rz) { /* ONLY UNIQUE LINE: see comment above */ if (!zspan->rectmask || intzverg > *rm) { @@ -1383,7 +1383,7 @@ static void zbuffillGL_onlyZ(ZSpan *zspan, int UNUSED(obi), int UNUSED(zvlnr), x= sn2-sn1; while (x>=0) { - int zvergi= (int)CLAMPIS(zverg, INT_MIN, INT_MAX); + int zvergi = round_db_to_int_clamp(zverg); /* option: maintain two depth values, closest and 2nd closest */ if (zvergi < *rz) { @@ -1564,20 +1564,13 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float * vy0= ((double)my2)*vyd + (double)xx1; /* correct span */ - sn1= (my0 + my2)/2; - if (zspan->span1[sn1] < zspan->span2[sn1]) { - span1= zspan->span1+my2; - span2= zspan->span2+my2; - } - else { - span1= zspan->span2+my2; - span2= zspan->span1+my2; - } + span1= zspan->span1+my2; + span2= zspan->span2+my2; for (i = 0, y = my2; y >= my0; i++, y--, span1--, span2--) { - sn1= floor(*span1); - sn2= floor(*span2); + sn1= floor(min_ff(*span1, *span2)); + sn2= floor(max_ff(*span1, *span2)); sn1++; if (sn2>=rectx) sn2= rectx-1; diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 925563a0777..f22ed34ca2e 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -100,16 +100,6 @@ if(WITH_OPENCOLLADA) add_definitions(-DWITH_COLLADA) endif() -if(WITH_CODEC_QUICKTIME) - list(APPEND INC - ../quicktime - ) - list(APPEND INC_SYS - ${QUICKTIME_INCLUDE_DIRS} - ) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_CODEC_FFMPEG) list(APPEND INC_SYS ${FFMPEG_INCLUDE_DIRS} diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 60a39b24208..7c1c388bcba 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -187,8 +187,9 @@ struct wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase /* mouse */ void WM_event_add_mousemove(struct bContext *C); -bool WM_modal_tweak_exit(const struct wmEvent *event, int tweak_event); +bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event); bool WM_event_is_absolute(const struct wmEvent *event); +bool WM_event_is_last_mousemove(const struct wmEvent *event); #ifdef WITH_INPUT_NDOF /* 3D mouse */ @@ -353,6 +354,7 @@ bool WM_operator_pystring_abbreviate(char *str, int str_len_max); char *WM_prop_pystring_assign(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, int index); void WM_operator_bl_idname(char *to, const char *from); void WM_operator_py_idname(char *to, const char *from); +bool WM_operator_py_idname_ok_or_report(struct ReportList *reports, const char *classname, const char *idname); /* *************** uilist types ******************** */ void WM_uilisttype_init(void); diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 67e961b9cd0..a09cc4aeb31 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -430,7 +430,7 @@ void wm_clear_default_size(bContext *C) /* on startup, it adds all data, for matching */ void wm_add_default(bContext *C) { - wmWindowManager *wm = BKE_libblock_alloc(CTX_data_main(C), ID_WM, "WinMan"); + wmWindowManager *wm = BKE_libblock_alloc(CTX_data_main(C), ID_WM, "WinMan", 0); wmWindow *win; bScreen *screen = CTX_wm_screen(C); /* XXX from file read hrmf */ @@ -495,6 +495,10 @@ void wm_close_and_free_all(bContext *C, ListBase *wmlist) void WM_main(bContext *C) { + /* Single refresh before handling events. + * This ensures we don't run operators before the depsgraph has been evaluated. */ + wm_event_do_refresh_wm_and_depsgraph(C); + while (1) { /* get events from ghost, handle window events, add to window queues */ diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 25c6980f58e..2b695c95258 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -867,25 +867,13 @@ static bool wm_draw_update_test_window(wmWindow *win) static int wm_automatic_draw_method(wmWindow *win) { - /* Ideally all cards would work well with triple buffer, since if it works - * well gives the least redraws and is considerably faster at partial redraw - * for sculpting or drawing overlapping menus. For typically lower end cards - * copy to texture is slow though and so we use overlap instead there. */ - + /* We assume all supported GPUs now support triple buffer well. */ if (win->drawmethod == USER_DRAW_AUTOMATIC) { - /* Windows software driver darkens color on each redraw */ - if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_SOFTWARE)) - return USER_DRAW_OVERLAP_FLIP; - else if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_UNIX, GPU_DRIVER_SOFTWARE)) - return USER_DRAW_OVERLAP; - /* drawing lower color depth again degrades colors each time */ - else if (GPU_color_depth() < 24) - return USER_DRAW_OVERLAP; - else - return USER_DRAW_TRIPLE; + return USER_DRAW_TRIPLE; } - else + else { return win->drawmethod; + } } bool WM_is_draw_triple(wmWindow *win) diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index f26ee0e73ec..7e7314cc0c8 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -263,13 +263,56 @@ static void wm_notifier_clear(wmNotifier *note) memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link)); } +/** + * Was part of #wm_event_do_notifiers, split out so it can be called once before entering the #WM_main loop. + * This ensures operators don't run before the UI and depsgraph are initialized. + */ +void wm_event_do_refresh_wm_and_depsgraph(bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + uint64_t win_combine_v3d_datamask = 0; + + /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */ + for (wmWindow *win = wm->windows.first; win; win = win->next) { + win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen); + } + + /* cached: editor refresh callbacks now, they get context */ + for (wmWindow *win = wm->windows.first; win; win = win->next) { + ScrArea *sa; + + CTX_wm_window_set(C, win); + for (sa = win->screen->areabase.first; sa; sa = sa->next) { + if (sa->do_refresh) { + CTX_wm_area_set(C, sa); + ED_area_do_refresh(C, sa); + } + } + + /* XXX make lock in future, or separated derivedmesh users in scene */ + if (G.is_rendering == false) { + /* depsgraph & animation: update tagged datablocks */ + Main *bmain = CTX_data_main(C); + + /* copied to set's in scene_update_tagged_recursive() */ + win->screen->scene->customdata_mask = win_combine_v3d_datamask; + + /* XXX, hack so operators can enforce datamasks [#26482], gl render */ + win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal; + + BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene); + } + } + + CTX_wm_window_set(C, NULL); +} + /* called in mainloop */ void wm_event_do_notifiers(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); wmNotifier *note, *next; wmWindow *win; - uint64_t win_combine_v3d_datamask = 0; if (wm == NULL) return; @@ -373,39 +416,7 @@ void wm_event_do_notifiers(bContext *C) MEM_freeN(note); } - /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */ - for (win = wm->windows.first; win; win = win->next) { - win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen); - } - - /* cached: editor refresh callbacks now, they get context */ - for (win = wm->windows.first; win; win = win->next) { - ScrArea *sa; - - CTX_wm_window_set(C, win); - for (sa = win->screen->areabase.first; sa; sa = sa->next) { - if (sa->do_refresh) { - CTX_wm_area_set(C, sa); - ED_area_do_refresh(C, sa); - } - } - - /* XXX make lock in future, or separated derivedmesh users in scene */ - if (G.is_rendering == false) { - /* depsgraph & animation: update tagged datablocks */ - Main *bmain = CTX_data_main(C); - - /* copied to set's in scene_update_tagged_recursive() */ - win->screen->scene->customdata_mask = win_combine_v3d_datamask; - - /* XXX, hack so operators can enforce datamasks [#26482], gl render */ - win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal; - - BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene); - } - } - - CTX_wm_window_set(C, NULL); + wm_event_do_refresh_wm_and_depsgraph(C); } static int wm_event_always_pass(const wmEvent *event) @@ -615,6 +626,16 @@ bool WM_event_is_absolute(const wmEvent *event) return (event->tablet_data != NULL); } +bool WM_event_is_last_mousemove(const wmEvent *event) +{ + while ((event = event->next)) { + if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + return false; + } + } + return true; +} + #ifdef WITH_INPUT_NDOF void WM_ndof_deadzone_set(float deadzone) { @@ -1079,6 +1100,9 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op)) #endif +/** + * Also used for exec when 'event' is NULL. + */ static int wm_operator_invoke( bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports, const bool poll_only) @@ -1094,7 +1118,9 @@ static int wm_operator_invoke( wmOperator *op = wm_operator_create(wm, ot, properties, reports); /* if reports == NULL, they'll be initialized */ const bool is_nested_call = (wm->op_undo_depth != 0); - op->flag |= OP_IS_INVOKE; + if (event != NULL) { + op->flag |= OP_IS_INVOKE; + } /* initialize setting from previous run */ if (!is_nested_call) { /* not called by py script */ @@ -2852,7 +2878,7 @@ void WM_event_add_mousemove(bContext *C) /* for modal callbacks, check configuration for how to interpret exit with tweaks */ -bool WM_modal_tweak_exit(const wmEvent *event, int tweak_event) +bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event) { /* if the release-confirm userpref setting is enabled, * tweak events can be canceled when mouse is released diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index b4a6366fb4e..637ace9cd82 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -449,7 +449,7 @@ void wm_file_read_report(bContext *C) * Logic shared between #WM_file_read & #wm_homefile_read, * updates to make after reading a file. */ -static void wm_file_read_post(bContext *C, bool is_startup_file) +static void wm_file_read_post(bContext *C, const bool is_startup_file, const bool use_userdef) { bool addons_loaded = false; wmWindowManager *wm = CTX_wm_manager(C); @@ -468,13 +468,14 @@ 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()"); + if (use_userdef) { + /* 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()"); } - /* sync addons, these may have changed from the defaults */ - BPY_execute_string(C, "__import__('addon_utils').reset_all()"); - BPY_python_reset(C); addons_loaded = true; } @@ -588,7 +589,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) } } - wm_file_read_post(C, false); + wm_file_read_post(C, false, false); success = true; } @@ -636,13 +637,15 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) * * \param use_factory_settings: Ignore on-disk startup file, use bundled ``datatoc_startup_blend`` instead. * Used for "Restore Factory Settings". + * \param use_userdef: Load factory settings as well as startup file. + * Disabled for "File New" we don't want to reload preferences. * \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 use_factory_settings, bool use_empty_data, + bool use_factory_settings, bool use_empty_data, bool use_userdef, const char *filepath_startup_override, const char *app_template_override) { ListBase wmbase; @@ -666,7 +669,7 @@ int wm_homefile_read( * And in this case versioning code is to be run. */ bool read_userdef_from_memory = false; - eBLOReadSkip skip_flags = 0; + eBLOReadSkip skip_flags = use_userdef ? 0 : BLO_READ_SKIP_USERDEF; /* options exclude eachother */ BLI_assert((use_factory_settings && filepath_startup_override) == 0); @@ -693,7 +696,9 @@ int wm_homefile_read( 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); + if (use_userdef) { + BLI_path_join(filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL); + } } else { use_factory_settings = true; @@ -705,14 +710,16 @@ int wm_homefile_read( } /* load preferences before startup.blend */ - 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); - MEM_freeN(userdef); - - skip_flags |= BLO_READ_SKIP_USERDEF; - printf("Read prefs: %s\n", filepath_userdef); + if (use_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); + MEM_freeN(userdef); + + skip_flags |= BLO_READ_SKIP_USERDEF; + printf("Read prefs: %s\n", filepath_userdef); + } } } @@ -721,23 +728,23 @@ int wm_homefile_read( if (filepath_startup_override != NULL) { /* pass */ } - else if (app_template_override && app_template_override[0]) { + else if (app_template_override) { + /* This may be clearing the current template by setting to an empty string. */ app_template = app_template_override; } else if (!use_factory_settings && U.app_template[0]) { app_template = U.app_template; } - if (app_template != NULL) { + if ((app_template != NULL) && (app_template[0] != '\0')) { 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) { + /* Insert template name into startup file. */ + /* 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(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL); 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'; @@ -772,8 +779,12 @@ int wm_homefile_read( success = BKE_blendfile_read_from_memory( C, datatoc_startup_blend, datatoc_startup_blend_size, NULL, skip_flags, true); - if (success && !(skip_flags & BLO_READ_SKIP_USERDEF)) { - read_userdef_from_memory = true; + if (success) { + if (use_userdef) { + if ((skip_flags & BLO_READ_SKIP_USERDEF) == 0) { + read_userdef_from_memory = true; + } + } } if (BLI_listbase_is_empty(&wmbase)) { wm_clear_default_size(C); @@ -801,21 +812,23 @@ int wm_homefile_read( 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); - read_userdef_from_memory = true; - } - if (userdef_template) { - BKE_blender_userdef_set_app_template(userdef_template); - BKE_blender_userdef_free_data(userdef_template); - MEM_freeN(userdef_template); + if (use_userdef) { + 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); + read_userdef_from_memory = true; + } + if (userdef_template) { + BKE_blender_userdef_set_app_template(userdef_template); + BKE_blender_userdef_free_data(userdef_template); + MEM_freeN(userdef_template); + } } } @@ -827,8 +840,10 @@ int wm_homefile_read( * can remove this eventually, only in a 2.53 and older, now its not written */ G.fileflags &= ~G_FILE_RELATIVE_REMAP; - /* check userdef before open window, keymaps etc */ - wm_init_userdef(C, read_userdef_from_memory); + if (use_userdef) { + /* check userdef before open window, keymaps etc */ + wm_init_userdef(C, read_userdef_from_memory); + } /* match the read WM with current WM */ wm_window_match_do(C, &wmbase); @@ -836,9 +851,11 @@ 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(); + if (use_userdef) { + /* When loading factory settings, the reset solid OpenGL lights need to be applied. */ + if (!G.background) { + GPU_default_lights(); + } } /* start with save preference untitled.blend */ @@ -846,7 +863,7 @@ int wm_homefile_read( /* disable auto-play in startup.blend... */ G.fileflags &= ~G_FILE_AUTOPLAY; - wm_file_read_post(C, true); + wm_file_read_post(C, true, use_userdef); return true; } @@ -1528,6 +1545,7 @@ void WM_OT_read_history(wmOperatorType *ot) static int wm_homefile_read_exec(bContext *C, wmOperator *op) { const bool use_factory_settings = (STREQ(op->type->idname, "WM_OT_read_factory_settings")); + bool use_userdef = false; char filepath_buf[FILE_MAX]; const char *filepath = NULL; @@ -1551,6 +1569,8 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op) else { /* always load UI for factory settings (prefs will re-init) */ G.fileflags &= ~G_FILE_NO_UI; + /* Always load preferences with factory settings. */ + use_userdef = true; } char app_template_buf[sizeof(U.app_template)]; @@ -1562,17 +1582,15 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op) 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; + + /* Always load preferences when switching templates. */ + use_userdef = true; } else { app_template = NULL; } - if (wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, filepath, app_template)) { + if (wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, use_userdef, filepath, app_template)) { if (use_splash) { WM_init_splash(C); } diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 46203333eb5..e04571fe572 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -137,7 +137,7 @@ int wm_gesture_evaluate(wmGesture *gesture) int dx = BLI_rcti_size_x(rect); int dy = BLI_rcti_size_y(rect); if (abs(dx) + abs(dy) > U.tweak_threshold) { - int theta = iroundf(4.0f * atan2f((float)dy, (float)dx) / (float)M_PI); + int theta = round_fl_to_int(4.0f * atan2f((float)dy, (float)dx) / (float)M_PI); int val = EVT_GESTURE_W; if (theta == 0) val = EVT_GESTURE_E; diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 00a9976e8be..e73ec2b081a 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -184,15 +184,12 @@ void WM_init(bContext *C, int argc, const char **argv) BLF_init(); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */ BLT_lang_init(); - /* Enforce loading the UI for the initial homefile */ - G.fileflags &= ~G_FILE_NO_UI; - /* reports cant be initialized before the wm, * but keep before file reading, since that may report errors */ wm_init_reports(C); /* get the default database, plus a wm */ - wm_homefile_read(C, NULL, G.factory_startup, false, NULL, NULL); + wm_homefile_read(C, NULL, G.factory_startup, false, true, NULL, NULL); BLT_lang_set(NULL); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index d3ebd3e4d2c..51c551cd9a5 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -177,7 +177,7 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *)) /* XXX All ops should have a description but for now allow them not to. */ RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP); - RNA_def_struct_identifier(ot->srna, ot->idname); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); } @@ -193,7 +193,7 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void * ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT; opfunc(ot, userdata); RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP); - RNA_def_struct_identifier(ot->srna, ot->idname); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); } @@ -398,7 +398,7 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam ot->description = UNDOCUMENTED_OPERATOR_TIP; RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); - RNA_def_struct_identifier(ot->srna, ot->idname); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); /* Use i18n context from ext.srna if possible (py operators). */ i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLT_I18NCONTEXT_OPERATOR_DEFAULT; RNA_def_struct_translation_context(ot->srna, i18n_context); @@ -432,7 +432,7 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *), opfunc(ot, userdata); RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); - RNA_def_struct_identifier(ot->srna, ot->idname); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); } @@ -573,6 +573,46 @@ void WM_operator_bl_idname(char *to, const char *from) } /** + * Sanity check to ensure #WM_operator_bl_idname won't fail. + * \returns true when there are no problems with \a idname, otherwise report an error. + */ +bool WM_operator_py_idname_ok_or_report(ReportList *reports, const char *classname, const char *idname) +{ + const char *ch = idname; + int dot = 0; + int i; + for (i = 0; *ch; i++, ch++) { + if ((*ch >= 'a' && *ch <= 'z') || (*ch >= '0' && *ch <= '9') || *ch == '_') { + /* pass */ + } + else if (*ch == '.') { + dot++; + } + else { + BKE_reportf(reports, RPT_ERROR, + "Registering operator class: '%s', invalid bl_idname '%s', at position %d", + classname, idname, i); + return false; + } + } + + if (i > (MAX_NAME - 3)) { + BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', " + "is too long, maximum length is %d", classname, idname, + MAX_NAME - 3); + return false; + } + + if (dot != 1) { + BKE_reportf(reports, RPT_ERROR, + "Registering operator class: '%s', invalid bl_idname '%s', must contain 1 '.' character", + classname, idname); + return false; + } + return true; +} + +/** * Print a string representation of the operator, with the args that it runs so python can run it again. * * When calling from an existing wmOperator, better to use simple version: @@ -806,9 +846,19 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert } \ } (void)0 +#define CTX_TEST_SPACE_TYPE(space_data_type, member_full, dataptr_cmp) \ + { \ + const char *ctx_member_full = member_full; \ + if (space_data->spacetype == space_data_type && ptr->data == dataptr_cmp) { \ + member_id = ctx_member_full; \ + break; \ + } \ + } (void)0 + switch (GS(((ID *)ptr->id.data)->name)) { case ID_SCE: { + CTX_TEST_PTR_DATA_TYPE(C, "active_gpencil_brush", RNA_GPencilBrush, ptr, CTX_data_active_gpencil_brush(C)); CTX_TEST_PTR_ID(C, "scene", ptr->id.data); break; } @@ -843,12 +893,22 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert { CTX_TEST_PTR_ID(C, "screen", ptr->id.data); - CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, CTX_wm_space_data(C)); + SpaceLink *space_data = CTX_wm_space_data(C); + + CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, space_data); CTX_TEST_PTR_DATA_TYPE(C, "area", RNA_Area, ptr, CTX_wm_area(C)); CTX_TEST_PTR_DATA_TYPE(C, "region", RNA_Region, ptr, CTX_wm_region(C)); + CTX_TEST_SPACE_TYPE(SPACE_IMAGE, "space_data.uv_editor", space_data); + CTX_TEST_SPACE_TYPE(SPACE_VIEW3D, "space_data.fx_settings", &(CTX_wm_view3d(C)->fx_settings)); + CTX_TEST_SPACE_TYPE(SPACE_NLA, "space_data.dopesheet", CTX_wm_space_nla(C)->ads); + CTX_TEST_SPACE_TYPE(SPACE_IPO, "space_data.dopesheet", CTX_wm_space_graph(C)->ads); + CTX_TEST_SPACE_TYPE(SPACE_ACTION, "space_data.dopesheet", &(CTX_wm_space_action(C)->ads)); + CTX_TEST_SPACE_TYPE(SPACE_FILE, "space_data.params", CTX_wm_space_file(C)->params); break; } + default: + break; } if (member_id) { @@ -860,6 +920,7 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert } #undef CTX_TEST_PTR_ID #undef CTX_TEST_PTR_ID_CAST +#undef CTX_TEST_SPACE_TYPE } return ret; diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 8afeb8e7b3d..9fe215f7712 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -377,7 +377,12 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win) void WM_window_set_dpi(wmWindow *win) { - int auto_dpi = GHOST_GetDPIHint(win->ghostwin); + float auto_dpi = GHOST_GetDPIHint(win->ghostwin); + + /* Clamp auto DPI to 96, since our font/interface drawing does not work well + * with lower sizes. The main case we are interested in supporting is higher + * DPI. If a smaller UI is desired it is still possible to adjust UI scale. */ + auto_dpi = max_ff(auto_dpi, 96.0f); /* Lazily init UI scale size, preserving backwards compatibility by * computing UI scale from ratio of previous DPI and auto DPI */ @@ -397,13 +402,16 @@ void WM_window_set_dpi(wmWindow *win) /* 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. */ + auto_dpi *= GHOST_GetNativePixelSize(win->ghostwin); 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); + int pixelsize = max_ii(1, (int)(dpi / 64)); + /* User adjustment for pixel size. */ + pixelsize = max_ii(1, pixelsize + U.ui_line_width); /* Set user preferences globals for drawing, and for forward compatibility. */ - U.pixelsize = GHOST_GetNativePixelSize(win->ghostwin) * pixelsize; + U.pixelsize = pixelsize; U.dpi = dpi / pixelsize; U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE; U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72; diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index efc01b1f8a8..3fb9cd617bf 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -87,7 +87,8 @@ void wm_event_do_handlers (bContext *C); void wm_event_add_ghostevent (wmWindowManager *wm, wmWindow *win, int type, int time, void *customdata); -void wm_event_do_notifiers (bContext *C); +void wm_event_do_refresh_wm_and_depsgraph(bContext *C); +void wm_event_do_notifiers(bContext *C); /* wm_keymap.c */ diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h index 9a1518e15b0..b102b6c7cc7 100644 --- a/source/blender/windowmanager/wm_files.h +++ b/source/blender/windowmanager/wm_files.h @@ -37,7 +37,7 @@ struct wmOperatorType; void wm_history_file_read(void); int wm_homefile_read( struct bContext *C, struct ReportList *reports, - bool use_factory_settings, bool use_empty_data, + bool use_factory_settings, bool use_empty_data, bool use_userdef, const char *filepath_startup_override, const char *app_template_override); void wm_file_read_report(bContext *C); diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index 66c72be3d5d..e5a5ff828dd 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -27,10 +27,6 @@ setup_libdirs() -if(WITH_CODEC_QUICKTIME) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WIN32 AND NOT UNIX) string(SUBSTRING ${BLENDER_VERSION} 0 1 bver1) string(SUBSTRING ${BLENDER_VERSION} 2 1 bver2) @@ -200,10 +196,6 @@ endif() list(APPEND BLENDER_SORTED_LIBS extern_xdnd) endif() - if(WITH_CODEC_QUICKTIME) - list(APPEND BLENDER_SORTED_LIBS bf_quicktime) - endif() - if(WITH_CXX_GUARDEDALLOC) list(APPEND BLENDER_SORTED_LIBS bf_intern_guardedalloc_cpp) endif() diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 7ee0e75b2f7..6afb6c103e0 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -271,6 +271,7 @@ void RE_sample_material_color( int tri_index, struct DerivedMesh *orcoDm, struct Object *ob) RET_NONE /* nodes */ struct Render *RE_GetRender(const char *name) RET_NULL +struct Render *RE_GetSceneRender(const struct Scene *scene) RET_NULL struct Object *RE_GetCamera(struct Render *re) RET_NULL float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]) RET_ZERO const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4] RET_NULL @@ -296,6 +297,7 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype) RET_NONE double elbeemEstimateMemreq(int res, float sx, float sy, float sz, int refine, char *retstr) RET_ZERO struct Render *RE_NewRender(const char *name) RET_NULL +struct Render *RE_NewSceneRender(const struct Scene *scene) RET_NULL void RE_SwapResult(struct Render *re, struct RenderResult **rr) RET_NONE void RE_BlenderFrame(struct Render *re, struct Main *bmain, struct Scene *scene, struct SceneRenderLayer *srl, struct Object *camera_override, unsigned int lay_override, int frame, const bool write_still) RET_NONE bool RE_WriteEnvmapResult(struct ReportList *reports, struct Scene *scene, struct EnvMap *env, const char *relpath, const char imtype, float layout[12]) RET_ZERO @@ -355,7 +357,7 @@ int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struc void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference) RET_NONE void WM_main_add_notifier(unsigned int type, void *reference) RET_NONE void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep) RET_NONE -void ED_armature_transform(struct bArmature *arm, float mat[4][4]) RET_NONE +void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props) RET_NONE struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op) RET_NULL struct wmTimer *WM_event_add_timer(struct wmWindowManager *wm, struct wmWindow *win, int event_type, double timestep) RET_NULL void WM_event_remove_timer(struct wmWindowManager *wm, struct wmWindow *win, struct wmTimer *timer) RET_NONE @@ -699,6 +701,7 @@ void WM_operatortype_append_ptr(void (*opfunc)(struct wmOperatorType *, void *), void WM_operatortype_append_macro_ptr(void (*opfunc)(struct wmOperatorType *, void *), void *userdata) RET_NONE void WM_operator_bl_idname(char *to, const char *from) RET_NONE void WM_operator_py_idname(char *to, const char *from) RET_NONE +bool WM_operator_py_idname_ok_or_report(struct ReportList *reports, const char *classname, const char *idname) RET_ZERO int WM_operator_ui_popup(struct bContext *C, struct wmOperator *op, int width, int height) RET_ZERO void update_autoflags_fcurve(struct FCurve *fcu, struct bContext *C, struct ReportList *reports, struct PointerRNA *ptr) RET_NONE short insert_keyframe(struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, char keytype, short flag) RET_ZERO diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 8f26e248424..54a212f805b 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -607,7 +607,7 @@ if(UNIX AND NOT APPLE) PATTERN "*.pyo" EXCLUDE # * any cache * ) # On some platforms requests does have extra dependencies. - set(_requests_deps "chardet" "urllib3") + set(_requests_deps "certifi" "chardet" "idna" "urllib3") foreach(_requests_dep ${_requests_deps}) if(EXISTS ${PYTHON_REQUESTS_PATH}/${_requests_dep}) install( @@ -701,7 +701,7 @@ elseif(WIN32) ) if(WITH_PYTHON_INSTALL_NUMPY) - set(PYTHON_NUMPY_VERSION 1.10) + set(PYTHON_NUMPY_VERSION 1.13) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages) @@ -845,6 +845,13 @@ elseif(APPLE) PATTERN "__MACOSX" EXCLUDE PATTERN ".DS_Store" EXCLUDE PATTERN "config-${PYTHON_VERSION}m/*.a" EXCLUDE # static lib + PATTERN "lib2to3" EXCLUDE # ./lib2to3 + PATTERN "tkinter" EXCLUDE # ./tkinter + PATTERN "lib-dynload/_tkinter.*" EXCLUDE # ./lib-dynload/_tkinter.co + PATTERN "idlelib" EXCLUDE # ./idlelib + PATTERN "test" EXCLUDE # ./test + PATTERN "turtledemo" EXCLUDE # ./turtledemo + PATTERN "turtle.py" EXCLUDE # ./turtle.py ) endmacro() @@ -908,40 +915,10 @@ elseif(APPLE) # python if(WITH_PYTHON AND NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK) - # the python zip is first extracted as part of the build process, - # and then later installed as part of make install. this is much - # quicker, and means we can easily exclude files on copy - # Not needed for PYTHON_MODULE or WEB_PLUGIN due uses Pyhon framework - # use a hash of the .zip path to handle switching between different - # lib directories without needing a clean build - string(SHA1 PYTHON_ZIP_HASH ${LIBDIR}/release/${PYTHON_ZIP}) - set(PYTHON_EXTRACT_DIR ${CMAKE_CURRENT_BINARY_DIR}/${PYTHON_ZIP_HASH}/python) - - add_custom_target( - extractpyzip - DEPENDS ${PYTHON_EXTRACT_DIR}) - - set(PYTHON_ZIP "python_${CMAKE_OSX_ARCHITECTURES}.zip") - - add_custom_command( - OUTPUT ${PYTHON_EXTRACT_DIR} - COMMAND ${CMAKE_COMMAND} -E remove_directory "${PYTHON_EXTRACT_DIR}/" - COMMAND ${CMAKE_COMMAND} -E make_directory "${PYTHON_EXTRACT_DIR}/" - COMMAND ${CMAKE_COMMAND} -E chdir "${PYTHON_EXTRACT_DIR}/" - ${CMAKE_COMMAND} -E tar xzfv "${LIBDIR}/release/${PYTHON_ZIP}" - DEPENDS ${LIBDIR}/release/${PYTHON_ZIP}) - - add_dependencies(blender extractpyzip) - - # copy extracted python files + # Copy the python libs into the install directory install_dir( - ${PYTHON_EXTRACT_DIR} - \${TARGETDIR_VER} - ) - # copy site-packages files - install_dir( - ${LIBDIR}/release/site-packages - \${TARGETDIR_VER}/python/lib/python${PYTHON_VERSION} + ${PYTHON_LIBPATH} + ${TARGETDIR_VER}/python/lib ) install(DIRECTORY ${LIBDIR}/python/bin @@ -997,18 +974,10 @@ elseif(APPLE) # python if(WITH_PYTHON AND NOT WITH_PYTHON_FRAMEWORK) - add_custom_command( - OUTPUT ${PYTHON_EXTRACT_DIR} - COMMAND ${CMAKE_COMMAND} -E remove_directory "${PYTHON_EXTRACT_DIR}/" - COMMAND ${CMAKE_COMMAND} -E make_directory "${PYTHON_EXTRACT_DIR}/" - COMMAND ${CMAKE_COMMAND} -E chdir "${PYTHON_EXTRACT_DIR}/" - ${CMAKE_COMMAND} -E tar xzfv "${LIBDIR}/release/${PYTHON_ZIP}" - DEPENDS ${LIBDIR}/release/${PYTHON_ZIP}) - - # copy extracted python files + # Copy the python libs into the install directory install_dir( - ${PYTHON_EXTRACT_DIR} - \${PLAYER_TARGETDIR_VER} + ${PYTHON_LIBPATH} + ${PLAYER_TARGETDIR_VER}/python/lib ) endif() diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 658a0b2db08..83e8bbb9ef3 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -1129,7 +1129,7 @@ static const char arg_handle_image_type_set_doc[] = "\t\tTGA RAWTGA JPEG IRIS IRIZ\n" "\t\tAVIRAW AVIJPEG PNG BMP\n" "\t(formats that can be compiled into blender, not available on all systems)\n" -"\t\tHDR TIFF EXR MULTILAYER MPEG FRAMESERVER QUICKTIME CINEON DPX DDS JP2" +"\t\tHDR TIFF EXR MULTILAYER MPEG FRAMESERVER CINEON DPX DDS JP2" ; static int arg_handle_image_type_set(int argc, const char **argv, void *data) { @@ -1362,7 +1362,7 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data) return 1; } - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); BLI_begin_threaded_malloc(); BKE_reports_init(&reports, RPT_STORE); @@ -1404,7 +1404,7 @@ static int arg_handle_render_animation(int UNUSED(argc), const char **UNUSED(arg Scene *scene = CTX_data_scene(C); if (scene) { Main *bmain = CTX_data_main(C); - Render *re = RE_NewRender(scene->id.name); + Render *re = RE_NewSceneRender(scene); ReportList reports; BLI_begin_threaded_malloc(); BKE_reports_init(&reports, RPT_STORE); diff --git a/source/gameengine/GameLogic/CMakeLists.txt b/source/gameengine/GameLogic/CMakeLists.txt index 05071f59707..b9eec74f6f4 100644 --- a/source/gameengine/GameLogic/CMakeLists.txt +++ b/source/gameengine/GameLogic/CMakeLists.txt @@ -139,6 +139,9 @@ if(WITH_SDL) if(WITH_GHOST_SDL) add_definitions(-DWITH_GHOST_SDL) endif() + if(WITH_SDL_DYNLOAD) + add_definitions(-DWITH_SDL_DYNLOAD) + endif() endif() blender_add_lib(ge_logic "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp index 1a66b2aee52..9f532527a80 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp +++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp @@ -38,7 +38,11 @@ #include "BLI_path_util.h" #ifdef WITH_SDL -# define SDL_CHECK(x) ((x) != (void *)0) +# ifdef WITH_SDL_DYNLOAD +# define SDL_CHECK(x) ((x) != (void *)0) +# else +# define SDL_CHECK(x) true +# endif #endif SCA_Joystick::SCA_Joystick(short int index) diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp index fd3d713b3d2..1dee1de9de2 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp +++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp @@ -82,9 +82,11 @@ void SCA_Joystick::HandleEvents(void) { SDL_Event sdl_event; +#ifdef WITH_SDL_DYNLOAD if (SDL_PollEvent == (void*)0) { return; } +#endif int i; for (i=0; i<m_joynum; i++) { /* could use JOYINDEX_MAX but no reason to */ diff --git a/source/gameengine/Ketsji/KX_FontObject.cpp b/source/gameengine/Ketsji/KX_FontObject.cpp index 364f8d4bfc6..91e8e4fd42b 100644 --- a/source/gameengine/Ketsji/KX_FontObject.cpp +++ b/source/gameengine/Ketsji/KX_FontObject.cpp @@ -281,7 +281,7 @@ int KX_FontObject::pyattr_set_text(void *self_v, const KX_PYATTRIBUTE_DEF *attrd KX_FontObject* self = static_cast<KX_FontObject*>(self_v); if (!PyUnicode_Check(value)) return PY_SET_ATTR_FAIL; - char* chars = _PyUnicode_AsString(value); + const char *chars = _PyUnicode_AsString(value); /* Allow for some logic brick control */ CValue* tprop = self->GetProperty("Text"); diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 97a7e161e9f..5540aad7a3f 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -40,11 +40,6 @@ # ifdef _XOPEN_SOURCE # undef _XOPEN_SOURCE # endif -# if defined(__sun) || defined(sun) -# if defined(_XPG4) -# undef _XPG4 -# endif -# endif # include <Python.h> extern "C" { diff --git a/source/gameengine/VideoTexture/FilterBase.cpp b/source/gameengine/VideoTexture/FilterBase.cpp index 5717a1edbcb..b41a2095890 100644 --- a/source/gameengine/VideoTexture/FilterBase.cpp +++ b/source/gameengine/VideoTexture/FilterBase.cpp @@ -114,6 +114,7 @@ void Filter_dealloc(PyFilter *self) delete self->m_filter; self->m_filter = NULL; } + Py_TYPE((PyObject *)self)->tp_free((PyObject *)self); } diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp index b91a312a5d7..a547d2a7a85 100644 --- a/source/gameengine/VideoTexture/ImageBase.cpp +++ b/source/gameengine/VideoTexture/ImageBase.cpp @@ -427,6 +427,7 @@ void Image_dealloc(PyImage *self) delete self->m_image; self->m_image = NULL; } + Py_TYPE((PyObject *)self)->tp_free((PyObject *)self); } // get image data |