diff options
author | Antonioya <blendergit@gmail.com> | 2019-07-23 10:46:29 +0300 |
---|---|---|
committer | Antonioya <blendergit@gmail.com> | 2019-07-23 10:46:29 +0300 |
commit | 2204bfcf9e1c3a38e60830bd97775dd72158f4d6 (patch) | |
tree | 4f9c827389a23a431f8771b4ca02f410860c0242 /source | |
parent | f64db794ee690f05905ace0a66d81d2e75549b90 (diff) | |
parent | 34ad6da4a06ef46cd19945f61cc5f968538546a8 (diff) |
Merge branch 'master' into temp-gpencil-drw-engine
Diffstat (limited to 'source')
381 files changed, 6319 insertions, 5055 deletions
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index e39b5686c82..56fb5a68402 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -165,6 +165,15 @@ static bool export_object(const ExportSettings *const settings, } } + Object *ob_eval = DEG_get_evaluated_object(settings->depsgraph, base->object); + if ((ob_eval->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) { + /* XXX fix after 2.80: the object was not part of the depsgraph, and thus we cannot get the + * evaluated copy to export. This will be handled more elegantly in the new + * AbstractHierarchyIterator that Sybren is working on. This condition is temporary, and avoids + * a BLI_assert() failure getting the evaluated mesh of this object. */ + return false; + } + // if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) { // return false; // } diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index de227be0044..b0129a358ec 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -409,6 +409,7 @@ void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh) { std::vector<Imath::V3f> points, normals; std::vector<int32_t> poly_verts, loop_counts; + std::vector<Imath::V3f> velocities; bool smooth_normal = false; @@ -458,9 +459,7 @@ void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh) } if (m_is_liquid) { - std::vector<Imath::V3f> velocities; getVelocities(mesh, velocities); - m_mesh_sample.setVelocities(V3fArraySample(velocities)); } @@ -973,8 +972,7 @@ static void *add_customdata_cb(void *user_data, const char *name, int data_type) return cd_ptr; } - /* create a new layer, taking care to construct the hopefully-soon-to-be-removed - * CD_MTEXPOLY layer too, with the same name. */ + /* Create a new layer. */ numloops = mesh->totloop; cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, NULL, numloops, name); return cd_ptr; @@ -1124,7 +1122,9 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, sample = m_schema.getValue(sample_sel); } catch (Alembic::Util::Exception &ex) { - *err_str = "Error reading mesh sample; more detail on the console"; + if (err_str != nullptr) { + *err_str = "Error reading mesh sample; more detail on the console"; + } printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n", m_iobject.getFullName().c_str(), m_schema.getName().c_str(), @@ -1419,7 +1419,9 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh, sample = m_schema.getValue(sample_sel); } catch (Alembic::Util::Exception &ex) { - *err_str = "Error reading mesh sample; more detail on the console"; + if (err_str != nullptr) { + *err_str = "Error reading mesh sample; more detail on the console"; + } printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n", m_iobject.getFullName().c_str(), m_schema.getName().c_str(), diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc index e437273c1be..54450ce1cb2 100644 --- a/source/blender/alembic/intern/abc_object.cc +++ b/source/blender/alembic/intern/abc_object.cc @@ -263,9 +263,6 @@ void AbcObjectReader::setupObjectTransform(const float time) data->cache_file = m_settings->cache_file; id_us_plus(&data->cache_file->id); - - data->reader = reinterpret_cast<CacheReader *>(this); - this->incref(); } } diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 69f3070fcba..a4863780d2e 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -160,6 +160,7 @@ void BKE_pose_copy_data(struct bPose **dst, const struct bPose *src, const bool 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); struct bPoseChannel *BKE_pose_channel_active(struct Object *ob); +struct bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob); struct bPoseChannel *BKE_pose_channel_verify(struct bPose *pose, const char *name); struct bPoseChannel *BKE_pose_channel_get_mirrored(const struct bPose *pose, const char *name); diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 6839e13ffe1..73e62f6a7b3 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -90,6 +90,8 @@ void BKE_armature_bone_hash_free(struct bArmature *arm); bool BKE_armature_bone_flag_test_recursive(const struct Bone *bone, int flag); +void BKE_armature_refresh_layer_used(struct bArmature *arm); + float distfactor_to_bone( const float vec[3], const float b1[3], const float b2[3], float r1, float r2, float rdist); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 5de8ad68c96..a400e4411cf 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,7 +27,7 @@ * \note Use #STRINGIFY() rather than defining with quotes. */ #define BLENDER_VERSION 280 -#define BLENDER_SUBVERSION 74 +#define BLENDER_SUBVERSION 75 /** Several breakages with 280, e.g. collections vs layers. */ #define BLENDER_MINVERSION 280 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index c1e36f5dd83..972ae5e8628 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -85,7 +85,7 @@ struct Scene *BKE_collection_master_scene_search(const struct Main *bmain, /* Collection Objects */ -bool BKE_collection_has_object(struct Collection *collection, struct Object *ob); +bool BKE_collection_has_object(struct Collection *collection, const struct Object *ob); bool BKE_collection_has_object_recursive(struct Collection *collection, struct Object *ob); struct Collection *BKE_collection_object_find(struct Main *bmain, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 0e3b0181fb9..ae1000d1b99 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -215,6 +215,7 @@ bool BKE_gpencil_smooth_stroke(struct bGPDstroke *gps, int i, float inf); bool BKE_gpencil_smooth_stroke_strength(struct bGPDstroke *gps, int point_index, float influence); bool BKE_gpencil_smooth_stroke_thickness(struct bGPDstroke *gps, int point_index, float influence); bool BKE_gpencil_smooth_stroke_uv(struct bGPDstroke *gps, int point_index, float influence); +bool BKE_gpencil_close_stroke(struct bGPDstroke *gps); void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe); float BKE_gpencil_multiframe_falloff_calc( diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h index d616c74520a..1f2f8ee57bf 100644 --- a/source/blender/blenkernel/BKE_gpencil_modifier.h +++ b/source/blender/blenkernel/BKE_gpencil_modifier.h @@ -52,10 +52,10 @@ struct bGPDstroke; ((((_md)->mode & eGpencilModifierMode_Editmode) == 0) && (_is_edit)) typedef enum { - /* Should not be used, only for None modifier type */ + /** Should not be used, only for None modifier type. */ eGpencilModifierTypeType_None, - /* grease pencil modifiers */ + /** Grease pencil modifiers. */ eGpencilModifierTypeType_Gpencil, } GpencilModifierTypeType; @@ -63,25 +63,26 @@ typedef enum { eGpencilModifierTypeFlag_SupportsMapping = (1 << 0), eGpencilModifierTypeFlag_SupportsEditmode = (1 << 1), - /* For modifiers that support editmode this determines if the - * modifier should be enabled by default in editmode. This should + /** + * For modifiers that support edit-mode this determines if the + * modifier should be enabled by default in edit-mode. This should * only be used by modifiers that are relatively speedy and - * also generally used in editmode, otherwise let the user enable - * it by hand. + * also generally used in edit-mode, otherwise let the user enable it by hand. */ eGpencilModifierTypeFlag_EnableInEditmode = (1 << 2), - /* For modifiers that require original data and so cannot - * be placed after any non-deformative modifier. + /** + * For modifiers that require original data and so cannot + * be placed after any non-deform modifier. */ eGpencilModifierTypeFlag_RequiresOriginalData = (1 << 3), - /* max one per type */ + /** Max one per type. */ eGpencilModifierTypeFlag_Single = (1 << 4), - /* can't be added manually by user */ + /** Can't be added manually by user. */ eGpencilModifierTypeFlag_NoUserAdd = (1 << 5), - /* can't be applied */ + /** Can't be applied. */ eGpencilModifierTypeFlag_NoApply = (1 << 6), } GpencilModifierTypeFlag; diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 6f4dc3aff3b..28769ba7de9 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -231,7 +231,7 @@ void BKE_main_lib_objects_recalc_all(struct Main *bmain); void BKE_main_id_repair_duplicate_names_listbase(struct ListBase *lb); #define MAX_ID_FULL_NAME (64 + 64 + 3 + 1) /* 64 is MAX_ID_NAME - 2 */ -#define MAX_ID_FULL_NAME_UI (MAX_ID_FULL_NAME + 3) /* Adds 'keycode' two letters at begining. */ +#define MAX_ID_FULL_NAME_UI (MAX_ID_FULL_NAME + 3) /* Adds 'keycode' two letters at beginning. */ void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const struct ID *id); void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI], const struct ID *id); diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h index 4f74b2b5a6b..b959b55b1d6 100644 --- a/source/blender/blenkernel/BKE_library_query.h +++ b/source/blender/blenkernel/BKE_library_query.h @@ -65,9 +65,10 @@ enum { enum { IDWALK_RET_NOP = 0, - IDWALK_RET_STOP_ITER = 1 << 0, /* Completely stop iteration. */ - IDWALK_RET_STOP_RECURSION = - 1 << 1, /* Stop recursion, that is, do not loop over ID used by current one. */ + /** Completely stop iteration. */ + IDWALK_RET_STOP_ITER = 1 << 0, + /** Stop recursion, that is, do not loop over ID used by current one. */ + IDWALK_RET_STOP_RECURSION = 1 << 1, }; /** diff --git a/source/blender/blenkernel/BKE_mesh_iterators.h b/source/blender/blenkernel/BKE_mesh_iterators.h index 7bbd64c0bac..28fd4b8bc28 100644 --- a/source/blender/blenkernel/BKE_mesh_iterators.h +++ b/source/blender/blenkernel/BKE_mesh_iterators.h @@ -59,6 +59,11 @@ void BKE_mesh_foreach_mapped_face_center( void (*func)(void *userData, int index, const float cent[3], const float no[3]), void *userData, MeshForeachFlag flag); +void BKE_mesh_foreach_mapped_subdiv_face_center( + struct Mesh *mesh, + void (*func)(void *userData, int index, const float cent[3], const float no[3]), + void *userData, + MeshForeachFlag flag); void BKE_mesh_foreach_mapped_vert_coords_get(struct Mesh *me_eval, float (*r_cos)[3], diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 30a366805b6..4aab2a346e7 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -382,6 +382,7 @@ struct Object *modifiers_isDeformedByMeshDeform(struct Object *ob); struct Object *modifiers_isDeformedByLattice(struct Object *ob); struct Object *modifiers_isDeformedByCurve(struct Object *ob); bool modifiers_usesArmature(struct Object *ob, struct bArmature *arm); +bool modifiers_usesSubsurfFacedots(struct Scene *scene, struct Object *ob); bool modifiers_isCorrectableDeformed(struct Scene *scene, struct Object *ob); void modifier_freeTemporaryData(struct ModifierData *md); bool modifiers_isPreview(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index 33672b5d397..c5955a9af8d 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -49,7 +49,9 @@ void multires_customdata_delete(struct Mesh *me); void multires_set_tot_level(struct Object *ob, struct MultiresModifierData *mmd, int lvl); -void multires_mark_as_modified(struct Object *ob, enum MultiresModifiedFlags flags); +void multires_mark_as_modified(struct Depsgraph *depsgraph, + struct Object *object, + enum MultiresModifiedFlags flags); void multires_force_update(struct Object *ob); void multires_force_render_update(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index fdd61580d9e..f59bf3579be 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -295,6 +295,7 @@ void BKE_object_eval_transform_all(struct Depsgraph *depsgraph, void BKE_object_eval_update_shading(struct Depsgraph *depsgraph, struct Object *object); void BKE_object_data_select_update(struct Depsgraph *depsgraph, struct ID *object_data); +void BKE_object_select_update(struct Depsgraph *depsgraph, struct Object *object); void BKE_object_eval_eval_base_flags(struct Depsgraph *depsgraph, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h index ad0f474a730..ab8d07d18e0 100644 --- a/source/blender/blenkernel/BKE_packedFile.h +++ b/source/blender/blenkernel/BKE_packedFile.h @@ -33,50 +33,84 @@ struct ReportList; struct VFont; struct bSound; +enum ePF_FileCompare { + PF_CMP_EQUAL = 0, + PF_CMP_DIFFERS = 1, + PF_CMP_NOFILE = 2, +}; + +enum ePF_FileStatus { + PF_WRITE_ORIGINAL = 3, + PF_WRITE_LOCAL = 4, + PF_USE_LOCAL = 5, + PF_USE_ORIGINAL = 6, + PF_KEEP = 7, + PF_REMOVE = 8, + PF_NOOP = 9, + + PF_ASK = 10, +}; + /* pack */ -struct PackedFile *dupPackedFile(const struct PackedFile *pf_src); -struct PackedFile *newPackedFile(struct ReportList *reports, - const char *filename, - const char *relabase); -struct PackedFile *newPackedFileMemory(void *mem, int memlen); +struct PackedFile *BKE_packedfile_duplicate(const struct PackedFile *pf_src); +struct PackedFile *BKE_packedfile_new(struct ReportList *reports, + const char *filename, + const char *relabase); +struct PackedFile *BKE_packedfile_new_from_memory(void *mem, int memlen); -void packAll(struct Main *bmain, struct ReportList *reports, bool verbose); -void packLibraries(struct Main *bmain, struct ReportList *reports); +void BKE_packedfile_pack_all(struct Main *bmain, struct ReportList *reports, bool verbose); +void BKE_packedfile_pack_all_libraries(struct Main *bmain, struct ReportList *reports); /* unpack */ -char *unpackFile(struct ReportList *reports, - const char *ref_file_name, - const char *abs_name, - const char *local_name, - struct PackedFile *pf, - int how); -int unpackVFont(struct Main *bmain, struct ReportList *reports, struct VFont *vfont, int how); -int unpackSound(struct Main *bmain, struct ReportList *reports, struct bSound *sound, int how); -int unpackImage(struct Main *bmain, struct ReportList *reports, struct Image *ima, int how); -void unpackAll(struct Main *bmain, struct ReportList *reports, int how); -int unpackLibraries(struct Main *bmain, struct ReportList *reports); +char *BKE_packedfile_unpack_to_file(struct ReportList *reports, + const char *ref_file_name, + const char *abs_name, + const char *local_name, + struct PackedFile *pf, + enum ePF_FileStatus how); +int BKE_packedfile_unpack_vfont(struct Main *bmain, + struct ReportList *reports, + struct VFont *vfont, + enum ePF_FileStatus how); +int BKE_packedfile_unpack_sound(struct Main *bmain, + struct ReportList *reports, + struct bSound *sound, + enum ePF_FileStatus how); +int BKE_packedfile_unpack_image(struct Main *bmain, + struct ReportList *reports, + struct Image *ima, + enum ePF_FileStatus how); +void BKE_packedfile_unpack_all(struct Main *bmain, + struct ReportList *reports, + enum ePF_FileStatus how); +int BKE_packedfile_unpack_all_libraries(struct Main *bmain, struct ReportList *reports); -int writePackedFile(struct ReportList *reports, - const char *ref_file_name, - const char *filename, - struct PackedFile *pf, - const bool guimode); +int BKE_packedfile_write_to_file(struct ReportList *reports, + const char *ref_file_name, + const char *filename, + struct PackedFile *pf, + const bool guimode); /* free */ -void freePackedFile(struct PackedFile *pf); +void BKE_packedfile_free(struct PackedFile *pf); /* info */ -int countPackedFiles(struct Main *bmain); -int checkPackedFile(const char *ref_file_name, const char *filename, struct PackedFile *pf); +int BKE_packedfile_count_all(struct Main *bmain); +enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name, + const char *filename, + struct PackedFile *pf); /* read */ -int seekPackedFile(struct PackedFile *pf, int offset, int whence); -void rewindPackedFile(struct PackedFile *pf); -int readPackedFile(struct PackedFile *pf, void *data, int size); +int BKE_packedfile_seek(struct PackedFile *pf, int offset, int whence); +void BKE_packedfile_rewind(struct PackedFile *pf); +int BKE_packedfile_read(struct PackedFile *pf, void *data, int size); /* ID should be not NULL, return 1 if there's a packed file */ -bool BKE_pack_check(struct ID *id); +bool BKE_packedfile_id_check(struct ID *id); /* ID should be not NULL, throws error when ID is Library */ -void BKE_unpack_id(struct Main *bmain, struct ID *id, struct ReportList *reports, int how); +void BKE_packedfile_id_unpack(struct Main *bmain, + struct ID *id, + struct ReportList *reports, + enum ePF_FileStatus how); #endif diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h index cc3f5bbb42e..4c023f54e04 100644 --- a/source/blender/blenkernel/BKE_rigidbody.h +++ b/source/blender/blenkernel/BKE_rigidbody.h @@ -44,8 +44,10 @@ void BKE_rigidbody_free_constraint(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); +void BKE_rigidbody_object_copy(struct Main *bmain, + struct Object *ob_dst, + const struct Object *ob_src, + const int flag); /* Callback format for performing operations on ID-pointers for rigidbody world. */ typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw, diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index dcf6d6c3907..5d3e7ad5ec2 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -350,6 +350,9 @@ void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizm struct ARegion *BKE_area_find_region_type(const struct ScrArea *sa, int type); struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa); struct ARegion *BKE_area_find_region_xy(struct ScrArea *sa, const int regiontype, int x, int y); +struct ARegion *BKE_screen_find_region_xy(struct bScreen *sc, const int regiontype, int x, int y) + ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); + struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index d26b9a86635..6509788932c 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -30,7 +30,6 @@ extern "C" { struct Main; struct Text; struct TextLine; -struct TextUndoBuf; void BKE_text_free_lines(struct Text *text); void BKE_text_free(struct Text *text); @@ -49,12 +48,12 @@ void BKE_text_copy_data(struct Main *bmain, 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, struct TextUndoBuf *utxt); -void BKE_text_write(struct Text *text, struct TextUndoBuf *utxt, const char *str); +void BKE_text_clear(struct Text *text); +void BKE_text_write(struct Text *text, const char *str); int BKE_text_file_modified_check(struct Text *text); void BKE_text_file_modified_ignore(struct Text *text); -char *txt_to_buf(struct Text *text); +char *txt_to_buf(struct Text *text, int *r_buf_strlen); void txt_clean_text(struct Text *text); void txt_order_cursors(struct Text *text, const bool reverse); int txt_find_string(struct Text *text, const char *findstr, int wrap, int match_case); @@ -77,29 +76,26 @@ void txt_move_eol(struct Text *text, const bool sel); void txt_move_toline(struct Text *text, unsigned int line, const bool sel); void txt_move_to(struct Text *text, unsigned int line, unsigned int ch, const bool sel); void txt_pop_sel(struct Text *text); -void txt_delete_char(struct Text *text, struct TextUndoBuf *utxt); -void txt_delete_word(struct Text *text, struct TextUndoBuf *utxt); -void txt_delete_selected(struct Text *text, struct TextUndoBuf *utxt); +void txt_delete_char(struct Text *text); +void txt_delete_word(struct Text *text); +void txt_delete_selected(struct Text *text); void txt_sel_all(struct Text *text); void txt_sel_clear(struct Text *text); void txt_sel_line(struct Text *text); -char *txt_sel_to_buf(struct Text *text); -void txt_insert_buf(struct Text *text, struct TextUndoBuf *utxt, const char *in_buffer); -void txt_undo_add_op(struct Text *text, struct TextUndoBuf *utxt, int op); -void txt_do_undo(struct Text *text, struct TextUndoBuf *utxt); -void txt_do_redo(struct Text *text, struct TextUndoBuf *utxt); -void txt_split_curline(struct Text *text, struct TextUndoBuf *utxt); -void txt_backspace_char(struct Text *text, struct TextUndoBuf *utxt); -void txt_backspace_word(struct Text *text, struct TextUndoBuf *utxt); -bool txt_add_char(struct Text *text, struct TextUndoBuf *utxt, unsigned int add); -bool txt_add_raw_char(struct Text *text, struct TextUndoBuf *utxt, unsigned int add); -bool txt_replace_char(struct Text *text, struct TextUndoBuf *utxt, unsigned int add); -void txt_unindent(struct Text *text, struct TextUndoBuf *utxt); -void txt_comment(struct Text *text, struct TextUndoBuf *utxt); -void txt_indent(struct Text *text, struct TextUndoBuf *utxt); -void txt_uncomment(struct Text *text, struct TextUndoBuf *utxt); -void txt_move_lines(struct Text *text, struct TextUndoBuf *utxt, const int direction); -void txt_duplicate_line(struct Text *text, struct TextUndoBuf *utxt); +char *txt_sel_to_buf(struct Text *text, int *r_buf_strlen); +void txt_insert_buf(struct Text *text, const char *in_buffer); +void txt_split_curline(struct Text *text); +void txt_backspace_char(struct Text *text); +void txt_backspace_word(struct Text *text); +bool txt_add_char(struct Text *text, unsigned int add); +bool txt_add_raw_char(struct Text *text, unsigned int add); +bool txt_replace_char(struct Text *text, unsigned int add); +void txt_unindent(struct Text *text); +void txt_comment(struct Text *text); +void txt_indent(struct Text *text); +void txt_uncomment(struct Text *text); +void txt_move_lines(struct Text *text, const int direction); +void txt_duplicate_line(struct Text *text); int txt_setcurr_tab_spaces(struct Text *text, int space); bool txt_cursor_is_line_start(struct Text *text); bool txt_cursor_is_line_end(struct Text *text); @@ -125,10 +121,9 @@ enum { TXT_MOVE_LINE_DOWN = 1, }; -typedef struct TextUndoBuf { - char *buf; - int pos, len; -} TextUndoBuf; +/* Fast non-validating buffer conversion for undo. */ +char *txt_to_buf_for_undo(struct Text *text, int *r_buf_strlen); +void txt_from_buf_for_undo(struct Text *text, const char *buf, int buf_len); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h index d4cb9331605..50c29c456d1 100644 --- a/source/blender/blenkernel/BKE_undo_system.h +++ b/source/blender/blenkernel/BKE_undo_system.h @@ -101,12 +101,13 @@ typedef struct UndoType { * None of these callbacks manage list add/removal. * * Note that 'step_encode_init' is optional, - * some undo types need to perform operatons before undo push finishes. + * some undo types need to perform operations before undo push finishes. */ void (*step_encode_init)(struct bContext *C, UndoStep *us); bool (*step_encode)(struct bContext *C, struct Main *bmain, UndoStep *us); - void (*step_decode)(struct bContext *C, struct Main *bmain, UndoStep *us, int dir); + void (*step_decode)( + struct bContext *C, struct Main *bmain, UndoStep *us, int dir, bool is_final); /** * \note When freeing all steps, @@ -122,7 +123,7 @@ typedef struct UndoType { int step_size; } UndoType; -/* expose since we need to perform operations on spesific undo types (rarely). */ +/* Expose since we need to perform operations on specific undo types (rarely). */ extern const UndoType *BKE_UNDOSYS_TYPE_IMAGE; extern const UndoType *BKE_UNDOSYS_TYPE_MEMFILE; extern const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE; diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 65b837048cb..a7159f85dc2 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -43,6 +43,7 @@ #include "BLT_translation.h" #include "BKE_action.h" +#include "BKE_armature.h" #include "BKE_anim.h" #include "BKE_animsys.h" #include "BKE_constraint.h" @@ -525,6 +526,38 @@ bPoseChannel *BKE_pose_channel_active(Object *ob) } /** + * Use this when detecting the "other selected bone", + * when we have multiple armatures in pose mode. + * + * In this case the active-selected is an obvious choice when finding the target for a + * constraint for eg. however from the users perspective the active pose bone of the + * active object is the _real_ active bone, so any other non-active selected bone + * is a candidate for being the other selected bone, see: T58447. + */ +bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob) +{ + bArmature *arm = (ob) ? ob->data : NULL; + + if (ELEM(NULL, ob, ob->pose, arm)) { + return NULL; + } + + bPoseChannel *pchan = BKE_pose_channel_active(ob); + if (pchan && (pchan->bone->flag & BONE_SELECTED) && PBONE_VISIBLE(arm, pchan->bone)) { + return pchan; + } + + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + if (pchan->bone != NULL) { + if ((pchan->bone->flag & BONE_SELECTED) && PBONE_VISIBLE(arm, pchan->bone)) { + return pchan; + } + } + } + return NULL; +} + +/** * \see #ED_armature_ebone_get_mirrored (edit-mode, matching function) */ bPoseChannel *BKE_pose_channel_get_mirrored(const bPose *pose, const char *name) @@ -729,6 +762,21 @@ void BKE_pose_channels_hash_free(bPose *pose) } } +static void pose_channels_remove_internal_links(Object *ob, bPoseChannel *unlinked_pchan) +{ + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + if (pchan->bbone_prev == unlinked_pchan) { + pchan->bbone_prev = NULL; + } + if (pchan->bbone_next == unlinked_pchan) { + pchan->bbone_next = NULL; + } + if (pchan->custom_tx == unlinked_pchan) { + pchan->custom_tx = NULL; + } + } +} + /** * Selectively remove pose channels. */ @@ -747,6 +795,7 @@ void BKE_pose_channels_remove(Object *ob, if (filter_fn(pchan->name, user_data)) { /* Bone itself is being removed */ BKE_pose_channel_free(pchan); + pose_channels_remove_internal_links(ob, pchan); if (ob->pose->chanhash) { BLI_ghash_remove(ob->pose->chanhash, pchan->name, NULL, NULL); } @@ -1522,8 +1571,8 @@ void what_does_obaction( workob->constraints.first = ob->constraints.first; workob->constraints.last = ob->constraints.last; - workob->pose = - pose; /* need to set pose too, since this is used for both types of Action Constraint */ + /* Need to set pose too, since this is used for both types of Action Constraint. */ + workob->pose = pose; if (pose) { /* This function is most likely to be used with a temporary pose with a single bone in there. * For such cases it makes no sense to create hash since it'll only waste CPU ticks on memory diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index df22aa1dcfb..c36acd1eae1 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -324,6 +324,24 @@ bool BKE_armature_bone_flag_test_recursive(const Bone *bone, int flag) } } +static void armature_refresh_layer_used_recursive(bArmature *arm, ListBase *bones) +{ + for (Bone *bone = bones->first; bone; bone = bone->next) { + arm->layer_used |= bone->layer; + armature_refresh_layer_used_recursive(arm, &bone->childbase); + } +} + +/* Update the layers_used variable after bones are moved between layer + * NOTE: Used to be done in drawing code in 2.7, but that won't work with + * Copy-on-Write, as drawing uses evaluated copies. + */ +void BKE_armature_refresh_layer_used(bArmature *arm) +{ + arm->layer_used = 0; + armature_refresh_layer_used_recursive(arm, &arm->bonebase); +} + /* Finds the best possible extension to the name on a particular axis. (For renaming, check for * unique names afterwards) strip_number: removes number extensions (TODO: not used) * axis: the axis to name on @@ -1370,7 +1388,12 @@ static void armature_vert_task(void *__restrict userdata, if (use_dverts || armature_def_nr != -1) { if (data->mesh) { BLI_assert(i < data->mesh->totvert); - dvert = data->mesh->dvert + i; + if (data->mesh->dvert != NULL) { + dvert = data->mesh->dvert + i; + } + else { + dvert = NULL; + } } else if (data->dverts && i < data->target_totvert) { dvert = data->dverts + i; diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 570805a01d0..afbd2627a2a 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -670,9 +670,14 @@ WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepat } if (bfd) { - workspace_config = MEM_mallocN(sizeof(*workspace_config), __func__); + workspace_config = MEM_callocN(sizeof(*workspace_config), __func__); workspace_config->main = bfd->main; - workspace_config->workspaces = bfd->main->workspaces; + + /* Only 2.80+ files have actual workspaces, don't try to use screens + * from older versions. */ + if (bfd->main->versionfile >= 280) { + workspace_config->workspaces = bfd->main->workspaces; + } MEM_freeN(bfd); } diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 78d965564e6..ec9a774a65c 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -73,8 +73,8 @@ static void brush_defaults(Brush *brush) brush->topology_rake_factor = 0.0f; brush->crease_pinch_factor = 0.5f; brush->sculpt_plane = SCULPT_DISP_DIR_AREA; - brush->plane_offset = - 0.0f; /* how far above or below the plane that is found by averaging the faces */ + /* How far above or below the plane that is found by averaging the faces. */ + brush->plane_offset = 0.0f; brush->plane_trim = 0.5f; brush->clone.alpha = 0.5f; brush->normal_weight = 0.0f; @@ -82,7 +82,8 @@ static void brush_defaults(Brush *brush) brush->flag |= BRUSH_ALPHA_PRESSURE; /* BRUSH PAINT TOOL SETTINGS */ - brush->rgb[0] = 1.0f; /* default rgb color of the brush when painting - white */ + /* Default rgb color of the brush when painting - white. */ + brush->rgb[0] = 1.0f; brush->rgb[1] = 1.0f; brush->rgb[2] = 1.0f; @@ -90,13 +91,14 @@ static void brush_defaults(Brush *brush) /* BRUSH STROKE SETTINGS */ brush->flag |= (BRUSH_SPACE | BRUSH_SPACE_ATTEN); - brush->spacing = - 10; /* how far each brush dot should be spaced as a percentage of brush diameter */ + /* How far each brush dot should be spaced as a percentage of brush diameter. */ + brush->spacing = 10; brush->smooth_stroke_radius = 75; brush->smooth_stroke_factor = 0.9f; - brush->rate = 0.1f; /* time delay between dots of paint or sculpting when doing airbrush mode */ + /* Time delay between dots of paint or sculpting when doing airbrush mode. */ + brush->rate = 0.1f; brush->jitter = 0.0f; diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 272413ece4a..2d6256f12e2 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -100,11 +100,11 @@ void BKE_cachefile_reader_open(CacheFile *cache_file, void BKE_cachefile_reader_free(CacheFile *cache_file, struct CacheReader **reader) { #ifdef WITH_ALEMBIC - if (cache_file) { - BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE); - } - if (*reader != NULL) { + if (cache_file) { + BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE); + } + CacheReader_free(*reader); *reader = NULL; diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index dc238641a86..63d58f7e32e 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -105,8 +105,10 @@ void cloth_init(ClothModifierData *clmd) clmd->sim_parms->maxspringlen = 10; clmd->sim_parms->vgroup_mass = 0; clmd->sim_parms->vgroup_shrink = 0; - clmd->sim_parms->shrink_min = - 0.0f; /* min amount the fabric will shrink by 0.0 = no shrinking, 1.0 = shrink to nothing*/ + + /* Min amount the fabric will shrink by 0.0 = no shrinking, 1.0 = shrink to nothing. */ + clmd->sim_parms->shrink_min = 0.0f; + clmd->sim_parms->avg_spring_len = 0.0; clmd->sim_parms->presets = 2; /* cotton as start setting */ clmd->sim_parms->timescale = 1.0f; /* speed factor, describes how fast cloth moves */ diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index ac55846714b..965f6e4bc51 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -287,16 +287,6 @@ static Collection *collection_duplicate_recursive(Main *bmain, collection_object_add(bmain, collection_new, ob_new, 0, true); collection_object_remove(bmain, collection_new, ob_old, false); - - if (ob_new->rigidbody_object != NULL) { - BLI_assert(ob_old->rigidbody_object != NULL); - for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) { - if (scene->rigidbody_world != NULL && - BKE_collection_has_object(scene->rigidbody_world->group, ob_old)) { - collection_object_add(bmain, scene->rigidbody_world->group, ob_new, 0, true); - } - } - } } } @@ -572,7 +562,7 @@ bool BKE_collection_object_cyclic_check(Main *bmain, Object *object, Collection /******************* Collection Object Membership *******************/ -bool BKE_collection_has_object(Collection *collection, Object *ob) +bool BKE_collection_has_object(Collection *collection, const Object *ob) { if (ELEM(NULL, collection, ob)) { return false; diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 45cb5e817d2..863d6351738 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -628,8 +628,6 @@ static void curvemap_make_table(CurveMap *cuma, const rctf *clipr) { CurveMapPoint *cmp = cuma->curve; BezTriple *bezt; - float *fp, *allpoints, *lastpoint, curf, range; - int a, totpoint; if (cuma->curve == NULL) { return; @@ -642,7 +640,7 @@ static void curvemap_make_table(CurveMap *cuma, const rctf *clipr) /* hrmf... we now rely on blender ipo beziers, these are more advanced */ bezt = MEM_callocN(cuma->totpoint * sizeof(BezTriple), "beztarr"); - for (a = 0; a < cuma->totpoint; a++) { + for (int a = 0; a < cuma->totpoint; a++) { cuma->mintable = min_ff(cuma->mintable, cmp[a].x); cuma->maxtable = max_ff(cuma->maxtable, cmp[a].x); bezt[a].vec[1][0] = cmp[a].x; @@ -659,7 +657,7 @@ static void curvemap_make_table(CurveMap *cuma, const rctf *clipr) } const BezTriple *bezt_prev = NULL; - for (a = 0; a < cuma->totpoint; a++) { + for (int a = 0; a < cuma->totpoint; a++) { const BezTriple *bezt_next = (a != cuma->totpoint - 1) ? &bezt[a + 1] : NULL; calchandle_curvemap(&bezt[a], bezt_prev, bezt_next); bezt_prev = &bezt[a]; @@ -687,7 +685,7 @@ static void curvemap_make_table(CurveMap *cuma, const rctf *clipr) sub_v3_v3v3(bezt[0].vec[0], bezt[0].vec[1], vec); } } - a = cuma->totpoint - 1; + int a = cuma->totpoint - 1; if (bezt[a].h2 == HD_AUTO) { hlen = len_v3v3(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */ @@ -710,23 +708,25 @@ static void curvemap_make_table(CurveMap *cuma, const rctf *clipr) if (cuma->table) { MEM_freeN(cuma->table); } - totpoint = (cuma->totpoint - 1) * CM_RESOL; - fp = allpoints = MEM_callocN(totpoint * 2 * sizeof(float), "table"); - for (a = 0; a < cuma->totpoint - 1; a++, fp += 2 * CM_RESOL) { + int totpoint = (cuma->totpoint - 1) * CM_RESOL; + float *allpoints = MEM_callocN(totpoint * 2 * sizeof(float), "table"); + float *point = allpoints; + + for (int a = 0; a < cuma->totpoint - 1; a++, point += 2 * CM_RESOL) { correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a + 1].vec[0], bezt[a + 1].vec[1]); BKE_curve_forward_diff_bezier(bezt[a].vec[1][0], bezt[a].vec[2][0], bezt[a + 1].vec[0][0], bezt[a + 1].vec[1][0], - fp, + point, CM_RESOL - 1, 2 * sizeof(float)); BKE_curve_forward_diff_bezier(bezt[a].vec[1][1], bezt[a].vec[2][1], bezt[a + 1].vec[0][1], bezt[a + 1].vec[1][1], - fp + 1, + point + 1, CM_RESOL - 1, 2 * sizeof(float)); } @@ -734,49 +734,63 @@ static void curvemap_make_table(CurveMap *cuma, const rctf *clipr) /* store first and last handle for extrapolation, unit length */ cuma->ext_in[0] = bezt[0].vec[0][0] - bezt[0].vec[1][0]; cuma->ext_in[1] = bezt[0].vec[0][1] - bezt[0].vec[1][1]; - range = sqrtf(cuma->ext_in[0] * cuma->ext_in[0] + cuma->ext_in[1] * cuma->ext_in[1]); - cuma->ext_in[0] /= range; - cuma->ext_in[1] /= range; - - a = cuma->totpoint - 1; - cuma->ext_out[0] = bezt[a].vec[1][0] - bezt[a].vec[2][0]; - cuma->ext_out[1] = bezt[a].vec[1][1] - bezt[a].vec[2][1]; - range = sqrtf(cuma->ext_out[0] * cuma->ext_out[0] + cuma->ext_out[1] * cuma->ext_out[1]); - cuma->ext_out[0] /= range; - cuma->ext_out[1] /= range; + float ext_in_range = sqrtf(cuma->ext_in[0] * cuma->ext_in[0] + + cuma->ext_in[1] * cuma->ext_in[1]); + cuma->ext_in[0] /= ext_in_range; + cuma->ext_in[1] /= ext_in_range; + + int out_a = cuma->totpoint - 1; + cuma->ext_out[0] = bezt[out_a].vec[1][0] - bezt[out_a].vec[2][0]; + cuma->ext_out[1] = bezt[out_a].vec[1][1] - bezt[out_a].vec[2][1]; + float ext_out_range = sqrtf(cuma->ext_out[0] * cuma->ext_out[0] + + cuma->ext_out[1] * cuma->ext_out[1]); + cuma->ext_out[0] /= ext_out_range; + cuma->ext_out[1] /= ext_out_range; /* cleanup */ MEM_freeN(bezt); - range = CM_TABLEDIV * (cuma->maxtable - cuma->mintable); + float range = CM_TABLEDIV * (cuma->maxtable - cuma->mintable); cuma->range = 1.0f / range; /* now make a table with CM_TABLE equal x distances */ - fp = allpoints; - lastpoint = allpoints + 2 * (totpoint - 1); + float *firstpoint = allpoints; + float *lastpoint = allpoints + 2 * (totpoint - 1); + point = allpoints; + cmp = MEM_callocN((CM_TABLE + 1) * sizeof(CurveMapPoint), "dist table"); - for (a = 0; a <= CM_TABLE; a++) { - curf = cuma->mintable + range * (float)a; - cmp[a].x = curf; + for (int a = 0; a <= CM_TABLE; a++) { + float cur_x = cuma->mintable + range * (float)a; + cmp[a].x = cur_x; - /* get the first x coordinate larger than curf */ - while (curf >= fp[0] && fp != lastpoint) { - fp += 2; + /* Get the first point with x coordinate larger than cur_x. */ + while (cur_x >= point[0] && point != lastpoint) { + point += 2; } - if (fp == allpoints || (curf >= fp[0] && fp == lastpoint)) { - cmp[a].y = curvemap_calc_extend(cuma, curf, allpoints, lastpoint); + + /* Check if we are on or outside the start or end point. */ + if (point == firstpoint || (point == lastpoint && cur_x >= point[0])) { + if (compare_ff(cur_x, point[0], 1e-6f)) { + /* When on the point exactly, use the value directly to avoid precision + * issues with extrapolation of extreme slopes. */ + cmp[a].y = point[1]; + } + else { + /* Extrapolate values that lie outside the start and end point. */ + cmp[a].y = curvemap_calc_extend(cuma, cur_x, firstpoint, lastpoint); + } } else { - float fac1 = fp[0] - fp[-2]; - float fac2 = fp[0] - curf; + float fac1 = point[0] - point[-2]; + float fac2 = point[0] - cur_x; if (fac1 > FLT_EPSILON) { fac1 = fac2 / fac1; } else { fac1 = 0.0f; } - cmp[a].y = fac1 * fp[-1] + (1.0f - fac1) * fp[1]; + cmp[a].y = fac1 * point[-1] + (1.0f - fac1) * point[1]; } } diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 5945fa4bf33..931c0ed73d3 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -54,6 +54,7 @@ #include "BKE_material.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "CLG_log.h" @@ -1817,8 +1818,9 @@ void BKE_curve_bevel_make(Object *ob, ListBase *disp) fp[3] = fp[4] = 0.0; fp[5] = cu->ext1; } - else if ((cu->flag & (CU_FRONT | CU_BACK)) == 0 && - cu->ext1 == 0.0f) { /* we make a full round bevel in that case */ + else if ((cu->flag & (CU_FRONT | CU_BACK)) == 0 && cu->ext1 == 0.0f) { + /* We make a full round bevel in that case. */ + nr = 4 + 2 * cu->bevresol; dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1"); @@ -4741,8 +4743,8 @@ bool BKE_nurb_check_valid_u(const Nurb *nu) if (nu->pntsu < nu->orderu) { return false; } - if (((nu->flagu & 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 */ @@ -4768,8 +4770,8 @@ bool BKE_nurb_check_valid_v(const Nurb *nu) if (nu->pntsv < nu->orderv) { return false; } - if (((nu->flagv & 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 */ @@ -5431,8 +5433,19 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu, void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve) { DEG_debug_print_eval(depsgraph, __func__, curve->id.name, curve); - if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) { - BKE_curve_texspace_calc(curve); + BKE_curve_texspace_calc(curve); + if (DEG_is_active(depsgraph)) { + Curve *curve_orig = (Curve *)DEG_get_original_id(&curve->id); + BoundBox *bb = curve->bb; + if (bb != NULL) { + if (curve_orig->bb == NULL) { + curve_orig->bb = MEM_mallocN(sizeof(*curve_orig->bb), __func__); + } + *curve_orig->bb = *bb; + copy_v3_v3(curve_orig->loc, curve->loc); + copy_v3_v3(curve_orig->size, curve->size); + copy_v3_v3(curve_orig->rot, curve->rot); + } } } diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 76098db5fd1..1fb29745dba 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -26,6 +26,9 @@ #include "MEM_guardedalloc.h" +/* Since we have versioning code here (CustomData_verify_versions()). */ +#define DNA_DEPRECATED_ALLOW + #include "DNA_customdata_types.h" #include "DNA_meshdata_types.h" #include "DNA_ID.h" @@ -4191,8 +4194,8 @@ bool CustomData_verify_versions(struct CustomData *data, int index) * Better to be safe here, and fix issue on the fly rather than crash... */ /* 0 structnum is used in writing code to tag layer types that should not be written. */ else if (typeInfo->structnum == 0 && - /* XXX Not sure why those two are exception, maybe that should be fixed? */ - !ELEM(layer->type, CD_PAINT_MASK, CD_FACEMAP)) { + /* XXX Not sure why those three are exception, maybe that should be fixed? */ + !ELEM(layer->type, CD_PAINT_MASK, CD_FACEMAP, CD_MTEXPOLY)) { keeplayer = false; CLOG_WARN(&LOG, ".blend file read: removing a data layer that should not have been written"); } diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index 8dcf1f0d001..0414c6d0a02 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -1,3 +1,4 @@ + /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -85,6 +86,7 @@ void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types, } else if (cddata_type == CD_FAKE_LNOR) { r_data_masks->vmask |= CD_MASK_NORMAL; + r_data_masks->pmask |= CD_MASK_NORMAL; r_data_masks->lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL; } } @@ -1408,8 +1410,8 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph, SpaceTransform auto_space_transform; Mesh *me_src; - bool dirty_nors_dst = - true; /* Assumed always true if not using an evaluated mesh as destination. */ + /* Assumed always true if not using an evaluated mesh as destination. */ + bool dirty_nors_dst = true; int i; MDeformVert *mdef = NULL; diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 8c6fbe98000..7e916feac24 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -1232,6 +1232,8 @@ void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd, dynamicPaint_freeSurface(tpmd, tpmd->canvas->surfaces.first); } + tpmd->canvas->active_sur = pmd->canvas->active_sur; + /* copy existing surfaces */ for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) { DynamicPaintSurface *t_surface = dynamicPaint_createNewSurface(tpmd->canvas, NULL); @@ -1298,7 +1300,7 @@ void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd, BLI_strncpy(t_surface->output_name2, surface->output_name2, sizeof(t_surface->output_name2)); } } - else if (tpmd->brush) { + if (tpmd->brush) { DynamicPaintBrushSettings *brush = pmd->brush, *t_brush = tpmd->brush; t_brush->pmd = tpmd; @@ -1930,7 +1932,8 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * { Mesh *result = BKE_mesh_copy_for_eval(mesh, false); - if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING)) { + if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING) && + pmd->type == MOD_DYNAMICPAINT_TYPE_CANVAS) { DynamicPaintSurface *surface; bool update_normals = false; @@ -2020,6 +2023,8 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) { dvert = CustomData_add_layer( &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, sData->total_points); + /* Make the dvert layer easily accessible from the mesh data. */ + result->dvert = dvert; } if (defgrp_index != -1 && dvert) { int i; @@ -2070,7 +2075,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * } } /* make a copy of mesh to use as brush data */ - if (pmd->brush) { + else if (pmd->brush && pmd->type == MOD_DYNAMICPAINT_TYPE_BRUSH) { DynamicPaintRuntime *runtime_data = dynamicPaint_Modifier_runtime_ensure(pmd); if (runtime_data->brush_mesh != NULL) { BKE_id_free(NULL, runtime_data->brush_mesh); @@ -2198,24 +2203,11 @@ Mesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Object *ob, Mesh *mesh) { - if (pmd->canvas) { - Mesh *ret; - - /* Update canvas data for a new frame */ - dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh); - - /* Return output mesh */ - ret = dynamicPaint_Modifier_apply(pmd, ob, mesh); + /* Update canvas data for a new frame */ + dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh); - return ret; - } - else { - /* Update canvas data for a new frame */ - dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh); - - /* Return output mesh */ - return dynamicPaint_Modifier_apply(pmd, ob, mesh); - } + /* Return output mesh */ + return dynamicPaint_Modifier_apply(pmd, ob, mesh); } /* -------------------------------------------------------------------- */ @@ -6252,7 +6244,7 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph, if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) { DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md; /* make sure we're dealing with a brush */ - if (pmd2->brush) { + if (pmd2->brush && pmd2->type == MOD_DYNAMICPAINT_TYPE_BRUSH) { DynamicPaintBrushSettings *brush = pmd2->brush; /* calculate brush speed vectors if required */ diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 3f8fc697c6c..a0216e9b413 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -86,7 +86,7 @@ void BKE_vfont_free_data(struct VFont *vfont) } if (vfont->temp_pf) { - freePackedFile(vfont->temp_pf); /* NULL when the font file can't be found on disk */ + BKE_packedfile_free(vfont->temp_pf); /* NULL when the font file can't be found on disk */ vfont->temp_pf = NULL; } } @@ -97,7 +97,7 @@ void BKE_vfont_free(struct VFont *vf) BKE_vfont_free_data(vf); if (vf->packedfile) { - freePackedFile(vf->packedfile); + BKE_packedfile_free(vf->packedfile); vf->packedfile = NULL; } } @@ -114,7 +114,7 @@ void BKE_vfont_copy_data(Main *UNUSED(bmain), vfont_dst->temp_pf = NULL; if (vfont_dst->packedfile) { - vfont_dst->packedfile = dupPackedFile(vfont_dst->packedfile); + vfont_dst->packedfile = BKE_packedfile_duplicate(vfont_dst->packedfile); } if (vfont_dst->data) { @@ -148,7 +148,7 @@ static PackedFile *get_builtin_packedfile(void) memcpy(mem, builtin_font_data, builtin_font_size); - return newPackedFileMemory(mem, builtin_font_size); + return BKE_packedfile_new_from_memory(mem, builtin_font_size); } } @@ -183,14 +183,15 @@ static VFontData *vfont_get_data(VFont *vfont) /* We need to copy a tmp font to memory unless it is already there */ if (vfont->temp_pf == NULL) { - vfont->temp_pf = dupPackedFile(pf); + vfont->temp_pf = BKE_packedfile_duplicate(pf); } } else { - pf = newPackedFile(NULL, vfont->name, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id)); + pf = BKE_packedfile_new(NULL, vfont->name, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id)); if (vfont->temp_pf == NULL) { - vfont->temp_pf = newPackedFile(NULL, vfont->name, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id)); + vfont->temp_pf = BKE_packedfile_new( + NULL, vfont->name, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id)); } } if (!pf) { @@ -208,7 +209,7 @@ static VFontData *vfont_get_data(VFont *vfont) if (pf) { vfont->data = BLI_vfontdata_from_freetypefont(pf); if (pf != vfont->packedfile) { - freePackedFile(pf); + BKE_packedfile_free(pf); } } @@ -234,7 +235,7 @@ void BKE_vfont_init(VFont *vfont) } /* Free the packed file */ - freePackedFile(pf); + BKE_packedfile_free(pf); } } @@ -253,7 +254,7 @@ VFont *BKE_vfont_load(Main *bmain, const char *filepath) } else { BLI_split_file_part(filepath, filename, sizeof(filename)); - pf = newPackedFile(NULL, filepath, BKE_main_blendfile_path(bmain)); + pf = BKE_packedfile_new(NULL, filepath, BKE_main_blendfile_path(bmain)); is_builtin = false; } @@ -279,13 +280,13 @@ VFont *BKE_vfont_load(Main *bmain, const char *filepath) /* Do not add FO_BUILTIN_NAME to temporary listbase */ if (!STREQ(filename, FO_BUILTIN_NAME)) { - vfont->temp_pf = newPackedFile(NULL, filepath, BKE_main_blendfile_path(bmain)); + vfont->temp_pf = BKE_packedfile_new(NULL, filepath, BKE_main_blendfile_path(bmain)); } } /* Free the packed file */ if (!vfont || vfont->packedfile != pf) { - freePackedFile(pf); + BKE_packedfile_free(pf); } } diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 842fa85bf76..058c0d10b8e 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -1324,6 +1324,7 @@ void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4]) return; } + const float scalef = mat4_to_scale(mat); for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* FIXME: For now, we just skip parented layers. * Otherwise, we have to update each frame to find @@ -1340,6 +1341,7 @@ void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4]) for (pt = gps->points, i = 0; i < gps->totpoints; pt++, i++) { mul_m4_v3(mat, &pt->x); + pt->pressure *= scalef; } /* TODO: Do we need to do this? distortion may mean we need to re-triangulate */ @@ -1958,3 +1960,83 @@ bool BKE_gpencil_trim_stroke(bGPDstroke *gps) } return intersect; } + +/** + * Close stroke + * \param gps: Stroke to close + */ +bool BKE_gpencil_close_stroke(bGPDstroke *gps) +{ + bGPDspoint *pt1 = NULL; + bGPDspoint *pt2 = NULL; + + /* Only can close a stroke with 3 points or more. */ + if (gps->totpoints < 3) { + return false; + } + + /* Calc average distance between points to get same level of sampling. */ + float dist_tot = 0.0f; + for (int i = 0; i < gps->totpoints - 1; i++) { + pt1 = &gps->points[i]; + pt2 = &gps->points[i + 1]; + dist_tot += len_v3v3(&pt1->x, &pt2->x); + } + /* Calc the average distance. */ + float dist_avg = dist_tot / (gps->totpoints - 1); + + /* Calc distance between last and first point. */ + pt1 = &gps->points[gps->totpoints - 1]; + pt2 = &gps->points[0]; + float dist_close = len_v3v3(&pt1->x, &pt2->x); + + /* Calc number of points required using the average distance. */ + int tot_newpoints = MAX2(dist_close / dist_avg, 1); + + /* Resize stroke array. */ + int old_tot = gps->totpoints; + gps->totpoints += tot_newpoints; + gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints); + if (gps->dvert != NULL) { + gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); + } + + /* Generate new points */ + pt1 = &gps->points[old_tot - 1]; + pt2 = &gps->points[0]; + bGPDspoint *pt = &gps->points[old_tot]; + for (int i = 1; i < tot_newpoints + 1; i++, pt++) { + float step = ((float)i / (float)tot_newpoints); + /* Clamp last point to be near, but not on top of first point. */ + CLAMP(step, 0.0f, 0.99f); + + /* Average point. */ + interp_v3_v3v3(&pt->x, &pt1->x, &pt2->x, step); + pt->pressure = interpf(pt2->pressure, pt1->pressure, step); + pt->strength = interpf(pt2->strength, pt1->strength, step); + pt->flag = 0; + + /* Set weights. */ + if (gps->dvert != NULL) { + MDeformVert *dvert1 = &gps->dvert[old_tot - 1]; + MDeformWeight *dw1 = defvert_verify_index(dvert1, 0); + float weight_1 = dw1 ? dw1->weight : 0.0f; + + MDeformVert *dvert2 = &gps->dvert[0]; + MDeformWeight *dw2 = defvert_verify_index(dvert2, 0); + float weight_2 = dw2 ? dw2->weight : 0.0f; + + MDeformVert *dvert_final = &gps->dvert[old_tot + i - 1]; + dvert_final->totweight = 0; + MDeformWeight *dw = defvert_verify_index(dvert_final, 0); + if (dvert_final->dw) { + dw->weight = interpf(weight_2, weight_1, step); + } + } + } + + /* Enable cyclic flag. */ + gps->flag |= GP_STROKE_CYCLIC; + + return true; +} diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index 2b27854ba82..7907be40984 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -28,6 +28,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_math_vector.h" +#include "BLI_math_geom.h" #include "BLI_string_utils.h" #include "BLT_translation.h" @@ -86,48 +87,6 @@ void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3]) normalize_v3(r_normal); } -/* Get points of stroke always flat to view not affected by camera view or view position */ -static void gpencil_stroke_project_2d(const bGPDspoint *points, int totpoints, vec2f *points2d) -{ - const bGPDspoint *pt0 = &points[0]; - const bGPDspoint *pt1 = &points[1]; - const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)]; - - float locx[3]; - float locy[3]; - float loc3[3]; - float normal[3]; - - /* local X axis (p0 -> p1) */ - sub_v3_v3v3(locx, &pt1->x, &pt0->x); - - /* point vector at 3/4 */ - sub_v3_v3v3(loc3, &pt3->x, &pt0->x); - - /* vector orthogonal to polygon plane */ - cross_v3_v3v3(normal, locx, loc3); - - /* local Y axis (cross to normal/x axis) */ - cross_v3_v3v3(locy, normal, locx); - - /* Normalize vectors */ - normalize_v3(locx); - normalize_v3(locy); - - /* Get all points in local space */ - for (int i = 0; i < totpoints; i++) { - const bGPDspoint *pt = &points[i]; - float loc[3]; - - /* Get local space using first point as origin */ - sub_v3_v3v3(loc, &pt->x, &pt0->x); - - vec2f *point = &points2d[i]; - point->x = dot_v3v3(loc, locx); - point->y = dot_v3v3(loc, locy); - } -} - /* Stroke Simplify ------------------------------------- */ /* Reduce a series of points to a simplified version, but @@ -136,15 +95,15 @@ static void gpencil_stroke_project_2d(const bGPDspoint *points, int totpoints, v * Ramer - Douglas - Peucker algorithm * by http ://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm */ -static void gpencil_rdp_stroke(bGPDstroke *gps, vec2f *points2d, float epsilon) +void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float epsilon) { - vec2f *old_points2d = points2d; + bGPDspoint *old_points = MEM_dupallocN(gps->points); int totpoints = gps->totpoints; char *marked = NULL; char work; - int start = 1; - int end = gps->totpoints - 2; + int start = 0; + int end = gps->totpoints - 1; marked = MEM_callocN(totpoints, "GP marked array"); marked[start] = 1; @@ -163,7 +122,6 @@ static void gpencil_rdp_stroke(bGPDstroke *gps, vec2f *points2d, float epsilon) /* while not over interval */ while (ls < end) { int max_i = 0; - float v1[2]; /* divided to get more control */ float max_dist = epsilon / 10.0f; @@ -172,25 +130,14 @@ static void gpencil_rdp_stroke(bGPDstroke *gps, vec2f *points2d, float epsilon) le++; } - /* perpendicular vector to ls-le */ - v1[1] = old_points2d[le].x - old_points2d[ls].x; - v1[0] = old_points2d[ls].y - old_points2d[le].y; - for (int i = ls + 1; i < le; i++) { - float mul; + float point_on_line[3]; float dist; - float v2[2]; - - v2[0] = old_points2d[i].x - old_points2d[ls].x; - v2[1] = old_points2d[i].y - old_points2d[ls].y; - - if (v2[0] == 0 && v2[1] == 0) { - continue; - } - mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]); + closest_to_line_segment_v3( + point_on_line, &old_points[i].x, &old_points[ls].x, &old_points[le].x); - dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]); + dist = len_v3v3(point_on_line, &old_points[i].x); if (dist > max_dist) { max_dist = dist; @@ -210,7 +157,6 @@ static void gpencil_rdp_stroke(bGPDstroke *gps, vec2f *points2d, float epsilon) } /* adding points marked */ - bGPDspoint *old_points = MEM_dupallocN(gps->points); MDeformVert *old_dvert = NULL; MDeformVert *dvert_src = NULL; @@ -253,19 +199,6 @@ static void gpencil_rdp_stroke(bGPDstroke *gps, vec2f *points2d, float epsilon) MEM_SAFE_FREE(marked); } -/* Simplify stroke using Ramer-Douglas-Peucker algorithm */ -void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float factor) -{ - /* first create temp data and convert points to 2D */ - vec2f *points2d = MEM_mallocN(sizeof(vec2f) * gps->totpoints, "GP Stroke temp 2d points"); - - gpencil_stroke_project_2d(gps->points, gps->totpoints, points2d); - - gpencil_rdp_stroke(gps, points2d, factor); - - MEM_SAFE_FREE(points2d); -} - /* Simplify alternate vertex of stroke except extremes */ void BKE_gpencil_simplify_fixed(bGPDstroke *gps) { diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 72bad56990f..8e04ef2d3ca 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -198,7 +198,7 @@ static void image_free_packedfiles(Image *ima) while (ima->packedfiles.last) { ImagePackedFile *imapf = ima->packedfiles.last; if (imapf->packedfile) { - freePackedFile(imapf->packedfile); + BKE_packedfile_free(imapf->packedfile); } BLI_remlink(&ima->packedfiles, imapf); MEM_freeN(imapf); @@ -377,7 +377,7 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src) STRNCPY(imapf_dst->filepath, imapf_src->filepath); if (imapf_src->packedfile) { - imapf_dst->packedfile = dupPackedFile(imapf_src->packedfile); + imapf_dst->packedfile = BKE_packedfile_duplicate(imapf_src->packedfile); } BLI_addtail(lb_dst, imapf_dst); @@ -617,6 +617,7 @@ static ImBuf *add_ibuf_size(unsigned int width, ImBuf *ibuf; unsigned char *rect = NULL; float *rect_float = NULL; + float fill_color[4]; if (floatbuf) { ibuf = IMB_allocImBuf(width, height, depth, IB_rectfloat); @@ -632,6 +633,15 @@ static ImBuf *add_ibuf_size(unsigned int width, rect_float = ibuf->rect_float; IMB_colormanagement_check_is_data(ibuf, colorspace_settings->name); } + + if (IMB_colormanagement_space_name_is_data(colorspace_settings->name)) { + copy_v4_v4(fill_color, color); + } + else { + /* The input color here should ideally be linear already, but for now + * we just convert and postpone breaking the API for later. */ + srgb_to_linearrgb_v4(fill_color, color); + } } else { ibuf = IMB_allocImBuf(width, height, depth, IB_rect); @@ -647,6 +657,8 @@ static ImBuf *add_ibuf_size(unsigned int width, rect = (unsigned char *)ibuf->rect; IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace_settings->name); } + + copy_v4_v4(fill_color, color); } if (!ibuf) { @@ -663,7 +675,7 @@ static ImBuf *add_ibuf_size(unsigned int width, BKE_image_buf_fill_checker_color(rect, rect_float, width, height); break; default: - BKE_image_buf_fill_color(rect, rect_float, width, height, color); + BKE_image_buf_fill_color(rect, rect_float, width, height, fill_color); break; } @@ -838,7 +850,7 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath) if (totfiles == 1) { ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file"); BLI_addtail(&ima->packedfiles, imapf); - imapf->packedfile = newPackedFile(reports, ima->name, basepath); + imapf->packedfile = BKE_packedfile_new(reports, ima->name, basepath); if (imapf->packedfile) { STRNCPY(imapf->filepath, ima->name); } @@ -852,7 +864,7 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath) ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file"); BLI_addtail(&ima->packedfiles, imapf); - imapf->packedfile = newPackedFile(reports, iv->filepath, basepath); + imapf->packedfile = BKE_packedfile_new(reports, iv->filepath, basepath); if (imapf->packedfile) { STRNCPY(imapf->filepath, iv->filepath); } @@ -876,7 +888,7 @@ void BKE_image_packfiles_from_mem(ReportList *reports, else { ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), __func__); BLI_addtail(&ima->packedfiles, imapf); - imapf->packedfile = newPackedFileMemory(data, data_len); + imapf->packedfile = BKE_packedfile_new_from_memory(data, data_len); STRNCPY(imapf->filepath, ima->name); } } @@ -3241,9 +3253,9 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) ImagePackedFile *imapf; for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) { PackedFile *pf; - pf = newPackedFile(NULL, imapf->filepath, ID_BLEND_PATH(bmain, &ima->id)); + pf = BKE_packedfile_new(NULL, imapf->filepath, ID_BLEND_PATH(bmain, &ima->id)); if (pf) { - freePackedFile(imapf->packedfile); + BKE_packedfile_free(imapf->packedfile); imapf->packedfile = pf; } else { @@ -4014,7 +4026,8 @@ static ImBuf *load_image_single(Image *ima, BLI_addtail(&ima->packedfiles, imapf); STRNCPY(imapf->filepath, filepath); - imapf->packedfile = newPackedFile(NULL, filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id)); + imapf->packedfile = BKE_packedfile_new( + NULL, filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id)); } } } diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c index c7fdfb60a1c..bb2c086f02c 100644 --- a/source/blender/blenkernel/intern/image_gen.c +++ b/source/blender/blenkernel/intern/image_gen.c @@ -46,11 +46,9 @@ static void image_buf_fill_color_slice( /* blank image */ if (rect_float) { - float linear_color[4]; - srgb_to_linearrgb_v4(linear_color, color); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { - copy_v4_v4(rect_float, linear_color); + copy_v4_v4(rect_float, color); rect_float += 4; } } @@ -242,9 +240,9 @@ static void checker_board_color_fill( } for (y = offset; y < height + offset; y++) { + /* Use a number lower then 1.0 else its too bright. */ + hsv[2] = 0.1 + (y * (0.4 / total_height)); - hsv[2] = 0.1 + - (y * (0.4 / total_height)); /* use a number lower then 1.0 else its too bright */ for (x = 0; x < width; x++) { hsv[0] = (float)((double)(x / hue_step) * 1.0 / width * hue_step); hsv_to_rgb_v(hsv, rgb); diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 2b064c6b2a7..7dc04214ba5 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -745,9 +745,6 @@ static short layer_collection_sync(ViewLayer *view_layer, } lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS; - - /* Make sure flags on base are usable right away. */ - BKE_base_eval_flags(base); } runtime_flag |= lc->runtime_flag; @@ -814,6 +811,10 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer) BLI_freelistN(&view_layer->object_bases); view_layer->object_bases = new_object_bases; + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + BKE_base_eval_flags(base); + } + /* Always set a valid active collection. */ LayerCollection *active = view_layer->active_collection; diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 974c6d6e0a6..b62ec88ed24 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1502,7 +1502,7 @@ void *BKE_libblock_copy_for_localize(const ID *id) void BKE_library_free(Library *lib) { if (lib->packedfile) { - freePackedFile(lib->packedfile); + BKE_packedfile_free(lib->packedfile); } } @@ -1855,8 +1855,9 @@ static void library_make_local_copying_check(ID *id, MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->id_used_to_user, id); BLI_gset_insert(loop_tags, id); for (; entry != NULL; entry = entry->next) { - ID *par_id = - (ID *)entry->id_pointer; /* used_to_user stores ID pointer, not pointer to ID pointer... */ + + /* Used_to_user stores ID pointer, not pointer to ID pointer. */ + ID *par_id = (ID *)entry->id_pointer; /* Our oh-so-beloved 'from' pointers... */ if (entry->usage_flag & IDWALK_CB_LOOPBACK) { @@ -1912,7 +1913,8 @@ static void library_make_local_copying_check(ID *id, * \param bmain: Almost certainly global main. * \param lib: If not NULL, only make local data-blocks from this library. * \param untagged_only: If true, only make local data-blocks not tagged with - * LIB_TAG_PRE_EXISTING. \param set_fake: If true, set fake user on all localized data-blocks + * LIB_TAG_PRE_EXISTING. + * \param set_fake: If true, set fake user on all localized data-blocks * (except group and objects ones). */ /* Note: Old (2.77) version was simply making (tagging) data-blocks as local, diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index f5f0dbc6610..2ab5b69a022 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -721,7 +721,7 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, } if (is_fill) { - /* applt intersections depending on fill settings */ + /* Apply intersections depending on fill settings. */ if (spline->flag & MASK_SPLINE_NOINTERSECT) { BKE_mask_spline_feather_collapse_inner_loops( spline, diff_feather_points, tot_diff_feather_points); @@ -730,8 +730,10 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, copy_v2_v2(co, diff_points[0]); sf_vert_prev = BLI_scanfill_vert_add(&sf_ctx, co); sf_vert_prev->tmp.u = sf_vert_tot; - sf_vert_prev->keyindex = sf_vert_tot + - tot_diff_point; /* absolute index of feather vert */ + + /* Absolute index of feather vert. */ + sf_vert_prev->keyindex = sf_vert_tot + tot_diff_point; + sf_vert_tot++; /* TODO, an alternate functions so we can avoid double vector copy! */ @@ -965,8 +967,8 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, } /* --- inefficient self-intersect case --- */ - /* if self intersections are found, its too trickty to attempt to map vertices - * so just realloc and add entirely new vertices - the result of the self-intersect check + /* if self intersections are found, its too tricky to attempt to map vertices + * so just realloc and add entirely new vertices - the result of the self-intersect check. */ if ((masklay->flag & MASK_LAYERFLAG_FILL_OVERLAP) && (is_isect = BLI_scanfill_calc_self_isect( diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 1218e78c6f0..687bd0a32c5 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -607,7 +607,7 @@ static void docube(PROCESS *process, CUBE *cube) } } - /* Using faces[] table, adds neighbouring cube if surface intersects face in this direction. */ + /* Using faces[] table, adds neighboring cube if surface intersects face in this direction. */ if (MB_BIT(faces[index], 0)) { add_cube(process, cube->i - 1, cube->j, cube->k); } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 755a8036e8e..f5e93dcf9b7 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -50,6 +50,7 @@ #include "BKE_editmesh.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" enum { MESHCMP_DVERT_WEIGHTMISMATCH = 1, @@ -557,8 +558,9 @@ void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int /* XXX WHAT? Why? Comment, please! And pretty sure this is not valid for regular Mesh copying? */ me_dst->runtime.is_original = false; - const bool do_tessface = ((me_src->totface != 0) && - (me_src->totpoly == 0)); /* only do tessface if we have no polys */ + /* Only do tessface if we have no polys. */ + const bool do_tessface = ((me_src->totface != 0) && (me_src->totpoly == 0)); + CustomData_MeshMasks mask = CD_MASK_MESH; if (me_src->id.tag & LIB_TAG_NO_MAIN) { @@ -663,6 +665,7 @@ static Mesh *mesh_new_nomain_from_template_ex(const Mesh *me_src, me_dst->cd_flag = me_src->cd_flag; me_dst->editflag = me_src->editflag; + me_dst->texflag = me_src->texflag; CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_CALLOC, verts_len); CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_CALLOC, edges_len); @@ -1995,9 +1998,7 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh) { DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh); - if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) { - BKE_mesh_texspace_calc(mesh); - } + BKE_mesh_texspace_calc(mesh); /* Clear autospace flag in evaluated mesh, so that texspace does not get recomputed when bbox is * (e.g. after modifiers, etc.) */ mesh->texflag &= ~ME_AUTOSPACE; @@ -2009,4 +2010,17 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh) BKE_id_free(NULL, mesh->runtime.mesh_eval); mesh->runtime.mesh_eval = NULL; } + if (DEG_is_active(depsgraph)) { + Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id); + BoundBox *bb = mesh->bb; + if (bb != NULL) { + if (mesh_orig->bb == NULL) { + mesh_orig->bb = MEM_mallocN(sizeof(*mesh_orig->bb), __func__); + } + *mesh_orig->bb = *bb; + copy_v3_v3(mesh_orig->loc, mesh->loc); + copy_v3_v3(mesh_orig->size, mesh->size); + copy_v3_v3(mesh_orig->rot, mesh->rot); + } + } } diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index dd36da44b92..fec83ebc899 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -1048,6 +1048,7 @@ static Mesh *mesh_new_from_curve_type_object(Object *object) /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked. If it didn't the curve did * not have any segments or otherwise would have generated an empty mesh. */ if (temp_object->type != OB_MESH) { + BKE_id_free(NULL, temp_object->data); BKE_id_free(NULL, temp_object); return NULL; } @@ -1216,6 +1217,10 @@ Mesh *BKE_mesh_new_from_object_to_bmain(Main *bmain, bool preserve_all_data_layers) { Mesh *mesh = BKE_mesh_new_from_object(depsgraph, object, preserve_all_data_layers); + if (mesh == NULL) { + /* Unable to convert the object to a mesh. */ + return NULL; + } /* Make sure mesh only points original datablocks, also increase users of materials and other * possibly referenced data-blocks. diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index f53700fbfb0..17b22a6d095 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -1164,8 +1164,10 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli */ const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */ const MVert *mv_pivot = &mverts[mv_pivot_index]; - const MEdge *me_org = - &medges[ml_curr->e]; /* ml_curr would be mlfan_prev if we needed that one */ + + /* ml_curr would be mlfan_prev if we needed that one. */ + const MEdge *me_org = &medges[ml_curr->e]; + const int *e2lfan_curr; float vec_curr[3], vec_prev[3], vec_org[3]; const MLoop *mlfan_curr; diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c index df6517066b8..f2ed9456b11 100644 --- a/source/blender/blenkernel/intern/mesh_iterators.c +++ b/source/blender/blenkernel/intern/mesh_iterators.c @@ -180,6 +180,54 @@ void BKE_mesh_foreach_mapped_face_center( } } +/* Copied from cdDM_foreachMappedFaceCenter */ +void BKE_mesh_foreach_mapped_subdiv_face_center( + Mesh *mesh, + void (*func)(void *userData, int index, const float cent[3], const float no[3]), + void *userData, + MeshForeachFlag flag) +{ + const MPoly *mp = mesh->mpoly; + const MLoop *ml; + const MVert *mv; + float _no_buf[3]; + float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL; + const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX); + + if (index) { + for (int i = 0; i < mesh->totpoly; i++, mp++) { + const int orig = *index++; + if (orig == ORIGINDEX_NONE) { + continue; + } + ml = &mesh->mloop[mp->loopstart]; + for (int j = 0; j < mp->totloop; j++, ml++) { + mv = &mesh->mvert[ml->v]; + if (mv->flag & ME_VERT_FACEDOT) { + if (flag & MESH_FOREACH_USE_NORMAL) { + normal_short_to_float_v3(no, mv->no); + } + func(userData, orig, mv->co, no); + } + } + } + } + else { + for (int i = 0; i < mesh->totpoly; i++, mp++) { + ml = &mesh->mloop[mp->loopstart]; + for (int j = 0; j < mp->totloop; j++, ml++) { + mv = &mesh->mvert[ml->v]; + if (mv->flag & ME_VERT_FACEDOT) { + if (flag & MESH_FOREACH_USE_NORMAL) { + normal_short_to_float_v3(no, mv->no); + } + func(userData, i, mv->co, no); + } + } + } + } +} + /* Helpers based on above foreach loopers> */ typedef struct MappedVCosData { diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c index 40e300e6e2d..78c0fa184f4 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.c +++ b/source/blender/blenkernel/intern/mesh_mapping.c @@ -631,6 +631,8 @@ typedef bool (*MeshRemap_CheckIslandBoundary)(const struct MPoly *mpoly, const struct MLoop *mloop, const struct MEdge *medge, const int nbr_egde_users, + const struct MPoly *mpoly_array, + const struct MeshElemMap *edge_poly_map, void *user_data); static void poly_edge_loop_islands_calc(const MEdge *medge, @@ -656,8 +658,10 @@ static void poly_edge_loop_islands_calc(const MEdge *medge, int poly_prev = 0; const int temp_poly_group_id = 3; /* Placeholder value. */ - const int poly_group_id_overflowed = - 5; /* Group we could not find any available bit, will be reset to 0 at end */ + + /* Group we could not find any available bit, will be reset to 0 at end. */ + const int poly_group_id_overflowed = 5; + int tot_group = 0; bool group_id_overflow = false; @@ -728,7 +732,7 @@ static void poly_edge_loop_islands_calc(const MEdge *medge, const MeshElemMap *map_ele = &edge_poly_map[me_idx]; const int *p = map_ele->indices; int i = map_ele->count; - if (!edge_boundary_check(mp, ml, me, i, edge_boundary_check_data)) { + if (!edge_boundary_check(mp, ml, me, i, mpoly, map_ele, edge_boundary_check_data)) { for (; i--; p++) { /* if we meet other non initialized its a bug */ BLI_assert(ELEM(poly_groups[*p], 0, poly_group_id)); @@ -780,8 +784,10 @@ static void poly_edge_loop_islands_calc(const MEdge *medge, "Warning, could not find an available id for current smooth group, faces will me " "marked " "as out of any smooth group...\n"); - poly_group_id = - poly_group_id_overflowed; /* Can't use 0, will have to set them to this value later. */ + + /* Can't use 0, will have to set them to this value later. */ + poly_group_id = poly_group_id_overflowed; + group_id_overflow = true; } if (gid_bit > tot_group) { @@ -828,11 +834,20 @@ static bool poly_is_island_boundary_smooth_cb(const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, const int nbr_egde_users, + const MPoly *mpoly_array, + const MeshElemMap *edge_poly_map, void *UNUSED(user_data)) { - /* Edge is sharp if its poly is sharp, or edge itself is sharp, + /* Edge is sharp if one of its polys is flat, or edge itself is sharp, * or edge is not used by exactly two polygons. */ - return (!(mp->flag & ME_SMOOTH) || (me->flag & ME_SHARP) || (nbr_egde_users != 2)); + if ((mp->flag & ME_SMOOTH) && !(me->flag & ME_SHARP) && (nbr_egde_users == 2)) { + /* In that case, edge appears to be smooth, but we need to check its other poly too. */ + const MPoly *mp_other = (mp == &mpoly_array[edge_poly_map->indices[0]]) ? + &mpoly_array[edge_poly_map->indices[1]] : + &mpoly_array[edge_poly_map->indices[0]]; + return (mp_other->flag & ME_SMOOTH) != 0; + } + return true; } /** @@ -998,6 +1013,8 @@ static bool mesh_check_island_boundary_uv(const MPoly *UNUSED(mp), const MLoop *ml, const MEdge *me, const int UNUSED(nbr_egde_users), + const MPoly *UNUSED(mpoly_array), + const MeshElemMap *UNUSED(edge_poly_map), void *user_data) { if (user_data) { diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 2254207e545..c23fe30d311 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -778,6 +778,41 @@ bool modifiers_usesArmature(Object *ob, bArmature *arm) return false; } +bool modifiers_usesSubsurfFacedots(struct Scene *scene, Object *ob) +{ + /* Search (backward) in the modifier stack to find if we have a subsurf modifier (enabled) before + * the last modifier displayed on cage (or if the subsurf is the last). */ + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + int cage_index = modifiers_getCageIndex(scene, ob, NULL, 1); + if (cage_index == -1) { + return false; + } + /* Find first modifier enabled on cage. */ + for (int i = 0; md && i < cage_index; i++) { + md = md->next; + } + /* Now from this point, search for subsurf modifier. */ + for (; md; md = md->prev) { + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + if (md->type == eModifierType_Subsurf) { + ModifierMode mode = eModifierMode_Realtime | eModifierMode_Editmode; + if (modifier_isEnabled(scene, md, mode)) { + return true; + } + } + else if (mti->type == eModifierTypeType_OnlyDeform) { + /* Theses modifiers do not reset the subdiv flag nor change the topology. + * We can still search for a subsurf modifier. */ + } + else { + /* Other modifiers may reset the subdiv facedot flag or create. */ + return false; + } + } + return false; +} + bool modifier_isCorrectableDeformed(ModifierData *md) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 17d6b623b33..29337ca9985 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -385,12 +385,20 @@ static void multires_ccg_mark_as_modified(SubdivCCG *subdiv_ccg, MultiresModifie } } -void multires_mark_as_modified(Object *ob, MultiresModifiedFlags flags) +void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresModifiedFlags flags) { - if (ob == NULL) { + if (object == NULL) { return; } - Mesh *mesh = ob->data; + /* NOTE: CCG live inside of evaluated object. + * + * While this is a bit weird to tag the only one, this is how other areas were built + * historically: they are tagging multires for update and then rely on object re-evaluation to + * do an actual update. + * + * In a longer term maybe special dependency graph tag can help sanitizing this a bit. */ + Object *object_eval = DEG_get_evaluated_object(depsgraph, object); + Mesh *mesh = object_eval->data; SubdivCCG *subdiv_ccg = mesh->runtime.subdiv_ccg; if (subdiv_ccg == NULL) { return; diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 62357b7f878..775f6eb37a7 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -2455,7 +2455,7 @@ static void ntree_interface_identifier(bNodeTree *ntree, char *description) { /* There is a possibility that different node tree names get mapped to the same identifier - * after sanitization (e.g. "SomeGroup_A", "SomeGroup.A" both get sanitized to "SomeGroup_A"). + * after sanitation (e.g. "SomeGroup_A", "SomeGroup.A" both get sanitized to "SomeGroup_A"). * On top of the sanitized id string add a number suffix if necessary to avoid duplicates. */ identifier[0] = '\0'; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 2a66edc8d42..d7256cc9604 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1417,8 +1417,7 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con } } BKE_object_copy_softbody(ob_dst, ob_src, 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_rigidbody_object_copy(bmain, ob_dst, ob_src, flag_subdata); BKE_object_copy_particlesystems(ob_dst, ob_src, flag_subdata); diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 6a6adb82225..202eadaa35a 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -31,6 +31,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_threads.h" #include "BLI_math.h" #include "BKE_animsys.h" @@ -393,6 +394,21 @@ void BKE_object_data_select_update(Depsgraph *depsgraph, ID *object_data) } } +void BKE_object_select_update(Depsgraph *depsgraph, Object *object) +{ + DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); + if (object->type == OB_MESH && !object->runtime.is_mesh_eval_owned) { + Mesh *mesh_input = object->runtime.mesh_orig; + Mesh_Runtime *mesh_runtime = &mesh_input->runtime; + BLI_mutex_lock(mesh_runtime->eval_mutex); + BKE_object_data_select_update(depsgraph, object->data); + BLI_mutex_unlock(mesh_runtime->eval_mutex); + } + else { + BKE_object_data_select_update(depsgraph, object->data); + } +} + void BKE_object_eval_eval_base_flags(Depsgraph *depsgraph, Scene *scene, const int view_layer_index, diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index dd91878a15b..8e647757b40 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -49,7 +49,7 @@ #include "BKE_report.h" #include "BKE_sound.h" -int seekPackedFile(PackedFile *pf, int offset, int whence) +int BKE_packedfile_seek(PackedFile *pf, int offset, int whence) { int oldseek = -1, seek = 0; @@ -81,12 +81,12 @@ int seekPackedFile(PackedFile *pf, int offset, int whence) return (oldseek); } -void rewindPackedFile(PackedFile *pf) +void BKE_packedfile_rewind(PackedFile *pf) { - seekPackedFile(pf, 0, SEEK_SET); + BKE_packedfile_seek(pf, 0, SEEK_SET); } -int readPackedFile(PackedFile *pf, void *data, int size) +int BKE_packedfile_read(PackedFile *pf, void *data, int size) { if ((pf != NULL) && (size >= 0) && (data != NULL)) { if (size + pf->seek > pf->size) { @@ -109,7 +109,7 @@ int readPackedFile(PackedFile *pf, void *data, int size) return (size); } -int countPackedFiles(Main *bmain) +int BKE_packedfile_count_all(Main *bmain) { Image *ima; VFont *vf; @@ -138,18 +138,18 @@ int countPackedFiles(Main *bmain) return count; } -void freePackedFile(PackedFile *pf) +void BKE_packedfile_free(PackedFile *pf) { if (pf) { MEM_freeN(pf->data); MEM_freeN(pf); } else { - printf("freePackedFile: Trying to free a NULL pointer\n"); + printf("%s: Trying to free a NULL pointer\n", __func__); } } -PackedFile *dupPackedFile(const PackedFile *pf_src) +PackedFile *BKE_packedfile_duplicate(const PackedFile *pf_src) { PackedFile *pf_dst; @@ -159,7 +159,7 @@ PackedFile *dupPackedFile(const PackedFile *pf_src) return pf_dst; } -PackedFile *newPackedFileMemory(void *mem, int memlen) +PackedFile *BKE_packedfile_new_from_memory(void *mem, int memlen) { PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile"); pf->data = mem; @@ -168,7 +168,7 @@ PackedFile *newPackedFileMemory(void *mem, int memlen) return pf; } -PackedFile *newPackedFile(ReportList *reports, const char *filename, const char *basepath) +PackedFile *BKE_packedfile_new(ReportList *reports, const char *filename, const char *basepath) { PackedFile *pf = NULL; int file, filelen; @@ -207,7 +207,7 @@ PackedFile *newPackedFile(ReportList *reports, const char *filename, const char data = MEM_mallocN(filelen, "packFile"); } if (read(file, data, filelen) == filelen) { - pf = newPackedFileMemory(data, filelen); + pf = BKE_packedfile_new_from_memory(data, filelen); } else { MEM_freeN(data); @@ -222,7 +222,7 @@ PackedFile *newPackedFile(ReportList *reports, const char *filename, const char } /* no libraries for now */ -void packAll(Main *bmain, ReportList *reports, bool verbose) +void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose) { Image *ima; VFont *vfont; @@ -247,14 +247,14 @@ void packAll(Main *bmain, ReportList *reports, bool verbose) for (vfont = bmain->fonts.first; vfont; vfont = vfont->id.next) { if (vfont->packedfile == NULL && !ID_IS_LINKED(vfont) && BKE_vfont_is_builtin(vfont) == false) { - vfont->packedfile = newPackedFile(reports, vfont->name, BKE_main_blendfile_path(bmain)); + vfont->packedfile = BKE_packedfile_new(reports, vfont->name, BKE_main_blendfile_path(bmain)); tot++; } } for (sound = bmain->sounds.first; sound; sound = sound->id.next) { if (sound->packedfile == NULL && !ID_IS_LINKED(sound)) { - sound->packedfile = newPackedFile(reports, sound->name, BKE_main_blendfile_path(bmain)); + sound->packedfile = BKE_packedfile_new(reports, sound->name, BKE_main_blendfile_path(bmain)); tot++; } } @@ -267,11 +267,11 @@ void packAll(Main *bmain, ReportList *reports, bool verbose) } } -int writePackedFile(ReportList *reports, - const char *ref_file_name, - const char *filename, - PackedFile *pf, - const bool guimode) +int BKE_packedfile_write_to_file(ReportList *reports, + const char *ref_file_name, + const char *filename, + PackedFile *pf, + const bool guimode) { int file, number; int ret_value = RET_OK; @@ -349,10 +349,12 @@ int writePackedFile(ReportList *reports, * - PF_DIFFERENT: the packed file and original file differ * - PF_NOFILE: the original file doesn't exist */ -int checkPackedFile(const char *ref_file_name, const char *filename, PackedFile *pf) +enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name, + const char *filename, + PackedFile *pf) { BLI_stat_t st; - int ret_val, i, len, file; + enum ePF_FileCompare ret_val; char buf[4096]; char name[FILE_MAX]; @@ -360,35 +362,35 @@ int checkPackedFile(const char *ref_file_name, const char *filename, PackedFile BLI_path_abs(name, ref_file_name); if (BLI_stat(name, &st) == -1) { - ret_val = PF_NOFILE; + ret_val = PF_CMP_NOFILE; } else if (st.st_size != pf->size) { - ret_val = PF_DIFFERS; + ret_val = PF_CMP_DIFFERS; } else { /* we'll have to compare the two... */ - file = BLI_open(name, O_BINARY | O_RDONLY, 0); + const int file = BLI_open(name, O_BINARY | O_RDONLY, 0); if (file == -1) { - ret_val = PF_NOFILE; + ret_val = PF_CMP_NOFILE; } else { - ret_val = PF_EQUAL; + ret_val = PF_CMP_EQUAL; - for (i = 0; i < pf->size; i += sizeof(buf)) { - len = pf->size - i; + for (int i = 0; i < pf->size; i += sizeof(buf)) { + int len = pf->size - i; if (len > sizeof(buf)) { len = sizeof(buf); } if (read(file, buf, len) != len) { /* read error ... */ - ret_val = PF_DIFFERS; + ret_val = PF_CMP_DIFFERS; break; } else { if (memcmp(buf, ((char *)pf->data) + i, len)) { - ret_val = PF_DIFFERS; + ret_val = PF_CMP_DIFFERS; break; } } @@ -402,7 +404,8 @@ int checkPackedFile(const char *ref_file_name, const char *filename, PackedFile } /** - * unpackFile() looks at the existing files (abs_name, local_name) and a packed file. + * #BKE_packedfile_unpack_to_file() looks at the existing files (abs_name, local_name) + * and a packed file. * * It returns a char *to the existing file name / new file name or NULL when * there was an error or when the user decides to cancel the operation. @@ -410,19 +413,18 @@ int checkPackedFile(const char *ref_file_name, const char *filename, PackedFile * \warning 'abs_name' may be relative still! (use a "//" prefix) * be sure to run #BLI_path_abs on it first. */ -char *unpackFile(ReportList *reports, - const char *ref_file_name, - const char *abs_name, - const char *local_name, - PackedFile *pf, - int how) +char *BKE_packedfile_unpack_to_file(ReportList *reports, + const char *ref_file_name, + const char *abs_name, + const char *local_name, + PackedFile *pf, + enum ePF_FileStatus how) { char *newname = NULL; const char *temp = NULL; if (pf != NULL) { switch (how) { - case -1: case PF_KEEP: break; case PF_REMOVE: @@ -443,7 +445,7 @@ char *unpackFile(ReportList *reports, ATTR_FALLTHROUGH; } case PF_WRITE_LOCAL: - if (writePackedFile(reports, ref_file_name, local_name, pf, 1) == RET_OK) { + if (BKE_packedfile_write_to_file(reports, ref_file_name, local_name, pf, 1) == RET_OK) { temp = local_name; } break; @@ -463,12 +465,12 @@ char *unpackFile(ReportList *reports, ATTR_FALLTHROUGH; } case PF_WRITE_ORIGINAL: - if (writePackedFile(reports, ref_file_name, abs_name, pf, 1) == RET_OK) { + if (BKE_packedfile_write_to_file(reports, ref_file_name, abs_name, pf, 1) == RET_OK) { temp = abs_name; } break; default: - printf("unpackFile: unknown return_value %d\n", how); + printf("%s: unknown return_value %u\n", __func__, how); break; } @@ -525,7 +527,10 @@ static void unpack_generate_paths(const char *name, } } -int unpackVFont(Main *bmain, ReportList *reports, VFont *vfont, int how) +int BKE_packedfile_unpack_vfont(Main *bmain, + ReportList *reports, + VFont *vfont, + enum ePF_FileStatus how) { char localname[FILE_MAX], absname[FILE_MAX]; char *newname; @@ -534,11 +539,11 @@ int unpackVFont(Main *bmain, ReportList *reports, VFont *vfont, int how) if (vfont != NULL) { unpack_generate_paths( vfont->name, (ID *)vfont, absname, localname, sizeof(absname), sizeof(localname)); - newname = unpackFile( + newname = BKE_packedfile_unpack_to_file( reports, BKE_main_blendfile_path(bmain), absname, localname, vfont->packedfile, how); if (newname != NULL) { ret_value = RET_OK; - freePackedFile(vfont->packedfile); + BKE_packedfile_free(vfont->packedfile); vfont->packedfile = NULL; BLI_strncpy(vfont->name, newname, sizeof(vfont->name)); MEM_freeN(newname); @@ -548,7 +553,10 @@ int unpackVFont(Main *bmain, ReportList *reports, VFont *vfont, int how) return (ret_value); } -int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how) +int BKE_packedfile_unpack_sound(Main *bmain, + ReportList *reports, + bSound *sound, + enum ePF_FileStatus how) { char localname[FILE_MAX], absname[FILE_MAX]; char *newname; @@ -557,13 +565,13 @@ int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how) if (sound != NULL) { unpack_generate_paths( sound->name, (ID *)sound, absname, localname, sizeof(absname), sizeof(localname)); - newname = unpackFile( + newname = BKE_packedfile_unpack_to_file( reports, BKE_main_blendfile_path(bmain), absname, localname, sound->packedfile, how); if (newname != NULL) { BLI_strncpy(sound->name, newname, sizeof(sound->name)); MEM_freeN(newname); - freePackedFile(sound->packedfile); + BKE_packedfile_free(sound->packedfile); sound->packedfile = NULL; BKE_sound_load(bmain, sound); @@ -575,7 +583,10 @@ int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how) return (ret_value); } -int unpackImage(Main *bmain, ReportList *reports, Image *ima, int how) +int BKE_packedfile_unpack_image(Main *bmain, + ReportList *reports, + Image *ima, + enum ePF_FileStatus how) { int ret_value = RET_ERROR; @@ -587,14 +598,14 @@ int unpackImage(Main *bmain, ReportList *reports, Image *ima, int how) unpack_generate_paths( imapf->filepath, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname)); - newname = unpackFile( + newname = BKE_packedfile_unpack_to_file( reports, BKE_main_blendfile_path(bmain), absname, localname, imapf->packedfile, how); if (newname != NULL) { ImageView *iv; ret_value = ret_value == RET_ERROR ? RET_ERROR : RET_OK; - freePackedFile(imapf->packedfile); + BKE_packedfile_free(imapf->packedfile); imapf->packedfile = NULL; /* update the new corresponding view filepath */ @@ -625,7 +636,7 @@ int unpackImage(Main *bmain, ReportList *reports, Image *ima, int how) return (ret_value); } -int unpackLibraries(Main *bmain, ReportList *reports) +int BKE_packedfile_unpack_all_libraries(Main *bmain, ReportList *reports) { Library *lib; char *newname; @@ -634,18 +645,18 @@ int unpackLibraries(Main *bmain, ReportList *reports) for (lib = bmain->libraries.first; lib; lib = lib->id.next) { if (lib->packedfile && lib->name[0]) { - newname = unpackFile(reports, - BKE_main_blendfile_path(bmain), - lib->filepath, - lib->filepath, - lib->packedfile, - PF_WRITE_ORIGINAL); + newname = BKE_packedfile_unpack_to_file(reports, + BKE_main_blendfile_path(bmain), + lib->filepath, + lib->filepath, + lib->packedfile, + PF_WRITE_ORIGINAL); if (newname != NULL) { ret_value = RET_OK; printf("Unpacked .blend library: %s\n", newname); - freePackedFile(lib->packedfile); + BKE_packedfile_free(lib->packedfile); lib->packedfile = NULL; MEM_freeN(newname); @@ -656,7 +667,7 @@ int unpackLibraries(Main *bmain, ReportList *reports) return (ret_value); } -void packLibraries(Main *bmain, ReportList *reports) +void BKE_packedfile_pack_all_libraries(Main *bmain, ReportList *reports) { Library *lib; @@ -674,12 +685,12 @@ void packLibraries(Main *bmain, ReportList *reports) for (lib = bmain->libraries.first; lib; lib = lib->id.next) { if (lib->packedfile == NULL) { - lib->packedfile = newPackedFile(reports, lib->name, BKE_main_blendfile_path(bmain)); + lib->packedfile = BKE_packedfile_new(reports, lib->name, BKE_main_blendfile_path(bmain)); } } } -void unpackAll(Main *bmain, ReportList *reports, int how) +void BKE_packedfile_unpack_all(Main *bmain, ReportList *reports, enum ePF_FileStatus how) { Image *ima; VFont *vf; @@ -687,25 +698,25 @@ void unpackAll(Main *bmain, ReportList *reports, int how) for (ima = bmain->images.first; ima; ima = ima->id.next) { if (BKE_image_has_packedfile(ima)) { - unpackImage(bmain, reports, ima, how); + BKE_packedfile_unpack_image(bmain, reports, ima, how); } } for (vf = bmain->fonts.first; vf; vf = vf->id.next) { if (vf->packedfile) { - unpackVFont(bmain, reports, vf, how); + BKE_packedfile_unpack_vfont(bmain, reports, vf, how); } } for (sound = bmain->sounds.first; sound; sound = sound->id.next) { if (sound->packedfile) { - unpackSound(bmain, reports, sound, how); + BKE_packedfile_unpack_sound(bmain, reports, sound, how); } } } /* ID should be not NULL, return 1 if there's a packed file */ -bool BKE_pack_check(ID *id) +bool BKE_packedfile_id_check(ID *id) { switch (GS(id->name)) { case ID_IM: { @@ -731,27 +742,27 @@ bool BKE_pack_check(ID *id) } /* ID should be not NULL */ -void BKE_unpack_id(Main *bmain, ID *id, ReportList *reports, int how) +void BKE_packedfile_id_unpack(Main *bmain, ID *id, ReportList *reports, enum ePF_FileStatus how) { switch (GS(id->name)) { case ID_IM: { Image *ima = (Image *)id; if (BKE_image_has_packedfile(ima)) { - unpackImage(bmain, reports, ima, how); + BKE_packedfile_unpack_image(bmain, reports, ima, how); } break; } case ID_VF: { VFont *vf = (VFont *)id; if (vf->packedfile) { - unpackVFont(bmain, reports, vf, how); + BKE_packedfile_unpack_vfont(bmain, reports, vf, how); } break; } case ID_SO: { bSound *snd = (bSound *)id; if (snd->packedfile) { - unpackSound(bmain, reports, snd, how); + BKE_packedfile_unpack_sound(bmain, reports, snd, how); } break; } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 13649eaf096..079a348745c 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -1645,7 +1645,7 @@ static int psys_map_index_on_dm(Mesh *mesh, * to their new location, which means a different index, and for faces * also a new face interpolation weights */ if (from == PART_FROM_VERT) { - if (index_dmcache == DMCACHE_NOTFOUND || index_dmcache > mesh->totvert) { + if (index_dmcache == DMCACHE_NOTFOUND || index_dmcache >= mesh->totvert) { return 0; } @@ -3291,6 +3291,10 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, int segments = 1 << pset->draw_step; int totpart = edit->totpoint, recalc_set = 0; + if (edit->psmd_eval == NULL) { + return; + } + segments = MAX2(segments, 4); if (!cache || edit->totpoint != edit->totcached) { diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index 070c3c7a566..27d85b91ba4 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -232,6 +232,8 @@ static void distribute_grid(Mesh *mesh, ParticleSystem *psys) /* lets intersect the faces */ for (i = 0; i < totface; i++, mface++) { + ParticleData *pa1 = NULL, *pa2 = NULL; + copy_v3_v3(v1, mvert[mface->v1].co); copy_v3_v3(v2, mvert[mface->v2].co); copy_v3_v3(v3, mvert[mface->v3].co); @@ -239,24 +241,32 @@ static void distribute_grid(Mesh *mesh, ParticleSystem *psys) 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; - } - else { /* store number of intersections */ - (pa + (int)(lambda * size[a]) * a0mul)->hair_index++; - } + pa1 = (pa + (int)(lambda * size[a]) * a0mul); } if (mface->v4 && (!intersects_tri || from == PART_FROM_VOLUME)) { copy_v3_v3(v4, mvert[mface->v4].co); 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 { - (pa + (int)(lambda * size[a]) * a0mul)->hair_index++; - } + pa2 = (pa + (int)(lambda * size[a]) * a0mul); + } + } + + if (pa1) { + if (from == PART_FROM_FACE) { + pa1->flag &= ~PARS_UNEXIST; + } + else { /* store number of intersections */ + pa1->hair_index++; + } + } + + if (pa2 && pa2 != pa1) { + if (from == PART_FROM_FACE) { + pa2->flag &= ~PARS_UNEXIST; + } + else { /* store number of intersections */ + pa2->hair_index++; } } } diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index d441ffdc8ff..b577efd2a22 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1590,7 +1590,7 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) pid->stack_index = pid->cache->index; - pid->default_step = 10; + pid->default_step = 1; pid->max_step = 20; pid->file_type = PTCACHE_FILE_PTCACHE; } @@ -1655,7 +1655,7 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p pid->info_types = (1 << BPHYS_DATA_TIMES); - pid->default_step = 10; + pid->default_step = 1; pid->max_step = 20; pid->file_type = PTCACHE_FILE_PTCACHE; } diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index a3a0ebd6cb3..c9b18dfc7e6 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -34,6 +34,7 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" +#include "BLI_listbase.h" #ifdef WITH_BULLET # include "RBI_api.h" @@ -228,7 +229,7 @@ void BKE_rigidbody_free_constraint(Object *ob) * be added to relevant groups later... */ -RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int flag) +static RigidBodyOb *rigidbody_copy_object(const Object *ob, const int flag) { RigidBodyOb *rboN = NULL; @@ -249,7 +250,7 @@ RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int flag) return rboN; } -RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int UNUSED(flag)) +static RigidBodyCon *rigidbody_copy_constraint(const Object *ob, const int UNUSED(flag)) { RigidBodyCon *rbcN = NULL; @@ -268,6 +269,54 @@ RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int UNUSED(f return rbcN; } +void BKE_rigidbody_object_copy(Main *bmain, Object *ob_dst, const Object *ob_src, const int flag) +{ + ob_dst->rigidbody_object = rigidbody_copy_object(ob_src, flag); + ob_dst->rigidbody_constraint = rigidbody_copy_constraint(ob_src, flag); + + if (flag & LIB_ID_CREATE_NO_MAIN) { + return; + } + + /* We have to ensure that duplicated object ends up in relevant rigidbody collections... + * Otherwise duplicating the RB data itself is meaningless. */ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + RigidBodyWorld *rigidbody_world = scene->rigidbody_world; + + if (rigidbody_world != NULL) { + bool need_objects_update = false; + bool need_constraints_update = false; + + if (ob_dst->rigidbody_object) { + if (BKE_collection_has_object(rigidbody_world->group, ob_src)) { + BKE_collection_object_add(bmain, rigidbody_world->group, ob_dst); + need_objects_update = true; + } + } + if (ob_dst->rigidbody_constraint) { + if (BKE_collection_has_object(rigidbody_world->constraints, ob_src)) { + BKE_collection_object_add(bmain, rigidbody_world->constraints, ob_dst); + need_constraints_update = true; + } + } + + if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0 && + (need_objects_update || need_constraints_update)) { + BKE_rigidbody_cache_reset(rigidbody_world); + + DEG_relations_tag_update(bmain); + if (need_objects_update) { + DEG_id_tag_update(&rigidbody_world->group->id, ID_RECALC_COPY_ON_WRITE); + } + if (need_constraints_update) { + DEG_id_tag_update(&rigidbody_world->constraints->id, ID_RECALC_COPY_ON_WRITE); + } + DEG_id_tag_update(&ob_dst->id, ID_RECALC_TRANSFORM); + } + } + } +} + /* ************************************** */ /* Setup Utilities - Validate Sim Instances */ @@ -1983,13 +2032,8 @@ void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime # pragma GCC diagnostic ignored "-Wunused-parameter" # endif -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) +void BKE_rigidbody_object_copy(Main *bmain, Object *ob_dst, const Object *ob_src, const int flag) { - return NULL; } void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild) { diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index d2d56569bff..a447b828bb1 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -2445,6 +2445,21 @@ void BKE_scene_cursor_from_mat4(View3DCursor *cursor, const float mat[4][4], boo /* Dependency graph evaluation. */ +static void scene_sequencer_disable_sound_strips(Scene *scene) +{ + if (scene->sound_scene == NULL) { + return; + } + Sequence *seq; + SEQ_BEGIN (scene->ed, seq) { + if (seq->scene_sound != NULL) { + BKE_sound_remove_scene_sound(scene, seq->scene_sound); + seq->scene_sound = NULL; + } + } + SEQ_END; +} + void BKE_scene_eval_sequencer_sequences(Depsgraph *depsgraph, Scene *scene) { DEG_debug_print_eval(depsgraph, __func__, scene->id.name, scene); @@ -2474,6 +2489,9 @@ void BKE_scene_eval_sequencer_sequences(Depsgraph *depsgraph, Scene *scene) * then it is no longer needed to do such manual forced updates. */ if (seq->type == SEQ_TYPE_SCENE && seq->scene != NULL) { BKE_sound_set_scene_volume(seq->scene, seq->scene->audio.volume); + if ((seq->flag & SEQ_SCENE_STRIPS) == 0) { + scene_sequencer_disable_sound_strips(seq->scene); + } } if (seq->sound != NULL) { if (scene->id.recalc & ID_RECALC_AUDIO || seq->sound->id.recalc & ID_RECALC_AUDIO) { diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 86fec1ee754..619845c9ecb 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -738,6 +738,23 @@ ARegion *BKE_area_find_region_xy(ScrArea *sa, const int regiontype, int x, int y } /** + * \note This is only for screen level regions (typically menus/popups). + */ +ARegion *BKE_screen_find_region_xy(bScreen *sc, const int regiontype, int x, int y) +{ + ARegion *ar_found = NULL; + for (ARegion *ar = sc->regionbase.first; ar; ar = ar->next) { + if ((regiontype == RGN_TYPE_ANY) || (ar->regiontype == regiontype)) { + if (BLI_rcti_isect_pt(&ar->winrct, x, y)) { + ar_found = ar; + break; + } + } + } + return ar_found; +} + +/** * \note, ideally we can get the area from the context, * there are a few places however where this isn't practical. */ diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 971ca77ff3d..c2d51b72b29 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -3740,9 +3740,6 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, ibuf = seq_render_scene_strip(context, seq, nr, cfra); } - /* Scene strips update all animation, so we need to restore original state.*/ - BKE_animsys_evaluate_all_animation(context->bmain, context->depsgraph, context->scene, cfra); - break; } @@ -5203,6 +5200,8 @@ void BKE_sequencer_offset_animdata(Scene *scene, Sequence *seq, int ofs) } } } + + DEG_id_tag_update(&scene->adt->action->id, ID_RECALC_ANIMATION); } void BKE_sequencer_dupe_animdata(Scene *scene, const char *name_src, const char *name_dst) @@ -5398,7 +5397,7 @@ static void seq_load_apply(Main *bmain, Scene *scene, Sequence *seq, SeqLoadInfo if (seq_load->flag & SEQ_LOAD_SOUND_CACHE) { if (seq->sound) { - BKE_sound_cache(seq->sound); + seq->sound->flags |= SOUND_FLAGS_CACHING; } } diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index d6858e2d4d2..bb8fd18ea58 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -1402,9 +1402,9 @@ static void emit_from_particles(Object *flow_ob, Scene *scene, float dt) { + /* Is particle system selected. */ if (sfs && sfs->psys && sfs->psys->part && - ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected - { + ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) { ParticleSimulationData sim; ParticleSystem *psys = sfs->psys; float *particle_pos; diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 5af3f22cad2..03fbdc24ce4 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -155,8 +155,8 @@ typedef struct SB_thread_context { #define BFF_INTERSECT 1 /* collider edge intrudes face */ #define BFF_CLOSEVERT 2 /* collider vertex repulses face */ -static float SoftHeunTol = - 1.0f; /* humm .. this should be calculated from sb parameters and sizes */ +/* humm .. this should be calculated from sb parameters and sizes. */ +static float SoftHeunTol = 1.0f; /* local prototypes */ static void free_softbody_intern(SoftBody *sb); @@ -251,7 +251,7 @@ static float _final_mass(Object *ob, BodyPoint *bp) /* * for each target object/face the axis aligned bounding box (AABB) is stored * faces parallel to global axes - * so only simple "value" in [min, max] ckecks are used + * so only simple "value" in [min, max] checks are used * float operations still */ diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index ad26314e877..6d782726e07 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -170,7 +170,7 @@ void BKE_sound_free(bSound *sound) /* No animdata here. */ if (sound->packedfile) { - freePackedFile(sound->packedfile); + BKE_packedfile_free(sound->packedfile); sound->packedfile = NULL; } @@ -211,7 +211,7 @@ void BKE_sound_copy_data(Main *UNUSED(bmain), sound_dst->newpackedfile = NULL; if (sound_dst->packedfile) { - sound_dst->packedfile = dupPackedFile(sound_dst->packedfile); + sound_dst->packedfile = BKE_packedfile_duplicate(sound_dst->packedfile); } BKE_sound_reset_runtime(sound_dst); @@ -389,7 +389,6 @@ void BKE_sound_cache(bSound *sound) { sound_verify_evaluated_id(&sound->id); - sound->flags |= SOUND_FLAGS_CACHING; if (sound->cache) { AUD_Sound_free(sound->cache); } @@ -405,7 +404,6 @@ void BKE_sound_cache(bSound *sound) void BKE_sound_delete_cache(bSound *sound) { - sound->flags &= ~SOUND_FLAGS_CACHING; if (sound->cache) { AUD_Sound_free(sound->cache); sound->cache = NULL; diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index 41ef2bd4b04..fac1e1dbe75 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -962,15 +962,31 @@ static void subdiv_ccg_average_inner_face_grids(SubdivCCG *subdiv_ccg, const int num_face_grids = face->num_grids; const int grid_size = subdiv_ccg->grid_size; CCGElem *prev_grid = grids[face->start_grid_index + num_face_grids - 1]; + /* Average boundary between neighbor grid. */ for (int corner = 0; corner < num_face_grids; corner++) { CCGElem *grid = grids[face->start_grid_index + corner]; - for (int i = 0; i < grid_size; i++) { + for (int i = 1; i < grid_size; i++) { CCGElem *prev_grid_element = CCG_grid_elem(key, prev_grid, i, 0); CCGElem *grid_element = CCG_grid_elem(key, grid, 0, i); average_grid_element(subdiv_ccg, key, prev_grid_element, grid_element); } prev_grid = grid; } + /* Average all grids centers into a single accumulator, and share it. + * Guarantees corrent and smooth averaging in the center. */ + GridElementAccumulator center_accumulator; + element_accumulator_init(¢er_accumulator); + for (int corner = 0; corner < num_face_grids; corner++) { + CCGElem *grid = grids[face->start_grid_index + corner]; + CCGElem *grid_center_element = CCG_grid_elem(key, grid, 0, 0); + element_accumulator_add(¢er_accumulator, subdiv_ccg, key, grid_center_element); + } + element_accumulator_mul_fl(¢er_accumulator, 1.0f / (float)num_face_grids); + for (int corner = 0; corner < num_face_grids; corner++) { + CCGElem *grid = grids[face->start_grid_index + corner]; + CCGElem *grid_center_element = CCG_grid_elem(key, grid, 0, 0); + element_accumulator_copy(subdiv_ccg, key, grid_center_element, ¢er_accumulator); + } } static void subdiv_ccg_average_inner_grids_task(void *__restrict userdata_v, diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c index 947f51b4ff9..75e05f8ffab 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -570,6 +570,8 @@ static void evaluate_vertex_and_apply_displacement_copy(const SubdivMeshContext normalize_v3(N); normal_float_to_short_v3(subdiv_vert->no, N); } + /* Remove facedot flag. This can happen if there is more than one subsurf modifier. */ + subdiv_vert->flag &= ~ME_VERT_FACEDOT; } static void evaluate_vertex_and_apply_displacement_interpolate( @@ -719,6 +721,31 @@ static void subdiv_mesh_vertex_edge(const SubdivForeachContext *foreach_context, ctx, ptex_face_index, u, v, &tls->vertex_interpolation, subdiv_vert); } +static bool subdiv_mesh_is_center_vertex(const MPoly *coarse_poly, const float u, const float v) +{ + if (coarse_poly->totloop == 4) { + if (u == 0.5f && v == 0.5f) { + return true; + } + } + else { + if (u == 1.0f && v == 1.0f) { + return true; + } + } + return false; +} + +static void subdiv_mesh_tag_center_vertex(const MPoly *coarse_poly, + MVert *subdiv_vert, + const float u, + const float v) +{ + if (subdiv_mesh_is_center_vertex(coarse_poly, u, v)) { + subdiv_vert->flag |= ME_VERT_FACEDOT; + } +} + static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context, void *tls_v, const int ptex_face_index, @@ -741,6 +768,7 @@ static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context subdiv_vertex_data_interpolate(ctx, subdiv_vert, &tls->vertex_interpolation, u, v); eval_final_point_and_vertex_normal( subdiv, ptex_face_index, u, v, subdiv_vert->co, subdiv_vert->no); + subdiv_mesh_tag_center_vertex(coarse_poly, subdiv_vert, u, v); } /* ============================================================================= @@ -1098,8 +1126,8 @@ static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context, foreach_context->vertex_every_edge = subdiv_mesh_vertex_every_edge; } else { - foreach_context->vertex_every_corner = NULL; - foreach_context->vertex_every_edge = NULL; + foreach_context->vertex_every_corner = subdiv_mesh_vertex_every_corner; + foreach_context->vertex_every_edge = subdiv_mesh_vertex_every_edge; } foreach_context->vertex_corner = subdiv_mesh_vertex_corner; foreach_context->vertex_edge = subdiv_mesh_vertex_edge; diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 7d5862c1fb6..056229ceb1c 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -79,96 +79,24 @@ * * Display * -- + * * The st->top determines at what line the top of the text is displayed. * If the user moves the cursor the st containing that cursor should * be popped ... other st's retain their own top location. - * - * Undo - * -- - * Undo/Redo works by storing - * events in a queue, and a pointer - * to the current position in the - * queue... - * - * Events are stored using an - * arbitrary op-code system - * to keep track of - * a) the two cursors (normal and selected) - * b) input (visible and control (ie backspace)) - * - * input data is stored as its - * ASCII value, the opcodes are - * then selected to not conflict. - * - * opcodes with data in between are - * written at the beginning and end - * of the data to allow undo and redo - * to simply check the code at the current - * undo position */ -/* Undo opcodes */ - -enum { - /* Complex editing */ - /* 1 - opcode is followed by 1 byte for ascii character and opcode (repeat)) */ - /* 2 - opcode is followed by 2 bytes for utf-8 character and opcode (repeat)) */ - /* 3 - opcode is followed by 3 bytes for utf-8 character and opcode (repeat)) */ - /* 4 - opcode is followed by 4 bytes for unicode character and opcode (repeat)) */ - UNDO_INSERT_1 = 013, - UNDO_INSERT_2 = 014, - UNDO_INSERT_3 = 015, - UNDO_INSERT_4 = 016, - - UNDO_BS_1 = 017, - UNDO_BS_2 = 020, - UNDO_BS_3 = 021, - UNDO_BS_4 = 022, - - UNDO_DEL_1 = 023, - UNDO_DEL_2 = 024, - UNDO_DEL_3 = 025, - UNDO_DEL_4 = 026, - - /* Text block (opcode is followed - * by 4 character length ID + the text - * block itself + the 4 character length - * ID (repeat) and opcode (repeat)) */ - UNDO_DBLOCK = 027, /* Delete block */ - UNDO_IBLOCK = 030, /* Insert block */ - - /* Misc */ - UNDO_INDENT = 032, - UNDO_UNINDENT = 033, - UNDO_COMMENT = 034, - UNDO_UNCOMMENT = 035, - - UNDO_MOVE_LINES_UP = 036, - UNDO_MOVE_LINES_DOWN = 037, - - UNDO_DUPLICATE = 040, -}; - /***/ static void txt_pop_first(Text *text); static void txt_pop_last(Text *text); -static void txt_undo_add_blockop(Text *text, TextUndoBuf *utxt, int op, const char *buf); static void txt_delete_line(Text *text, TextLine *line); -static void txt_delete_sel(Text *text, TextUndoBuf *utxt); +static void txt_delete_sel(Text *text); static void txt_make_dirty(Text *text); /***/ /** - * Set to true when undoing (so we don't generate undo steps while undoing). - * - * Also use to disable undo entirely. - */ -static bool undoing; - -/** - * \note caller must handle `undo_buf` and `compiled` members. + * \note caller must handle `compiled` member. */ void BKE_text_free_lines(Text *text) { @@ -238,6 +166,8 @@ Text *BKE_text_add(Main *bmain, const char *name) Text *ta; ta = BKE_libblock_alloc(bmain, ID_TXT, name, 0); + /* Texts always have 'real' user (see also read code). */ + id_us_ensure_real(&ta->id); BKE_text_init(ta); @@ -426,7 +356,8 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const } ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs), 0); - ta->id.us = 0; + /* Texts always have 'real' user (see also read code). */ + id_us_ensure_real(&ta->id); BLI_listbase_clear(&ta->lines); ta->curl = ta->sell = NULL; @@ -516,29 +447,17 @@ void BKE_text_make_local(Main *bmain, Text *text, const bool lib_local) BKE_id_make_local_generic(bmain, &text->id, true, lib_local); } -void BKE_text_clear(Text *text, TextUndoBuf *utxt) /* called directly from rna */ +void BKE_text_clear(Text *text) /* called directly from rna */ { - const bool undoing_orig = undoing; - undoing = (utxt == NULL); - txt_sel_all(text); - txt_delete_sel(text, utxt); - - undoing = undoing_orig; - + txt_delete_sel(text); txt_make_dirty(text); } -void BKE_text_write(Text *text, TextUndoBuf *utxt, const char *str) /* called directly from rna */ +void BKE_text_write(Text *text, const char *str) /* called directly from rna */ { - const bool undoing_orig = undoing; - undoing = (utxt == NULL); - - txt_insert_buf(text, utxt, str); + txt_insert_buf(text, str); txt_move_eof(text, 0); - - undoing = undoing_orig; - txt_make_dirty(text); } @@ -1270,7 +1189,7 @@ bool txt_has_sel(Text *text) return ((text->curl != text->sell) || (text->curc != text->selc)); } -static void txt_delete_sel(Text *text, TextUndoBuf *utxt) +static void txt_delete_sel(Text *text) { TextLine *tmpl; char *buf; @@ -1288,12 +1207,6 @@ static void txt_delete_sel(Text *text, TextUndoBuf *utxt) txt_order_cursors(text, false); - if (!undoing) { - buf = txt_sel_to_buf(text); - txt_undo_add_blockop(text, utxt, UNDO_DBLOCK, buf); - MEM_freeN(buf); - } - buf = MEM_mallocN(text->curc + (text->sell->len - text->selc) + 1, "textline_string"); strncpy(buf, text->curl->line, text->curc); @@ -1349,17 +1262,121 @@ void txt_sel_line(Text *text) text->selc = text->sell->len; } +/* -------------------------------------------------------------------- */ +/** \name Buffer Conversion for Undo/Redo + * + * Buffer conversion functions that rely on the buffer already being validated. + * + * The only requirement for these functions is that they're reverse-able, + * the undo logic doesn't inspect their content. + * + * Currently buffers: + * - Always ends with a new-line. + * - Are not null terminated. + * \{ */ + +/** + * Create a buffer, the only requirement is #txt_from_buf_for_undo can decode it. + */ +char *txt_to_buf_for_undo(Text *text, int *r_buf_len) +{ + int buf_len = 0; + for (const TextLine *l = text->lines.first; l; l = l->next) { + buf_len += l->len + 1; + } + char *buf = MEM_mallocN(buf_len, __func__); + char *buf_step = buf; + for (const TextLine *l = text->lines.first; l; l = l->next) { + memcpy(buf_step, l->line, l->len); + buf_step += l->len; + *buf_step++ = '\n'; + } + *r_buf_len = buf_len; + return buf; +} + +/** + * Decode a buffer from #txt_to_buf_for_undo. + */ +void txt_from_buf_for_undo(Text *text, const char *buf, int buf_len) +{ + const char *buf_end = buf + buf_len; + const char *buf_step = buf; + + /* First re-use existing lines. + * Good for undo since it means in practice many operations re-use all + * except for the modified line. */ + TextLine *l_src = text->lines.first; + BLI_listbase_clear(&text->lines); + while (buf_step != buf_end && l_src) { + /* New lines are ensured by #txt_to_buf_for_undo. */ + const char *buf_step_next = strchr(buf_step, '\n'); + const int len = buf_step_next - buf_step; + + TextLine *l = l_src; + l_src = l_src->next; + if (l->len != len) { + l->line = MEM_reallocN(l->line, len + 1); + l->len = len; + } + MEM_SAFE_FREE(l->format); + + memcpy(l->line, buf_step, len); + l->line[len] = '\0'; + BLI_addtail(&text->lines, l); + buf_step = buf_step_next + 1; + } + + /* If we have extra lines. */ + while (l_src != NULL) { + TextLine *l_src_next = l_src->next; + MEM_freeN(l_src->line); + if (l_src->format) { + MEM_freeN(l_src->format); + } + MEM_freeN(l_src); + l_src = l_src_next; + } + + while (buf_step != buf_end) { + /* New lines are ensured by #txt_to_buf_for_undo. */ + const char *buf_step_next = strchr(buf_step, '\n'); + const int len = buf_step_next - buf_step; + + TextLine *l = MEM_mallocN(sizeof(TextLine), "textline"); + l->line = MEM_mallocN(len + 1, "textline_string"); + l->len = len; + l->format = NULL; + + memcpy(l->line, buf_step, len); + l->line[len] = '\0'; + BLI_addtail(&text->lines, l); + buf_step = buf_step_next + 1; + } + + text->curl = text->sell = text->lines.first; + text->curc = text->selc = 0; + + txt_make_dirty(text); +} + +/** \} */ + /***************************/ /* Cut and paste functions */ /***************************/ -char *txt_to_buf(Text *text) +char *txt_to_buf(Text *text, int *r_buf_strlen) { int length; TextLine *tmp, *linef, *linel; int charf, charl; char *buf; + if (r_buf_strlen) { + *r_buf_strlen = 0; + } + if (!text->curl) { return NULL; } @@ -1419,6 +1436,10 @@ char *txt_to_buf(Text *text) buf[length] = 0; } + if (r_buf_strlen) { + *r_buf_strlen = length; + } + return buf; } @@ -1475,13 +1496,17 @@ int txt_find_string(Text *text, const char *findstr, int wrap, int match_case) } } -char *txt_sel_to_buf(Text *text) +char *txt_sel_to_buf(Text *text, int *r_buf_strlen) { char *buf; int length = 0; TextLine *tmp, *linef, *linel; int charf, charl; + if (r_buf_strlen) { + *r_buf_strlen = 0; + } + if (!text->curl) { return NULL; } @@ -1556,12 +1581,15 @@ char *txt_sel_to_buf(Text *text) buf[length] = 0; } + if (r_buf_strlen) { + *r_buf_strlen = length; + } + return buf; } -void txt_insert_buf(Text *text, TextUndoBuf *utxt, const char *in_buffer) +void txt_insert_buf(Text *text, const char *in_buffer) { - const bool undoing_orig = undoing; int l = 0, len; size_t i = 0, j; TextLine *add; @@ -1571,24 +1599,19 @@ void txt_insert_buf(Text *text, TextUndoBuf *utxt, const char *in_buffer) return; } - txt_delete_sel(text, utxt); + txt_delete_sel(text); len = strlen(in_buffer); buffer = BLI_strdupn(in_buffer, len); len += txt_extended_ascii_as_utf8(&buffer); - if (!undoing) { - txt_undo_add_blockop(text, utxt, UNDO_IBLOCK, buffer); - } - undoing = true; - /* Read the first line (or as close as possible */ while (buffer[i] && buffer[i] != '\n') { - txt_add_raw_char(text, utxt, BLI_str_utf8_as_unicode_step(buffer, &i)); + txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &i)); } if (buffer[i] == '\n') { - txt_split_curline(text, utxt); + txt_split_curline(text); i++; while (i < len) { @@ -1606,7 +1629,7 @@ void txt_insert_buf(Text *text, TextUndoBuf *utxt, const char *in_buffer) } else { for (j = i - l; j < i && j < len;) { - txt_add_raw_char(text, utxt, BLI_str_utf8_as_unicode_step(buffer, &j)); + txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &j)); } break; } @@ -1614,1046 +1637,13 @@ void txt_insert_buf(Text *text, TextUndoBuf *utxt, const char *in_buffer) } MEM_freeN(buffer); - undoing = undoing_orig; -} - -/******************/ -/* Undo functions */ -/******************/ - -static bool max_undo_test(TextUndoBuf *utxt, int x) -{ - /* Normally over-allocating is preferred, - * however in this case the buffer is small enough and re-allocation - * fast enough for each undo step that it's not a problem to allocate each time. - * This also saves on some memory when we have many text buffers - * that would have an empty undo memory allocated. - */ - - /* Add one for the null terminator. */ - utxt->len = utxt->pos + x + 1; - if (utxt->len > TXT_MAX_UNDO) { - /* XXX error("Undo limit reached, buffer cleared\n"); */ - MEM_freeN(utxt->buf); - return false; - } - else { - /* Small reallocations on each undo step is fine. */ - utxt->buf = MEM_recallocN(utxt->buf, utxt->len); - } - return true; -} - -static void txt_undo_end(Text *UNUSED(text), TextUndoBuf *utxt) -{ - int undo_pos_end = utxt->pos + 1; - BLI_assert(undo_pos_end + 1 == utxt->len); - utxt->buf[undo_pos_end] = '\0'; -} - -/* Call once undo is done. */ -#ifndef NDEBUG - -#endif - -#if 0 /* UNUSED */ -static void dump_buffer(TextUndoBuf *utxt) -{ - int i = 0; - - while (i++ < utxt->undo_pos) - printf("%d: %d %c\n", i, utxt->buf[i], utxt->buf[i]); -} - -/* Note: this function is outdated and must be updated if needed for future use */ -void txt_print_undo(Text *text) -{ - int i = 0; - int op; - const char *ops; - int linep, charp; - - dump_buffer(text); - - printf("---< Undo Buffer >---\n"); - - printf("UndoPosition is %d\n", utxt->pos); - - while (i <= utxt->pos) { - op = utxt->buf[i]; - - if (op == UNDO_INSERT_1) { - ops = "Insert ascii "; - } - else if (op == UNDO_INSERT_2) { - ops = "Insert 2 bytes "; - } - else if (op == UNDO_INSERT_3) { - ops = "Insert 3 bytes "; - } - else if (op == UNDO_INSERT_4) { - ops = "Insert unicode "; - } - else if (op == UNDO_BS_1) { - ops = "Backspace for ascii "; - } - else if (op == UNDO_BS_2) { - ops = "Backspace for 2 bytes "; - } - else if (op == UNDO_BS_3) { - ops = "Backspace for 3 bytes "; - } - else if (op == UNDO_BS_4) { - ops = "Backspace for unicode "; - } - else if (op == UNDO_DEL_1) { - ops = "Delete ascii "; - } - else if (op == UNDO_DEL_2) { - ops = "Delete 2 bytes "; - } - else if (op == UNDO_DEL_3) { - ops = "Delete 3 bytes "; - } - else if (op == UNDO_DEL_4) { - ops = "Delete unicode "; - } - else if (op == UNDO_DBLOCK) { - ops = "Delete text block"; - } - else if (op == UNDO_IBLOCK) { - ops = "Insert text block"; - } - else if (op == UNDO_INDENT) { - ops = "Indent "; - } - else if (op == UNDO_UNINDENT) { - ops = "Unindent "; - } - else if (op == UNDO_COMMENT) { - ops = "Comment "; - } - else if (op == UNDO_UNCOMMENT) { - ops = "Uncomment "; - } - else { - ops = "Unknown"; - } - - printf("Op (%o) at %d = %s", op, i, ops); - if (op >= UNDO_INSERT_1 && op <= UNDO_DEL_4) { - i++; - printf(" - Char is "); - switch (op) { - case UNDO_INSERT_1: - case UNDO_BS_1: - case UNDO_DEL_1: - printf("%c", utxt->buf[i]); - i++; - break; - case UNDO_INSERT_2: - case UNDO_BS_2: - case UNDO_DEL_2: - printf("%c%c", utxt->buf[i], utxt->buf[i + 1]); - i += 2; - break; - case UNDO_INSERT_3: - case UNDO_BS_3: - case UNDO_DEL_3: - printf("%c%c%c", utxt->buf[i], utxt->buf[i + 1], utxt->buf[i + 2]); - i += 3; - break; - case UNDO_INSERT_4: - case UNDO_BS_4: - case UNDO_DEL_4: { - unsigned int uc; - char c[BLI_UTF8_MAX + 1]; - size_t c_len; - uc = utxt->buf[i]; - i++; - uc = uc + (utxt->buf[i] << 8); - i++; - uc = uc + (utxt->buf[i] << 16); - i++; - uc = uc + (utxt->buf[i] << 24); - i++; - c_len = BLI_str_utf8_from_unicode(uc, c); - c[c_len] = '\0'; - puts(c); - break; - } - } - } - else if (op == UNDO_DBLOCK || op == UNDO_IBLOCK) { - i++; - - linep = utxt->buf[i]; - i++; - linep = linep + (utxt->buf[i] << 8); - i++; - linep = linep + (utxt->buf[i] << 16); - i++; - linep = linep + (utxt->buf[i] << 24); - i++; - - printf(" (length %d) <", linep); - - while (linep > 0) { - putchar(utxt->buf[i]); - linep--; - i++; - } - - linep = utxt->buf[i]; - i++; - linep = linep + (utxt->buf[i] << 8); - i++; - linep = linep + (utxt->buf[i] << 16); - i++; - linep = linep + (utxt->buf[i] << 24); - i++; - printf("> (%d)", linep); - } - else if (op == UNDO_INDENT || op == UNDO_UNINDENT) { - i++; - - charp = utxt->buf[i]; - i++; - charp = charp + (utxt->buf[i] << 8); - i++; - - linep = utxt->buf[i]; - i++; - linep = linep + (utxt->buf[i] << 8); - i++; - linep = linep + (utxt->buf[i] << 16); - i++; - linep = linep + (utxt->buf[i] << 24); - i++; - - printf("to <%d, %d> ", linep, charp); - - charp = utxt->buf[i]; - i++; - charp = charp + (utxt->buf[i] << 8); - i++; - - linep = utxt->buf[i]; - i++; - linep = linep + (utxt->buf[i] << 8); - i++; - linep = linep + (utxt->buf[i] << 16); - i++; - linep = linep + (utxt->buf[i] << 24); - i++; - - printf("from <%d, %d>", linep, charp); - } - - printf(" %d\n", i); - i++; - } -} -#endif - -static void txt_undo_store_uint16(char *undo_buf, int *undo_pos, unsigned short value) -{ - undo_buf[*undo_pos] = (value)&0xff; - (*undo_pos)++; - undo_buf[*undo_pos] = (value >> 8) & 0xff; - (*undo_pos)++; -} - -static void txt_undo_store_uint32(char *undo_buf, int *undo_pos, unsigned int value) -{ - undo_buf[*undo_pos] = (value)&0xff; - (*undo_pos)++; - undo_buf[*undo_pos] = (value >> 8) & 0xff; - (*undo_pos)++; - undo_buf[*undo_pos] = (value >> 16) & 0xff; - (*undo_pos)++; - undo_buf[*undo_pos] = (value >> 24) & 0xff; - (*undo_pos)++; -} - -/* store the cur cursor to the undo buffer (6 bytes)*/ -static void txt_undo_store_cur(Text *text, TextUndoBuf *utxt) -{ - txt_undo_store_uint16(utxt->buf, &utxt->pos, text->curc); - txt_undo_store_uint32(utxt->buf, &utxt->pos, txt_get_span(text->lines.first, text->curl)); -} - -/* store the sel cursor to the undo buffer (6 bytes) */ -static void txt_undo_store_sel(Text *text, TextUndoBuf *utxt) -{ - txt_undo_store_uint16(utxt->buf, &utxt->pos, text->selc); - txt_undo_store_uint32(utxt->buf, &utxt->pos, txt_get_span(text->lines.first, text->sell)); -} - -/* store both cursors to the undo buffer (12 bytes) */ -static void txt_undo_store_cursors(Text *text, TextUndoBuf *utxt) -{ - txt_undo_store_cur(text, utxt); - txt_undo_store_sel(text, utxt); -} - -/* store an operator along with a block of data */ -static void txt_undo_add_blockop(Text *text, TextUndoBuf *utxt, int op, const char *buf) -{ - unsigned int length = strlen(buf); - - if (!max_undo_test(utxt, 2 + 12 + 4 + length + 4 + 1)) { - return; - } - /* 2 bytes */ - utxt->pos++; - utxt->buf[utxt->pos] = op; - utxt->pos++; - /* 12 bytes */ - txt_undo_store_cursors(text, utxt); - /* 4 bytes */ - txt_undo_store_uint32(utxt->buf, &utxt->pos, length); - /* 'length' bytes */ - memcpy(utxt->buf + utxt->pos, buf, length); - utxt->pos += length; - /* 4 bytes */ - txt_undo_store_uint32(utxt->buf, &utxt->pos, length); - /* 1 byte */ - utxt->buf[utxt->pos] = op; - - txt_undo_end(text, utxt); -} - -/* store a regular operator */ -void txt_undo_add_op(Text *text, TextUndoBuf *utxt, int op) -{ - if (!max_undo_test(utxt, 2 + 12 + 1)) { - return; - } - - /* 2 bytes */ - utxt->pos++; - utxt->buf[utxt->pos] = op; - utxt->pos++; - /* 12 bytes */ - txt_undo_store_cursors(text, utxt); - /* 1 byte */ - utxt->buf[utxt->pos] = op; - - txt_undo_end(text, utxt); -} - -/* store an operator for a single character */ -static void txt_undo_add_charop(Text *text, TextUndoBuf *utxt, int op_start, unsigned int c) -{ - char utf8[BLI_UTF8_MAX]; - size_t i, utf8_size = BLI_str_utf8_from_unicode(c, utf8); - - if (utf8_size < 4 && 0) { - if (!max_undo_test(utxt, 2 + 6 + utf8_size + 1)) { - return; - } - /* 2 bytes */ - utxt->pos++; - utxt->buf[utxt->pos] = op_start + utf8_size - 1; - utxt->pos++; - /* 6 bytes */ - txt_undo_store_cur(text, utxt); - /* 'utf8_size' bytes */ - for (i = 0; i < utf8_size; i++) { - utxt->buf[utxt->pos] = utf8[i]; - utxt->pos++; - } - /* 1 byte */ - utxt->buf[utxt->pos] = op_start + utf8_size - 1; - } - else { - if (!max_undo_test(utxt, 2 + 6 + 4 + 1)) { - return; - } - /* 2 bytes */ - utxt->pos++; - utxt->buf[utxt->pos] = op_start + 3; - utxt->pos++; - /* 6 bytes */ - txt_undo_store_cur(text, utxt); - /* 4 bytes */ - txt_undo_store_uint32(utxt->buf, &utxt->pos, c); - /* 1 byte */ - utxt->buf[utxt->pos] = op_start + 3; - } - - txt_undo_end(text, utxt); -} - -/* extends Link */ -struct LinkInt { - struct LinkInt *next, *prev; - int value; -}; - -/** - * UnindentLines points to a #ListBase composed of #LinkInt elements, listing the numbers - * of the lines that should not be indented back. - */ -static void txt_undo_add_unprefix_op(Text *text, - TextUndoBuf *utxt, - char undo_op, - const ListBase *line_index_mask, - const int line_index_mask_len) -{ - struct LinkInt *idata; - - BLI_assert(BLI_listbase_count(line_index_mask) == line_index_mask_len); - - /* OP byte + u32 count + counted u32 line numbers + u32 count + 12-bytes selection + OP byte. */ - if (!max_undo_test(utxt, 2 + 4 + (line_index_mask_len * 4) + 4 + 12 + 1)) { - return; - } - - /* 2 bytes */ - utxt->pos++; - utxt->buf[utxt->pos] = undo_op; - utxt->pos++; - /* Adding number of line numbers to read - * 4 bytes */ - txt_undo_store_uint32(utxt->buf, &utxt->pos, line_index_mask_len); - - /* Adding line-numbers of lines that shall not be indented if undoing. - * 'line_index_mask_len * 4' bytes */ - for (idata = line_index_mask->first; idata; idata = idata->next) { - txt_undo_store_uint32(utxt->buf, &utxt->pos, idata->value); - } - - /* Adding number of line numbers to read again. - * 4 bytes */ - txt_undo_store_uint32(utxt->buf, &utxt->pos, line_index_mask_len); - /* Adding current selection. - * 12 bytes */ - txt_undo_store_cursors(text, utxt); - /* Closing with OP (same as above). - * 1 byte */ - utxt->buf[utxt->pos] = undo_op; - /* Marking as last undo operation */ - txt_undo_end(text, utxt); -} - -static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos) -{ - unsigned short val; - val = undo_buf[*undo_pos]; - (*undo_pos)--; - val = (val << 8) + undo_buf[*undo_pos]; - (*undo_pos)--; - return val; -} - -static unsigned int txt_undo_read_uint32(const char *undo_buf, int *undo_pos) -{ - unsigned int val; - val = undo_buf[*undo_pos]; - (*undo_pos)--; - val = (val << 8) + undo_buf[*undo_pos]; - (*undo_pos)--; - val = (val << 8) + undo_buf[*undo_pos]; - (*undo_pos)--; - val = (val << 8) + undo_buf[*undo_pos]; - (*undo_pos)--; - return val; -} - -/* read the cur cursor from the undo buffer */ -static void txt_undo_read_cur(const char *undo_buf, - int *undo_pos, - unsigned int *curln, - unsigned short *curc) -{ - *curln = txt_undo_read_uint32(undo_buf, undo_pos); - *curc = txt_undo_read_uint16(undo_buf, undo_pos); -} - -/* read the sel cursor from the undo buffer */ -static void txt_undo_read_sel(const char *undo_buf, - int *undo_pos, - unsigned int *selln, - unsigned short *selc) -{ - *selln = txt_undo_read_uint32(undo_buf, undo_pos); - *selc = txt_undo_read_uint16(undo_buf, undo_pos); -} - -/* read both cursors from the undo buffer */ -static void txt_undo_read_cursors(const char *undo_buf, - int *undo_pos, - unsigned int *curln, - unsigned short *curc, - unsigned int *selln, - unsigned short *selc) -{ - txt_undo_read_sel(undo_buf, undo_pos, selln, selc); - txt_undo_read_cur(undo_buf, undo_pos, curln, curc); -} - -static unsigned int txt_undo_read_unicode(const char *undo_buf, int *undo_pos, short bytes) -{ - unsigned int unicode; - char utf8[BLI_UTF8_MAX + 1]; - - switch (bytes) { - case 1: /* ascii */ - unicode = undo_buf[*undo_pos]; - (*undo_pos)--; - break; - case 2: /* 2-byte symbol */ - utf8[2] = '\0'; - utf8[1] = undo_buf[*undo_pos]; - (*undo_pos)--; - utf8[0] = undo_buf[*undo_pos]; - (*undo_pos)--; - unicode = BLI_str_utf8_as_unicode(utf8); - break; - case 3: /* 3-byte symbol */ - utf8[3] = '\0'; - utf8[2] = undo_buf[*undo_pos]; - (*undo_pos)--; - utf8[1] = undo_buf[*undo_pos]; - (*undo_pos)--; - utf8[0] = undo_buf[*undo_pos]; - (*undo_pos)--; - unicode = BLI_str_utf8_as_unicode(utf8); - break; - case 4: /* 32-bit unicode symbol */ - unicode = txt_undo_read_uint32(undo_buf, undo_pos); - break; - default: - /* should never happen */ - BLI_assert(0); - unicode = 0; - break; - } - - return unicode; -} - -static unsigned short txt_redo_read_uint16(const char *undo_buf, int *undo_pos) -{ - unsigned short val; - val = undo_buf[*undo_pos]; - (*undo_pos)++; - val = val + (undo_buf[*undo_pos] << 8); - (*undo_pos)++; - return val; -} - -static unsigned int txt_redo_read_uint32(const char *undo_buf, int *undo_pos) -{ - unsigned int val; - val = undo_buf[*undo_pos]; - (*undo_pos)++; - val = val + (undo_buf[*undo_pos] << 8); - (*undo_pos)++; - val = val + (undo_buf[*undo_pos] << 16); - (*undo_pos)++; - val = val + (undo_buf[*undo_pos] << 24); - (*undo_pos)++; - return val; -} - -/* redo read cur cursor from the undo buffer */ -static void txt_redo_read_cur(const char *undo_buf, - int *undo_pos, - unsigned int *curln, - unsigned short *curc) -{ - *curc = txt_redo_read_uint16(undo_buf, undo_pos); - *curln = txt_redo_read_uint32(undo_buf, undo_pos); -} - -/* redo read sel cursor from the undo buffer */ -static void txt_redo_read_sel(const char *undo_buf, - int *undo_pos, - unsigned int *selln, - unsigned short *selc) -{ - *selc = txt_redo_read_uint16(undo_buf, undo_pos); - *selln = txt_redo_read_uint32(undo_buf, undo_pos); -} - -/* redo read both cursors from the undo buffer */ -static void txt_redo_read_cursors(const char *undo_buf, - int *undo_pos, - unsigned int *curln, - unsigned short *curc, - unsigned int *selln, - unsigned short *selc) -{ - txt_redo_read_cur(undo_buf, undo_pos, curln, curc); - txt_redo_read_sel(undo_buf, undo_pos, selln, selc); -} - -static unsigned int txt_redo_read_unicode(const char *undo_buf, int *undo_pos, short bytes) -{ - unsigned int unicode; - char utf8[BLI_UTF8_MAX + 1]; - - switch (bytes) { - case 1: /* ascii */ - unicode = undo_buf[*undo_pos]; - (*undo_pos)++; - break; - case 2: /* 2-byte symbol */ - utf8[0] = undo_buf[*undo_pos]; - (*undo_pos)++; - utf8[1] = undo_buf[*undo_pos]; - (*undo_pos)++; - utf8[2] = '\0'; - unicode = BLI_str_utf8_as_unicode(utf8); - break; - case 3: /* 3-byte symbol */ - utf8[0] = undo_buf[*undo_pos]; - (*undo_pos)++; - utf8[1] = undo_buf[*undo_pos]; - (*undo_pos)++; - utf8[2] = undo_buf[*undo_pos]; - (*undo_pos)++; - utf8[3] = '\0'; - unicode = BLI_str_utf8_as_unicode(utf8); - break; - case 4: /* 32-bit unicode symbol */ - unicode = txt_redo_read_uint32(undo_buf, undo_pos); - break; - default: - /* should never happen */ - BLI_assert(0); - unicode = 0; - break; - } - - return unicode; -} - -void txt_do_undo(Text *text, TextUndoBuf *utxt) -{ - int op = utxt->buf[utxt->pos]; - int prev_flags; - unsigned int linep; - unsigned int uni_char; - unsigned int curln, selln; - unsigned short curc, selc; - unsigned short charp; - char *buf; - - if (utxt->pos < 0) { - return; - } - - utxt->pos--; - - undoing = 1; - - switch (op) { - case UNDO_INSERT_1: - case UNDO_INSERT_2: - case UNDO_INSERT_3: - case UNDO_INSERT_4: - utxt->pos -= op - UNDO_INSERT_1 + 1; - - /* get and restore the cursors */ - txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc); - txt_move_to(text, curln, curc, 0); - txt_move_to(text, curln, curc, 1); - - txt_delete_char(text, utxt); - - utxt->pos--; - break; - - case UNDO_BS_1: - case UNDO_BS_2: - case UNDO_BS_3: - case UNDO_BS_4: - charp = op - UNDO_BS_1 + 1; - uni_char = txt_undo_read_unicode(utxt->buf, &utxt->pos, charp); - - /* get and restore the cursors */ - txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc); - txt_move_to(text, curln, curc, 0); - txt_move_to(text, curln, curc, 1); - - txt_add_char(text, utxt, uni_char); - - utxt->pos--; - break; - - case UNDO_DEL_1: - case UNDO_DEL_2: - case UNDO_DEL_3: - case UNDO_DEL_4: - charp = op - UNDO_DEL_1 + 1; - uni_char = txt_undo_read_unicode(utxt->buf, &utxt->pos, charp); - - /* get and restore the cursors */ - txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc); - txt_move_to(text, curln, curc, 0); - txt_move_to(text, curln, curc, 1); - - txt_add_char(text, utxt, uni_char); - - txt_move_left(text, 0); - - utxt->pos--; - break; - - case UNDO_DBLOCK: { - int i; - /* length of the string in the buffer */ - linep = txt_undo_read_uint32(utxt->buf, &utxt->pos); - - buf = MEM_mallocN(linep + 1, "dblock buffer"); - for (i = 0; i < linep; i++) { - buf[(linep - 1) - i] = utxt->buf[utxt->pos]; - utxt->pos--; - } - buf[i] = 0; - - /* skip over the length that was stored again */ - utxt->pos -= 4; - - /* Get the cursor positions */ - txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); - - /* move cur to location that needs buff inserted */ - txt_move_to(text, curln, curc, 0); - - txt_insert_buf(text, utxt, buf); - MEM_freeN(buf); - - /* restore the cursors */ - txt_move_to(text, curln, curc, 0); - txt_move_to(text, selln, selc, 1); - - utxt->pos--; - - break; - } - case UNDO_IBLOCK: { - int i; - /* length of the string in the buffer */ - linep = txt_undo_read_uint32(utxt->buf, &utxt->pos); - - /* txt_backspace_char removes utf8-characters, not bytes */ - buf = MEM_mallocN(linep + 1, "iblock buffer"); - for (i = 0; i < linep; i++) { - buf[(linep - 1) - i] = utxt->buf[utxt->pos]; - utxt->pos--; - } - buf[i] = 0; - linep = BLI_strlen_utf8(buf); - MEM_freeN(buf); - - /* skip over the length that was stored again */ - utxt->pos -= 4; - - /* get and restore the cursors */ - txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); - - txt_move_to(text, curln, curc, 0); - txt_move_to(text, selln, selc, 1); - - if ((curln == selln) && (curc == selc)) { - /* disable tabs to spaces since moving right may involve skipping multiple spaces */ - prev_flags = text->flags; - text->flags &= ~TXT_TABSTOSPACES; - - for (i = 0; i < linep; i++) { - txt_move_right(text, 1); - } - - text->flags = prev_flags; - } - - txt_delete_selected(text, utxt); - - utxt->pos--; - break; - } - case UNDO_INDENT: - case UNDO_COMMENT: - case UNDO_DUPLICATE: - case UNDO_MOVE_LINES_UP: - case UNDO_MOVE_LINES_DOWN: - /* get and restore the cursors */ - txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); - txt_move_to(text, curln, curc, 0); - txt_move_to(text, selln, selc, 1); - - if (op == UNDO_INDENT) { - txt_unindent(text, utxt); - } - else if (op == UNDO_COMMENT) { - txt_uncomment(text, utxt); - } - else if (op == UNDO_DUPLICATE) { - txt_delete_line(text, text->curl->next); - } - else if (op == UNDO_MOVE_LINES_UP) { - txt_move_lines(text, utxt, TXT_MOVE_LINE_DOWN); - } - else if (op == UNDO_MOVE_LINES_DOWN) { - txt_move_lines(text, utxt, TXT_MOVE_LINE_UP); - } - - utxt->pos--; - break; - case UNDO_UNINDENT: - case UNDO_UNCOMMENT: { - void (*txt_prefix_fn)(Text *, TextUndoBuf *); - void (*txt_unprefix_fn)(Text *, TextUndoBuf *); - int count; - int i; - /* Get and restore the cursors */ - txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); - txt_move_to(text, curln, curc, 0); - txt_move_to(text, selln, selc, 1); - - /* Un-unindent */ - if (op == UNDO_UNINDENT) { - txt_prefix_fn = txt_indent; - txt_unprefix_fn = txt_unindent; - } - else { - txt_prefix_fn = txt_comment; - txt_unprefix_fn = txt_uncomment; - } - - txt_prefix_fn(text, utxt); - - /* Get the count */ - count = txt_undo_read_uint32(utxt->buf, &utxt->pos); - /* Iterate! */ - txt_pop_sel(text); - - for (i = 0; i < count; i++) { - txt_move_to(text, txt_undo_read_uint32(utxt->buf, &utxt->pos), 0, 0); - /* Un-un-unindent/comment */ - txt_unprefix_fn(text, utxt); - } - /* Restore selection */ - txt_move_to(text, curln, curc, 0); - txt_move_to(text, selln, selc, 1); - /* Jumo over count */ - txt_undo_read_uint32(utxt->buf, &utxt->pos); - /* Jump over closing OP byte */ - utxt->pos--; - break; - } - default: - // XXX error("Undo buffer error - resetting"); - utxt->pos = -1; - - break; - } - - undoing = 0; -} - -void txt_do_redo(Text *text, TextUndoBuf *utxt) -{ - char op; - char *buf; - unsigned int linep; - unsigned short charp; - unsigned int uni_uchar; - unsigned int curln, selln; - unsigned short curc, selc; - - utxt->pos++; - op = utxt->buf[utxt->pos]; - - if (!op) { - utxt->pos--; - return; - } - - undoing = 1; - - switch (op) { - case UNDO_INSERT_1: - case UNDO_INSERT_2: - case UNDO_INSERT_3: - case UNDO_INSERT_4: - utxt->pos++; - - /* get and restore the cursors */ - txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc); - txt_move_to(text, curln, curc, 0); - txt_move_to(text, curln, curc, 1); - - charp = op - UNDO_INSERT_1 + 1; - uni_uchar = txt_redo_read_unicode(utxt->buf, &utxt->pos, charp); - - txt_add_char(text, utxt, uni_uchar); - break; - - case UNDO_BS_1: - case UNDO_BS_2: - case UNDO_BS_3: - case UNDO_BS_4: - utxt->pos++; - - /* get and restore the cursors */ - txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc); - txt_move_to(text, curln, curc, 0); - txt_move_to(text, curln, curc, 1); - - utxt->pos += op - UNDO_BS_1 + 1; - - /* move right so we backspace the correct char */ - txt_move_right(text, 0); - txt_backspace_char(text, utxt); - - break; - - case UNDO_DEL_1: - case UNDO_DEL_2: - case UNDO_DEL_3: - case UNDO_DEL_4: - utxt->pos++; - - /* get and restore the cursors */ - txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc); - txt_move_to(text, curln, curc, 0); - txt_move_to(text, curln, curc, 1); - - utxt->pos += op - UNDO_DEL_1 + 1; - - txt_delete_char(text, utxt); - - break; - - case UNDO_DBLOCK: - utxt->pos++; - - /* get and restore the cursors */ - txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); - txt_move_to(text, curln, curc, 0); - txt_move_to(text, selln, selc, 1); - - /* length of the block */ - linep = txt_redo_read_uint32(utxt->buf, &utxt->pos); - - utxt->pos += linep; - - /* skip over the length that was stored again */ - utxt->pos += 4; - - txt_delete_sel(text, utxt); - - break; - - case UNDO_IBLOCK: - utxt->pos++; - - /* get and restore the cursors */ - txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); - txt_move_to(text, curln, curc, 0); - txt_move_to(text, curln, curc, 1); - - /* length of the block */ - linep = txt_redo_read_uint32(utxt->buf, &utxt->pos); - - buf = MEM_mallocN(linep + 1, "iblock buffer"); - memcpy(buf, &utxt->buf[utxt->pos], linep); - utxt->pos += linep; - buf[linep] = 0; - - txt_insert_buf(text, utxt, buf); - MEM_freeN(buf); - - /* skip over the length that was stored again */ - utxt->pos += 4; - - break; - - case UNDO_INDENT: - case UNDO_COMMENT: - case UNDO_UNCOMMENT: - case UNDO_DUPLICATE: - case UNDO_MOVE_LINES_UP: - case UNDO_MOVE_LINES_DOWN: - utxt->pos++; - - /* get and restore the cursors */ - txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); - txt_move_to(text, curln, curc, 0); - txt_move_to(text, selln, selc, 1); - - if (op == UNDO_INDENT) { - txt_indent(text, utxt); - } - else if (op == UNDO_COMMENT) { - txt_comment(text, utxt); - } - else if (op == UNDO_UNCOMMENT) { - txt_uncomment(text, utxt); - } - else if (op == UNDO_DUPLICATE) { - txt_duplicate_line(text, utxt); - } - else if (op == UNDO_MOVE_LINES_UP) { - /* offset the cursor by + 1 */ - txt_move_to(text, curln + 1, curc, 0); - txt_move_to(text, selln + 1, selc, 1); - - txt_move_lines(text, utxt, TXT_MOVE_LINE_UP); - } - else if (op == UNDO_MOVE_LINES_DOWN) { - /* offset the cursor by - 1 */ - txt_move_to(text, curln - 1, curc, 0); - txt_move_to(text, selln - 1, selc, 1); - - txt_move_lines(text, utxt, TXT_MOVE_LINE_DOWN); - } - - /* re-restore the cursors since they got moved when redoing */ - txt_move_to(text, curln, curc, 0); - txt_move_to(text, selln, selc, 1); - - break; - case UNDO_UNINDENT: { - int count; - int i; - - utxt->pos++; - /* Scan all the stuff described in txt_undo_add_unindent_op */ - count = txt_redo_read_uint32(utxt->buf, &utxt->pos); - for (i = 0; i < count; i++) { - txt_redo_read_uint32(utxt->buf, &utxt->pos); - } - /* Count again */ - txt_redo_read_uint32(utxt->buf, &utxt->pos); - /* Get the selection and re-unindent */ - txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); - txt_move_to(text, curln, curc, 0); - txt_move_to(text, selln, selc, 1); - txt_unindent(text, utxt); - break; - } - default: - // XXX error("Undo buffer error - resetting"); - utxt->pos = -1; - - break; - } - - undoing = 0; } /**************************/ /* Line editing functions */ /**************************/ -void txt_split_curline(Text *text, TextUndoBuf *utxt) +void txt_split_curline(Text *text) { TextLine *ins; char *left, *right; @@ -2662,11 +1652,7 @@ void txt_split_curline(Text *text, TextUndoBuf *utxt) return; } - txt_delete_sel(text, utxt); - - if (!undoing) { - txt_undo_add_charop(text, utxt, UNDO_INSERT_1, '\n'); - } + txt_delete_sel(text); /* Make the two half strings */ @@ -2749,7 +1735,7 @@ static void txt_combine_lines(Text *text, TextLine *linea, TextLine *lineb) txt_clean_text(text); } -void txt_duplicate_line(Text *text, TextUndoBuf *utxt) +void txt_duplicate_line(Text *text) { TextLine *textline; @@ -2763,14 +1749,10 @@ void txt_duplicate_line(Text *text, TextUndoBuf *utxt) txt_make_dirty(text); txt_clean_text(text); - - if (!undoing) { - txt_undo_add_op(text, utxt, UNDO_DUPLICATE); - } } } -void txt_delete_char(Text *text, TextUndoBuf *utxt) +void txt_delete_char(Text *text) { unsigned int c = '\n'; @@ -2779,7 +1761,7 @@ void txt_delete_char(Text *text, TextUndoBuf *utxt) } if (txt_has_sel(text)) { /* deleting a selection */ - txt_delete_sel(text, utxt); + txt_delete_sel(text); txt_make_dirty(text); return; } @@ -2795,6 +1777,7 @@ void txt_delete_char(Text *text, TextUndoBuf *utxt) else { /* Just deleting a char */ size_t c_len = 0; c = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &c_len); + UNUSED_VARS(c); memmove(text->curl->line + text->curc, text->curl->line + text->curc + c_len, @@ -2807,20 +1790,16 @@ void txt_delete_char(Text *text, TextUndoBuf *utxt) txt_make_dirty(text); txt_clean_text(text); - - if (!undoing) { - txt_undo_add_charop(text, utxt, UNDO_DEL_1, c); - } } -void txt_delete_word(Text *text, TextUndoBuf *utxt) +void txt_delete_word(Text *text) { txt_jump_right(text, true, true); - txt_delete_sel(text, utxt); + txt_delete_sel(text); txt_make_dirty(text); } -void txt_backspace_char(Text *text, TextUndoBuf *utxt) +void txt_backspace_char(Text *text) { unsigned int c = '\n'; @@ -2829,7 +1808,7 @@ void txt_backspace_char(Text *text, TextUndoBuf *utxt) } if (txt_has_sel(text)) { /* deleting a selection */ - txt_delete_sel(text, utxt); + txt_delete_sel(text); txt_make_dirty(text); return; } @@ -2848,6 +1827,7 @@ void txt_backspace_char(Text *text, TextUndoBuf *utxt) size_t c_len = 0; const char *prev = BLI_str_prev_char_utf8(text->curl->line + text->curc); c = BLI_str_utf8_as_unicode_and_size(prev, &c_len); + UNUSED_VARS(c); /* source and destination overlap, don't use memcpy() */ memmove(text->curl->line + text->curc - c_len, @@ -2862,16 +1842,12 @@ void txt_backspace_char(Text *text, TextUndoBuf *utxt) txt_make_dirty(text); txt_clean_text(text); - - if (!undoing) { - txt_undo_add_charop(text, utxt, UNDO_BS_1, c); - } } -void txt_backspace_word(Text *text, TextUndoBuf *utxt) +void txt_backspace_word(Text *text) { txt_jump_left(text, true, true); - txt_delete_sel(text, utxt); + txt_delete_sel(text); txt_make_dirty(text); } @@ -2880,17 +1856,17 @@ void txt_backspace_word(Text *text, TextUndoBuf *utxt) * Remember to change this string according to max tab size */ static char tab_to_spaces[] = " "; -static void txt_convert_tab_to_spaces(Text *text, TextUndoBuf *utxt) +static void txt_convert_tab_to_spaces(Text *text) { /* sb aims to pad adjust the tab-width needed so that the right number of spaces * is added so that the indention of the line is the right width (i.e. aligned * to multiples of TXT_TABSIZE) */ const char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE]; - txt_insert_buf(text, utxt, sb); + txt_insert_buf(text, sb); } -static bool txt_add_char_intern(Text *text, TextUndoBuf *utxt, unsigned int add, bool replace_tabs) +static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs) { char *tmp, ch[BLI_UTF8_MAX]; size_t add_len; @@ -2900,21 +1876,17 @@ static bool txt_add_char_intern(Text *text, TextUndoBuf *utxt, unsigned int add, } if (add == '\n') { - txt_split_curline(text, utxt); + txt_split_curline(text); return true; } /* insert spaces rather than tabs */ if (add == '\t' && replace_tabs) { - txt_convert_tab_to_spaces(text, utxt); + txt_convert_tab_to_spaces(text); return true; } - txt_delete_sel(text, utxt); - - if (!undoing) { - txt_undo_add_charop(text, utxt, UNDO_INSERT_1, add); - } + txt_delete_sel(text); add_len = BLI_str_utf8_from_unicode(add, ch); @@ -2937,23 +1909,23 @@ static bool txt_add_char_intern(Text *text, TextUndoBuf *utxt, unsigned int add, return 1; } -bool txt_add_char(Text *text, TextUndoBuf *utxt, unsigned int add) +bool txt_add_char(Text *text, unsigned int add) { - return txt_add_char_intern(text, utxt, add, (text->flags & TXT_TABSTOSPACES) != 0); + return txt_add_char_intern(text, add, (text->flags & TXT_TABSTOSPACES) != 0); } -bool txt_add_raw_char(Text *text, TextUndoBuf *utxt, unsigned int add) +bool txt_add_raw_char(Text *text, unsigned int add) { - return txt_add_char_intern(text, utxt, add, 0); + return txt_add_char_intern(text, add, 0); } -void txt_delete_selected(Text *text, TextUndoBuf *utxt) +void txt_delete_selected(Text *text) { - txt_delete_sel(text, utxt); + txt_delete_sel(text); txt_make_dirty(text); } -bool txt_replace_char(Text *text, TextUndoBuf *utxt, unsigned int add) +bool txt_replace_char(Text *text, unsigned int add) { unsigned int del; size_t del_size = 0, add_size; @@ -2965,10 +1937,11 @@ bool txt_replace_char(Text *text, TextUndoBuf *utxt, unsigned int add) /* If text is selected or we're at the end of the line just use txt_add_char */ if (text->curc == text->curl->len || txt_has_sel(text) || add == '\n') { - return txt_add_char(text, utxt, add); + return txt_add_char(text, add); } del = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &del_size); + UNUSED_VARS(del); add_size = BLI_str_utf8_from_unicode(add, ch); if (add_size > del_size) { @@ -2994,16 +1967,6 @@ bool txt_replace_char(Text *text, TextUndoBuf *utxt, unsigned int add) txt_pop_sel(text); txt_make_dirty(text); txt_clean_text(text); - - /* Should probably create a new op for this */ - if (!undoing) { - txt_undo_add_charop(text, utxt, UNDO_INSERT_1, add); - text->curc -= add_size; - txt_pop_sel(text); - txt_undo_add_charop(text, utxt, UNDO_DEL_1, del); - text->curc += add_size; - txt_pop_sel(text); - } return true; } @@ -3082,26 +2045,14 @@ static void txt_select_prefix(Text *text, const char *add) * * \note caller must handle undo. */ -static void txt_select_unprefix(Text *text, - const char *remove, - ListBase *r_line_index_mask, - int *r_line_index_mask_len) +static void txt_select_unprefix(Text *text, const char *remove) { int num = 0; const int indentlen = strlen(remove); bool unindented_first = false; - int curl_span_init = 0; - BLI_assert(!ELEM(NULL, text->curl, text->sell)); - BLI_listbase_clear(r_line_index_mask); - *r_line_index_mask_len = 0; - - if (!undoing) { - curl_span_init = txt_get_span(text->lines.first, text->curl); - } - while (true) { bool changed = false; if (STREQLEN(text->curl->line, remove, indentlen)) { @@ -3112,16 +2063,6 @@ static void txt_select_unprefix(Text *text, memmove(text->curl->line, text->curl->line + indentlen, text->curl->len + 1); changed = true; } - else { - if (!undoing) { - /* Create list element for 0 indent line */ - struct LinkInt *idata = MEM_mallocN(sizeof(struct LinkInt), __func__); - idata->value = curl_span_init + num; - BLI_assert(idata->value == txt_get_span(text->lines.first, text->curl)); - BLI_addtail(r_line_index_mask, idata); - (*r_line_index_mask_len) += 1; - } - } txt_make_dirty(text); txt_clean_text(text); @@ -3150,7 +2091,7 @@ static void txt_select_unprefix(Text *text, /* caller must handle undo */ } -void txt_comment(Text *text, TextUndoBuf *utxt) +void txt_comment(Text *text) { const char *prefix = "#"; @@ -3159,32 +2100,20 @@ void txt_comment(Text *text, TextUndoBuf *utxt) } txt_select_prefix(text, prefix); - - if (!undoing) { - txt_undo_add_op(text, utxt, UNDO_COMMENT); - } } -void txt_uncomment(Text *text, TextUndoBuf *utxt) +void txt_uncomment(Text *text) { const char *prefix = "#"; - ListBase line_index_mask; - int line_index_mask_len; if (ELEM(NULL, text->curl, text->sell)) { return; } - txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len); - - if (!undoing) { - txt_undo_add_unprefix_op(text, utxt, UNDO_UNCOMMENT, &line_index_mask, line_index_mask_len); - } - - BLI_freelistN(&line_index_mask); + txt_select_unprefix(text, prefix); } -void txt_indent(Text *text, TextUndoBuf *utxt) +void txt_indent(Text *text) { const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t"; @@ -3193,32 +2122,20 @@ void txt_indent(Text *text, TextUndoBuf *utxt) } txt_select_prefix(text, prefix); - - if (!undoing) { - txt_undo_add_op(text, utxt, UNDO_INDENT); - } } -void txt_unindent(Text *text, TextUndoBuf *utxt) +void txt_unindent(Text *text) { const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t"; - ListBase line_index_mask; - int line_index_mask_len; if (ELEM(NULL, text->curl, text->sell)) { return; } - txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len); - - if (!undoing) { - txt_undo_add_unprefix_op(text, utxt, UNDO_UNINDENT, &line_index_mask, line_index_mask_len); - } - - BLI_freelistN(&line_index_mask); + txt_select_unprefix(text, prefix); } -void txt_move_lines(struct Text *text, TextUndoBuf *utxt, const int direction) +void txt_move_lines(struct Text *text, const int direction) { TextLine *line_other; @@ -3247,11 +2164,6 @@ void txt_move_lines(struct Text *text, TextUndoBuf *utxt, const int direction) txt_make_dirty(text); txt_clean_text(text); - - if (!undoing) { - txt_undo_add_op( - text, utxt, (direction == TXT_MOVE_LINE_DOWN) ? UNDO_MOVE_LINES_DOWN : UNDO_MOVE_LINES_UP); - } } int txt_setcurr_tab_spaces(Text *text, int space) diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index 88b81392189..b852e8a12cd 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -672,14 +672,14 @@ static void average_marker_positions(StabContext *ctx, int framenr, float r_ref_ } else { /* No usable tracking data on any track on this frame. - * Use data from neighbouring frames to extrapolate... + * Use data from neighboring frames to extrapolate... */ int next_lower = MINAFRAME; int next_higher = MAXFRAME; use_values_from_fcurves(ctx, true); for (track = tracking->tracks.first; track; track = track->next) { /* Note: we deliberately do not care if this track - * is already initialized for stabilisation */ + * is already initialized for stabilization. */ if (track->flag & TRACK_USE_2D_STAB) { int startpoint = search_closest_marker_index(track, framenr); retrieve_next_higher_usable_frame(ctx, track, startpoint, framenr, &next_higher); diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c index b33884e4f0e..8ea5b47de5f 100644 --- a/source/blender/blenkernel/intern/undo_system.c +++ b/source/blender/blenkernel/intern/undo_system.c @@ -50,7 +50,7 @@ /** Make sure all ID's created at the point we add an undo step that uses ID's. */ #define WITH_GLOBAL_UNDO_ENSURE_UPDATED -/** Make sure we don't apply edits ontop of a newer memfile state, see: T56163. +/** Make sure we don't apply edits on top of a newer memfile state, see: T56163. * \note Keep an eye on this, could solve differently. */ #define WITH_GLOBAL_UNDO_CORRECT_ORDER @@ -120,7 +120,7 @@ static const UndoType *BKE_undosys_type_from_context(bContext *C) /* -------------------------------------------------------------------- */ /** \name Internal Callback Wrappers * - * #UndoRefID is simply a way to avoid inlining name copy and lookups, + * #UndoRefID is simply a way to avoid in-lining name copy and lookups, * since it's easy to forget a single case when done inline (crashing in some cases). * * \{ */ @@ -173,7 +173,8 @@ static bool undosys_step_encode(bContext *C, Main *bmain, UndoStack *ustack, Und return ok; } -static void undosys_step_decode(bContext *C, Main *bmain, UndoStack *ustack, UndoStep *us, int dir) +static void undosys_step_decode( + bContext *C, Main *bmain, UndoStack *ustack, UndoStep *us, int dir, bool is_final) { CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name); @@ -188,7 +189,7 @@ static void undosys_step_decode(bContext *C, Main *bmain, UndoStack *ustack, Und else { /* Load the previous memfile state so any ID's referenced in this * undo step will be correctly resolved, see: T56163. */ - undosys_step_decode(C, bmain, ustack, us_iter, dir); + undosys_step_decode(C, bmain, ustack, us_iter, dir, false); /* May have been freed on memfile read. */ bmain = G.main; } @@ -203,7 +204,7 @@ static void undosys_step_decode(bContext *C, Main *bmain, UndoStack *ustack, Und } UNDO_NESTED_CHECK_BEGIN; - us->type->step_decode(C, bmain, us, dir); + us->type->step_decode(C, bmain, us, dir, is_final); UNDO_NESTED_CHECK_END; #ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER @@ -310,13 +311,20 @@ static void undosys_stack_clear_all_last(UndoStack *ustack, UndoStep *us) } } -static void undosys_stack_clear_all_first(UndoStack *ustack, UndoStep *us) +static void undosys_stack_clear_all_first(UndoStack *ustack, UndoStep *us, UndoStep *us_exclude) { + if (us && us == us_exclude) { + us = us->prev; + } + if (us) { bool is_not_empty = true; UndoStep *us_iter; do { us_iter = ustack->steps.first; + if (us_iter == us_exclude) { + us_iter = us_iter->next; + } BLI_assert(us_iter != ustack->step_active); undosys_step_free_and_unlink(ustack, us_iter); undosys_stack_validate(ustack, is_not_empty); @@ -394,9 +402,7 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size CLOG_INFO(&LOG, 1, "steps=%d, memory_limit=%zu", steps, memory_limit); UndoStep *us; -#ifdef WITH_GLOBAL_UNDO_KEEP_ONE UndoStep *us_exclude = NULL; -#endif /* keep at least two (original + other) */ size_t data_size_all = 0; size_t us_count = 0; @@ -426,23 +432,14 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size /* Hack, we need to keep at least one BKE_UNDOSYS_TYPE_MEMFILE. */ if (us->type != BKE_UNDOSYS_TYPE_MEMFILE) { us_exclude = us->prev; - while (us_exclude && us->type != BKE_UNDOSYS_TYPE_MEMFILE) { + while (us_exclude && us_exclude->type != BKE_UNDOSYS_TYPE_MEMFILE) { us_exclude = us_exclude->prev; } - if (us_exclude) { - BLI_remlink(&ustack->steps, us_exclude); - } } #endif /* Free from first to last, free functions may update de-duplication info * (see #MemFileUndoStep). */ - undosys_stack_clear_all_first(ustack, us->prev); - -#ifdef WITH_GLOBAL_UNDO_KEEP_ONE - if (us_exclude) { - BLI_addhead(&ustack->steps, us_exclude); - } -#endif + undosys_stack_clear_all_first(ustack, us->prev, us_exclude); } } @@ -550,7 +547,7 @@ bool BKE_undosys_step_push_with_type(UndoStack *ustack, BLI_strncpy(us->name, name, sizeof(us->name)); } us->type = ut; - /* initialized, not added yet. */ + /* Initialized, not added yet. */ if (!undosys_step_encode(C, G_MAIN, ustack, us)) { MEM_freeN(us); @@ -678,22 +675,36 @@ bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack, * - skip successive steps that store the same data, eg: memfile steps. * - or steps that include another steps data, eg: a memfile step includes text undo data. */ - undosys_step_decode(C, G_MAIN, ustack, us_iter, -1); + undosys_step_decode(C, G_MAIN, ustack, us_iter, -1, false); + us_iter = us_iter->prev; } } - undosys_step_decode(C, G_MAIN, ustack, us, -1); - - ustack->step_active = us_prev; - undosys_stack_validate(ustack, true); + UndoStep *us_active = us_prev; if (use_skip) { - if (ustack->step_active && ustack->step_active->skip) { - CLOG_INFO( - &LOG, 2, "undo continue with skip %p '%s', type='%s'", us, us->name, us->type->name); - BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active); + while (us_active->skip && us_active->prev) { + us_active = us_active->prev; } } + + { + UndoStep *us_iter = us_prev; + do { + const bool is_final = (us_iter == us_active); + if (is_final == false) { + CLOG_INFO(&LOG, + 2, + "undo continue with skip %p '%s', type='%s'", + us_iter, + us_iter->name, + us_iter->type->name); + } + undosys_step_decode(C, G_MAIN, ustack, us_iter, -1, is_final); + ustack->step_active = us_iter; + } while ((us_active != us_iter) && (us_iter = us_iter->prev)); + } + return true; } return false; @@ -732,20 +743,34 @@ bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack, if (ustack->step_active && ustack->step_active->next) { UndoStep *us_iter = ustack->step_active->next; while (us_iter != us) { - undosys_step_decode(C, G_MAIN, ustack, us_iter, 1); + undosys_step_decode(C, G_MAIN, ustack, us_iter, 1, false); us_iter = us_iter->next; } } - undosys_step_decode(C, G_MAIN, ustack, us, 1); - ustack->step_active = us_next; + UndoStep *us_active = us_next; if (use_skip) { - if (ustack->step_active && ustack->step_active->skip) { - CLOG_INFO( - &LOG, 2, "redo continue with skip %p '%s', type='%s'", us, us->name, us->type->name); - BKE_undosys_step_redo_with_data(ustack, C, ustack->step_active); + while (us_active->skip && us_active->prev) { + us_active = us_active->next; } } + + { + UndoStep *us_iter = us_next; + do { + const bool is_final = (us_iter == us_active); + if (is_final == false) { + CLOG_INFO(&LOG, + 2, + "redo continue with skip %p '%s', type='%s'", + us_iter, + us_iter->name, + us_iter->type->name); + } + undosys_step_decode(C, G_MAIN, ustack, us_iter, 1, is_final); + ustack->step_active = us_iter; + } while ((us_active != us_iter) && (us_iter = us_iter->next)); + } return true; } return false; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 345d9ce1193..f3336adda30 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -601,7 +601,7 @@ static AVStream *alloc_video_stream(FFMpegContext *context, /* This calculates a fraction (DENUM_MAX / num) which approximates the scene frame rate * (frs_sec / frs_sec_base). It uses the maximum denominator allowed by FFmpeg. */ - const double DENUM_MAX = (codec_id == AV_CODEC_ID_MPEG4) ? (1L << 16) - 1 : (1L << 31) - 1; + const double DENUM_MAX = (codec_id == AV_CODEC_ID_MPEG4) ? (1UL << 16) - 1 : (1UL << 31) - 1; const double num = (DENUM_MAX / (double)rd->frs_sec) * rd->frs_sec_base; c->time_base.den = (int)DENUM_MAX; @@ -696,9 +696,9 @@ static AVStream *alloc_video_stream(FFMpegContext *context, } if (codec_id == AV_CODEC_ID_QTRLE) { - if (rd->im_format.planes == R_IMF_PLANES_RGBA) { - c->pix_fmt = AV_PIX_FMT_ARGB; - } + /* Always write to ARGB. The default pixel format of QTRLE is RGB24, which uses 3 bytes per + * pixels, which breaks the export. */ + c->pix_fmt = AV_PIX_FMT_ARGB; } if (codec_id == AV_CODEC_ID_PNG) { diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 484d5af194d..d5485765844 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -302,6 +302,13 @@ bool isect_line_line_strict_v3(const float v1[3], float vi[3], float *r_lambda); +bool isect_ray_ray_v3(const float ray_origin_a[3], + const float ray_direction_a[3], + const float ray_origin_b[3], + const float ray_direction_b[3], + float *r_lambda_a, + float *r_lambda_b); + bool isect_ray_plane_v3(const float ray_origin[3], const float ray_direction[3], const float plane[4], diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c index 836b11baa85..88b7f83385c 100644 --- a/source/blender/blenlib/intern/BLI_heap.c +++ b/source/blender/blenlib/intern/BLI_heap.c @@ -366,7 +366,7 @@ void BLI_heap_remove(Heap *heap, HeapNode *node) /** * Can be used to avoid #BLI_heap_remove, #BLI_heap_insert calls, * balancing the tree still has a performance cost, - * but is often much less than remove/insert, difference is most noticable with large heaps. + * but is often much less than remove/insert, difference is most noticeable with large heaps. */ void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value) { diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 5dbd2a52d07..8b715ebf87b 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -2798,6 +2798,46 @@ bool isect_line_line_strict_v3(const float v1[3], } } +/** + * Check if two rays are not parallel and returns a factor that indicates + * the distance from \a ray_origin_b to the closest point on ray-a to ray-b. + * + * \note Neither directions need to be normalized. + */ +bool isect_ray_ray_v3(const float ray_origin_a[3], + const float ray_direction_a[3], + const float ray_origin_b[3], + const float ray_direction_b[3], + float *r_lambda_a, + float *r_lambda_b) +{ + BLI_assert(r_lambda_a || r_lambda_b); + float n[3]; + cross_v3_v3v3(n, ray_direction_b, ray_direction_a); + const float nlen = len_squared_v3(n); + + if (UNLIKELY(nlen == 0.0f)) { + /* The lines are parallel. */ + return false; + } + + float t[3], c[3], cray[3]; + sub_v3_v3v3(t, ray_origin_b, ray_origin_a); + sub_v3_v3v3(c, n, t); + + if (r_lambda_a != NULL) { + cross_v3_v3v3(cray, c, ray_direction_a); + *r_lambda_a = dot_v3v3(cray, n) / nlen; + } + + if (r_lambda_b != NULL) { + cross_v3_v3v3(cray, c, ray_direction_b); + *r_lambda_b = dot_v3v3(cray, n) / nlen; + } + + return true; +} + bool isect_aabb_aabb_v3(const float min1[3], const float max1[3], const float min2[3], diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 61b773f6016..111b530a527 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -1037,7 +1037,7 @@ bool BLI_path_abs(char *path, const char *basepath) * in this case, there is no use in trying C:/ since it * will never exist on a unix os. * - * Add a / prefix and lowercase the driveletter, remove the : + * Add a '/' prefix and lowercase the drive-letter, remove the ':'. * C:\foo.JPG -> /c/foo.JPG */ if (isalpha(tmp[0]) && tmp[1] == ':' && (tmp[2] == '\\' || tmp[2] == '/')) { @@ -1552,7 +1552,7 @@ bool BLI_path_extension_glob_validate(char *ext_fnmatch) only_wildcards = true; } /* Only one group in the pattern, so even if its only made of wildcard(s), - * it is assumed vaid. */ + * it is assumed valid. */ return false; } diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index b34a9c0a44e..39af73ac175 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -15,12 +15,12 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Reorganised mar-01 nzc - * Some really low-level file thingies. */ /** \file * \ingroup bli + * + * Some really low-level file operations. */ #include <sys/types.h> @@ -303,12 +303,24 @@ void *BLI_file_read_text_as_mem(const char *filepath, size_t pad_bytes, size_t * void *mem = NULL; if (fp) { - fseek(fp, 0L, SEEK_END); + struct stat st; + if (fstat(fileno(fp), &st) == -1) { + goto finally; + } + if (S_ISDIR(st.st_mode)) { + goto finally; + } + if (fseek(fp, 0L, SEEK_END) == -1) { + goto finally; + } + /* Don't use the 'st_size' because it may be the symlink. */ const long int filelen = ftell(fp); if (filelen == -1) { goto finally; } - fseek(fp, 0L, SEEK_SET); + if (fseek(fp, 0L, SEEK_SET) == -1) { + goto finally; + } mem = MEM_mallocN(filelen + pad_bytes, __func__); if (mem == NULL) { @@ -344,12 +356,24 @@ void *BLI_file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t void *mem = NULL; if (fp) { - fseek(fp, 0L, SEEK_END); + struct stat st; + if (fstat(fileno(fp), &st) == -1) { + goto finally; + } + if (S_ISDIR(st.st_mode)) { + goto finally; + } + if (fseek(fp, 0L, SEEK_END) == -1) { + goto finally; + } + /* Don't use the 'st_size' because it may be the symlink. */ const long int filelen = ftell(fp); if (filelen == -1) { goto finally; } - fseek(fp, 0L, SEEK_SET); + if (fseek(fp, 0L, SEEK_SET) == -1) { + goto finally; + } mem = MEM_mallocN(filelen + pad_bytes, __func__); if (mem == NULL) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 3c57de0a9d8..44039ad59ee 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1712,22 +1712,26 @@ BlendThumbnail *BLO_thumbnail_from_file(const char *filepath) /** \name Old/New Pointer Map * \{ */ -static void *newdataadr(FileData *fd, const void *adr) /* only direct databocks */ +/* only direct databocks */ +static void *newdataadr(FileData *fd, const void *adr) { return oldnewmap_lookup_and_inc(fd->datamap, adr, true); } -static void *newdataadr_no_us(FileData *fd, const void *adr) /* only direct databocks */ +/* only direct databocks */ +static void *newdataadr_no_us(FileData *fd, const void *adr) { return oldnewmap_lookup_and_inc(fd->datamap, adr, false); } -static void *newglobadr(FileData *fd, const void *adr) /* direct data-locks with global linking */ +/* direct datablocks with global linking */ +static void *newglobadr(FileData *fd, const void *adr) { return oldnewmap_lookup_and_inc(fd->globmap, adr, true); } -static void *newimaadr(FileData *fd, const void *adr) /* used to restore image data after undo */ +/* used to restore image data after undo */ +static void *newimaadr(FileData *fd, const void *adr) { if (fd->imamap && adr) { return oldnewmap_lookup_and_inc(fd->imamap, adr, true); @@ -1735,7 +1739,8 @@ static void *newimaadr(FileData *fd, const void *adr) /* used to restore image d return NULL; } -static void *newsceadr(FileData *fd, const void *adr) /* used to restore scene data after undo */ +/* used to restore scene data after undo */ +static void *newsceadr(FileData *fd, const void *adr) { if (fd->scenemap && adr) { return oldnewmap_lookup_and_inc(fd->scenemap, adr, true); @@ -1743,8 +1748,8 @@ static void *newsceadr(FileData *fd, const void *adr) /* used to restore scene d return NULL; } -static void *newmclipadr(FileData *fd, - const void *adr) /* used to restore movie clip data after undo */ +/* used to restore movie clip data after undo */ +static void *newmclipadr(FileData *fd, const void *adr) { if (fd->movieclipmap && adr) { return oldnewmap_lookup_and_inc(fd->movieclipmap, adr, true); @@ -1752,7 +1757,8 @@ static void *newmclipadr(FileData *fd, return NULL; } -static void *newsoundadr(FileData *fd, const void *adr) /* used to restore sound data after undo */ +/* used to restore sound data after undo */ +static void *newsoundadr(FileData *fd, const void *adr) { if (fd->soundmap && adr) { return oldnewmap_lookup_and_inc(fd->soundmap, adr, true); @@ -1760,8 +1766,8 @@ static void *newsoundadr(FileData *fd, const void *adr) /* used to restore sound return NULL; } -static void *newpackedadr(FileData *fd, - const void *adr) /* used to restore packed data after undo */ +/* used to restore packed data after undo */ +static void *newpackedadr(FileData *fd, const void *adr) { if (fd->packedmap && adr) { return oldnewmap_lookup_and_inc(fd->packedmap, adr, true); @@ -1770,19 +1776,20 @@ static void *newpackedadr(FileData *fd, return oldnewmap_lookup_and_inc(fd->datamap, adr, true); } -static void *newlibadr(FileData *fd, const void *lib, const void *adr) /* only lib data */ +/* only lib data */ +static void *newlibadr(FileData *fd, const void *lib, const void *adr) { return oldnewmap_liblookup(fd->libmap, adr, lib); } -void *blo_do_versions_newlibadr(FileData *fd, const void *lib, const void *adr) /* only lib data */ +/* only lib data */ +void *blo_do_versions_newlibadr(FileData *fd, const void *lib, const void *adr) { return newlibadr(fd, lib, adr); } -static void *newlibadr_us(FileData *fd, - const void *lib, - const void *adr) /* increases user number */ +/* increases user number */ +static void *newlibadr_us(FileData *fd, const void *lib, const void *adr) { ID *id = newlibadr(fd, lib, adr); @@ -1791,16 +1798,14 @@ static void *newlibadr_us(FileData *fd, return id; } -void *blo_do_versions_newlibadr_us(FileData *fd, - const void *lib, - const void *adr) /* increases user number */ +/* increases user number */ +void *blo_do_versions_newlibadr_us(FileData *fd, const void *lib, const void *adr) { return newlibadr_us(fd, lib, adr); } -static void *newlibadr_real_us(FileData *fd, - const void *lib, - const void *adr) /* ensures real user */ +/* ensures real user */ +static void *newlibadr_real_us(FileData *fd, const void *lib, const void *adr) { ID *id = newlibadr(fd, lib, adr); @@ -4507,8 +4512,9 @@ static void direct_link_pointcache_cb(FileData *fd, void *data) /* the cache saves non-struct data without DNA */ if (pm->data[i] && ptcache_data_struct[i][0] == '\0' && (fd->flags & FD_FLAGS_SWITCH_ENDIAN)) { - int tot = (BKE_ptcache_data_size(i) * pm->totpoint) / - sizeof(int); /* data_size returns bytes */ + /* data_size returns bytes. */ + int tot = (BKE_ptcache_data_size(i) * pm->totpoint) / sizeof(int); + int *poin = pm->data[i]; BLI_endian_switch_int32_array(poin, tot); @@ -4776,8 +4782,10 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles) if (psys->particles && psys->particles->boid) { pa = psys->particles; pa->boid = newdataadr(fd, pa->boid); - pa->boid->ground = - NULL; /* This is purely runtime data, but still can be an issue if left dangling. */ + + /* This is purely runtime data, but still can be an issue if left dangling. */ + pa->boid->ground = NULL; + for (a = 1, pa++; a < psys->totpart; a++, pa++) { pa->boid = (pa - 1)->boid + 1; pa->boid->ground = NULL; @@ -7169,8 +7177,10 @@ static void direct_link_area(FileData *fd, ScrArea *area) BLI_listbase_clear(&area->handlers); area->type = NULL; /* spacetype callbacks */ - area->butspacetype = - SPACE_EMPTY; /* Should always be unset so that rna_Area_type_get works correctly */ + + /* Should always be unset so that rna_Area_type_get works correctly. */ + area->butspacetype = SPACE_EMPTY; + area->region_active_win = -1; area->flag &= ~AREA_FLAG_ACTIVE_TOOL_UPDATE; @@ -7180,8 +7190,9 @@ static void direct_link_area(FileData *fd, ScrArea *area) /* if we do not have the spacetype registered we cannot * free it, so don't allocate any new memory for such spacetypes. */ if (!BKE_spacetype_exists(area->spacetype)) { - area->butspacetype = - area->spacetype; /* Hint for versioning code to replace deprecated space types. */ + /* Hint for versioning code to replace deprecated space types. */ + area->butspacetype = area->spacetype; + area->spacetype = SPACE_EMPTY; } @@ -9498,7 +9509,7 @@ static void lib_link_all(FileData *fd, Main *main) * re-read all library data-blocks. * Unfortunately, that means that we do not clear Collections' parents lists, which then get * improperly extended in some cases by lib_link_scene() and lib_link_collection() calls above - * (when ome local collection is parent of linked ones). + * (when one local collection is parent of linked ones). * I do not really see a way to address that issue, besides brute force call below which * invalidates and re-creates all parenting relationships between collections. Yet another * example of why it is such a bad idea to keep that kind of double-linked relationships info diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 4b55364f0b1..cb2b64957f0 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -1180,12 +1180,11 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) /* MTexPoly now removed. */ if (DNA_struct_find(fd->filesdna, "MTexPoly")) { - const int cd_mtexpoly = 15; /* CD_MTEXPOLY, deprecated */ for (Mesh *me = bmain->meshes.first; me; me = me->id.next) { /* If we have UV's, so this file will have MTexPoly layers too! */ if (me->mloopuv != NULL) { CustomData_update_typemap(&me->pdata); - CustomData_free_layers(&me->pdata, cd_mtexpoly, me->totpoly); + CustomData_free_layers(&me->pdata, CD_MTEXPOLY, me->totpoly); BKE_mesh_update_customdata_pointers(me, false); } } @@ -3496,19 +3495,45 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - { - /* Versioning code until next subversion bump goes here. */ - + if (!MAIN_VERSION_ATLEAST(bmain, 280, 75)) { for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { if (scene->master_collection != NULL) { scene->master_collection->flag &= ~(COLLECTION_RESTRICT_VIEWPORT | COLLECTION_RESTRICT_SELECT | COLLECTION_RESTRICT_RENDER); } + + UnitSettings *unit = &scene->unit; + if (unit->system == USER_UNIT_NONE) { + unit->length_unit = (char)USER_UNIT_ADAPTIVE; + unit->mass_unit = (char)USER_UNIT_ADAPTIVE; + } + + RenderData *render_data = &scene->r; + switch (render_data->ffcodecdata.ffmpeg_preset) { + case FFM_PRESET_ULTRAFAST: + case FFM_PRESET_SUPERFAST: + render_data->ffcodecdata.ffmpeg_preset = FFM_PRESET_REALTIME; + break; + case FFM_PRESET_VERYFAST: + case FFM_PRESET_FASTER: + case FFM_PRESET_FAST: + case FFM_PRESET_MEDIUM: + render_data->ffcodecdata.ffmpeg_preset = FFM_PRESET_GOOD; + break; + case FFM_PRESET_SLOW: + case FFM_PRESET_SLOWER: + case FFM_PRESET_VERYSLOW: + render_data->ffcodecdata.ffmpeg_preset = FFM_PRESET_BEST; + } } LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) { arm->flag &= ~(ARM_FLAG_UNUSED_6); } } + + { + /* Versioning code until next subversion bump goes here. */ + } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 115387a697b..5954ba9cf8e 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -553,10 +553,8 @@ static void writestruct_id( writestruct_at_address_id(wd, filecode, structname, nr, adr, adr); } -static void writedata(WriteData *wd, - int filecode, - int len, - const void *adr) /* do not use for structs */ +/* do not use for structs */ +static void writedata(WriteData *wd, int filecode, int len, const void *adr) { BHead bh; diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c index 7a100167b48..2000689b496 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_conv.c +++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c @@ -984,7 +984,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh /** * A version of #BM_mesh_bm_to_me intended for getting the mesh * to pass to the modifier stack for evaluation, - * instad of mode switching (where we make sure all data is kept + * instead of mode switching (where we make sure all data is kept * and do expensive lookups to maintain shape keys). * * Key differences: diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c index 12ec4617f0a..323bb5a7748 100644 --- a/source/blender/bmesh/operators/bmo_inset.c +++ b/source/blender/bmesh/operators/bmo_inset.c @@ -186,7 +186,7 @@ static void bm_loop_customdata_merge(BMesh *bm, BM_ELEM_CD_GET_VOID_P(l_a_outer, offset), BM_ELEM_CD_GET_VOID_P(l_b_outer, offset)) == true) - /* epsilon for comparing UV's is too big, gives noticable problems */ + /* Epsilon for comparing UV's is too big, gives noticeable problems. */ # if 0 && /* check if the data ends up diverged */ diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index c8338081443..90df3cd225e 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -3201,7 +3201,7 @@ static BoundVert *pipe_test(BevVert *bv) /* check face planes: all should have normals perpendicular to epipe */ for (e = &bv->edges[0]; e != &bv->edges[bv->edgecount]; e++) { if (e->fnext) { - if (dot_v3v3(dir1, e->fnext->no) > BEVEL_EPSILON_BIG) { + if (fabsf(dot_v3v3(dir1, e->fnext->no)) > BEVEL_EPSILON_BIG) { return NULL; } } diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c index 66845b6f33c..9a3cade85db 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.c +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -896,7 +896,7 @@ static int isect_bvhtree_point_v3(BVHTree *tree, const float **looptris, const f float dir[3] = {1.0f, 0.0f, 0.0f}; /* Need to initialize hit even tho it's not used. - * This is to make it so kdotree believes we didn't intersect anything and + * This is to make it so kd-tree believes we didn't intersect anything and * keeps calling the intersect callback. */ hit.index = -1; diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp index e79a97c890f..15c34226cf6 100644 --- a/source/blender/collada/ArmatureImporter.cpp +++ b/source/blender/collada/ArmatureImporter.cpp @@ -791,8 +791,8 @@ void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &object std::vector<Object *> ob_arms; std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it; - leaf_bone_length = - FLT_MAX; /*TODO: Make this work for more than one armature in the import file*/ + /* TODO: Make this work for more than one armature in the import file. */ + leaf_bone_length = FLT_MAX; for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) { diff --git a/source/blender/collada/BCAnimationSampler.cpp b/source/blender/collada/BCAnimationSampler.cpp index 2e89ea0af4d..49d87f92fda 100644 --- a/source/blender/collada/BCAnimationSampler.cpp +++ b/source/blender/collada/BCAnimationSampler.cpp @@ -334,15 +334,16 @@ bool BCAnimationSampler::get_object_samples(BCMatrixSampleMap &samples, Object * #if 0 /** - * Add sampled values to FCurve - * If no FCurve exists, create a temporary FCurve; - * Note: The temporary FCurve will later be removed when the - * BCAnimationSampler is removed (by its destructor) + * Add sampled values to #FCurve + * If no #FCurve exists, create a temporary #FCurve; + * \note The temporary #FCurve will later be removed when the + * #BCAnimationSampler is removed (by its destructor). * - * curve: The curve to whioch the data is added - * matrices: The set of matrix values from where the data is taken - * animation_type BC_ANIMATION_EXPORT_SAMPLES: Use all matrix data - * animation_type BC_ANIMATION_EXPORT_KEYS: Only take data from matrices for keyframes + * \param curve: The curve to which the data is added. + * \param matrices: The set of matrix values from where the data is taken. + * \param animation_type: + * - #BC_ANIMATION_EXPORT_SAMPLES: Use all matrix data. + * - #BC_ANIMATION_EXPORT_KEYS: Only take data from matrices for keyframes. */ void BCAnimationSampler::add_value_set(BCAnimationCurve &curve, BCFrameSampleMap &samples, diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 06f6682f401..eabd9469582 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -804,7 +804,10 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia matNode.set_alpha(ef->getOpaqueMode(), ef->getTransparent(), ef->getTransparency()); /* following mapping still needs to be verified */ +#if 0 + // needs rework to be done for 2.81 matNode.set_shininess(ef->getShininess()); +#endif matNode.set_reflectivity(ef->getReflectivity()); /* not supported by principled BSDF */ diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp index 394c79bb988..80f84738f6e 100644 --- a/source/blender/collada/EffectExporter.cpp +++ b/source/blender/collada/EffectExporter.cpp @@ -102,7 +102,12 @@ void EffectsExporter::set_shader_type(COLLADASW::EffectProfile &ep, Material *ma void EffectsExporter::set_transparency(COLLADASW::EffectProfile &ep, Material *ma) { double alpha = bc_get_alpha(ma); - ep.setTransparency(alpha, false, "alpha"); + if (alpha < 1) { + // workaround use <transparent> to avoid wrong handling of <transparency> by other tools + COLLADASW::ColorOrTexture cot = bc_get_cot(0, 0, 0, alpha); + ep.setTransparent(cot, false, "alpha"); + ep.setOpaque(COLLADASW::EffectProfile::A_ONE); + } } void EffectsExporter::set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma) @@ -134,7 +139,9 @@ void EffectsExporter::set_reflective(COLLADASW::EffectProfile &ep, Material *ma) void EffectsExporter::set_reflectivity(COLLADASW::EffectProfile &ep, Material *ma) { double reflectivity = bc_get_reflectivity(ma); - ep.setReflectivity(reflectivity, false, "specular"); + if (reflectivity > 0.0) { + ep.setReflectivity(reflectivity, false, "specular"); + } } void EffectsExporter::set_emission(COLLADASW::EffectProfile &ep, Material *ma) @@ -208,21 +215,20 @@ void EffectsExporter::operator()(Material *ma, Object *ob) COLLADASW::EffectProfile ep(mSW); ep.setProfileType(COLLADASW::EffectProfile::COMMON); ep.openProfile(); - set_shader_type(ep, ma); + set_shader_type(ep, ma); // creates a Lambert Shader for now COLLADASW::ColorOrTexture cot; set_diffuse_color(ep, ma); set_emission(ep, ma); set_ior(ep, ma); - set_shininess(ep, ma); set_reflectivity(ep, ma); set_transparency(ep, ma); - /* TODO: from where to get ambient, specular and reflective? */ + /* TODO: */ + // set_shininess(ep, ma); shininess not supported for lambert // set_ambient(ep, ma); // set_specular(ep, ma); - // set_reflective(ep, ma); get_images(ma, material_image_map); std::string active_uv(getActiveUVLayerName(ob)); diff --git a/source/blender/collada/Materials.cpp b/source/blender/collada/Materials.cpp index aa35b71b9db..e1d5b2e9d5c 100644 --- a/source/blender/collada/Materials.cpp +++ b/source/blender/collada/Materials.cpp @@ -131,18 +131,24 @@ void MaterialNode::add_link(bNode *from_node, int from_index, bNode *to_node, in void MaterialNode::set_reflectivity(COLLADAFW::FloatOrParam &val) { float reflectivity = val.getFloatValue(); - bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Metallic"); - ((bNodeSocketValueFloat *)socket->default_value)->value = reflectivity; - - material->metallic = reflectivity; + if (reflectivity >= 0) { + bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Metallic"); + ((bNodeSocketValueFloat *)socket->default_value)->value = reflectivity; + material->metallic = reflectivity; + } } +#if 0 +// needs rework to be done for 2.81 void MaterialNode::set_shininess(COLLADAFW::FloatOrParam &val) { float roughness = val.getFloatValue(); - bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Roughness"); - ((bNodeSocketValueFloat *)socket->default_value)->value = roughness; + if (roughness >= 0) { + bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Roughness"); + ((bNodeSocketValueFloat *)socket->default_value)->value = roughness; + } } +#endif void MaterialNode::set_ior(COLLADAFW::FloatOrParam &val) { @@ -162,13 +168,37 @@ void MaterialNode::set_alpha(COLLADAFW::EffectCommon::OpaqueMode mode, COLLADAFW::ColorOrTexture &cot, COLLADAFW::FloatOrParam &val) { + /* Handling the alpha value according to the Collada 1.4 reference guide + * see page 7-5 Determining Transparency (Opacity) + */ + if (effect == nullptr) { return; } if (cot.isColor() || !cot.isValid()) { - COLLADAFW::Color col = (cot.isValid()) ? cot.getColor() : COLLADAFW::Color(1, 1, 1, 1); - float alpha = val.getFloatValue() * col.getAlpha(); // Assuming A_ONE opaque mode + // transparent_cot is either a color or not defined + + float transparent_alpha; + if (cot.isValid()) { + COLLADAFW::Color col = cot.getColor(); + transparent_alpha = col.getAlpha(); + } + else { + // no transparent color defined + transparent_alpha = 1; + } + + float transparency_alpha = val.getFloatValue(); + if (transparency_alpha < 0) { + // transparency is not defined + transparency_alpha = 1; // set to opaque + } + + float alpha = transparent_alpha * transparency_alpha; + if (mode == COLLADASW::EffectProfile::RGB_ZERO) { + alpha = 1 - alpha; + } bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Alpha"); ((bNodeSocketValueFloat *)socket->default_value)->value = alpha; @@ -176,7 +206,6 @@ void MaterialNode::set_alpha(COLLADAFW::EffectCommon::OpaqueMode mode, else if (cot.isTexture()) { int locy = -300 * (node_map.size() - 2); add_texture_node(cot, -300, locy, "Alpha"); - // TODO: Connect node } } diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h index ee2d4b7be54..18e06410adf 100644 --- a/source/blender/depsgraph/DEG_depsgraph_build.h +++ b/source/blender/depsgraph/DEG_depsgraph_build.h @@ -110,6 +110,9 @@ typedef enum eDepsSceneComponentType { } eDepsSceneComponentType; typedef enum eDepsObjectComponentType { + /* Used in query API, to denote which component caller is interested in. */ + DEG_OB_COMP_ANY, + /* Parameters Component - Default when nothing else fits * (i.e. just SDNA property setting). */ DEG_OB_COMP_PARAMETERS, diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h index 4148529d3f8..e3381e79e9c 100644 --- a/source/blender/depsgraph/DEG_depsgraph_query.h +++ b/source/blender/depsgraph/DEG_depsgraph_query.h @@ -219,6 +219,9 @@ void DEG_iterator_ids_end(struct BLI_Iterator *iter); /* ************************ DEG traversal ********************* */ typedef void (*DEGForeachIDCallback)(ID *id, void *user_data); +typedef void (*DEGForeachIDComponentCallback)(ID *id, + eDepsObjectComponentType component, + void *user_data); /* NOTE: Modifies runtime flags in depsgraph nodes, so can not be used in * parallel. Keep an eye on that! @@ -232,6 +235,14 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph, DEGForeachIDCallback callback, void *user_data); +/* Starts traversal from given component of the given ID, invokes callback for every other + * component which is directly on indirectly dependent on the source one. */ +void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph, + const ID *id, + eDepsObjectComponentType source_component_type, + DEGForeachIDComponentCallback callback, + void *user_data); + void DEG_foreach_ID(const Depsgraph *depsgraph, DEGForeachIDCallback callback, void *user_data); #ifdef __cplusplus diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index e65dd3b4560..fa6d7bc6028 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -595,7 +595,7 @@ void DepsgraphNodeBuilder::build_object(int base_index, } /* Object data. */ build_object_data(object, is_visible); - /* Paramaters, used by both drivers/animation and also to inform dependency + /* Parameters, used by both drivers/animation and also to inform dependency * from object's data. */ build_parameters(&object->id); /* Build animation data, @@ -697,6 +697,12 @@ void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visi break; } } + /* Materials. */ + Material ***materials_ptr = give_matarar(object); + if (materials_ptr != NULL) { + short *num_materials_ptr = give_totcolp(object); + build_materials(*materials_ptr, *num_materials_ptr); + } } void DepsgraphNodeBuilder::build_object_data_camera(Object *object) @@ -753,7 +759,7 @@ void DepsgraphNodeBuilder::build_object_transform(Object *object) NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL, function_bind(BKE_object_eval_uber_transform, _1, ob_cow)); - /* Operation to take of rigid body simulation. soft bodies and other firends + /* Operation to take of rigid body simulation. soft bodies and other friends * in the context of point cache invalidation. */ add_operation_node(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_SIMULATION_INIT); /* Object transform is done. */ @@ -1195,18 +1201,16 @@ void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_ob function_bind(BKE_object_eval_uber_data, _1, scene_cow, object_cow)); op_node->set_as_exit(); /* Materials. */ - if (object->totcol != 0) { - for (int a = 1; a <= object->totcol; a++) { - Material *ma = give_current_material(object, a); - if (ma != NULL) { - build_material(ma); - } - } - } + build_materials(object->mat, object->totcol); /* Point caches. */ build_object_pointcache(object); /* Geometry. */ build_object_data_geometry_datablock((ID *)object->data, is_object_visible); + /* Batch cache. */ + add_operation_node(&object->id, + NodeType::BATCH_CACHE, + OperationCode::GEOMETRY_SELECT_UPDATE, + function_bind(BKE_object_select_update, _1, object_cow)); } void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool is_object_visible) @@ -1429,6 +1433,16 @@ void DepsgraphNodeBuilder::build_material(Material *material) build_nodetree(material->nodetree); } +void DepsgraphNodeBuilder::build_materials(Material **materials, int num_materials) +{ + for (int i = 0; i < num_materials; ++i) { + if (materials[i] == NULL) { + continue; + } + build_material(materials[i]); + } +} + /* Recursively build graph for texture */ void DepsgraphNodeBuilder::build_texture(Tex *texture) { @@ -1514,6 +1528,19 @@ void DepsgraphNodeBuilder::build_mask(Mask *mask) NodeType::PARAMETERS, OperationCode::MASK_EVAL, function_bind(BKE_mask_eval_update, _1, mask_cow)); + /* Build parents. */ + LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) { + LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) { + for (int i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &spline->points[i]; + MaskParent *parent = &point->parent; + if (parent == NULL || parent->id == NULL) { + continue; + } + build_id(parent->id); + } + } + } } void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 9983b346355..de9f0e4d6cd 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -202,6 +202,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { void build_light(Light *lamp); void build_nodetree(bNodeTree *ntree); void build_material(Material *ma); + void build_materials(Material **materials, int num_materials); void build_texture(Tex *tex); void build_image(Image *image); void build_world(World *world); 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 3486d2c92ae..777512acf89 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc @@ -56,8 +56,8 @@ void DepsgraphNodeBuilder::build_scene_parameters(Scene *scene) if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_PARAMETERS)) { return; } + build_parameters(&scene->id); add_operation_node(&scene->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL); - add_operation_node(&scene->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); /* NOTE: This is a bit overkill and can potentially pull a bit too much into the graph, but: * * - We definitely need an ID node for the scene's compositor, otherwise re-mapping will no diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index c7f6116e81d..86cbb330170 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -200,6 +200,11 @@ static OperationCode bone_target_opcode(ID *target, return OperationCode::BONE_DONE; } +static bool object_have_geometry_component(const Object *object) +{ + return ELEM(object->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_MBALL, OB_LATTICE, OB_GPENCIL); +} + /* **** General purpose functions **** */ DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain, @@ -374,6 +379,14 @@ void DepsgraphRelationBuilder::add_particle_forcefield_relations(const Operation { ListBase *relations = build_effector_relations(graph_, eff->group); + /* Make sure physics effects like wind are properly re-evaluating the modifier stack. */ + if (!BLI_listbase_is_empty(relations)) { + TimeSourceKey time_src_key; + ComponentKey geometry_key(&object->id, NodeType::GEOMETRY); + add_relation( + time_src_key, geometry_key, "Effector Time -> Particle", RELATION_CHECK_BEFORE_ADD); + } + LISTBASE_FOREACH (EffectorRelation *, relation, relations) { if (relation->ob != object) { /* Relation to forcefield object, optionally including geometry. */ @@ -746,6 +759,12 @@ void DepsgraphRelationBuilder::build_object_data(Object *object) add_relation(key_key, geometry_key, "Shapekeys"); build_nested_shapekey(&object->id, key); } + /* Materials. */ + Material ***materials_ptr = give_matarar(object); + if (materials_ptr != NULL) { + short *num_materials_ptr = give_totcolp(object); + build_materials(*materials_ptr, *num_materials_ptr); + } } void DepsgraphRelationBuilder::build_object_data_camera(Object *object) @@ -1929,14 +1948,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) } } /* Materials. */ - if (object->totcol) { - for (int a = 1; a <= object->totcol; a++) { - Material *ma = give_current_material(object, a); - if (ma != NULL) { - build_material(ma); - } - } - } + build_materials(object->mat, object->totcol); /* Geometry collision. */ if (ELEM(object->type, OB_MESH, OB_CURVE, OB_LATTICE)) { // add geometry collider relations @@ -1988,10 +2000,18 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) } } /* Syncronization back to original object. */ - ComponentKey final_geometry_jey(&object->id, NodeType::GEOMETRY); + ComponentKey final_geometry_key(&object->id, NodeType::GEOMETRY); OperationKey synchronize_key( &object->id, NodeType::SYNCHRONIZATION, OperationCode::SYNCHRONIZE_TO_ORIGINAL); - add_relation(final_geometry_jey, synchronize_key, "Synchronize to Original"); + add_relation(final_geometry_key, synchronize_key, "Synchronize to Original"); + /* Batch cache. */ + OperationKey object_data_select_key( + obdata, NodeType::BATCH_CACHE, OperationCode::GEOMETRY_SELECT_UPDATE); + OperationKey object_select_key( + &object->id, NodeType::BATCH_CACHE, OperationCode::GEOMETRY_SELECT_UPDATE); + add_relation(object_data_select_key, object_select_key, "Data Selection -> Object Selection"); + add_relation( + geom_key, object_select_key, "Object Geometry -> Select Update", RELATION_FLAG_NO_FLUSH); } void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) @@ -2149,9 +2169,11 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) else if (id_type == ID_OB) { build_object(NULL, (Object *)id); ComponentKey object_transform_key(id, NodeType::TRANSFORM); - ComponentKey object_geometry_key(id, NodeType::GEOMETRY); add_relation(object_transform_key, shading_key, "Object Transform -> Node"); - add_relation(object_geometry_key, shading_key, "Object Geometry -> Node"); + if (object_have_geometry_component(reinterpret_cast<Object *>(id))) { + ComponentKey object_geometry_key(id, NodeType::GEOMETRY); + add_relation(object_geometry_key, shading_key, "Object Geometry -> Node"); + } } else if (id_type == ID_SCE) { Scene *node_scene = (Scene *)id; @@ -2221,6 +2243,16 @@ void DepsgraphRelationBuilder::build_material(Material *material) } } +void DepsgraphRelationBuilder::build_materials(Material **materials, int num_materials) +{ + for (int i = 0; i < num_materials; ++i) { + if (materials[i] == NULL) { + continue; + } + build_material(materials[i]); + } +} + /* Recursively build graph for texture */ void DepsgraphRelationBuilder::build_texture(Tex *texture) { @@ -2305,6 +2337,24 @@ void DepsgraphRelationBuilder::build_mask(Mask *mask) /* Final mask evaluation. */ OperationKey mask_eval_key(mask_id, NodeType::PARAMETERS, OperationCode::MASK_EVAL); add_relation(mask_animation_key, mask_eval_key, "Mask Animation -> Mask Eval"); + /* Build parents. */ + LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) { + LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) { + for (int i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &spline->points[i]; + MaskParent *parent = &point->parent; + if (parent == NULL || parent->id == NULL) { + continue; + } + build_id(parent->id); + if (parent->id_type == ID_MC) { + OperationKey movieclip_eval_key( + parent->id, NodeType::PARAMETERS, OperationCode::MOVIECLIP_EVAL); + add_relation(movieclip_eval_key, mask_eval_key, "Movie Clip -> Mask Eval"); + } + } + } + } } void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index cfed5a73a49..0e15818622f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -186,7 +186,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder { const char *description, int flags = 0); - /* Adds relation from proper transformation opertation to the modifier. + /* Adds relation from proper transformation operation to the modifier. * Takes care of checking for possible physics solvers modifying position * of this object. */ void add_modifier_to_transform_relation(const DepsNodeHandle *handle, const char *description); @@ -264,6 +264,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder { void build_light(Light *lamp); void build_nodetree(bNodeTree *ntree); void build_material(Material *ma); + void build_materials(Material **materials, int num_materials); void build_texture(Tex *tex); void build_image(Image *image); void build_gpencil(bGPdata *gpd); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc index daaf90011c5..4e0c2cbba0c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc @@ -52,8 +52,9 @@ void DepsgraphRelationBuilder::build_scene_parameters(Scene *scene) if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_PARAMETERS)) { return; } + build_parameters(&scene->id); OperationKey parameters_eval_key( - &scene->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); + &scene->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT); OperationKey scene_eval_key(&scene->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL); add_relation(parameters_eval_key, scene_eval_key, "Parameters -> Scene Eval"); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index a8d357cd5bd..5bb3ebf40c4 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -314,6 +314,10 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, node_identifier.type = NodeType::OBJECT_FROM_LAYER; return node_identifier; } + else if (STREQ(prop_identifier, "dimensions")) { + node_identifier.type = NodeType::GEOMETRY; + return node_identifier; + } } } else if (ptr->type == &RNA_ShapeKey) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.h b/source/blender/depsgraph/intern/builder/deg_builder_rna.h index 26d7963e0a8..8a79d9abef9 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.h @@ -85,7 +85,7 @@ class RNANodeQuery { /* Indexed by an ID, returns RNANodeQueryIDData associated with that ID. */ GHash *id_data_map_; - /* Construct identifier of the node which correspods given configuration + /* Construct identifier of the node which corresponds given configuration * of RNA property. */ RNANodeIdentifier construct_node_identifier(const PointerRNA *ptr, const PropertyRNA *prop, diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index 279c5e7839a..dd2d7f70ed5 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -77,31 +77,6 @@ static DEG::NodeType deg_build_scene_component_type(eDepsSceneComponentType comp return DEG::NodeType::UNDEFINED; } -static DEG::NodeType deg_build_object_component_type(eDepsObjectComponentType component) -{ - switch (component) { - case DEG_OB_COMP_PARAMETERS: - return DEG::NodeType::PARAMETERS; - case DEG_OB_COMP_PROXY: - return DEG::NodeType::PROXY; - case DEG_OB_COMP_ANIMATION: - return DEG::NodeType::ANIMATION; - case DEG_OB_COMP_TRANSFORM: - return DEG::NodeType::TRANSFORM; - case DEG_OB_COMP_GEOMETRY: - return DEG::NodeType::GEOMETRY; - case DEG_OB_COMP_EVAL_POSE: - return DEG::NodeType::EVAL_POSE; - case DEG_OB_COMP_BONE: - return DEG::NodeType::BONE; - case DEG_OB_COMP_SHADING: - return DEG::NodeType::SHADING; - case DEG_OB_COMP_CACHE: - return DEG::NodeType::CACHE; - } - return DEG::NodeType::UNDEFINED; -} - static DEG::DepsNodeHandle *get_node_handle(DepsNodeHandle *node_handle) { return reinterpret_cast<DEG::DepsNodeHandle *>(node_handle); @@ -123,7 +98,7 @@ void DEG_add_object_relation(DepsNodeHandle *node_handle, eDepsObjectComponentType component, const char *description) { - DEG::NodeType type = deg_build_object_component_type(component); + DEG::NodeType type = DEG::nodeTypeFromObjectComponent(component); DEG::ComponentKey comp_key(&object->id, type); DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); deg_node_handle->builder->add_node_handle_relation(comp_key, deg_node_handle, description); @@ -134,7 +109,7 @@ void DEG_add_object_cache_relation(DepsNodeHandle *node_handle, eDepsObjectComponentType component, const char *description) { - DEG::NodeType type = deg_build_object_component_type(component); + DEG::NodeType type = DEG::nodeTypeFromObjectComponent(component); DEG::ComponentKey comp_key(&cache_file->id, type); DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); deg_node_handle->builder->add_node_handle_relation(comp_key, deg_node_handle, description); @@ -146,7 +121,7 @@ void DEG_add_bone_relation(DepsNodeHandle *node_handle, eDepsObjectComponentType component, const char *description) { - DEG::NodeType type = deg_build_object_component_type(component); + DEG::NodeType type = DEG::nodeTypeFromObjectComponent(component); DEG::ComponentKey comp_key(&object->id, type, bone_name); DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); deg_node_handle->builder->add_node_handle_relation(comp_key, deg_node_handle, description); @@ -157,7 +132,7 @@ void DEG_add_object_pointcache_relation(struct DepsNodeHandle *node_handle, eDepsObjectComponentType component, const char *description) { - DEG::NodeType type = deg_build_object_component_type(component); + DEG::NodeType type = DEG::nodeTypeFromObjectComponent(component); DEG::ComponentKey comp_key(&object->id, type); DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); DEG::DepsgraphRelationBuilder *relation_builder = deg_node_handle->builder; diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index f821af8cdc7..23f2bf4194f 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -289,7 +289,7 @@ bool DEG_is_original_id(ID *id) * Localization is usually happening from evaluated data-block, or will have some special pointer * magic which will make them to act as evaluated. * - * NOTE: We conder ID evaluated if ANY of those flags is set. We do NOT require ALL of them. */ + * NOTE: We consider ID evaluated if ANY of those flags is set. We do NOT require ALL of them. */ if (id->tag & (LIB_TAG_COPIED_ON_WRITE | LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT | LIB_TAG_LOCALIZED)) { return false; diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc index 717793d60f1..33cb1ba7416 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc @@ -48,25 +48,30 @@ extern "C" { /* ************************ DEG TRAVERSAL ********************* */ namespace DEG { +namespace { typedef std::deque<OperationNode *> TraversalQueue; enum { DEG_NODE_VISITED = (1 << 0), }; -static void deg_foreach_clear_flags(const Depsgraph *graph) +typedef void (*DEGForeachOperation)(OperationNode *op_node, void *user_data); + +void deg_foreach_clear_flags(const Depsgraph *graph) { for (OperationNode *op_node : graph->operations) { op_node->scheduled = false; + op_node->owner->custom_flags = 0; } for (IDNode *id_node : graph->id_nodes) { id_node->custom_flags = 0; } } -static void deg_foreach_dependent_ID(const Depsgraph *graph, +void deg_foreach_dependent_operation(const Depsgraph *graph, const ID *id, - DEGForeachIDCallback callback, + eDepsObjectComponentType source_component_type, + DEGForeachOperation callback, void *user_data) { /* Start with getting ID node from the graph. */ @@ -81,9 +86,14 @@ static void deg_foreach_dependent_ID(const Depsgraph *graph, /* Start with scheduling all operations from ID node. */ TraversalQueue queue; GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, target_id_node->components) { + if (source_component_type != DEG_OB_COMP_ANY && + nodeTypeToObjectComponent(comp_node->type) != source_component_type) { + continue; + } for (OperationNode *op_node : comp_node->operations) { queue.push_back(op_node); op_node->scheduled = true; + op_node->owner->custom_flags |= DEG_NODE_VISITED; } } GHASH_FOREACH_END(); @@ -94,14 +104,7 @@ static void deg_foreach_dependent_ID(const Depsgraph *graph, OperationNode *op_node = queue.front(); queue.pop_front(); for (;;) { - /* Check whether we need to inform callee about corresponding ID node. */ - ComponentNode *comp_node = op_node->owner; - IDNode *id_node = comp_node->owner; - if ((id_node->custom_flags & DEG_NODE_VISITED) == 0) { - /* TODO(sergey): Is it orig or CoW? */ - callback(id_node->id_orig, user_data); - id_node->custom_flags |= DEG_NODE_VISITED; - } + callback(op_node, user_data); /* Schedule outgoing operation nodes. */ if (op_node->outlinks.size() == 1) { OperationNode *to_node = (OperationNode *)op_node->outlinks[0]->to; @@ -127,10 +130,68 @@ static void deg_foreach_dependent_ID(const Depsgraph *graph, } } -static void deg_foreach_ancestor_ID(const Depsgraph *graph, - const ID *id, - DEGForeachIDCallback callback, - void *user_data) +struct ForeachIDComponentData { + DEGForeachIDComponentCallback callback; + void *user_data; +}; + +void deg_foreach_dependent_component_callback(OperationNode *op_node, void *user_data_v) +{ + ForeachIDComponentData *user_data = reinterpret_cast<ForeachIDComponentData *>(user_data_v); + ComponentNode *comp_node = op_node->owner; + if ((comp_node->custom_flags & DEG_NODE_VISITED) == 0) { + IDNode *id_node = comp_node->owner; + user_data->callback( + id_node->id_orig, nodeTypeToObjectComponent(comp_node->type), user_data->user_data); + comp_node->custom_flags |= DEG_NODE_VISITED; + } +} + +void deg_foreach_dependent_ID_component(const Depsgraph *graph, + const ID *id, + eDepsObjectComponentType source_component_type, + DEGForeachIDComponentCallback callback, + void *user_data) +{ + ForeachIDComponentData data; + data.callback = callback; + data.user_data = user_data; + deg_foreach_dependent_operation( + graph, id, source_component_type, deg_foreach_dependent_component_callback, &data); +} + +struct ForeachIDData { + DEGForeachIDCallback callback; + void *user_data; +}; + +void deg_foreach_dependent_ID_callback(OperationNode *op_node, void *user_data_v) +{ + ForeachIDData *user_data = reinterpret_cast<ForeachIDData *>(user_data_v); + ComponentNode *comp_node = op_node->owner; + IDNode *id_node = comp_node->owner; + if ((id_node->custom_flags & DEG_NODE_VISITED) == 0) { + user_data->callback(id_node->id_orig, user_data->user_data); + id_node->custom_flags |= DEG_NODE_VISITED; + } +} + +void deg_foreach_dependent_ID(const Depsgraph *graph, + const ID *id, + DEGForeachIDCallback callback, + void *user_data) +{ + ForeachIDData data; + data.callback = callback; + data.user_data = user_data; + deg_foreach_dependent_operation( + graph, id, DEG_OB_COMP_ANY, deg_foreach_dependent_ID_callback, &data); +} + +void deg_foreach_ancestor_ID(const Depsgraph *graph, + const ID *id, + DEGForeachIDCallback callback, + void *user_data) { /* Start with getting ID node from the graph. */ IDNode *target_id_node = graph->find_id_node(id); @@ -196,15 +257,14 @@ static void deg_foreach_ancestor_ID(const Depsgraph *graph, } } -static void deg_foreach_id(const Depsgraph *depsgraph, - DEGForeachIDCallback callback, - void *user_data) +void deg_foreach_id(const Depsgraph *depsgraph, DEGForeachIDCallback callback, void *user_data) { for (const IDNode *id_node : depsgraph->id_nodes) { callback(id_node->id_orig, user_data); } } +} // namespace } // namespace DEG void DEG_foreach_dependent_ID(const Depsgraph *depsgraph, @@ -215,6 +275,16 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph, DEG::deg_foreach_dependent_ID((const DEG::Depsgraph *)depsgraph, id, callback, user_data); } +void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph, + const ID *id, + eDepsObjectComponentType source_component_type, + DEGForeachIDComponentCallback callback, + void *user_data) +{ + DEG::deg_foreach_dependent_ID_component( + (const DEG::Depsgraph *)depsgraph, id, source_component_type, callback, user_data); +} + void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph, const ID *id, DEGForeachIDCallback callback, diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index be78eee91cc..1f310957896 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -87,6 +87,7 @@ extern "C" { #include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_object.h" +#include "BKE_pointcache.h" #include "BKE_sequencer.h" #include "BKE_sound.h" } @@ -577,6 +578,7 @@ void update_armature_edit_mode_pointers(const Depsgraph * /*depsgraph*/, const bArmature *armature_orig = (const bArmature *)id_orig; bArmature *armature_cow = (bArmature *)id_cow; armature_cow->edbo = armature_orig->edbo; + armature_cow->act_edbone = armature_orig->act_edbone; } void update_curve_edit_mode_pointers(const Depsgraph * /*depsgraph*/, @@ -683,10 +685,29 @@ void set_particle_system_modifiers_loaded(Object *object_cow) } } -void update_particles_after_copy(const Object *object_orig, Object *object_cow) +void reset_particle_system_edit_eval(const Depsgraph *depsgraph, Object *object_cow) +{ + /* Inactive (and render) dependency graphs are living in own little bubble, should not care about + * edit mode at all. */ + if (!DEG_is_active(reinterpret_cast<const ::Depsgraph *>(depsgraph))) { + return; + } + LISTBASE_FOREACH (ParticleSystem *, psys, &object_cow->particlesystem) { + ParticleSystem *orig_psys = psys->orig_psys; + if (orig_psys->edit != NULL) { + orig_psys->edit->psys_eval = NULL; + orig_psys->edit->psmd_eval = NULL; + } + } +} + +void update_particles_after_copy(const Depsgraph *depsgraph, + const Object *object_orig, + Object *object_cow) { update_particle_system_orig_pointers(object_orig, object_cow); set_particle_system_modifiers_loaded(object_cow); + reset_particle_system_edit_eval(depsgraph, object_cow); } void update_pose_orig_pointers(const bPose *pose_orig, bPose *pose_cow) @@ -765,7 +786,7 @@ void update_id_after_copy(const Depsgraph *depsgraph, } BKE_pose_pchan_index_rebuild(object_cow->pose); } - update_particles_after_copy(object_orig, object_cow); + update_particles_after_copy(depsgraph, object_orig, object_cow); update_modifiers_orig_pointers(object_orig, object_cow); break; } @@ -1321,6 +1342,50 @@ void ObjectRuntimeBackup::restore_pose_channel_runtime_data(Object *object) } } +/* Backup of movie clip runtime data. */ + +class MovieClipBackup { + public: + MovieClipBackup(); + + void reset(); + + void init_from_movieclip(MovieClip *movieclip); + void restore_to_movieclip(MovieClip *movieclip); + + struct anim *anim; + struct MovieClipCache *cache; +}; + +MovieClipBackup::MovieClipBackup() +{ + reset(); +} + +void MovieClipBackup::reset() +{ + anim = NULL; + cache = NULL; +} + +void MovieClipBackup::init_from_movieclip(MovieClip *movieclip) +{ + anim = movieclip->anim; + cache = movieclip->cache; + /* Clear pointers stored in the movie clip, so they are not freed when copied-on-written + * datablock is freed for re-allocation. */ + movieclip->anim = NULL; + movieclip->cache = NULL; +} + +void MovieClipBackup::restore_to_movieclip(MovieClip *movieclip) +{ + movieclip->anim = anim; + movieclip->cache = cache; + + reset(); +} + class RuntimeBackup { public: RuntimeBackup() : drawdata_ptr(NULL) @@ -1339,6 +1404,7 @@ class RuntimeBackup { ObjectRuntimeBackup object_backup; DrawDataList drawdata_backup; DrawDataList *drawdata_ptr; + MovieClipBackup movieclip_backup; }; void RuntimeBackup::init_from_id(ID *id) @@ -1357,6 +1423,9 @@ void RuntimeBackup::init_from_id(ID *id) case ID_SO: sound_backup.init_from_sound(reinterpret_cast<bSound *>(id)); break; + case ID_MC: + movieclip_backup.init_from_movieclip(reinterpret_cast<MovieClip *>(id)); + break; default: break; } @@ -1382,6 +1451,9 @@ void RuntimeBackup::restore_to_id(ID *id) case ID_SO: sound_backup.restore_to_sound(reinterpret_cast<bSound *>(id)); break; + case ID_MC: + movieclip_backup.restore_to_movieclip(reinterpret_cast<MovieClip *>(id)); + break; default: break; } diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc index 289c9a76cc7..16c934e72fe 100644 --- a/source/blender/depsgraph/intern/node/deg_node.cc +++ b/source/blender/depsgraph/intern/node/deg_node.cc @@ -120,6 +120,134 @@ const char *nodeTypeAsString(NodeType type) return "UNKNOWN"; } +NodeType nodeTypeFromSceneComponent(eDepsSceneComponentType component) +{ + switch (component) { + case DEG_SCENE_COMP_PARAMETERS: + return NodeType::PARAMETERS; + case DEG_SCENE_COMP_ANIMATION: + return NodeType::ANIMATION; + case DEG_SCENE_COMP_SEQUENCER: + return NodeType::SEQUENCER; + } + return NodeType::UNDEFINED; +} + +eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type) +{ + switch (type) { + case NodeType::PARAMETERS: + return DEG_SCENE_COMP_PARAMETERS; + case NodeType::ANIMATION: + return DEG_SCENE_COMP_ANIMATION; + case NodeType::SEQUENCER: + return DEG_SCENE_COMP_SEQUENCER; + + case NodeType::OPERATION: + case NodeType::TIMESOURCE: + case NodeType::ID_REF: + case NodeType::LAYER_COLLECTIONS: + case NodeType::COPY_ON_WRITE: + case NodeType::OBJECT_FROM_LAYER: + case NodeType::AUDIO: + case NodeType::ARMATURE: + case NodeType::GENERIC_DATABLOCK: + case NodeType::PARTICLE_SYSTEM: + case NodeType::PARTICLE_SETTINGS: + case NodeType::SHADING_PARAMETERS: + case NodeType::POINT_CACHE: + case NodeType::BATCH_CACHE: + case NodeType::DUPLI: + case NodeType::SYNCHRONIZATION: + case NodeType::UNDEFINED: + case NodeType::NUM_TYPES: + case NodeType::TRANSFORM: + case NodeType::GEOMETRY: + case NodeType::EVAL_POSE: + case NodeType::BONE: + case NodeType::SHADING: + case NodeType::CACHE: + case NodeType::PROXY: + return DEG_SCENE_COMP_PARAMETERS; + } + BLI_assert(!"Unhandled node type, not suppsed to happen."); + return DEG_SCENE_COMP_PARAMETERS; +} + +NodeType nodeTypeFromObjectComponent(eDepsObjectComponentType component_type) +{ + switch (component_type) { + case DEG_OB_COMP_ANY: + return NodeType::UNDEFINED; + case DEG_OB_COMP_PARAMETERS: + return NodeType::PARAMETERS; + case DEG_OB_COMP_PROXY: + return NodeType::PROXY; + case DEG_OB_COMP_ANIMATION: + return NodeType::ANIMATION; + case DEG_OB_COMP_TRANSFORM: + return NodeType::TRANSFORM; + case DEG_OB_COMP_GEOMETRY: + return NodeType::GEOMETRY; + case DEG_OB_COMP_EVAL_POSE: + return NodeType::EVAL_POSE; + case DEG_OB_COMP_BONE: + return NodeType::BONE; + case DEG_OB_COMP_SHADING: + return NodeType::SHADING; + case DEG_OB_COMP_CACHE: + return NodeType::CACHE; + } + return NodeType::UNDEFINED; +} + +eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type) +{ + switch (type) { + case NodeType::PARAMETERS: + return DEG_OB_COMP_PARAMETERS; + case NodeType::PROXY: + return DEG_OB_COMP_PROXY; + case NodeType::ANIMATION: + return DEG_OB_COMP_ANIMATION; + case NodeType::TRANSFORM: + return DEG_OB_COMP_TRANSFORM; + case NodeType::GEOMETRY: + return DEG_OB_COMP_GEOMETRY; + case NodeType::EVAL_POSE: + return DEG_OB_COMP_EVAL_POSE; + case NodeType::BONE: + return DEG_OB_COMP_BONE; + case NodeType::SHADING: + return DEG_OB_COMP_SHADING; + case NodeType::CACHE: + return DEG_OB_COMP_CACHE; + + case NodeType::OPERATION: + case NodeType::TIMESOURCE: + case NodeType::ID_REF: + case NodeType::SEQUENCER: + case NodeType::LAYER_COLLECTIONS: + case NodeType::COPY_ON_WRITE: + case NodeType::OBJECT_FROM_LAYER: + case NodeType::AUDIO: + case NodeType::ARMATURE: + case NodeType::GENERIC_DATABLOCK: + case NodeType::PARTICLE_SYSTEM: + case NodeType::PARTICLE_SETTINGS: + case NodeType::SHADING_PARAMETERS: + case NodeType::POINT_CACHE: + case NodeType::BATCH_CACHE: + case NodeType::DUPLI: + case NodeType::SYNCHRONIZATION: + case NodeType::UNDEFINED: + case NodeType::NUM_TYPES: + return DEG_OB_COMP_PARAMETERS; + } + BLI_assert(!"Unhandled node type, not suppsed to happen."); + return DEG_OB_COMP_PARAMETERS; +} + /******************************************************************************* * Type information. */ diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h index 705dae41470..eea69502baa 100644 --- a/source/blender/depsgraph/intern/node/deg_node.h +++ b/source/blender/depsgraph/intern/node/deg_node.h @@ -27,6 +27,8 @@ #include "BLI_utildefines.h" +#include "DEG_depsgraph_build.h" + struct GHash; struct ID; struct Scene; @@ -95,7 +97,7 @@ enum class NodeType { /* Audio-related evaluation. */ AUDIO, ARMATURE, - /* Un-interestying datablock, which is a part of dependency graph, but does + /* Un-interesting data-block, which is a part of dependency graph, but does * not have very distinctive update procedure. */ GENERIC_DATABLOCK, @@ -130,6 +132,12 @@ enum class NodeType { }; const char *nodeTypeAsString(NodeType type); +NodeType nodeTypeFromSceneComponent(eDepsSceneComponentType component_type); +eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type); + +NodeType nodeTypeFromObjectComponent(eDepsObjectComponentType component_type); +eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type); + /* All nodes in Depsgraph are descended from this. */ struct Node { /* Helper class for static typeinfo in subclasses. */ diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c index d0f544dd3c6..12d70131031 100644 --- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c +++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c @@ -97,6 +97,9 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), int buffer_size[2] = {(int)viewport_size[0] / 2, (int)viewport_size[1] / 2}; + buffer_size[0] = max_ii(1, buffer_size[0]); + buffer_size[1] = max_ii(1, buffer_size[1]); + eGPUTextureFormat down_format = DRW_state_draw_background() ? GPU_R11F_G11F_B10F : GPU_RGBA16F; effects->dof_down_near = DRW_texture_pool_query_2d( diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 021afa64fee..1b152afa3bf 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -161,6 +161,12 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, effects->enabled_effects |= EEVEE_occlusion_init(sldata, vedata); effects->enabled_effects |= EEVEE_screen_raytrace_init(sldata, vedata); + if ((effects->enabled_effects & EFFECT_TAA) && effects->taa_current_sample > 1) { + /* Update matrices here because EEVEE_screen_raytrace_init can have reset the + * taa_current_sample. (See T66811) */ + EEVEE_temporal_sampling_update_matrices(vedata); + } + EEVEE_volumes_init(sldata, vedata); EEVEE_subsurface_init(sldata, vedata); diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 99be7ec631c..b36ad540ef9 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -303,6 +303,16 @@ static void eevee_draw_background(void *vedata) DRW_stats_group_end(); DRW_view_set_active(NULL); + + if (DRW_state_is_image_render() && (stl->effects->enabled_effects & EFFECT_SSR) && + !stl->effects->ssr_was_valid_double_buffer) { + /* SSR needs one iteration to start properly. */ + loop_len++; + /* Reset sampling (and accumulation) after the first sample to avoid + * washed out first bounce for SSR. */ + EEVEE_temporal_sampling_reset(vedata); + stl->effects->ssr_was_valid_double_buffer = stl->g_data->valid_double_buffer; + } } /* Tonemapping and transfer result to default framebuffer. */ diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index ddc5eae768e..5341661735f 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -212,6 +212,7 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) common_data->spec_toggle = true; common_data->ssr_toggle = true; + common_data->ssrefract_toggle = true; common_data->sss_toggle = true; /* Placeholder planar pool: used when rendering planar reflections (avoid dependency loop). */ @@ -1264,6 +1265,7 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v common_data->prb_num_planar = 0; /* Turn off ssr to avoid black specular */ common_data->ssr_toggle = false; + common_data->ssrefract_toggle = false; common_data->sss_toggle = false; common_data->ray_type = EEVEE_RAY_GLOSSY; @@ -1281,6 +1283,7 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v /* Restore */ common_data->prb_num_planar = pinfo->num_planar; common_data->ssr_toggle = true; + common_data->ssrefract_toggle = true; common_data->sss_toggle = true; /* Prefilter for SSR */ diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c index 2d4cc069697..e6e699bef10 100644 --- a/source/blender/draw/engines/eevee/eevee_lookdev.c +++ b/source/blender/draw/engines/eevee/eevee_lookdev.c @@ -71,6 +71,8 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, View3D *v3d = draw_ctx->v3d; Scene *scene = draw_ctx->scene; + effects->lookdev_view = NULL; + if (LOOK_DEV_OVERLAY_ENABLED(v3d)) { /* Viewport / Spheres size. */ rcti rect; diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index f5f3a7a70e3..61da9e21cc8 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -1659,14 +1659,17 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, char *name = auto_layer_names; for (int j = 0; j < auto_layer_count; ++j) { /* TODO don't add these uniform when not needed (default pass shaders). */ + /* FIXME: This is broken, as it overrides any autolayers srgb bool of the previous mesh + * that shares the same material. */ if (shgrp_array[i]) { - DRW_shgroup_uniform_bool(shgrp_array[i], name, &auto_layer_is_srgb[j], 1); + DRW_shgroup_uniform_bool_copy(shgrp_array[i], name, auto_layer_is_srgb[j]); } if (shgrp_depth_array[i]) { - DRW_shgroup_uniform_bool(shgrp_depth_array[i], name, &auto_layer_is_srgb[j], 1); + DRW_shgroup_uniform_bool_copy(shgrp_depth_array[i], name, auto_layer_is_srgb[j]); } if (shgrp_depth_clip_array[i]) { - DRW_shgroup_uniform_bool(shgrp_depth_clip_array[i], name, &auto_layer_is_srgb[j], 1); + DRW_shgroup_uniform_bool_copy( + shgrp_depth_clip_array[i], name, auto_layer_is_srgb[j]); } /* Go to next layer name. */ while (*name != '\0') { diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 166e8ac7473..bd08a61e3b8 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -562,6 +562,7 @@ typedef struct EEVEE_EffectsInfo { /* SSR */ bool reflection_trace_full; bool ssr_was_persp; + bool ssr_was_valid_double_buffer; int ssr_neighbor_ofs; int ssr_halfres_ofs[2]; struct GPUTexture *ssr_normal_input; /* Textures from pool */ @@ -653,11 +654,11 @@ typedef struct EEVEE_CommonUniformBuffer { float ao_offset, ao_bounce_fac, ao_quality, ao_settings; /* vec4 */ /* Volumetric */ /* -- 16 byte aligned -- */ - int vol_tex_size[3], pad3; /* ivec3 */ - float vol_depth_param[3], pad4; /* vec3 */ - float vol_inv_tex_size[3], pad5; /* vec3 */ - float vol_jitter[3], pad6; /* vec3 */ - float vol_coord_scale[2], pad7[2]; /* vec2 */ + int vol_tex_size[3], pad3; /* ivec3 */ + float vol_depth_param[3], pad4; /* vec3 */ + float vol_inv_tex_size[3], pad5; /* vec3 */ + float vol_jitter[3], pad6; /* vec3 */ + float vol_coord_scale[4]; /* vec4 */ /* -- 16 byte aligned -- */ float vol_history_alpha; /* float */ float vol_light_clamp; /* float */ @@ -671,6 +672,7 @@ typedef struct EEVEE_CommonUniformBuffer { float ssr_firefly_fac; /* float */ float ssr_brdf_bias; /* float */ int ssr_toggle; /* bool */ + int ssrefract_toggle; /* bool */ /* SubSurface Scattering */ float sss_jitter_threshold; /* float */ int sss_toggle; /* bool */ @@ -690,8 +692,6 @@ typedef struct EEVEE_CommonUniformBuffer { int hiz_mip_offset; /* int */ int ray_type; /* int */ float ray_depth; /* float */ - - float pad_common_ubo; } EEVEE_CommonUniformBuffer; BLI_STATIC_ASSERT_ALIGN(EEVEE_CommonUniformBuffer, 16) diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 2afd0b1d313..286bcd8f738 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -536,6 +536,11 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl return; } + /* SSR needs one iteration to start properly. */ + if (stl->effects->enabled_effects & EFFECT_SSR) { + tot_sample += 1; + } + while (render_samples < tot_sample && !RE_engine_test_break(engine)) { float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float clear_depth = 1.0f; @@ -544,6 +549,25 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl double offset[3] = {0.0, 0.0, 0.0}; double r[3]; + if ((stl->effects->enabled_effects & EFFECT_SSR) && (render_samples == 1) && + !stl->effects->ssr_was_valid_double_buffer) { + /* SSR needs one iteration to start properly. + * This iteration was done, reset to the original target sample count. */ + render_samples--; + tot_sample--; + /* Reset sampling (and accumulation) after the first sample to avoid + * washed out first bounce for SSR. */ + EEVEE_temporal_sampling_reset(vedata); + stl->effects->ssr_was_valid_double_buffer = stl->g_data->valid_double_buffer; + } + /* Don't print every samples as it can lead to bad performance. (see T59649) */ + else if ((render_samples % 25) == 0 || (render_samples + 1) == tot_sample) { + char info[42]; + BLI_snprintf( + info, sizeof(info), "Rendering %u / %u samples", render_samples + 1, tot_sample); + RE_engine_update_stats(engine, NULL, info); + } + /* Copy previous persmat to UBO data */ copy_m4_m4(sldata->common_data.prev_persmat, stl->effects->prev_persmat); @@ -557,14 +581,6 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl EEVEE_lightprobes_refresh(sldata, vedata); EEVEE_lightprobes_refresh_planar(sldata, vedata); - /* Don't print every samples as it can lead to bad performance. (see T59649) */ - if ((render_samples % 25) == 0 || (render_samples + 1) == tot_sample) { - char info[42]; - BLI_snprintf( - info, sizeof(info), "Rendering %u / %u samples", render_samples + 1, tot_sample); - RE_engine_update_stats(engine, NULL, info); - } - /* Refresh Shadows */ EEVEE_lights_update(sldata, vedata); EEVEE_draw_shadows(sldata, vedata, stl->effects->taa_view); diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 7b80daf8ed6..d53ed239f4e 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -135,6 +135,12 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) stl->g_data->valid_double_buffer = false; } + if (!effects->ssr_was_valid_double_buffer) { + DRW_viewport_request_redraw(); + EEVEE_temporal_sampling_reset(vedata); + } + effects->ssr_was_valid_double_buffer = stl->g_data->valid_double_buffer; + effects->reflection_trace_full = (scene_eval->eevee.flag & SCE_EEVEE_SSR_HALF_RESOLUTION) == 0; common_data->ssr_thickness = scene_eval->eevee.ssr_thickness; common_data->ssr_border_fac = scene_eval->eevee.ssr_border_fade; @@ -153,6 +159,9 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) const bool high_qual_input = true; /* TODO dither low quality input */ const eGPUTextureFormat format = (high_qual_input) ? GPU_RGBA16F : GPU_RGBA8; + tracing_res[0] = max_ii(1, tracing_res[0]); + tracing_res[1] = max_ii(1, tracing_res[1]); + /* MRT for the shading pass in order to output needed data for the SSR pass. */ effects->ssr_specrough_input = DRW_texture_pool_query_2d( size_fs[0], size_fs[1], format, &draw_engine_eevee_type); diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index 099147a82dd..96924efa8bc 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -253,7 +253,6 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data if (!DRW_state_is_image_render()) { effects->taa_current_sample += 1; repro_flag = 0; - EEVEE_temporal_sampling_update_matrices(vedata); } } else { diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 9c8ec6e52a4..f85c30044a9 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -178,6 +178,8 @@ void EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) common_data->vol_coord_scale[0] = viewport_size[0] / (float)(tile_size * tex_size[0]); common_data->vol_coord_scale[1] = viewport_size[1] / (float)(tile_size * tex_size[1]); + common_data->vol_coord_scale[2] = 1.0f / viewport_size[0]; + common_data->vol_coord_scale[3] = 1.0f / viewport_size[1]; /* TODO compute snap to maxZBuffer for clustered rendering */ if ((common_data->vol_tex_size[0] != tex_size[0]) || diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 3a31afc0224..274269846bc 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -915,8 +915,7 @@ void main() # endif # if defined(USE_ALPHA_BLEND) - /* XXX fragile, better use real viewport resolution */ - vec2 uvs = gl_FragCoord.xy / vec2(2 * textureSize(maxzBuffer, 0).xy); + vec2 uvs = gl_FragCoord.xy * volCoordScale.zw; vec3 transmittance, scattering; volumetric_resolve(uvs, gl_FragCoord.z, transmittance, scattering); fragColor.rgb = cl.radiance * transmittance + scattering; diff --git a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl index da0778b8a10..c7ae2417904 100644 --- a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl @@ -23,6 +23,7 @@ layout(std140) uniform common_block float ssrFireflyFac; float ssrBrdfBias; bool ssrToggle; + bool ssrefractToggle; /* SubSurface Scattering */ float sssJitterThreshold; bool sssToggle; diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index 6b3d9ee4517..53f1517505c 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -1,14 +1,14 @@ #ifndef LIT_SURFACE_UNIFORM -#define LIT_SURFACE_UNIFORM +# define LIT_SURFACE_UNIFORM uniform float refractionDepth; -#ifndef UTIL_TEX -# define UTIL_TEX +# ifndef UTIL_TEX +# define UTIL_TEX uniform sampler2DArray utilTex; -# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) -#endif /* UTIL_TEX */ +# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) +# endif /* UTIL_TEX */ in vec3 worldPosition; in vec3 viewPosition; @@ -16,7 +16,7 @@ in vec3 viewPosition; in vec3 worldNormal; in vec3 viewNormal; -#ifdef HAIR_SHADER +# ifdef HAIR_SHADER in vec3 hairTangent; /* world space */ in float hairThickTime; in float hairThickness; @@ -24,7 +24,7 @@ in float hairTime; flat in int hairStrandID; uniform int hairThicknessRes = 1; -#endif +# endif #endif /* LIT_SURFACE_UNIFORM */ @@ -33,82 +33,82 @@ uniform int hairThicknessRes = 1; * This leads to a lot of deadcode. Better idea would be to only generate the one needed. */ #if !defined(SURFACE_DEFAULT) -#define SURFACE_DEFAULT -#define CLOSURE_NAME eevee_closure_default -#define CLOSURE_DIFFUSE -#define CLOSURE_GLOSSY +# define SURFACE_DEFAULT +# define CLOSURE_NAME eevee_closure_default +# define CLOSURE_DIFFUSE +# define CLOSURE_GLOSSY #endif /* SURFACE_DEFAULT */ #if !defined(SURFACE_DEFAULT_CLEARCOAT) && !defined(CLOSURE_NAME) -#define SURFACE_DEFAULT_CLEARCOAT -#define CLOSURE_NAME eevee_closure_default_clearcoat -#define CLOSURE_DIFFUSE -#define CLOSURE_GLOSSY -#define CLOSURE_CLEARCOAT +# define SURFACE_DEFAULT_CLEARCOAT +# define CLOSURE_NAME eevee_closure_default_clearcoat +# define CLOSURE_DIFFUSE +# define CLOSURE_GLOSSY +# define CLOSURE_CLEARCOAT #endif /* SURFACE_DEFAULT_CLEARCOAT */ #if !defined(SURFACE_PRINCIPLED) && !defined(CLOSURE_NAME) -#define SURFACE_PRINCIPLED -#define CLOSURE_NAME eevee_closure_principled -#define CLOSURE_DIFFUSE -#define CLOSURE_GLOSSY -#define CLOSURE_CLEARCOAT -#define CLOSURE_REFRACTION -#define CLOSURE_SUBSURFACE +# define SURFACE_PRINCIPLED +# define CLOSURE_NAME eevee_closure_principled +# define CLOSURE_DIFFUSE +# define CLOSURE_GLOSSY +# define CLOSURE_CLEARCOAT +# define CLOSURE_REFRACTION +# define CLOSURE_SUBSURFACE #endif /* SURFACE_PRINCIPLED */ #if !defined(SURFACE_CLEARCOAT) && !defined(CLOSURE_NAME) -#define SURFACE_CLEARCOAT -#define CLOSURE_NAME eevee_closure_clearcoat -#define CLOSURE_GLOSSY -#define CLOSURE_CLEARCOAT +# define SURFACE_CLEARCOAT +# define CLOSURE_NAME eevee_closure_clearcoat +# define CLOSURE_GLOSSY +# define CLOSURE_CLEARCOAT #endif /* SURFACE_CLEARCOAT */ #if !defined(SURFACE_DIFFUSE) && !defined(CLOSURE_NAME) -#define SURFACE_DIFFUSE -#define CLOSURE_NAME eevee_closure_diffuse -#define CLOSURE_DIFFUSE +# define SURFACE_DIFFUSE +# define CLOSURE_NAME eevee_closure_diffuse +# define CLOSURE_DIFFUSE #endif /* SURFACE_DIFFUSE */ #if !defined(SURFACE_SUBSURFACE) && !defined(CLOSURE_NAME) -#define SURFACE_SUBSURFACE -#define CLOSURE_NAME eevee_closure_subsurface -#define CLOSURE_DIFFUSE -#define CLOSURE_SUBSURFACE +# define SURFACE_SUBSURFACE +# define CLOSURE_NAME eevee_closure_subsurface +# define CLOSURE_DIFFUSE +# define CLOSURE_SUBSURFACE #endif /* SURFACE_SUBSURFACE */ #if !defined(SURFACE_SKIN) && !defined(CLOSURE_NAME) -#define SURFACE_SKIN -#define CLOSURE_NAME eevee_closure_skin -#define CLOSURE_DIFFUSE -#define CLOSURE_SUBSURFACE -#define CLOSURE_GLOSSY +# define SURFACE_SKIN +# define CLOSURE_NAME eevee_closure_skin +# define CLOSURE_DIFFUSE +# define CLOSURE_SUBSURFACE +# define CLOSURE_GLOSSY #endif /* SURFACE_SKIN */ #if !defined(SURFACE_GLOSSY) && !defined(CLOSURE_NAME) -#define SURFACE_GLOSSY -#define CLOSURE_NAME eevee_closure_glossy -#define CLOSURE_GLOSSY +# define SURFACE_GLOSSY +# define CLOSURE_NAME eevee_closure_glossy +# define CLOSURE_GLOSSY #endif /* SURFACE_GLOSSY */ #if !defined(SURFACE_REFRACT) && !defined(CLOSURE_NAME) -#define SURFACE_REFRACT -#define CLOSURE_NAME eevee_closure_refraction -#define CLOSURE_REFRACTION +# define SURFACE_REFRACT +# define CLOSURE_NAME eevee_closure_refraction +# define CLOSURE_REFRACTION #endif /* SURFACE_REFRACT */ #if !defined(SURFACE_GLASS) && !defined(CLOSURE_NAME) -#define SURFACE_GLASS -#define CLOSURE_NAME eevee_closure_glass -#define CLOSURE_GLOSSY -#define CLOSURE_REFRACTION +# define SURFACE_GLASS +# define CLOSURE_NAME eevee_closure_glass +# define CLOSURE_GLOSSY +# define CLOSURE_REFRACTION #endif /* SURFACE_GLASS */ /* Safety : CLOSURE_CLEARCOAT implies CLOSURE_GLOSSY */ #ifdef CLOSURE_CLEARCOAT -#ifndef CLOSURE_GLOSSY -# define CLOSURE_GLOSSY -#endif +# ifndef CLOSURE_GLOSSY +# define CLOSURE_GLOSSY +# endif #endif /* CLOSURE_CLEARCOAT */ void CLOSURE_NAME(vec3 N @@ -184,7 +184,7 @@ void CLOSURE_NAME(vec3 N #ifdef SHADOW_SHADER return; -#endif +#else /* Zero length vectors cause issues, see: T51979. */ float len = length(N); @@ -193,23 +193,23 @@ void CLOSURE_NAME(vec3 N } N /= len; -#ifdef CLOSURE_CLEARCOAT +# ifdef CLOSURE_CLEARCOAT len = length(C_N); if (isnan(len)) { return; } C_N /= len; -#endif +# endif -#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION) +# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION) roughness = clamp(roughness, 1e-8, 0.9999); float roughnessSquared = roughness * roughness; -#endif +# endif -#ifdef CLOSURE_CLEARCOAT +# ifdef CLOSURE_CLEARCOAT C_roughness = clamp(C_roughness, 1e-8, 0.9999); float C_roughnessSquared = C_roughness * C_roughness; -#endif +# endif vec3 V = cameraVec; @@ -219,16 +219,16 @@ void CLOSURE_NAME(vec3 N /* -------------------- SCENE LIGHTS LIGHTING --------------------- */ /* ---------------------------------------------------------------- */ -#ifdef CLOSURE_GLOSSY +# ifdef CLOSURE_GLOSSY vec2 lut_uv = lut_coords_ltc(dot(N, V), roughness); vec4 ltc_mat = texture(utilTex, vec3(lut_uv, 0.0)).rgba; -#endif +# endif -#ifdef CLOSURE_CLEARCOAT +# ifdef CLOSURE_CLEARCOAT vec2 lut_uv_clear = lut_coords_ltc(dot(C_N, V), C_roughness); vec4 ltc_mat_clear = texture(utilTex, vec3(lut_uv_clear, 0.0)).rgba; vec3 out_spec_clear = vec3(0.0); -#endif +# endif for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) { LightData ld = lights_data[i]; @@ -245,34 +245,34 @@ void CLOSURE_NAME(vec3 N vec3 l_color_vis = ld.l_color * l_vis; -#ifdef CLOSURE_DIFFUSE +# ifdef CLOSURE_DIFFUSE out_diff += l_color_vis * light_diffuse(ld, N, V, l_vector); -#endif +# endif -#ifdef CLOSURE_SUBSURFACE +# ifdef CLOSURE_SUBSURFACE out_trans += ld.l_color * light_translucent(ld, worldPosition, -N, l_vector, sss_scale); -#endif +# endif -#ifdef CLOSURE_GLOSSY +# ifdef CLOSURE_GLOSSY out_spec += l_color_vis * light_specular(ld, ltc_mat, N, V, l_vector) * ld.l_spec; -#endif +# endif -#ifdef CLOSURE_CLEARCOAT +# ifdef CLOSURE_CLEARCOAT out_spec_clear += l_color_vis * light_specular(ld, ltc_mat_clear, C_N, V, l_vector) * ld.l_spec; -#endif +# endif } -#ifdef CLOSURE_GLOSSY +# ifdef CLOSURE_GLOSSY vec2 brdf_lut_lights = texture(utilTex, vec3(lut_uv, 1.0)).ba; out_spec *= F_area(f0, f90, brdf_lut_lights.xy); -#endif +# endif -#ifdef CLOSURE_CLEARCOAT +# ifdef CLOSURE_CLEARCOAT vec2 brdf_lut_lights_clear = texture(utilTex, vec3(lut_uv_clear, 1.0)).ba; out_spec_clear *= F_area(vec3(0.04), vec3(1.0), brdf_lut_lights_clear.xy); out_spec += out_spec_clear * C_intensity; -#endif +# endif /* ---------------------------------------------------------------- */ /* ---------------- SPECULAR ENVIRONMENT LIGHTING ----------------- */ @@ -280,19 +280,19 @@ void CLOSURE_NAME(vec3 N /* Accumulate incoming light from all sources until accumulator is full. Then apply Occlusion and * BRDF. */ -#ifdef CLOSURE_GLOSSY +# ifdef CLOSURE_GLOSSY vec4 spec_accum = vec4(0.0); -#endif +# endif -#ifdef CLOSURE_CLEARCOAT +# ifdef CLOSURE_CLEARCOAT vec4 C_spec_accum = vec4(0.0); -#endif +# endif -#ifdef CLOSURE_REFRACTION +# ifdef CLOSURE_REFRACTION vec4 refr_accum = vec4(0.0); -#endif +# endif -#ifdef CLOSURE_GLOSSY +# ifdef CLOSURE_GLOSSY /* ---------------------------- */ /* Planar Reflections */ /* ---------------------------- */ @@ -310,23 +310,23 @@ void CLOSURE_NAME(vec3 N accumulate_light(spec, fade, spec_accum); } -#ifdef CLOSURE_CLEARCOAT +# ifdef CLOSURE_CLEARCOAT vec3 C_spec = probe_evaluate_planar(float(i), pd, worldPosition, C_N, V, C_roughness, fade); accumulate_light(C_spec, fade, C_spec_accum); -#endif +# endif } } -#endif +# endif -#ifdef CLOSURE_GLOSSY +# ifdef CLOSURE_GLOSSY vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughnessSquared); -#endif +# endif -#ifdef CLOSURE_CLEARCOAT +# ifdef CLOSURE_CLEARCOAT vec3 C_spec_dir = get_specular_reflection_dominant_dir(C_N, V, C_roughnessSquared); -#endif +# endif -#ifdef CLOSURE_REFRACTION +# ifdef CLOSURE_REFRACTION /* Refract the view vector using the depth heuristic. * Then later Refract a second time the already refracted * ray using the inverse ior. */ @@ -337,14 +337,14 @@ void CLOSURE_NAME(vec3 N worldPosition, refr_V, worldPosition - N * refractionDepth, N) : worldPosition; vec3 refr_dir = get_specular_refraction_dominant_dir(N, refr_V, roughness, final_ior); -#endif +# endif -#ifdef CLOSURE_REFRACTION +# ifdef CLOSURE_REFRACTION /* ---------------------------- */ /* Screen Space Refraction */ /* ---------------------------- */ -#ifdef USE_REFRACTION - if (ssrToggle && roughness < ssrMaxRoughness + 0.2) { +# ifdef USE_REFRACTION + if (ssrefractToggle && roughness < ssrMaxRoughness + 0.2) { /* Find approximated position of the 2nd refraction event. */ vec3 refr_vpos = (refractionDepth > 0.0) ? transform_point(ViewMatrix, refr_pos) : viewPosition; @@ -352,25 +352,25 @@ void CLOSURE_NAME(vec3 N trans.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness); accumulate_light(trans.rgb, trans.a, refr_accum); } -#endif +# endif -#endif +# endif /* ---------------------------- */ /* Specular probes */ /* ---------------------------- */ -#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION) - -#if defined(CLOSURE_GLOSSY) && defined(CLOSURE_REFRACTION) -# define GLASS_ACCUM 1 -# define ACCUM min(refr_accum.a, spec_accum.a) -#elif defined(CLOSURE_REFRACTION) -# define GLASS_ACCUM 0 -# define ACCUM refr_accum.a -#else -# define GLASS_ACCUM 0 -# define ACCUM spec_accum.a -#endif +# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION) + +# if defined(CLOSURE_GLOSSY) && defined(CLOSURE_REFRACTION) +# define GLASS_ACCUM 1 +# define ACCUM min(refr_accum.a, spec_accum.a) +# elif defined(CLOSURE_REFRACTION) +# define GLASS_ACCUM 0 +# define ACCUM refr_accum.a +# else +# define GLASS_ACCUM 0 +# define ACCUM spec_accum.a +# endif /* Starts at 1 because 0 is world probe */ for (int i = 1; ACCUM < 0.999 && i < prbNumRenderCube && i < MAX_PROBE; ++i) { @@ -378,80 +378,80 @@ void CLOSURE_NAME(vec3 N if (fade > 0.0) { -#if GLASS_ACCUM +# if GLASS_ACCUM if (spec_accum.a < 0.999) { -#endif -#ifdef CLOSURE_GLOSSY +# endif +# ifdef CLOSURE_GLOSSY if (!(ssrToggle && ssr_id == outputSsrId)) { vec3 spec = probe_evaluate_cube(i, worldPosition, spec_dir, roughness); accumulate_light(spec, fade, spec_accum); } -#endif +# endif -#ifdef CLOSURE_CLEARCOAT +# ifdef CLOSURE_CLEARCOAT vec3 C_spec = probe_evaluate_cube(i, worldPosition, C_spec_dir, C_roughness); accumulate_light(C_spec, fade, C_spec_accum); -#endif -#if GLASS_ACCUM +# endif +# if GLASS_ACCUM } -#endif +# endif -#if GLASS_ACCUM +# if GLASS_ACCUM if (refr_accum.a < 0.999) { -#endif -#ifdef CLOSURE_REFRACTION +# endif +# ifdef CLOSURE_REFRACTION vec3 trans = probe_evaluate_cube(i, refr_pos, refr_dir, roughnessSquared); accumulate_light(trans, fade, refr_accum); -#endif -#if GLASS_ACCUM +# endif +# if GLASS_ACCUM } -#endif +# endif } } -#undef GLASS_ACCUM -#undef ACCUM +# undef GLASS_ACCUM +# undef ACCUM /* ---------------------------- */ /* World Probe */ /* ---------------------------- */ -#ifdef CLOSURE_GLOSSY +# ifdef CLOSURE_GLOSSY if (spec_accum.a < 0.999) { if (!(ssrToggle && ssr_id == outputSsrId)) { vec3 spec = probe_evaluate_world_spec(spec_dir, roughness); accumulate_light(spec, 1.0, spec_accum); } -# ifdef CLOSURE_CLEARCOAT +# ifdef CLOSURE_CLEARCOAT vec3 C_spec = probe_evaluate_world_spec(C_spec_dir, C_roughness); accumulate_light(C_spec, 1.0, C_spec_accum); -# endif +# endif } -#endif +# endif -#ifdef CLOSURE_REFRACTION +# ifdef CLOSURE_REFRACTION if (refr_accum.a < 0.999) { vec3 trans = probe_evaluate_world_spec(refr_dir, roughnessSquared); accumulate_light(trans, 1.0, refr_accum); } -#endif -#endif /* Specular probes */ +# endif +# endif /* Specular probes */ /* ---------------------------- */ /* Ambient Occlusion */ /* ---------------------------- */ -#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE) +# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE) /* HACK: Fix for translucent BSDF. (see T65631) */ bool same_side = dot((gl_FrontFacing) ? worldNormal : -worldNormal, N) > 0.0; vec3 bent_normal; float final_ao = occlusion_compute(same_side ? N : -N, viewPosition, ao, rand, bent_normal); -#endif +# endif /* ---------------------------- */ /* Specular Output */ /* ---------------------------- */ float NV = dot(N, V); -#ifdef CLOSURE_GLOSSY +# ifdef CLOSURE_GLOSSY vec2 uv = lut_coords(NV, roughness); vec2 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rg; @@ -466,15 +466,15 @@ void CLOSURE_NAME(vec3 N } out_spec += spec_accum.rgb * ssr_spec * spec_occlu; -#endif +# endif -#ifdef CLOSURE_REFRACTION +# ifdef CLOSURE_REFRACTION float btdf = get_btdf_lut(utilTex, NV, roughness, ior); out_refr += refr_accum.rgb * btdf; -#endif +# endif -#ifdef CLOSURE_CLEARCOAT +# ifdef CLOSURE_CLEARCOAT NV = dot(C_N, V); vec2 C_uv = lut_coords(NV, C_roughness); vec2 C_brdf_lut = texture(utilTex, vec3(C_uv, 1.0)).rg; @@ -482,19 +482,19 @@ void CLOSURE_NAME(vec3 N specular_occlusion(NV, final_ao, C_roughness); out_spec += C_spec_accum.rgb * C_fresnel * C_intensity; -#endif +# endif -#ifdef CLOSURE_GLOSSY +# ifdef CLOSURE_GLOSSY /* Global toggle for lightprobe baking. */ out_spec *= float(specToggle); -#endif +# endif /* ---------------------------------------------------------------- */ /* ---------------- DIFFUSE ENVIRONMENT LIGHTING ------------------ */ /* ---------------------------------------------------------------- */ /* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */ -#ifdef CLOSURE_DIFFUSE +# ifdef CLOSURE_DIFFUSE vec4 diff_accum = vec4(0.0); /* ---------------------------- */ @@ -522,6 +522,7 @@ void CLOSURE_NAME(vec3 N } out_diff += diff_accum.rgb * gtao_multibounce(final_ao, albedo); +# endif #endif } @@ -529,21 +530,21 @@ void CLOSURE_NAME(vec3 N #undef CLOSURE_NAME #ifdef CLOSURE_DIFFUSE -#undef CLOSURE_DIFFUSE +# undef CLOSURE_DIFFUSE #endif #ifdef CLOSURE_GLOSSY -#undef CLOSURE_GLOSSY +# undef CLOSURE_GLOSSY #endif #ifdef CLOSURE_CLEARCOAT -#undef CLOSURE_CLEARCOAT +# undef CLOSURE_CLEARCOAT #endif #ifdef CLOSURE_REFRACTION -#undef CLOSURE_REFRACTION +# undef CLOSURE_REFRACTION #endif #ifdef CLOSURE_SUBSURFACE -#undef CLOSURE_SUBSURFACE +# undef CLOSURE_SUBSURFACE #endif diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl index e756cafba52..acd1e58ff97 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl @@ -48,6 +48,10 @@ void main() float cell_depth = volume_z_to_view_z((float(i) + 1.0) / tex_size.z); float ray_len = orig_ray_len * cell_depth; + /* Emission does not work of there is no extinction because + * Tr evaluates to 1.0 leading to Lscat = 0.0. (See T65771) */ + s_extinction = max(vec3(1e-7) * step(1e-5, Lscat), s_extinction); + /* Evaluate Scattering */ float s_len = abs(ray_len - prev_ray_len); prev_ray_len = ray_len; diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_resolve_frag.glsl index 757eb59eaa1..1ff7e848c40 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_resolve_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_resolve_frag.glsl @@ -2,9 +2,7 @@ /* Based on Frosbite Unified Volumetric. * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */ -/* Step 4 : Apply final integration on top of the scene color. - * Note that we do the blending ourself instead of relying - * on hardware blending which would require 2 pass. */ +/* Step 4 : Apply final integration on top of the scene color. */ uniform sampler2D inSceneDepth; diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c index 97d2d3393a9..181d2efbabb 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c @@ -57,7 +57,7 @@ #define SOLID 0 #define GRADIENT 1 #define RADIAL 2 -#define CHESS 3 +#define CHECKER 3 #define TEXTURE 4 #define PATTERN 5 @@ -240,7 +240,7 @@ static void gpencil_recalc_geometry_caches(Object *ob, if (gps->flag & GP_STROKE_RECALC_GEOMETRY) { /* Calculate triangles cache for filling area (must be done only after changes) */ if ((gps->tot_triangles == 0) || (gps->triangles == NULL)) { - if ((gps->totpoints > 2) && + if ((gps->totpoints > 2) && (gp_style->flag & GP_STYLE_FILL_SHOW) && ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0) || (gpl->blend_mode != eGplBlendMode_Regular))) { gpencil_triangulate_stroke_fill(ob, gps); @@ -387,8 +387,8 @@ static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata, stl->shgroups[id].fill_style = RADIAL; } break; - case GP_STYLE_FILL_STYLE_CHESSBOARD: - stl->shgroups[id].fill_style = CHESS; + case GP_STYLE_FILL_STYLE_CHECKER: + stl->shgroups[id].fill_style = CHECKER; break; case GP_STYLE_FILL_STYLE_TEXTURE: if (gp_style->flag & GP_STYLE_FILL_PATTERN) { diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 646fb359836..408c9759682 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -789,8 +789,11 @@ static void gpencil_prepare_fast_drawing(GPENCIL_StorageList *stl, } } -static void gpencil_free_runtime_data(GPENCIL_StorageList *stl) +void DRW_gpencil_free_runtime_data(void *ved) { + GPENCIL_Data *vedata = (GPENCIL_Data *)ved; + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + /* free gpu data */ DRW_TEXTURE_FREE_SAFE(stl->g_data->gpencil_blank_texture); @@ -976,8 +979,6 @@ void GPENCIL_draw_scene(void *ved) /* if the draw is for select, do a basic drawing and return */ if (DRW_state_is_select() || DRW_state_is_depth()) { drw_gpencil_select_render(stl, psl); - /* free memory */ - gpencil_free_runtime_data(stl); return; } @@ -1010,7 +1011,7 @@ void GPENCIL_draw_scene(void *ved) } /* free memory */ - gpencil_free_runtime_data(stl); + DRW_gpencil_free_runtime_data(ved); return; } @@ -1161,7 +1162,7 @@ void GPENCIL_draw_scene(void *ved) } } /* free memory */ - gpencil_free_runtime_data(stl); + DRW_gpencil_free_runtime_data(ved); /* reset */ if (DRW_state_is_fbo()) { diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index ee1ba805fad..14615a19760 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -363,12 +363,12 @@ typedef struct GpencilBatchCacheElem { } GpencilBatchCacheElem; typedef struct GpencilBatchGroup { - bGPDlayer *gpl; /* reference to original layer */ - bGPDframe *gpf; /* reference to original frame */ - bGPDstroke *gps; /* reference to original stroke */ - short type; /* type of element */ - bool onion; /* the group is part of onion skin */ - int vertex_idx; /* index of vertex data */ + struct bGPDlayer *gpl; /* reference to original layer */ + struct bGPDframe *gpf; /* reference to original frame */ + struct bGPDstroke *gps; /* reference to original stroke */ + short type; /* type of element */ + bool onion; /* the group is part of onion skin */ + int vertex_idx; /* index of vertex data */ } GpencilBatchGroup; typedef enum GpencilBatchGroup_Type { @@ -511,6 +511,10 @@ void GPENCIL_render_to_image(void *vedata, struct RenderLayer *render_layer, const rcti *rect); +/* TODO: GPXX workaround function to call free memory from draw manager while draw manager support + * scene finish callback. */ +void DRW_gpencil_free_runtime_data(void *ved); + /* Use of multisample framebuffers. */ #define MULTISAMPLE_GP_SYNC_ENABLE(lvl, fbl) \ { \ diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c index faef95fe1a9..56ba90067cf 100644 --- a/source/blender/draw/engines/gpencil/gpencil_render.c +++ b/source/blender/draw/engines/gpencil/gpencil_render.c @@ -103,12 +103,9 @@ void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgra invert_m4_m4(viewmat, viewinv); - /* Reuse the view created by EEVEE or Workbench */ - if (DRW_view_default_get() == NULL) { - DRWView *view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); - DRW_view_default_set(view); - DRW_view_set_active(view); - } + DRWView *view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); + DRW_view_default_set(view); + DRW_view_set_active(view); DRW_view_persmat_get(NULL, persmat, false); diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl index 87bf116ff89..64bb70f2a3f 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl @@ -30,7 +30,7 @@ uniform vec4 wire_color; #define SOLID 0 #define GRADIENT 1 #define RADIAL 2 -#define CHESS 3 +#define CHECKER 3 #define TEXTURE 4 #define PATTERN 5 @@ -103,7 +103,7 @@ void main() texture_read_as_srgb( myTexture, myTexturePremultiplied, clamp(rot_tex * texture_scale, 0.0, 1.0)); vec4 text_color = vec4(tmp_color[0], tmp_color[1], tmp_color[2], tmp_color[3] * texture_opacity); - vec4 chesscolor; + vec4 checker_color; /* wireframe with x-ray discard */ if ((viewport_xray == 1) && (shading_type[0] == OB_WIRE)) { @@ -152,18 +152,18 @@ void main() texture_flip, fragColor); } - /* chessboard */ - if (fill_type == CHESS) { + /* Checkerboard */ + if (fill_type == CHECKER) { vec2 pos = rot / pattern_gridsize; if ((fract(pos.x) < 0.5 && fract(pos.y) < 0.5) || (fract(pos.x) > 0.5 && fract(pos.y) > 0.5)) { - chesscolor = (texture_flip == 0) ? finalColor : color2; + checker_color = (texture_flip == 0) ? finalColor : color2; } else { - chesscolor = (texture_flip == 0) ? color2 : finalColor; + checker_color = (texture_flip == 0) ? color2 : finalColor; } /* mix with texture */ - fragColor = (texture_mix == 1) ? mix(chesscolor, text_color, mix_factor) : chesscolor; + fragColor = (texture_mix == 1) ? mix(checker_color, text_color, mix_factor) : checker_color; fragColor.a *= layer_opacity; } /* texture */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl index 7872c1380ed..7eb12dbdeb9 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl @@ -2,14 +2,14 @@ #ifndef HAIR_SHADER in vec3 pos; in vec3 nor; -in vec2 u; /* active texture layer */ +in vec2 au; /* active texture layer */ # ifdef V3D_SHADING_VERTEX_COLOR -in vec3 c; /* active color */ +in vec3 ac; /* active color */ # endif -# define uv u +# define uv au #else /* HAIR_SHADER */ # ifdef V3D_SHADING_TEXTURE_COLOR -uniform samplerBuffer u; /* active texture layer */ +uniform samplerBuffer au; /* active texture layer */ # endif flat out float hair_rand; #endif /* HAIR_SHADER */ @@ -58,7 +58,7 @@ void main() { #ifdef HAIR_SHADER # ifdef V3D_SHADING_TEXTURE_COLOR - vec2 uv = hair_get_customdata_vec2(u); + vec2 uv = hair_get_customdata_vec2(au); # endif float time, thick_time, thickness; vec3 world_pos, tan, binor; @@ -86,7 +86,7 @@ void main() #ifdef V3D_SHADING_VERTEX_COLOR # ifndef HAIR_SHADER - vertexColor = srgb_to_linear_attr(c); + vertexColor = srgb_to_linear_attr(ac); # endif #endif diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl index 8ee70c37949..2c9190bfcf4 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl @@ -37,6 +37,7 @@ in VertexData vData[]; #define DEGENERATE_TRIS_WORKAROUND +#define DEGENERATE_TRIS_AREA_THRESHOLD 4e-17 #define len_sqr(a) dot(a, a) @@ -67,7 +68,7 @@ void main() #ifdef DEGENERATE_TRIS_WORKAROUND /* Check if area is null */ vec2 faces_area = vec2(len_sqr(n1), len_sqr(n2)); - bvec2 degen_faces = equal(abs(faces_area), vec2(0.0)); + bvec2 degen_faces = lessThan(abs(faces_area), vec2(DEGENERATE_TRIS_AREA_THRESHOLD)); /* Both triangles are degenerate, abort. */ if (all(degen_faces)) { diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 04e1255521f..743a1fc42b6 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -24,6 +24,8 @@ #include "DNA_userdef_types.h" +#include "ED_view3d.h" + #include "UI_resources.h" #include "GPU_batch.h" @@ -43,16 +45,14 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wpd->preferences = &U; View3D *v3d = draw_ctx->v3d; - if (!v3d) { - wpd->shading = scene->display.shading; - wpd->use_color_render_settings = true; - } - else if (v3d->shading.type == OB_RENDER && BKE_scene_uses_blender_workbench(scene)) { + if (!v3d || (v3d->shading.type == OB_RENDER && BKE_scene_uses_blender_workbench(scene))) { wpd->shading = scene->display.shading; + wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display)); wpd->use_color_render_settings = true; } else { wpd->shading = v3d->shading; + wpd->shading.xray_alpha = XRAY_ALPHA(v3d); wpd->use_color_render_settings = false; } diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index 49b84b41744..735a0dcf7a0 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -215,13 +215,16 @@ static GPUShader *workbench_cavity_shader_get(bool cavity, bool curvature) static GPUShader *ensure_deferred_prepass_shader(WORKBENCH_PrivateData *wpd, bool is_uniform_color, bool is_hair, + bool is_texture_painting, eGPUShaderConfig sh_cfg) { WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - int index = workbench_material_get_prepass_shader_index(wpd, is_uniform_color, is_hair); + int index = workbench_material_get_prepass_shader_index( + wpd, is_uniform_color, is_hair, is_texture_painting); if (sh_data->prepass_sh_cache[index] == NULL) { const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg]; - char *defines = workbench_material_build_defines(wpd, is_uniform_color, is_hair); + char *defines = workbench_material_build_defines( + wpd, is_uniform_color, is_hair, is_texture_painting); char *prepass_vert = workbench_build_prepass_vert(is_hair); char *prepass_frag = workbench_build_prepass_frag(); sh_data->prepass_sh_cache[index] = GPU_shader_create_from_arrays({ @@ -240,7 +243,7 @@ static GPUShader *ensure_deferred_composite_shader(WORKBENCH_PrivateData *wpd) { int index = workbench_material_get_composite_shader_index(wpd); if (e_data.composite_sh_cache[index] == NULL) { - char *defines = workbench_material_build_defines(wpd, false, false); + char *defines = workbench_material_build_defines(wpd, false, false, false); char *composite_frag = workbench_build_composite_frag(wpd); e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); MEM_freeN(composite_frag); @@ -267,10 +270,11 @@ static GPUShader *ensure_background_shader(WORKBENCH_PrivateData *wpd) static void select_deferred_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg) { - wpd->prepass_sh = ensure_deferred_prepass_shader(wpd, false, false, sh_cfg); - wpd->prepass_hair_sh = ensure_deferred_prepass_shader(wpd, false, true, sh_cfg); - wpd->prepass_uniform_sh = ensure_deferred_prepass_shader(wpd, true, false, sh_cfg); - wpd->prepass_uniform_hair_sh = ensure_deferred_prepass_shader(wpd, true, true, sh_cfg); + wpd->prepass_sh = ensure_deferred_prepass_shader(wpd, false, false, false, sh_cfg); + wpd->prepass_hair_sh = ensure_deferred_prepass_shader(wpd, false, true, false, sh_cfg); + wpd->prepass_uniform_sh = ensure_deferred_prepass_shader(wpd, true, false, false, sh_cfg); + wpd->prepass_uniform_hair_sh = ensure_deferred_prepass_shader(wpd, true, true, false, sh_cfg); + wpd->prepass_textured_sh = ensure_deferred_prepass_shader(wpd, false, false, true, sh_cfg); wpd->composite_sh = ensure_deferred_composite_shader(wpd); wpd->background_sh = ensure_background_shader(wpd); } @@ -451,6 +455,8 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) WORKBENCH_PrivateData *wpd = stl->g_data; workbench_private_data_init(wpd); + wpd->shading.xray_alpha = 1.0f; + workbench_dof_engine_init(vedata, camera); if (OIT_ENABLED(wpd)) { @@ -481,7 +487,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) e_data.composite_buffer_tx = DRW_texture_pool_query_2d( size[0], size[1], comp_tex_format, &draw_engine_workbench_solid); - if (MATDATA_PASS_ENABLED(wpd) || GPU_unused_fb_slot_workaround()) { + if (workbench_is_matdata_pass_enabled(wpd) || GPU_unused_fb_slot_workaround()) { e_data.color_buffer_tx = DRW_texture_pool_query_2d( size[0], size[1], col_tex_format, &draw_engine_workbench_solid); } @@ -521,7 +527,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx), }); - if (!MATDATA_PASS_ENABLED(wpd) && !GPU_unused_fb_slot_workaround()) { + if (!workbench_is_matdata_pass_enabled(wpd) && !GPU_unused_fb_slot_workaround()) { e_data.color_buffer_tx = DRW_texture_pool_query_2d( size[0], size[1], col_tex_format, &draw_engine_workbench_solid); } @@ -673,7 +679,7 @@ void workbench_deferred_engine_free(void) static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp) { DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - if (MATDATA_PASS_ENABLED(wpd)) { + if (workbench_is_matdata_pass_enabled(wpd)) { DRW_shgroup_uniform_texture_ref(grp, "materialBuffer", &e_data.color_buffer_tx); } else { @@ -712,7 +718,6 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata) Scene *scene = draw_ctx->scene; workbench_volume_cache_init(vedata); - select_deferred_shaders(wpd, draw_ctx->sh_cfg); /* Background Pass */ @@ -867,7 +872,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat const bool is_ghost = (ob->dtx & OB_DRAWXRAY); /* Solid */ - workbench_material_update_data(wpd, ob, mat, &material_template); + workbench_material_update_data(wpd, ob, mat, &material_template, color_type); material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1; material_template.color_type = color_type; material_template.ima = ima; @@ -878,9 +883,14 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat material = BLI_ghash_lookup(wpd->material_hash, POINTER_FROM_UINT(hash)); if (material == NULL) { material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__); + /* select the correct prepass shader */ + GPUShader *shader = (wpd->shading.color_type == color_type) ? wpd->prepass_sh : + wpd->prepass_uniform_sh; + if (color_type == V3D_SHADING_TEXTURE_COLOR) { + shader = wpd->prepass_textured_sh; + } material->shgrp = DRW_shgroup_create( - (wpd->shading.color_type == color_type) ? wpd->prepass_sh : wpd->prepass_uniform_sh, - (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass); + shader, (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass); workbench_material_copy(material, &material_template); DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF); DRW_shgroup_uniform_int(material->shgrp, "object_id", &material->object_id, 1); @@ -933,6 +943,49 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o } } +static void workbench_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata, Object *ob) +{ + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_PrivateData *wpd = stl->g_data; + const DRWContextState *draw_ctx = DRW_context_state_get(); + + Scene *scene = draw_ctx->scene; + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); + WORKBENCH_MaterialData *material; + + /* Force workbench to render active object textured when in texture paint mode */ + const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; + + /* Single Image mode */ + if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) { + Image *image = imapaint->canvas; + int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : + SHD_INTERP_CLOSEST; + int color_type = workbench_material_determine_color_type(wpd, image, ob, use_sculpt_pbvh); + struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); + material = get_or_create_material_data(vedata, ob, NULL, image, NULL, color_type, interp); + + DRW_shgroup_call(material->shgrp, geom, ob); + } + else { + /* IMAGEPAINT_MODE_MATERIAL */ + const int materials_len = MAX2(1, ob->totcol); + struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); + for (int i = 0; i < materials_len; i++) { + if (geom_array != NULL && geom_array[i] != NULL) { + Material *mat; + Image *image; + ImageUser *iuser; + int interp; + workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); + int color_type = workbench_material_determine_color_type(wpd, image, ob, use_sculpt_pbvh); + material = get_or_create_material_data(vedata, ob, mat, image, iuser, color_type, interp); + DRW_shgroup_call(material->shgrp, geom_array[i], ob); + } + } + } +} + void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) { WORKBENCH_StorageList *stl = vedata->stl; @@ -961,7 +1014,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { return; } - if ((ob->dt < OB_SOLID) && !DRW_state_is_image_render()) { + if ((ob->dt < OB_SOLID) && !DRW_state_is_scene_render()) { return; } @@ -973,8 +1026,15 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) const int materials_len = MAX2(1, ob->totcol); const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; bool has_transp_mat = false; + const bool use_texture_paint_drawing = !(DRW_state_is_image_render() && + draw_ctx->v3d == NULL) && + workbench_is_object_in_texture_paint_mode(ob) && me && + me->mloopuv; - if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { + if (use_texture_paint_drawing) { + workbench_cache_populate_texture_paint_mode(vedata, ob); + } + else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { /* Draw textured */ struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); for (int i = 0; i < materials_len; i++) { @@ -987,10 +1047,8 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) int color_type = workbench_material_determine_color_type( wpd, image, ob, use_sculpt_pbvh); if (color_type == V3D_SHADING_MATERIAL_COLOR && mat && mat->a < 1.0) { - /* Hack */ - wpd->shading.xray_alpha = mat->a; material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, 0, use_sculpt_pbvh); + vedata, ob, mat, image, iuser, color_type, 0); has_transp_mat = true; } else { @@ -1009,10 +1067,8 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) int color_type = workbench_material_determine_color_type(wpd, NULL, ob, use_sculpt_pbvh); if ((ob->color[3] < 1.0f) && (color_type == V3D_SHADING_OBJECT_COLOR)) { - /* Hack */ - wpd->shading.xray_alpha = ob->color[3]; material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, NULL, NULL, color_type, 0, use_sculpt_pbvh); + vedata, ob, NULL, NULL, NULL, color_type, 0); has_transp_mat = true; } else { @@ -1046,10 +1102,8 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) for (int i = 0; i < materials_len; ++i) { struct Material *mat = give_current_material(ob, i + 1); if (mat != NULL && mat->a < 1.0f) { - /* Hack */ - wpd->shading.xray_alpha = mat->a; material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, use_sculpt_pbvh); + vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); has_transp_mat = true; } else { @@ -1071,10 +1125,8 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) if (geoms != NULL && geoms[i] != NULL) { Material *mat = give_current_material(ob, i + 1); if (mat != NULL && mat->a < 1.0f) { - /* Hack */ - wpd->shading.xray_alpha = mat->a; material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, use_sculpt_pbvh); + vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); has_transp_mat = true; } else { diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c index 69d0500f155..22840a2a756 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_dof.c +++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c @@ -173,7 +173,7 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera) } const float *full_size = DRW_viewport_size_get(); - int size[2] = {full_size[0] / 2, full_size[1] / 2}; + int size[2] = {max_ii(1, (int)full_size[0] / 2), max_ii(1, (int)full_size[1] / 2)}; #if 0 /* NOTE: We Ceil here in order to not miss any edge texel if using a NPO2 texture. */ int shrink_h_size[2] = {ceilf(size[0] / 8.0f), size[1]}; diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c index 612a3901ca0..4c1fce550e8 100644 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ b/source/blender/draw/engines/workbench/workbench_forward.c @@ -141,8 +141,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ Image *ima, ImageUser *iuser, int color_type, - int interp, - bool use_sculpt_pbvh) + int interp) { const DRWContextState *draw_ctx = DRW_context_state_get(); WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; @@ -160,7 +159,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ DRWShadingGroup *grp; /* Solid */ - workbench_material_update_data(wpd, ob, mat, &material_template); + workbench_material_update_data(wpd, ob, mat, &material_template, color_type); material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1; material_template.color_type = color_type; material_template.ima = ima; @@ -173,12 +172,17 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__); /* transparent accum */ - grp = DRW_shgroup_create(wpd->shading.color_type == color_type ? - wpd->transparent_accum_sh : - wpd->transparent_accum_uniform_sh, - psl->transparent_accum_pass); + /* select the correct transparent accum shader */ + GPUShader *shader = (wpd->shading.color_type == color_type) ? + wpd->transparent_accum_sh : + wpd->transparent_accum_uniform_sh; + if (color_type == V3D_SHADING_TEXTURE_COLOR) { + shader = wpd->transparent_accum_textured_sh; + } + + grp = DRW_shgroup_create(shader, psl->transparent_accum_pass); DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", wpd->shading.xray_alpha); + DRW_shgroup_uniform_float_copy(grp, "alpha", material_template.alpha); DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); workbench_material_copy(material, &material_template); if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { @@ -199,8 +203,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ material->shgrp = grp; /* Depth */ - if (workbench_material_determine_color_type(wpd, material->ima, ob, use_sculpt_pbvh) == - V3D_SHADING_TEXTURE_COLOR) { + if (color_type == V3D_SHADING_TEXTURE_COLOR) { material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_texture_sh, psl->object_outline_pass); GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D); @@ -223,13 +226,16 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ static GPUShader *ensure_forward_accum_shaders(WORKBENCH_PrivateData *wpd, bool is_uniform_color, bool is_hair, + bool is_texture_painting, eGPUShaderConfig sh_cfg) { WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - int index = workbench_material_get_accum_shader_index(wpd, is_uniform_color, is_hair); + int index = workbench_material_get_accum_shader_index( + wpd, is_uniform_color, is_hair, is_texture_painting); if (sh_data->transparent_accum_sh_cache[index] == NULL) { const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg]; - char *defines = workbench_material_build_defines(wpd, is_uniform_color, is_hair); + char *defines = workbench_material_build_defines( + wpd, is_uniform_color, is_hair, is_texture_painting); char *transparent_accum_vert = workbench_build_forward_vert(is_hair); char *transparent_accum_frag = workbench_build_forward_transparent_accum_frag(); sh_data->transparent_accum_sh_cache[index] = GPU_shader_create_from_arrays({ @@ -248,7 +254,7 @@ static GPUShader *ensure_forward_composite_shaders(WORKBENCH_PrivateData *wpd) { int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0; if (e_data.composite_sh_cache[index] == NULL) { - char *defines = workbench_material_build_defines(wpd, false, false); + char *defines = workbench_material_build_defines(wpd, false, false, false); char *composite_frag = workbench_build_forward_composite_frag(); e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); MEM_freeN(composite_frag); @@ -260,10 +266,14 @@ static GPUShader *ensure_forward_composite_shaders(WORKBENCH_PrivateData *wpd) void workbench_forward_choose_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg) { wpd->composite_sh = ensure_forward_composite_shaders(wpd); - wpd->transparent_accum_sh = ensure_forward_accum_shaders(wpd, false, false, sh_cfg); - wpd->transparent_accum_hair_sh = ensure_forward_accum_shaders(wpd, false, true, sh_cfg); - wpd->transparent_accum_uniform_sh = ensure_forward_accum_shaders(wpd, true, false, sh_cfg); - wpd->transparent_accum_uniform_hair_sh = ensure_forward_accum_shaders(wpd, true, true, sh_cfg); + wpd->transparent_accum_sh = ensure_forward_accum_shaders(wpd, false, false, false, sh_cfg); + wpd->transparent_accum_hair_sh = ensure_forward_accum_shaders(wpd, false, true, false, sh_cfg); + wpd->transparent_accum_uniform_sh = ensure_forward_accum_shaders( + wpd, true, false, false, sh_cfg); + wpd->transparent_accum_uniform_hair_sh = ensure_forward_accum_shaders( + wpd, true, true, false, sh_cfg); + wpd->transparent_accum_textured_sh = ensure_forward_accum_shaders( + wpd, false, false, true, sh_cfg); } void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg) @@ -272,9 +282,9 @@ void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUSh if (sh_data->object_outline_sh == NULL) { const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg]; - char *defines = workbench_material_build_defines(wpd, false, false); - char *defines_texture = workbench_material_build_defines(wpd, true, false); - char *defines_hair = workbench_material_build_defines(wpd, false, true); + char *defines = workbench_material_build_defines(wpd, false, false, false); + char *defines_texture = workbench_material_build_defines(wpd, true, false, false); + char *defines_hair = workbench_material_build_defines(wpd, false, true, false); char *forward_vert = workbench_build_forward_vert(false); char *forward_hair_vert = workbench_build_forward_vert(true); @@ -503,7 +513,7 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O workbench_material_get_image_and_mat(ob, part->omat, &image, &iuser, &interp, &mat); int color_type = workbench_material_determine_color_type(wpd, image, ob, false); WORKBENCH_MaterialData *material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp, false); + vedata, ob, mat, image, iuser, color_type, interp); struct GPUShader *shader = (wpd->shading.color_type == color_type) ? wpd->transparent_accum_hair_sh : @@ -533,6 +543,53 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O } } } +static void workbench_forward_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata, Object *ob) +{ + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_PrivateData *wpd = stl->g_data; + const DRWContextState *draw_ctx = DRW_context_state_get(); + + Scene *scene = draw_ctx->scene; + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); + WORKBENCH_MaterialData *material; + + /* Force workbench to render active object textured when in texture paint mode */ + const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; + + /* Single Image mode */ + if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) { + Image *image = imapaint->canvas; + int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : + SHD_INTERP_CLOSEST; + int color_type = workbench_material_determine_color_type(wpd, image, ob, use_sculpt_pbvh); + struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); + material = workbench_forward_get_or_create_material_data( + vedata, ob, NULL, image, NULL, color_type, interp); + + DRW_shgroup_call(material->shgrp, geom, ob); + DRW_shgroup_call(material->shgrp_object_outline, geom, ob); + } + else { + /* IMAGEPAINT_MODE_MATERIAL */ + const int materials_len = MAX2(1, ob->totcol); + struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); + for (int i = 0; i < materials_len; i++) { + if (geom_array != NULL && geom_array[i] != NULL) { + Material *mat; + Image *image; + ImageUser *iuser; + int interp; + workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); + int color_type = workbench_material_determine_color_type(wpd, image, ob, use_sculpt_pbvh); + material = workbench_forward_get_or_create_material_data( + vedata, ob, mat, image, iuser, color_type, interp); + + DRW_shgroup_call(material->shgrp, geom_array[i], ob); + DRW_shgroup_call(material->shgrp_object_outline, geom_array[i], ob); + } + } + } +} void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) { @@ -571,8 +628,15 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); const int materials_len = MAX2(1, ob->totcol); const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; + const bool use_texture_paint_drawing = !(DRW_state_is_image_render() && + draw_ctx->v3d == NULL) && + workbench_is_object_in_texture_paint_mode(ob) && me && + me->mloopuv; - if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { + if (use_texture_paint_drawing) { + workbench_forward_cache_populate_texture_paint_mode(vedata, ob); + } + else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); for (int i = 0; i < materials_len; i++) { Material *mat; @@ -582,7 +646,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); int color_type = workbench_material_determine_color_type(wpd, image, ob, use_sculpt_pbvh); material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp, use_sculpt_pbvh); + vedata, ob, mat, image, iuser, color_type, interp); DRW_shgroup_call(material->shgrp_object_outline, geom_array[i], ob); DRW_shgroup_call(material->shgrp, geom_array[i], ob); } @@ -597,7 +661,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) if (use_sculpt_pbvh) { material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, NULL, NULL, color_type, 0, use_sculpt_pbvh); + vedata, ob, NULL, NULL, NULL, color_type, 0); bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR); /* TODO(fclem) make this call optional */ DRW_shgroup_call_sculpt(material->shgrp_object_outline, ob, false, false, false); @@ -611,7 +675,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) DRW_cache_object_surface_get(ob); if (geom) { material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, NULL, NULL, color_type, 0, use_sculpt_pbvh); + vedata, ob, NULL, NULL, NULL, color_type, 0); /* TODO(fclem) make this call optional */ DRW_shgroup_call(material->shgrp_object_outline, geom, ob); if (!is_wire) { @@ -628,7 +692,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) for (int i = 0; i < materials_len; ++i) { struct Material *mat = give_current_material(ob, i + 1); material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, use_sculpt_pbvh); + vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); shgrps[i] = material->shgrp; } /* TODO(fclem) make this call optional */ @@ -651,7 +715,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) Material *mat = give_current_material(ob, i + 1); material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, use_sculpt_pbvh); + vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); /* TODO(fclem) make this call optional */ DRW_shgroup_call(material->shgrp_object_outline, mat_geom[i], ob); if (!is_wire) { diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index d570fda9dac..6699a1954ba 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -41,23 +41,24 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, - WORKBENCH_MaterialData *data) + WORKBENCH_MaterialData *data, + int color_type) { - /* When V3D_SHADING_TEXTURE_COLOR is active, use V3D_SHADING_MATERIAL_COLOR as fallback when no - * texture could be determined */ - int color_type = wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR ? - V3D_SHADING_MATERIAL_COLOR : - wpd->shading.color_type; copy_v3_fl3(data->diffuse_color, 0.8f, 0.8f, 0.8f); copy_v3_v3(data->base_color, data->diffuse_color); copy_v3_fl3(data->specular_color, 0.05f, 0.05f, 0.05f); /* Dielectric: 5% reflective. */ data->metallic = 0.0f; data->roughness = 0.632455532f; /* sqrtf(0.4f); */ + data->alpha = wpd->shading.xray_alpha; if (color_type == V3D_SHADING_SINGLE_COLOR) { copy_v3_v3(data->diffuse_color, wpd->shading.single_color); copy_v3_v3(data->base_color, data->diffuse_color); } + else if (color_type == V3D_SHADING_ERROR_COLOR) { + copy_v3_fl3(data->diffuse_color, 0.8, 0.0, 0.8); + copy_v3_v3(data->base_color, data->diffuse_color); + } else if (color_type == V3D_SHADING_RANDOM_COLOR) { uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name); if (ob->id.lib) { @@ -72,10 +73,12 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd, else if (ELEM(color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_VERTEX_COLOR)) { copy_v3_v3(data->diffuse_color, ob->color); copy_v3_v3(data->base_color, data->diffuse_color); + data->alpha *= ob->color[3]; } else { - /* V3D_SHADING_MATERIAL_COLOR */ + /* V3D_SHADING_MATERIAL_COLOR or V3D_SHADING_TEXTURE_COLOR */ if (mat) { + data->alpha *= mat->a; if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) { copy_v3_v3(data->base_color, &mat->r); mul_v3_v3fl(data->diffuse_color, &mat->r, 1.0f - mat->metallic); @@ -94,13 +97,19 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd, char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool is_uniform_color, - bool is_hair) + bool is_hair, + bool is_texture_painting) { char *str = NULL; bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color; bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) && !is_uniform_color; + if (is_texture_painting) { + use_textures = true; + use_vertex_colors = false; + } + DynStr *ds = BLI_dynstr_new(); if (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) { @@ -127,7 +136,7 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, if (OBJECT_ID_PASS_ENABLED(wpd)) { BLI_dynstr_append(ds, "#define OBJECT_ID_PASS_ENABLED\n"); } - if (MATDATA_PASS_ENABLED(wpd)) { + if (workbench_is_matdata_pass_enabled(wpd)) { BLI_dynstr_append(ds, "#define MATDATA_PASS_ENABLED\n"); } if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) { @@ -169,6 +178,7 @@ uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool input[3] = (uint)(material_template->roughness * 512); result += BLI_ghashutil_uinthash_v4_murmur(input); + result += BLI_ghashutil_uinthash((uint)(material_template->alpha * 512)); result += BLI_ghashutil_uinthash((uint)is_ghost); result += BLI_ghashutil_uinthash(material_template->color_type); @@ -189,22 +199,27 @@ int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd) SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 2); SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 3); SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 4); - SET_FLAG_FROM_TEST(index, MATDATA_PASS_ENABLED(wpd), 1 << 5); + SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 5); BLI_assert(index < MAX_COMPOSITE_SHADERS); return index; } int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd, bool is_uniform_color, - bool is_hair) + bool is_hair, + bool is_texture_painting) { bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color; bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) && !is_uniform_color; + if (is_texture_painting) { + use_textures = true; + use_vertex_colors = false; + } /* NOTE: change MAX_PREPASS_SHADERS accordingly when modifying this function. */ int index = 0; SET_FLAG_FROM_TEST(index, is_hair, 1 << 0); - SET_FLAG_FROM_TEST(index, MATDATA_PASS_ENABLED(wpd), 1 << 1); + SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 1); SET_FLAG_FROM_TEST(index, OBJECT_ID_PASS_ENABLED(wpd), 1 << 2); SET_FLAG_FROM_TEST(index, NORMAL_VIEWPORT_PASS_ENABLED(wpd), 1 << 3); SET_FLAG_FROM_TEST(index, MATCAP_ENABLED(wpd), 1 << 4); @@ -216,11 +231,18 @@ int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd, int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd, bool is_uniform_color, - bool is_hair) + bool is_hair, + bool is_texture_painting) { bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color; bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) && !is_uniform_color; + if (is_texture_painting) { + use_textures = true; + use_vertex_colors = false; + is_hair = false; + } + /* NOTE: change MAX_ACCUM_SHADERS accordingly when modifying this function. */ int index = 0; /* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */ @@ -249,6 +271,13 @@ int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, if (color_type == V3D_SHADING_VERTEX_COLOR && (me == NULL || me->mloopcol == NULL)) { color_type = V3D_SHADING_OBJECT_COLOR; } + + /* Force V3D_SHADING_TEXTURE_COLOR for active object when in texture painting + * no matter the shading color that the user has chosen, when there is no + * texture we will render the object with the error color */ + if (workbench_is_object_in_texture_paint_mode(ob)) { + color_type = ima ? V3D_SHADING_TEXTURE_COLOR : V3D_SHADING_ERROR_COLOR; + } return color_type; } @@ -288,33 +317,31 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd, const bool deferred, const int interp) { - if (deferred && !MATDATA_PASS_ENABLED(wpd)) { - return; - } - - if (workbench_material_determine_color_type(wpd, material->ima, ob, false) == - V3D_SHADING_TEXTURE_COLOR) { - GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D); - DRW_shgroup_uniform_texture(grp, "image", tex); - DRW_shgroup_uniform_bool_copy( - grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL)); - DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST)); - } - else { - DRW_shgroup_uniform_vec3(grp, - "materialDiffuseColor", - (use_metallic) ? material->base_color : material->diffuse_color, - 1); - } - - if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) { - if (use_metallic) { - DRW_shgroup_uniform_float(grp, "materialMetallic", &material->metallic, 1); + if (!deferred || workbench_is_matdata_pass_enabled(wpd)) { + if (workbench_material_determine_color_type(wpd, material->ima, ob, false) == + V3D_SHADING_TEXTURE_COLOR) { + GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D); + DRW_shgroup_uniform_texture(grp, "image", tex); + DRW_shgroup_uniform_bool_copy( + grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL)); + DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST)); } else { - DRW_shgroup_uniform_vec3(grp, "materialSpecularColor", material->specular_color, 1); + DRW_shgroup_uniform_vec3(grp, + "materialDiffuseColor", + (use_metallic) ? material->base_color : material->diffuse_color, + 1); + } + + if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) { + if (use_metallic) { + DRW_shgroup_uniform_float(grp, "materialMetallic", &material->metallic, 1); + } + else { + DRW_shgroup_uniform_vec3(grp, "materialSpecularColor", material->specular_color, 1); + } + DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1); } - DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1); } if (WORLD_CLIPPING_ENABLED(wpd)) { diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 34196c6aa04..17144c4dc10 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -43,6 +43,7 @@ #define TEXTURE_DRAWING_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) #define VERTEX_COLORS_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) +#define MATERIAL_COLORS_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_MATERIAL_COLOR) #define FLAT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_FLAT) #define STUDIOLIGHT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_STUDIO) #define MATCAP_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_MATCAP) @@ -81,8 +82,6 @@ (!STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd))) #define OBJECT_OUTLINE_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) #define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) -#define MATDATA_PASS_ENABLED(wpd) \ - (wpd->shading.color_type != V3D_SHADING_SINGLE_COLOR || MATCAP_ENABLED(wpd)) #define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) \ (MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd)) #define NORMAL_VIEWPORT_PASS_ENABLED(wpd) \ @@ -208,12 +207,14 @@ typedef struct WORKBENCH_PrivateData { struct GPUShader *prepass_hair_sh; struct GPUShader *prepass_uniform_sh; struct GPUShader *prepass_uniform_hair_sh; + struct GPUShader *prepass_textured_sh; struct GPUShader *composite_sh; struct GPUShader *background_sh; struct GPUShader *transparent_accum_sh; struct GPUShader *transparent_accum_hair_sh; struct GPUShader *transparent_accum_uniform_sh; struct GPUShader *transparent_accum_uniform_hair_sh; + struct GPUShader *transparent_accum_textured_sh; View3DShading shading; StudioLight *studio_light; const UserDef *preferences; @@ -286,6 +287,7 @@ typedef struct WORKBENCH_MaterialData { float base_color[3]; float diffuse_color[3]; float specular_color[3]; + float alpha; float metallic; float roughness; int object_id; @@ -353,6 +355,32 @@ BLI_INLINE bool workbench_is_fxaa_enabled(WORKBENCH_PrivateData *wpd) } } +/** Is texture paint mode enabled (globally) */ +BLI_INLINE bool workbench_is_in_texture_paint_mode(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + return draw_ctx->object_mode == OB_MODE_TEXTURE_PAINT; +} + +/** Is texture paint mode active for the given object */ +BLI_INLINE bool workbench_is_object_in_texture_paint_mode(Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + if (ob->type == OB_MESH && (draw_ctx->obact == ob)) { + const enum eContextObjectMode mode = CTX_data_mode_enum_ex( + draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode); + return (mode == CTX_MODE_PAINT_TEXTURE); + } + + return false; +} + +BLI_INLINE bool workbench_is_matdata_pass_enabled(WORKBENCH_PrivateData *wpd) +{ + return (wpd->shading.color_type != V3D_SHADING_SINGLE_COLOR || MATCAP_ENABLED(wpd)) || + workbench_is_in_texture_paint_mode(); +} + /* workbench_deferred.c */ void workbench_deferred_engine_init(WORKBENCH_Data *vedata); void workbench_deferred_engine_free(void); @@ -382,8 +410,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ Image *ima, ImageUser *iuser, int color_type, - int interp, - bool use_sculpt_pbvh); + int interp); /* workbench_effect_aa.c */ void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx); @@ -421,19 +448,23 @@ void workbench_material_get_image_and_mat( Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp, Material **r_mat); char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool is_uniform_color, - bool is_hair); + bool is_hair, + bool is_texture_painting); void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, - WORKBENCH_MaterialData *data); + WORKBENCH_MaterialData *data, + int color_type); uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost); int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd); int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd, bool is_uniform_color, - bool is_hair); + bool is_hair, + bool is_texture_painting); int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd, bool is_uniform_color, - bool is_hair); + bool is_hair, + bool is_texture_painting); void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp, WORKBENCH_MaterialData *material, diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index 4f387de16a8..30e51333f0f 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -883,7 +883,7 @@ static void update_color(const Object *ob, const float const_color[4]) #define NO_ALPHA(c) (((c)[3] = 1.0f), (c)) UI_GetThemeColor3fv(TH_SELECT, NO_ALPHA(g_theme.select_color)); - UI_GetThemeColor3fv(TH_EDGE_SELECT, NO_ALPHA(g_theme.edge_select_color)); + UI_GetThemeColorShade3fv(TH_EDGE_SELECT, 60, NO_ALPHA(g_theme.edge_select_color)); UI_GetThemeColorShade3fv(TH_EDGE_SELECT, -20, NO_ALPHA(g_theme.bone_select_color)); UI_GetThemeColor3fv(TH_WIRE, NO_ALPHA(g_theme.wire_color)); UI_GetThemeColor3fv(TH_WIRE_EDIT, NO_ALPHA(g_theme.wire_edit_color)); @@ -1886,19 +1886,23 @@ static void draw_armature_edit(Object *ob) { const DRWContextState *draw_ctx = DRW_context_state_get(); EditBone *eBone; - bArmature *arm = ob->data; int index; const bool is_select = DRW_state_is_select(); - update_color(ob, NULL); - edbo_compute_bbone_child(arm); - const bool show_text = DRW_state_show_text(); const bool show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0); - const Object *orig_object = DEG_get_original_object(ob); + const Object *ob_orig = DEG_get_original_object(ob); + /* FIXME(campbell): We should be able to use the CoW object, + * however the active bone isn't updated. Long term solution is an 'EditArmature' struct. + * for now we can draw from the original armature. See: T66773. */ + // bArmature *arm = ob->data; + bArmature *arm = ob_orig->data; - for (eBone = arm->edbo->first, index = orig_object->runtime.select_id; eBone; + update_color(ob, NULL); + edbo_compute_bbone_child(arm); + + for (eBone = arm->edbo->first, index = ob_orig->runtime.select_id; eBone; eBone = eBone->next, index += 0x10000) { if (eBone->layer & arm->layer) { if ((eBone->flag & BONE_HIDDEN_A) == 0) { @@ -1974,6 +1978,7 @@ static void draw_armature_edit(Object *ob) static void draw_armature_pose(Object *ob, const float const_color[4]) { const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; bArmature *arm = ob->data; bPoseChannel *pchan; int index = -1; @@ -1986,19 +1991,35 @@ static void draw_armature_pose(Object *ob, const float const_color[4]) return; } - // if (!(base->flag & OB_FROMDUPLI)) // TODO - { + bool is_pose_select = false; + /* Object can be edited in the scene. */ + if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) { if ((draw_ctx->object_mode & OB_MODE_POSE) || (ob == draw_ctx->object_pose)) { arm->flag |= ARM_POSEMODE; } + is_pose_select = + /* If we're in pose-mode or object-mode with the ability to enter pose mode. */ + ( + /* Draw as if in pose mode (when selection is possible). */ + (arm->flag & ARM_POSEMODE) || + /* When we're in object mode, which may select bones. */ + ((ob->mode & OB_MODE_POSE) && + ( + /* Switch from object mode when object lock is disabled. */ + ((draw_ctx->object_mode == OB_MODE_OBJECT) && + (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) || + /* Allow selection when in weight-paint mode + * (selection code ensures this wont become active). */ + ((draw_ctx->object_mode == OB_MODE_WEIGHT_PAINT) && + (draw_ctx->object_pose != NULL))))) && + DRW_state_is_select(); - if (arm->flag & ARM_POSEMODE) { - const Object *orig_object = DEG_get_original_object(ob); - index = orig_object->runtime.select_id; + if (is_pose_select) { + const Object *ob_orig = DEG_get_original_object(ob); + index = ob_orig->runtime.select_id; } } - const bool is_pose_select = (arm->flag & ARM_POSEMODE) && DRW_state_is_select(); const bool show_text = DRW_state_show_text(); const bool show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0); diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 88125e884d5..e2e98a2db5a 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -3016,7 +3016,7 @@ GPUBatch *DRW_cache_bone_dof_sphere_get(void) pz = z; } } - /* TODO alloc right count from the begining. */ + /* TODO allocate right count from the beginning. */ GPU_vertbuf_data_resize(vbo, v); SHC.drw_bone_dof_sphere = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO); @@ -4037,7 +4037,7 @@ void drw_batch_cache_generate_requested(Object *ob) const enum eContextObjectMode mode = CTX_data_mode_enum_ex( draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode); const bool is_paint_mode = ELEM( - mode, CTX_MODE_PAINT_TEXTURE, CTX_MODE_PAINT_VERTEX, CTX_MODE_PAINT_WEIGHT); + mode, CTX_MODE_SCULPT, CTX_MODE_PAINT_TEXTURE, CTX_MODE_PAINT_VERTEX, CTX_MODE_PAINT_WEIGHT); const bool use_hide = ((ob->type == OB_MESH) && ((is_paint_mode && (ob == draw_ctx->obact) && diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c index 1d6f2aaa070..75c498dfd88 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.c +++ b/source/blender/draw/intern/draw_cache_impl_curve.c @@ -791,7 +791,7 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata, } else if (bp) { int pt_len = nu->pntsu * nu->pntsv; - for (int a = 0; a < pt_len; a++, bp++) { + for (int a = 0; a < pt_len; a++, bp++, vbo_len_used += 1) { if (bp->hide == true) { continue; } @@ -819,7 +819,6 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata, if (vbo_pos) { GPU_vertbuf_attr_set(vbo_pos, attr_id.pos, vbo_len_used, bp->vec); } - vbo_len_used += 1; } } } diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index f4acb586c5e..306031809d1 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -25,6 +25,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_bitmap.h" #include "BLI_buffer.h" #include "BLI_utildefines.h" #include "BLI_math_vector.h" @@ -46,6 +47,7 @@ #include "BKE_mesh.h" #include "BKE_mesh_tangent.h" #include "BKE_mesh_runtime.h" +#include "BKE_modifier.h" #include "BKE_object_deform.h" #include "atomic_ops.h" @@ -244,17 +246,21 @@ typedef struct MeshRenderData { struct { struct { MLoopUV **uv; + MLoopCol **vcol; + float (**tangent)[4]; + int uv_len; int uv_active; + int uv_render; int uv_mask_active; - MLoopCol **vcol; int vcol_len; int vcol_active; + int vcol_render; - float (**tangent)[4]; int tangent_len; int tangent_active; + int tangent_render; bool *auto_vcol; } layers; @@ -469,7 +475,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, case CD_MTFACE: { if (layer == -1) { layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name) : - CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); + CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); } if (layer != -1) { cd_used.uv |= (1 << layer); @@ -479,11 +485,11 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, case CD_TANGENT: { if (layer == -1) { layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name) : - CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); + CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); /* Only fallback to orco (below) when we have no UV layers, see: T56545 */ if (layer == -1 && name[0] != '\0') { - layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); + layer = CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); } } if (layer != -1) { @@ -499,7 +505,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, case CD_MCOL: { if (layer == -1) { layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name) : - CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL); + CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL); } if (layer != -1) { cd_used.vcol |= (1 << layer); @@ -883,9 +889,12 @@ static MeshRenderData *mesh_render_data_create_ex(Mesh *me, } rdata->cd.layers.uv_active = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); + rdata->cd.layers.uv_render = CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); rdata->cd.layers.uv_mask_active = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV); rdata->cd.layers.vcol_active = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL); + rdata->cd.layers.vcol_render = CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL); rdata->cd.layers.tangent_active = rdata->cd.layers.uv_active; + rdata->cd.layers.tangent_render = rdata->cd.layers.uv_render; #define CD_VALIDATE_ACTIVE_LAYER(active_index, used) \ if ((active_index != -1) && (used & (1 << active_index)) == 0) { \ @@ -894,9 +903,12 @@ static MeshRenderData *mesh_render_data_create_ex(Mesh *me, ((void)0) CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.uv_active, cd_used->uv); + CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.uv_render, cd_used->uv); CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.uv_mask_active, cd_used->uv); CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.tangent_active, cd_used->tan); + CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.tangent_render, cd_used->tan); CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.vcol_active, cd_used->vcol); + CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.vcol_render, cd_used->vcol); #undef CD_VALIDATE_ACTIVE_LAYER @@ -980,6 +992,7 @@ static MeshRenderData *mesh_render_data_create_ex(Mesh *me, * NOTE 2 : Replicate changes to code_generate_vertex_new() in gpu_codegen.c */ if (rdata->cd.layers.vcol_len != 0) { int act_vcol = rdata->cd.layers.vcol_active; + int ren_vcol = rdata->cd.layers.vcol_render; for (int i_src = 0, i_dst = 0; i_src < cd_layers_src.vcol_len; i_src++, i_dst++) { if ((cd_used->vcol & (1 << i_src)) == 0) { /* This is a non-used VCol slot. Skip. */ @@ -987,6 +1000,9 @@ static MeshRenderData *mesh_render_data_create_ex(Mesh *me, if (rdata->cd.layers.vcol_active >= i_src) { act_vcol--; } + if (rdata->cd.layers.vcol_render >= i_src) { + ren_vcol--; + } } else { const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i_src); @@ -1009,10 +1025,13 @@ static MeshRenderData *mesh_render_data_create_ex(Mesh *me, } } } + /* Actual active Vcol slot inside vcol layers used for shading. */ if (rdata->cd.layers.vcol_active != -1) { - /* Actual active Vcol slot inside vcol layers used for shading. */ rdata->cd.layers.vcol_active = act_vcol; } + if (rdata->cd.layers.vcol_render != -1) { + rdata->cd.layers.vcol_render = ren_vcol; + } } /* Start Fresh */ @@ -1020,11 +1039,15 @@ static MeshRenderData *mesh_render_data_create_ex(Mesh *me, CustomData_free_layers(cd_ldata, CD_MLOOPTANGENT, rdata->loop_len); if (rdata->cd.layers.uv_len != 0) { + int ren_uv = rdata->cd.layers.uv_render; int act_uv = rdata->cd.layers.uv_active; for (int i_src = 0, i_dst = 0; i_src < cd_layers_src.uv_len; i_src++, i_dst++) { if ((cd_used->uv & (1 << i_src)) == 0) { /* This is a non-used UV slot. Skip. */ i_dst--; + if (rdata->cd.layers.uv_render >= i_src) { + ren_uv--; + } if (rdata->cd.layers.uv_active >= i_src) { act_uv--; } @@ -1043,8 +1066,11 @@ static MeshRenderData *mesh_render_data_create_ex(Mesh *me, rdata->cd.uuid.auto_mix[i_dst], sizeof(*rdata->cd.uuid.auto_mix), "a%u", hash); } } + /* Actual active / Render UV slot inside uv layers used for shading. */ + if (rdata->cd.layers.uv_render != -1) { + rdata->cd.layers.uv_render = ren_uv; + } if (rdata->cd.layers.uv_active != -1) { - /* Actual active UV slot inside uv layers used for shading. */ rdata->cd.layers.uv_active = act_uv; } } @@ -1143,9 +1169,13 @@ static MeshRenderData *mesh_render_data_create_ex(Mesh *me, int i_dst = 0; int act_tan = rdata->cd.layers.tangent_active; + int ren_tan = rdata->cd.layers.tangent_render; for (int i_src = 0; i_src < cd_layers_src.uv_len; i_src++, i_dst++) { if ((cd_used->tan & (1 << i_src)) == 0) { i_dst--; + if (rdata->cd.layers.tangent_render >= i_src) { + ren_tan--; + } if (rdata->cd.layers.tangent_active >= i_src) { act_tan--; } @@ -1171,10 +1201,13 @@ static MeshRenderData *mesh_render_data_create_ex(Mesh *me, } } } + /* Actual active rangent slot inside uv layers used for shading. */ if (rdata->cd.layers.tangent_active != -1) { - /* Actual active UV slot inside uv layers used for shading. */ rdata->cd.layers.tangent_active = act_tan; } + if (rdata->cd.layers.tangent_render != -1) { + rdata->cd.layers.tangent_render = ren_tan; + } if (cd_used->tan_orco != 0) { const char *name = CustomData_get_layer_name(&rdata->cd.output.ldata, CD_TANGENT, i_dst); @@ -1812,6 +1845,36 @@ static bool add_edit_facedot_mapped(MeshRenderData *rdata, return true; } +static bool add_edit_facedot_subdiv(MeshRenderData *rdata, + GPUVertBuf *vbo, + const uint fdot_pos_id, + const uint fdot_nor_flag_id, + const int vert, + const int poly, + const int base_vert_idx) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); + const int *p_origindex = rdata->mapped.p_origindex; + const int p_orig = p_origindex[poly]; + if (p_orig == ORIGINDEX_NONE) { + return false; + } + BMEditMesh *em = rdata->edit_bmesh; + const BMFace *efa = BM_face_at_index(em->bm, p_orig); + if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + return false; + } + + Mesh *me_cage = em->mesh_eval_cage; + const MVert *mvert = &me_cage->mvert[vert]; + + GPUPackedNormal nor = GPU_normal_convert_i10_s3(mvert->no); + nor.w = BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == em->bm->act_face) ? -1 : 1) : 0; + GPU_vertbuf_attr_set(vbo, fdot_nor_flag_id, base_vert_idx, &nor); + GPU_vertbuf_attr_set(vbo, fdot_pos_id, base_vert_idx, mvert->co); + + return true; +} /** \} */ @@ -1985,6 +2048,7 @@ typedef struct MeshBatchCache { /* Indices to vloops. */ GPUIndexBuf *loops_tris; GPUIndexBuf *loops_lines; + GPUIndexBuf *loops_lines_paint_mask; GPUIndexBuf *loops_line_strips; /* Edit mode. */ GPUIndexBuf *edit_loops_points; /* verts */ @@ -2025,7 +2089,7 @@ typedef struct MeshBatchCache { GPUBatch *loose_edges; GPUBatch *edge_detection; GPUBatch *wire_edges; /* Individual edges with face normals. */ - GPUBatch *wire_loops; /* Loops around faces. */ + GPUBatch *wire_loops; /* Loops around faces. no edges between selected faces */ GPUBatch *wire_loops_uvs; /* Same as wire_loops but only has uvs. */ } batch; @@ -2227,15 +2291,17 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) case BKE_MESH_BATCH_DIRTY_SELECT_PAINT: /* Paint mode selection flag is packed inside the nor attrib. * Note that it can be slow if auto smooth is enabled. (see T63946) */ + GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.loops_lines_paint_mask); GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_pos_nor); GPU_BATCH_DISCARD_SAFE(cache->batch.surface); GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops); + GPU_BATCH_DISCARD_SAFE(cache->batch.wire_edges); if (cache->surf_per_mat) { for (int i = 0; i < cache->mat_len; i++) { GPU_BATCH_DISCARD_SAFE(cache->surf_per_mat[i]); } } - cache->batch_ready &= ~(MBC_SURFACE | MBC_WIRE_LOOPS | MBC_SURF_PER_MAT); + cache->batch_ready &= ~(MBC_SURFACE | MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SURF_PER_MAT); break; case BKE_MESH_BATCH_DIRTY_ALL: cache->is_dirty = true; @@ -2719,7 +2785,10 @@ static void mesh_create_edit_vertex_loops(MeshRenderData *rdata, } /* TODO: We could use gl_PrimitiveID as index instead of using another VBO. */ -static void mesh_create_edit_facedots_select_id(MeshRenderData *rdata, GPUVertBuf *vbo) +static void mesh_create_edit_facedots_select_id(MeshRenderData *rdata, + GPUVertBuf *vbo, + Scene *scene, + Object *ob) { const int poly_len = mesh_render_data_polys_len_get_maybe_mapped(rdata); @@ -2754,12 +2823,32 @@ static void mesh_create_edit_facedots_select_id(MeshRenderData *rdata, GPUVertBu } else { const int *p_origindex = rdata->mapped.p_origindex; - for (int poly = 0; poly < poly_len; poly++) { - const int p_orig = p_origindex[poly]; - if (p_orig != ORIGINDEX_NONE) { - const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, p_orig); - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - *((uint *)GPU_vertbuf_raw_step(&idx_step)) = p_orig; + if (modifiers_usesSubsurfFacedots(scene, ob)) { + Mesh *me_cage = rdata->mapped.me_cage; + const MPoly *mpoly = me_cage->mpoly; + for (int p = 0; p < poly_len; p++, mpoly++) { + const int p_orig = p_origindex[p]; + if (p_orig != ORIGINDEX_NONE) { + const MLoop *mloop = me_cage->mloop + mpoly->loopstart; + for (int l = 0; l < mpoly->totloop; l++, mloop++) { + if (me_cage->mvert[mloop->v].flag & ME_VERT_FACEDOT) { + const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, p_orig); + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + *((uint *)GPU_vertbuf_raw_step(&idx_step)) = p_orig; + } + } + } + } + } + } + else { + for (int poly = 0; poly < poly_len; poly++) { + const int p_orig = p_origindex[poly]; + if (p_orig != ORIGINDEX_NONE) { + const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, p_orig); + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + *((uint *)GPU_vertbuf_raw_step(&idx_step)) = p_orig; + } } } } @@ -2929,7 +3018,7 @@ static void mesh_create_loop_edge_fac(MeshRenderData *rdata, GPUVertBuf *vbo) BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) { float ratio = mesh_loop_edge_factor_get( efa->no, loop->v->co, loop->v->no, loop->next->v->co); - vertbuf_raw_step(&wd_step, ratio * 255); + vertbuf_raw_step(&wd_step, ratio * 253 + 1); } } BLI_assert(GPU_vertbuf_raw_used(&wd_step) == loop_len); @@ -3201,9 +3290,12 @@ static void mesh_create_loop_uv_and_tan(MeshRenderData *rdata, GPUVertBuf *vbo) attr_name = mesh_render_data_uv_auto_layer_uuid_get(rdata, i); GPU_vertformat_alias_add(&format, attr_name); - if (i == rdata->cd.layers.uv_active) { + if (i == rdata->cd.layers.uv_render) { GPU_vertformat_alias_add(&format, "u"); } + if (i == rdata->cd.layers.uv_active) { + GPU_vertformat_alias_add(&format, "au"); + } if (i == rdata->cd.layers.uv_mask_active) { GPU_vertformat_alias_add(&format, "mu"); } @@ -3217,9 +3309,12 @@ static void mesh_create_loop_uv_and_tan(MeshRenderData *rdata, GPUVertBuf *vbo) #else tangent_id[i] = GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT); #endif - if (i == rdata->cd.layers.tangent_active) { + if (i == rdata->cd.layers.tangent_render) { GPU_vertformat_alias_add(&format, "t"); } + if (i == rdata->cd.layers.tangent_active) { + GPU_vertformat_alias_add(&format, "at"); + } } /* HACK: Create a dummy attribute in case there is no valid UV/tangent layer. */ @@ -3318,9 +3413,12 @@ static void mesh_create_loop_vcol(MeshRenderData *rdata, GPUVertBuf *vbo) attr_name = mesh_render_data_vcol_auto_layer_uuid_get(rdata, i); GPU_vertformat_alias_add(&format, attr_name); } - if (i == rdata->cd.layers.vcol_active) { + if (i == rdata->cd.layers.vcol_render) { GPU_vertformat_alias_add(&format, "c"); } + if (i == rdata->cd.layers.vcol_active) { + GPU_vertformat_alias_add(&format, "ac"); + } } GPU_vertbuf_init_with_format(vbo, &format); @@ -3369,7 +3467,10 @@ static void mesh_create_loop_vcol(MeshRenderData *rdata, GPUVertBuf *vbo) #undef USE_COMP_MESH_DATA } -static void mesh_create_edit_facedots(MeshRenderData *rdata, GPUVertBuf *vbo_facedots_pos_nor_data) +static void mesh_create_edit_facedots(MeshRenderData *rdata, + GPUVertBuf *vbo_facedots_pos_nor_data, + Scene *scene, + Object *ob) { const int poly_len = mesh_render_data_polys_len_get_maybe_mapped(rdata); const int verts_facedot_len = poly_len; @@ -3411,21 +3512,37 @@ static void mesh_create_edit_facedots(MeshRenderData *rdata, GPUVertBuf *vbo_fac } } else { -#if 0 /* TODO(fclem): Mapped facedots are not following the original face. */ - Mesh *me_cage = rdata->mapped.me_cage; - const MVert *mvert = me_cage->mvert; - const MEdge *medge = me_cage->medge; - const int *e_origindex = rdata->mapped.e_origindex; - const int *v_origindex = rdata->mapped.v_origindex; -#endif - for (int i = 0; i < poly_len; i++) { - if (add_edit_facedot_mapped(rdata, - vbo_facedots_pos_nor_data, - attr_id.fdot_pos, - attr_id.fdot_nor_flag, - i, - facedot_len_used)) { - facedot_len_used += 1; + if (modifiers_usesSubsurfFacedots(scene, ob)) { + /* Facedots that follow surbsurf face center. */ + Mesh *me_cage = rdata->mapped.me_cage; + const MPoly *mpoly = me_cage->mpoly; + for (int p = 0; p < poly_len; p++, mpoly++) { + const MLoop *mloop = me_cage->mloop + mpoly->loopstart; + for (int l = 0; l < mpoly->totloop; l++, mloop++) { + if (me_cage->mvert[mloop->v].flag & ME_VERT_FACEDOT) { + if (add_edit_facedot_subdiv(rdata, + vbo_facedots_pos_nor_data, + attr_id.fdot_pos, + attr_id.fdot_nor_flag, + mloop->v, + p, + facedot_len_used)) { + facedot_len_used += 1; + } + } + } + } + } + else { + for (int i = 0; i < poly_len; i++) { + if (add_edit_facedot_mapped(rdata, + vbo_facedots_pos_nor_data, + attr_id.fdot_pos, + attr_id.fdot_nor_flag, + i, + facedot_len_used)) { + facedot_len_used += 1; + } } } } @@ -3788,10 +3905,89 @@ static void mesh_create_loops_lines(MeshRenderData *rdata, GPUIndexBuf *ibo, con } } } - else { - /* Implement ... eventually if needed. */ + + GPU_indexbuf_build_in_place(&elb, ibo); +} + +static void mesh_create_loops_lines_paint_mask(MeshRenderData *rdata, GPUIndexBuf *ibo) +{ + const int loop_len = mesh_render_data_loops_len_get(rdata); + const int poly_len = mesh_render_data_polys_len_get(rdata); + const int edge_len = mesh_render_data_edges_len_get(rdata); + + GPUIndexBufBuilder elb; + GPU_indexbuf_init(&elb, GPU_PRIM_LINES, loop_len, loop_len); + + if (rdata->edit_bmesh) { + /* painting does not use the edit_bmesh */ BLI_assert(0); } + else { + if (rdata->me->editflag & ME_EDIT_PAINT_FACE_SEL) { + /* Each edge has two bits used to count selected edges as 0, 1, 2+. */ + BLI_bitmap *edges_used = BLI_BITMAP_NEW(edge_len * 2, __func__); + + /* Fill the edge bitmap table. */ + for (int poly = 0; poly < poly_len; poly++) { + const MPoly *mpoly = &rdata->mpoly[poly]; + + /* Do not check faces that are hidden and faces that aren't selected */ + if (mpoly->flag & ME_HIDE || ((mpoly->flag & ME_FACE_SEL) == 0)) { + continue; + } + + for (int loop_index = mpoly->loopstart, loop_index_end = mpoly->loopstart + mpoly->totloop; + loop_index < loop_index_end; + loop_index++) { + const MLoop *mloop = &rdata->mloop[loop_index]; + const int e_a = mloop->e * 2; + const int e_b = e_a + 1; + if (!BLI_BITMAP_TEST(edges_used, e_a)) { + BLI_BITMAP_ENABLE(edges_used, e_a); + } + else { + BLI_BITMAP_ENABLE(edges_used, e_b); + } + } + } + + for (int poly = 0; poly < poly_len; poly++) { + const MPoly *mpoly = &rdata->mpoly[poly]; + if (!(mpoly->flag & ME_HIDE)) { + + for (int loop_index_next = mpoly->loopstart, + loop_index_end = mpoly->loopstart + mpoly->totloop, + loop_index_curr = loop_index_end - 1; + loop_index_next < loop_index_end; + loop_index_curr = loop_index_next++) { + const MLoop *mloop = &rdata->mloop[loop_index_curr]; + const int e_a = mloop->e * 2; + const int e_b = e_a + 1; + + /* Draw if a boundary or entirely unselected. */ + if (!BLI_BITMAP_TEST(edges_used, e_b)) { + GPU_indexbuf_add_line_verts(&elb, loop_index_curr, loop_index_next); + } + } + } + } + + MEM_freeN(edges_used); + } + else { + /* Add edges. */ + for (int poly = 0; poly < poly_len; poly++) { + const MPoly *mpoly = &rdata->mpoly[poly]; + for (int loop_index_next = mpoly->loopstart, + loop_index_end = mpoly->loopstart + mpoly->totloop, + loop_index_curr = loop_index_end - 1; + loop_index_next < loop_index_end; + loop_index_curr = loop_index_next++) { + GPU_indexbuf_add_line_verts(&elb, loop_index_curr, loop_index_next); + } + } + } + } GPU_indexbuf_build_in_place(&elb, ibo); } @@ -5053,8 +5249,8 @@ void DRW_mesh_batch_cache_create_requested( DRW_vbo_request(cache->batch.surface_weights, &cache->ordered.pos_nor); DRW_vbo_request(cache->batch.surface_weights, &cache->ordered.weights); } - if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINE_STRIP)) { - DRW_ibo_request(cache->batch.wire_loops, &cache->ibo.loops_line_strips); + if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINES)) { + DRW_ibo_request(cache->batch.wire_loops, &cache->ibo.loops_lines_paint_mask); DRW_vbo_request(cache->batch.wire_loops, &cache->ordered.loop_pos_nor); } if (DRW_batch_requested(cache->batch.wire_edges, GPU_PRIM_LINES)) { @@ -5207,6 +5403,9 @@ void DRW_mesh_batch_cache_create_requested( mr_flag, cache->ibo.loops_tris, MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPTRI); DRW_ADD_FLAG_FROM_IBO_REQUEST( mr_flag, cache->ibo.loops_lines, MR_DATATYPE_LOOP | MR_DATATYPE_EDGE | MR_DATATYPE_POLY); + DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, + cache->ibo.loops_lines_paint_mask, + MR_DATATYPE_LOOP | MR_DATATYPE_EDGE | MR_DATATYPE_POLY); DRW_ADD_FLAG_FROM_IBO_REQUEST( mr_flag, cache->ibo.loops_line_strips, MR_DATATYPE_LOOP | MR_DATATYPE_POLY); DRW_ADD_FLAG_FROM_IBO_REQUEST( @@ -5323,6 +5522,9 @@ void DRW_mesh_batch_cache_create_requested( if (DRW_ibo_requested(cache->ibo.loops_lines)) { mesh_create_loops_lines(rdata, cache->ibo.loops_lines, use_hide); } + if (DRW_ibo_requested(cache->ibo.loops_lines_paint_mask)) { + mesh_create_loops_lines_paint_mask(rdata, cache->ibo.loops_lines_paint_mask); + } if (DRW_ibo_requested(cache->ibo.loops_line_strips)) { mesh_create_loops_line_strips(rdata, cache->ibo.loops_line_strips, use_hide); } @@ -5359,10 +5561,12 @@ void DRW_mesh_batch_cache_create_requested( cache->edit.loop_face_idx); } if (DRW_vbo_requested(cache->edit.facedots_pos_nor_data)) { - mesh_create_edit_facedots(rdata, cache->edit.facedots_pos_nor_data); + Scene *scene = DRW_context_state_get()->scene; + mesh_create_edit_facedots(rdata, cache->edit.facedots_pos_nor_data, scene, ob); } if (DRW_vbo_requested(cache->edit.facedots_idx)) { - mesh_create_edit_facedots_select_id(rdata, cache->edit.facedots_idx); + Scene *scene = DRW_context_state_get()->scene; + mesh_create_edit_facedots_select_id(rdata, cache->edit.facedots_idx, scene, ob); } if (DRW_ibo_requested(cache->ibo.edit_loops_points) || DRW_ibo_requested(cache->ibo.edit_loops_lines)) { diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c index c66a737d684..6cd03d14bfd 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.c +++ b/source/blender/draw/intern/draw_cache_impl_particles.c @@ -835,7 +835,9 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit ParticleHairCache *cache) { int active_uv = 0; + int render_uv = 0; int active_col = 0; + int render_col = 0; ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; @@ -843,10 +845,12 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPUV)) { cache->num_uv_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPUV); active_uv = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPUV); + render_uv = CustomData_get_render_layer(&psmd->mesh_final->ldata, CD_MLOOPUV); } if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL)) { cache->num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPCOL); active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL); + render_col = CustomData_get_render_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL); } } @@ -897,7 +901,10 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%u", hash); if (i == active_uv) { - BLI_strncpy(cache->uv_layer_names[i][n], "u", MAX_LAYER_NAME_LEN); + BLI_strncpy(cache->uv_layer_names[i][n++], "au", MAX_LAYER_NAME_LEN); + } + if (i == render_uv) { + BLI_strncpy(cache->uv_layer_names[i][n++], "u", MAX_LAYER_NAME_LEN); } } /* Vertex colors */ @@ -917,7 +924,10 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit } if (i == active_col) { - BLI_strncpy(cache->col_layer_names[i][n], "c", MAX_LAYER_NAME_LEN); + BLI_strncpy(cache->col_layer_names[i][n++], "ac", MAX_LAYER_NAME_LEN); + } + if (i == render_col) { + BLI_strncpy(cache->col_layer_names[i][n++], "c", MAX_LAYER_NAME_LEN); } } @@ -1435,11 +1445,12 @@ static void drw_particle_get_hair_source(Object *object, PTCacheEdit *edit, ParticleDrawSource *r_draw_source) { + const DRWContextState *draw_ctx = DRW_context_state_get(); r_draw_source->object = object; r_draw_source->psys = psys; r_draw_source->md = md; r_draw_source->edit = edit; - if ((object->mode & OB_MODE_PARTICLE_EDIT) != 0) { + if (psys_in_edit_mode(draw_ctx->depsgraph, psys)) { r_draw_source->object = DEG_get_original_object(object); r_draw_source->psys = psys_orig_get(psys); } diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h index 72c89832d3d..6eaba7e8811 100644 --- a/source/blender/draw/intern/draw_hair_private.h +++ b/source/blender/draw/intern/draw_hair_private.h @@ -24,7 +24,7 @@ #ifndef __DRAW_HAIR_PRIVATE_H__ #define __DRAW_HAIR_PRIVATE_H__ -#define MAX_LAYER_NAME_CT 3 /* u0123456789, u, a0123456789 */ +#define MAX_LAYER_NAME_CT 4 /* u0123456789, u, au, a0123456789 */ #define MAX_LAYER_NAME_LEN DECIMAL_DIGITS_BOUND(uint) + 2 #define MAX_THICKRES 2 /* see eHairType */ #define MAX_HAIR_SUBDIV 4 /* see hair_subdiv rna */ diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c index 3e5dfb53fc7..802f49d6549 100644 --- a/source/blender/draw/intern/draw_instance_data.c +++ b/source/blender/draw/intern/draw_instance_data.c @@ -141,7 +141,8 @@ GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist, GPUBatch *batch = BLI_memblock_alloc(idatalist->pool_instancing); bool is_compatible = (batch->gl_prim_type == geom->gl_prim_type) && (batch->inst == buf) && - (buf->vbo_id != 0) && (batch->phase == GPU_BATCH_READY_TO_DRAW); + (buf->vbo_id != 0) && (batch->phase == GPU_BATCH_READY_TO_DRAW) && + (batch->elem == geom->elem); for (int i = 0; i < GPU_BATCH_VBO_MAX_LEN && is_compatible; i++) { if (batch->verts[i] != geom->verts[i]) { is_compatible = false; diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index c4e3bd5cf91..2841e017ef6 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -88,6 +88,7 @@ #include "engines/basic/basic_engine.h" #include "engines/workbench/workbench_engine.h" #include "engines/external/external_engine.h" +#include "engines/gpencil/gpencil_engine.h" #include "GPU_context.h" @@ -206,6 +207,8 @@ bool DRW_object_use_hide_faces(const struct Object *ob) const Mesh *me = ob->data; switch (ob->mode) { + case OB_MODE_SCULPT: + return true; case OB_MODE_TEXTURE_PAINT: return (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; case OB_MODE_VERTEX_PAINT: @@ -1916,6 +1919,13 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph DST.buffer_finish_called = false; } +static void drw_view_reset(void) +{ + DST.view_default = NULL; + DST.view_active = NULL; + DST.view_previous = NULL; +} + void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) { Scene *scene = DEG_get_evaluated_scene(depsgraph); @@ -1998,14 +2008,12 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) for (RenderView *render_view = render_result->views.first; render_view != NULL; render_view = render_view->next) { RE_SetActiveRenderView(render, render_view->name); - /* Reset the view. */ - DST.view_default = NULL; - DST.view_active = NULL; - DST.view_previous = NULL; + drw_view_reset(); engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect); /* grease pencil: render result is merged in the previous render result. */ if (DRW_render_check_grease_pencil(depsgraph)) { DRW_state_reset(); + drw_view_reset(); DRW_render_gpencil_to_image(engine, render_layer, &render_rect); } DST.buffer_finish_called = false; @@ -2374,6 +2382,13 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, } } + /* TODO: GPXX Workaround for grease pencil selection while draw manager support a callback from + * scene finish */ + void *data = GPU_viewport_engine_data_get(DST.viewport, &draw_engine_gpencil_type); + if (data != NULL) { + DRW_gpencil_free_runtime_data(data); + } + DRW_state_lock(0); DRW_draw_callbacks_post_scene(); @@ -2590,6 +2605,8 @@ void DRW_draw_depth_object(ARegion *ar, GPUViewport *viewport, Object *object) world_clip_planes = rv3d->clip_local; } + drw_batch_cache_validate(object); + switch (object->type) { case OB_MESH: { GPUBatch *batch; @@ -2715,6 +2732,14 @@ void DRW_draw_select_id_object(Scene *scene, select_mode = ts->selectmode; } + /* Init the scene of the draw context. When using face dot selection on + * when the subsurf modifier is active on the cage, the scene needs to be + * valid. It is read from the context in the + * `DRW_mesh_batch_cache_create_requested` and used in the `isDisabled` + * method of the SubSurfModifier. */ + DRWContextState *draw_ctx = &DST.draw_ctx; + draw_ctx->scene = scene; + GPU_matrix_mul(ob->obmat); const float(*world_clip_planes)[4] = NULL; diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 5c3b5aa8a8e..d0aa6d55c03 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -202,12 +202,8 @@ static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred) /* Get the running job or a new one if none is running. Can only have one job per type & owner. */ - wmJob *wm_job = WM_jobs_get(wm, - win, - scene, - "Shaders Compilation", - WM_JOB_PROGRESS | WM_JOB_SUSPEND, - WM_JOB_TYPE_SHADER_COMPILATION); + wmJob *wm_job = WM_jobs_get( + wm, win, scene, "Shaders Compilation", WM_JOB_PROGRESS, WM_JOB_TYPE_SHADER_COMPILATION); DRWShaderCompiler *old_comp = (DRWShaderCompiler *)WM_jobs_customdata_get(wm_job); @@ -238,6 +234,7 @@ static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred) WM_jobs_customdata_set(wm_job, comp, drw_deferred_shader_compilation_free); WM_jobs_timer(wm_job, 0.1, NC_MATERIAL | ND_SHADING_DRAW, 0); + WM_jobs_delay_start(wm_job, 0.1); WM_jobs_callbacks(wm_job, drw_deferred_shader_compilation_exec, NULL, NULL, NULL); WM_jobs_start(wm, wm_job); } @@ -252,12 +249,8 @@ void DRW_deferred_shader_remove(GPUMaterial *mat) continue; } for (wmWindow *win = wm->windows.first; win; win = win->next) { - wmJob *wm_job = WM_jobs_get(wm, - win, - scene, - "Shaders Compilation", - WM_JOB_PROGRESS | WM_JOB_SUSPEND, - WM_JOB_TYPE_SHADER_COMPILATION); + wmJob *wm_job = WM_jobs_get( + wm, win, scene, "Shaders Compilation", WM_JOB_PROGRESS, WM_JOB_TYPE_SHADER_COMPILATION); DRWShaderCompiler *comp = (DRWShaderCompiler *)WM_jobs_customdata_get(wm_job); if (comp != NULL) { diff --git a/source/blender/draw/modes/edit_mesh_mode_text.c b/source/blender/draw/modes/edit_mesh_mode_text.c index f3630a77e9a..7c7a9a586fa 100644 --- a/source/blender/draw/modes/edit_mesh_mode_text.c +++ b/source/blender/draw/modes/edit_mesh_mode_text.c @@ -66,7 +66,7 @@ void DRW_edit_mesh_mode_text_measure_stats(ARegion *ar, /* when 2 edge-info options are enabled, space apart */ const bool do_edge_textpair = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_LEN) && (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_ANG); - const short edge_texpair_sep = (short)(5.0f * U.ui_scale); + const short edge_texpair_sep = (short)(5.0f * U.dpi_fac); float clip_planes[4][4]; /* allow for displaying shape keys and deform mods */ BMIter iter; diff --git a/source/blender/draw/modes/edit_text_mode.c b/source/blender/draw/modes/edit_text_mode.c index 03f26e8ce63..448dc33077e 100644 --- a/source/blender/draw/modes/edit_text_mode.c +++ b/source/blender/draw/modes/edit_text_mode.c @@ -383,10 +383,10 @@ static void EDIT_TEXT_draw_scene(void *vedata) DRW_draw_pass(psl->text_box_pass); } - set_inverted_drawing(1); + GPU_logic_op_invert_set(true); DRW_draw_pass(psl->overlay_select_pass); DRW_draw_pass(psl->overlay_cursor_pass); - set_inverted_drawing(0); + GPU_logic_op_invert_set(false); /* If you changed framebuffer, double check you rebind * the default one with its textures attached before finishing */ diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index 68f3e058693..9fc11e4f36f 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -322,6 +322,7 @@ typedef struct OBJECT_DupliData { GPUBatch *outline_geom; DRWShadingGroup *extra_shgrp; GPUBatch *extra_geom; + short base_flag; } OBJECT_DupliData; static struct { @@ -3276,7 +3277,12 @@ static void OBJECT_cache_populate_particles(OBJECT_Shaders *sh_data, ParticleSettings *part = psys->part; int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; - if (draw_as != PART_DRAW_PATH) { + if (part->type == PART_HAIR) { + /* Hairs should have been rendered by the render engine.*/ + continue; + } + + if (!ELEM(draw_as, PART_DRAW_NOT, PART_DRAW_OB, PART_DRAW_GR)) { struct GPUBatch *geom = DRW_cache_particles_get_dots(ob, psys); DRWShadingGroup *shgrp = NULL; struct GPUBatch *shape = NULL; @@ -3286,6 +3292,7 @@ static void OBJECT_cache_populate_particles(OBJECT_Shaders *sh_data, Material *ma = give_current_material(ob, part->omat); switch (draw_as) { + default: case PART_DRAW_DOT: shgrp = DRW_shgroup_create(sh_data->part_dot, psl->particle); DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1); @@ -3320,8 +3327,6 @@ static void OBJECT_cache_populate_particles(OBJECT_Shaders *sh_data, DRW_shgroup_uniform_bool_copy(shgrp, "screen_space", false); DRW_shgroup_call_instances_with_attribs(shgrp, NULL, shape, geom); break; - default: - break; } } } @@ -3398,6 +3403,10 @@ BLI_INLINE OBJECT_DupliData *OBJECT_duplidata_get(Object *ob, void *vedata, bool *dupli_data = MEM_callocN(sizeof(OBJECT_DupliData), "OBJECT_DupliData"); *init = true; } + else if ((*dupli_data)->base_flag != ob->base_flag) { + /* Select state might have change, reinit. */ + *init = true; + } return *dupli_data; } return NULL; @@ -3458,6 +3467,9 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) if (dupli_data && !init_duplidata) { geom = dupli_data->outline_geom; shgroup = dupli_data->outline_shgrp; + /* TODO: Remove. Only here to increment outline id counter. */ + theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); + shgroup = shgroup_theme_id_to_outline_or_null(stl, theme_id, ob->base_flag); } else { if (stl->g_data->xray_enabled_and_not_wire || is_flat_object_viewed_from_side) { @@ -3665,6 +3677,7 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) if (init_duplidata) { dupli_data->extra_shgrp = shgroup; dupli_data->extra_geom = geom; + dupli_data->base_flag = ob->base_flag; } } diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c index ae5c0064cde..a5b1133abf4 100644 --- a/source/blender/draw/modes/overlay_mode.c +++ b/source/blender/draw/modes/overlay_mode.c @@ -50,6 +50,7 @@ typedef struct OVERLAY_DupliData { DRWShadingGroup *shgrp; struct GPUBatch *geom; + short base_flag; } OVERLAY_DupliData; typedef struct OVERLAY_StorageList { @@ -370,9 +371,16 @@ static void overlay_cache_populate(void *vedata, Object *ob) } else { if ((*dupli_data)->shgrp && (*dupli_data)->geom) { - DRW_shgroup_call((*dupli_data)->shgrp, (*dupli_data)->geom, ob); + if ((*dupli_data)->base_flag == ob->base_flag) { + DRW_shgroup_call((*dupli_data)->shgrp, (*dupli_data)->geom, ob); + } + else { + /* Continue and create a new Shgroup. */ + } + } + else { + return; } - return; } } @@ -437,6 +445,7 @@ static void overlay_cache_populate(void *vedata, Object *ob) if (dupli_data) { (*dupli_data)->shgrp = shgrp; (*dupli_data)->geom = geom; + (*dupli_data)->base_flag = ob->base_flag; } } } diff --git a/source/blender/draw/modes/paint_texture_mode.c b/source/blender/draw/modes/paint_texture_mode.c index 6c2f170a220..7c164a74f2f 100644 --- a/source/blender/draw/modes/paint_texture_mode.c +++ b/source/blender/draw/modes/paint_texture_mode.c @@ -63,7 +63,7 @@ typedef struct PAINT_TEXTURE_PassList { /* Declare all passes here and init them in * PAINT_TEXTURE_cache_init(). * Only contains (DRWPass *) */ - struct DRWPass *image_faces; + struct DRWPass *stencil_mask_overlay; struct DRWPass *wire_select_overlay; struct DRWPass *face_select_overlay; @@ -107,9 +107,7 @@ typedef struct PAINT_TEXTURE_Shaders { * Add sources to source/blender/draw/modes/shaders * init in PAINT_TEXTURE_engine_init(); * free in PAINT_TEXTURE_engine_free(); */ - struct GPUShader *fallback; - struct GPUShader *image; - struct GPUShader *image_mask; + struct GPUShader *stencil_mask_overlay; struct GPUShader *wire_select_overlay; struct GPUShader *face_select_overlay; @@ -124,8 +122,7 @@ static struct { typedef struct PAINT_TEXTURE_PrivateData { /* This keeps the references of the shading groups for * easy access in PAINT_TEXTURE_cache_populate() */ - DRWShadingGroup *shgroup_fallback; - DRWShadingGroup **shgroup_image_array; + DRWShadingGroup *shgroup_stencil_mask; /* face-mask */ DRWShadingGroup *lwire_select_shgrp; @@ -144,18 +141,9 @@ static void PAINT_TEXTURE_engine_init(void *vedata) const DRWContextState *draw_ctx = DRW_context_state_get(); PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->fallback) { + if (!sh_data->stencil_mask_overlay) { const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; - sh_data->fallback = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, - datatoc_common_view_lib_glsl, - datatoc_paint_face_vert_glsl, - NULL}, - .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg_data->def, NULL}, - }); - - sh_data->image = GPU_shader_create_from_arrays({ + sh_data->stencil_mask_overlay = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, datatoc_common_globals_lib_glsl, datatoc_common_view_lib_glsl, @@ -167,18 +155,6 @@ static void PAINT_TEXTURE_engine_init(void *vedata) .defs = (const char *[]){sh_cfg_data->def, NULL}, }); - sh_data->image_mask = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, - datatoc_common_globals_lib_glsl, - datatoc_common_view_lib_glsl, - datatoc_paint_texture_vert_glsl, - NULL}, - .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl, - datatoc_paint_texture_frag_glsl, - NULL}, - .defs = (const char *[]){sh_cfg_data->def, "#define TEXTURE_PAINT_MASK\n", NULL}, - }); - sh_data->wire_select_overlay = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, datatoc_common_globals_lib_glsl, @@ -204,45 +180,39 @@ static void PAINT_TEXTURE_engine_init(void *vedata) if (!stl->g_data) { /* Alloc transient pointers */ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); - stl->g_data->shgroup_image_array = NULL; + stl->g_data->shgroup_stencil_mask = NULL; } stl->g_data->view_wires = DRW_view_create_with_zoffset(draw_ctx->rv3d, 1.0f); } -static DRWShadingGroup *create_texture_paint_shading_group(PAINT_TEXTURE_PassList *psl, - const Image *image, - const struct GPUTexture *texture, - const DRWContextState *draw_ctx, - const bool nearest_interp) +static DRWShadingGroup *create_texture_paint_stencil_mask_shading_group( + PAINT_TEXTURE_PassList *psl, const DRWContextState *draw_ctx) { PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; Scene *scene = draw_ctx->scene; const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; - const bool masking_enabled = imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL && - imapaint->stencil != NULL; - DRWShadingGroup *grp = DRW_shgroup_create(masking_enabled ? sh_data->image_mask : sh_data->image, - psl->image_faces); - DRW_shgroup_uniform_texture(grp, "image", texture); - DRW_shgroup_uniform_bool_copy( - grp, "imagePremultiplied", (image->alpha_mode == IMA_ALPHA_PREMUL)); + DRWShadingGroup *grp = DRW_shgroup_create(sh_data->stencil_mask_overlay, + psl->stencil_mask_overlay); DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_bool_copy(grp, "nearestInterp", nearest_interp); - - if (masking_enabled) { - const bool masking_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) > 0; - GPUTexture *stencil = GPU_texture_from_blender(imapaint->stencil, NULL, GL_TEXTURE_2D); - DRW_shgroup_uniform_texture(grp, "maskingImage", stencil); - DRW_shgroup_uniform_bool_copy( - grp, "maskingImagePremultiplied", (imapaint->stencil->alpha_mode == IMA_ALPHA_PREMUL)); - DRW_shgroup_uniform_vec3(grp, "maskingColor", imapaint->stencil_col, 1); - DRW_shgroup_uniform_bool_copy(grp, "maskingInvertStencil", masking_inverted); - } + + const bool masking_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) > 0; + GPUTexture *stencil = GPU_texture_from_blender(imapaint->stencil, NULL, GL_TEXTURE_2D); + DRW_shgroup_uniform_texture(grp, "maskingImage", stencil); + DRW_shgroup_uniform_bool_copy( + grp, "maskingImagePremultiplied", (imapaint->stencil->alpha_mode == IMA_ALPHA_PREMUL)); + DRW_shgroup_uniform_vec3(grp, "maskingColor", imapaint->stencil_col, 1); + DRW_shgroup_uniform_bool_copy(grp, "maskingInvertStencil", masking_inverted); return grp; } +static bool PAINT_TEXTURE_stencil_mask_enabled(const ImagePaintSettings *imapaint) +{ + return imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL && imapaint->stencil != NULL; +} + /* Here init all passes and shading groups * Assume that all Passes are NULL */ static void PAINT_TEXTURE_cache_init(void *vedata) @@ -251,69 +221,17 @@ static void PAINT_TEXTURE_cache_init(void *vedata) PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl; const DRWContextState *draw_ctx = DRW_context_state_get(); - PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - - /* Create a pass */ - { - DRWPass *pass = DRW_pass_create( - "Image Color Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA); - DRWShadingGroup *shgrp = DRW_shgroup_create(sh_data->fallback, pass); - - /* Uniforms need a pointer to it's value so be sure it's accessible at - * any given time (i.e. use static vars) */ - static const float color[4] = {1.0f, 0.0f, 1.0f, 1.0}; - DRW_shgroup_uniform_vec4(shgrp, "color", color, 1); - - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES); - } - psl->image_faces = pass; - stl->g_data->shgroup_fallback = shgrp; - } + Scene *scene = draw_ctx->scene; + const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; - MEM_SAFE_FREE(stl->g_data->shgroup_image_array); + PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - Object *ob = draw_ctx->obact; - if (ob && ob->type == OB_MESH) { - Scene *scene = draw_ctx->scene; - const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; - const bool use_material_slots = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL); - const Mesh *me = ob->data; - const int mat_nr = max_ii(1, me->totcol); - - stl->g_data->shgroup_image_array = MEM_mallocN( - sizeof(*stl->g_data->shgroup_image_array) * (use_material_slots ? mat_nr : 1), __func__); - - if (use_material_slots) { - for (int i = 0; i < mat_nr; i++) { - Material *ma = give_current_material(ob, i + 1); - Image *ima = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].ima : NULL; - int interp = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].interp : 0; - GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D); - - if (tex) { - DRWShadingGroup *grp = create_texture_paint_shading_group( - psl, ima, tex, draw_ctx, interp == SHD_INTERP_CLOSEST); - stl->g_data->shgroup_image_array[i] = grp; - } - else { - stl->g_data->shgroup_image_array[i] = NULL; - } - } - } - else { - Image *ima = imapaint->canvas; - GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D); - - if (tex) { - DRWShadingGroup *grp = create_texture_paint_shading_group( - psl, ima, tex, draw_ctx, imapaint->interp == IMAGEPAINT_INTERP_CLOSEST); - stl->g_data->shgroup_image_array[0] = grp; - } - else { - stl->g_data->shgroup_image_array[0] = NULL; - } - } + /* Stencil Mask */ + if (PAINT_TEXTURE_stencil_mask_enabled(imapaint)) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA; + psl->stencil_mask_overlay = DRW_pass_create("Stencil Mask Pass", state); + stl->g_data->shgroup_stencil_mask = create_texture_paint_stencil_mask_shading_group(psl, + draw_ctx); } /* Face Mask */ @@ -358,41 +276,18 @@ static void PAINT_TEXTURE_cache_populate(void *vedata, Object *ob) if ((ob->type == OB_MESH) && (draw_ctx->obact == ob)) { /* Get geometry cache */ - const Mesh *me = ob->data; const Mesh *me_orig = DEG_get_original_object(ob)->data; Scene *scene = draw_ctx->scene; - const bool use_surface = draw_ctx->v3d->overlay.texture_paint_mode_opacity != - 0.0; // DRW_object_is_mode_shade(ob) == true; - const bool use_material_slots = (scene->toolsettings->imapaint.mode == - IMAGEPAINT_MODE_MATERIAL); + const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; + const bool use_face_sel = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const bool masking_enabled = imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL && + imapaint->stencil != NULL; - if (use_surface) { - if (me->mloopuv != NULL) { - if (use_material_slots) { - int mat_nr = max_ii(1, me->totcol); - struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); - - for (int i = 0; i < mat_nr; i++) { - const int index = use_material_slots ? i : 0; - if ((i < me->totcol) && stl->g_data->shgroup_image_array[index]) { - DRW_shgroup_call(stl->g_data->shgroup_image_array[index], geom_array[i], ob); - } - else { - DRW_shgroup_call(stl->g_data->shgroup_fallback, geom_array[i], ob); - } - } - } - else { - if (stl->g_data->shgroup_image_array[0]) { - struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); - DRW_shgroup_call(stl->g_data->shgroup_image_array[0], geom, ob); - } - } - } - else { - struct GPUBatch *geom = DRW_cache_mesh_surface_get(ob); - DRW_shgroup_call(stl->g_data->shgroup_fallback, geom, ob); + if (masking_enabled) { + if (stl->g_data->shgroup_stencil_mask) { + struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); + DRW_shgroup_call(stl->g_data->shgroup_stencil_mask, geom, ob); } } @@ -408,32 +303,15 @@ static void PAINT_TEXTURE_cache_populate(void *vedata, Object *ob) } } -/* Optional: Post-cache_populate callback */ -static void PAINT_TEXTURE_cache_finish(void *vedata) -{ - PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl; - PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl; - - /* Do something here! dependent on the objects gathered */ - UNUSED_VARS(psl); - - MEM_SAFE_FREE(stl->g_data->shgroup_image_array); -} - /* Draw time ! Control rendering pipeline from here */ static void PAINT_TEXTURE_draw_scene(void *vedata) { PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl; - PAINT_TEXTURE_FramebufferList *fbl = ((PAINT_TEXTURE_Data *)vedata)->fbl; PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl; - /* Default framebuffer and texture */ - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - - UNUSED_VARS(fbl, dfbl, dtxl); - - DRW_draw_pass(psl->image_faces); + if (psl->stencil_mask_overlay) { + DRW_draw_pass(psl->stencil_mask_overlay); + } DRW_draw_pass(psl->face_select_overlay); @@ -469,7 +347,7 @@ DrawEngineType draw_engine_paint_texture_type = { &PAINT_TEXTURE_engine_free, &PAINT_TEXTURE_cache_init, &PAINT_TEXTURE_cache_populate, - &PAINT_TEXTURE_cache_finish, + NULL, NULL, /* draw_background but not needed by mode engines */ &PAINT_TEXTURE_draw_scene, NULL, diff --git a/source/blender/draw/modes/paint_vertex_mode.c b/source/blender/draw/modes/paint_vertex_mode.c index 862fb92287c..bfd189189b4 100644 --- a/source/blender/draw/modes/paint_vertex_mode.c +++ b/source/blender/draw/modes/paint_vertex_mode.c @@ -227,8 +227,9 @@ static void PAINT_VERTEX_cache_init(void *vedata) } { - DRWPass *pass = DRW_pass_create( - "Wire Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL); + DRWPass *pass = DRW_pass_create("Wire Pass", + (DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | + DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL)); for (int i = 0; i < MODE_LEN; i++) { DRWShadingGroup *shgrp = DRW_shgroup_create(sh_data->by_mode[i].wire_overlay, pass); DRW_shgroup_uniform_block(shgrp, "globalsBlock", G_draw.block_ubo); diff --git a/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl index ac6b353412d..bc1975bac81 100644 --- a/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl +++ b/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl @@ -35,7 +35,7 @@ void main() vertFlag = data; - gl_PointSize = sizeVertex; + gl_PointSize = sizeVertex * 2.0; gl_Position = pPos; #ifdef USE_WORLD_CLIP_PLANES diff --git a/source/blender/draw/modes/shaders/paint_texture_frag.glsl b/source/blender/draw/modes/shaders/paint_texture_frag.glsl index e8722590802..edd7c2af001 100644 --- a/source/blender/draw/modes/shaders/paint_texture_frag.glsl +++ b/source/blender/draw/modes/shaders/paint_texture_frag.glsl @@ -1,35 +1,17 @@ - -in vec2 uv_interp; -#ifdef TEXTURE_PAINT_MASK in vec2 masking_uv_interp; -#endif out vec4 fragColor; -uniform sampler2D image; -uniform bool imagePremultiplied; uniform float alpha = 1.0; -uniform bool nearestInterp; -#ifdef TEXTURE_PAINT_MASK uniform sampler2D maskingImage; uniform bool maskingImagePremultiplied; uniform vec3 maskingColor; uniform bool maskingInvertStencil; -#endif void main() { - vec2 uv = uv_interp; - if (nearestInterp) { - vec2 tex_size = vec2(textureSize(image, 0).xy); - uv = (floor(uv_interp * tex_size) + 0.5) / tex_size; - } - - vec4 color = texture_read_as_srgb(image, imagePremultiplied, uv); - color.a *= alpha; -#ifdef TEXTURE_PAINT_MASK vec4 mask = vec4( texture_read_as_srgb(maskingImage, maskingImagePremultiplied, masking_uv_interp).rgb, 1.0); if (maskingInvertStencil) { @@ -37,8 +19,7 @@ void main() } float mask_step = smoothstep(0, 3.0, mask.r + mask.g + mask.b); mask.rgb *= maskingColor; - color = mix(color, mask, mask_step); -#endif + mask.a = mask_step * alpha; - fragColor = color; + fragColor = mask; } diff --git a/source/blender/draw/modes/shaders/paint_texture_vert.glsl b/source/blender/draw/modes/shaders/paint_texture_vert.glsl index 564f988348e..ddfc2b51437 100644 --- a/source/blender/draw/modes/shaders/paint_texture_vert.glsl +++ b/source/blender/draw/modes/shaders/paint_texture_vert.glsl @@ -1,27 +1,15 @@ -in vec2 u; /* active uv map */ in vec3 pos; - -#ifdef TEXTURE_PAINT_MASK in vec2 mu; /* masking uv map */ -#endif - -out vec2 uv_interp; -#ifdef TEXTURE_PAINT_MASK out vec2 masking_uv_interp; -#endif void main() { vec3 world_pos = point_object_to_world(pos); gl_Position = point_world_to_ndc(world_pos); - uv_interp = u; - -#ifdef TEXTURE_PAINT_MASK masking_uv_interp = mu; -#endif #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); diff --git a/source/blender/draw/modes/shaders/paint_vertex_vert.glsl b/source/blender/draw/modes/shaders/paint_vertex_vert.glsl index 53e72cc8a20..24033432a48 100644 --- a/source/blender/draw/modes/shaders/paint_vertex_vert.glsl +++ b/source/blender/draw/modes/shaders/paint_vertex_vert.glsl @@ -1,6 +1,6 @@ in vec3 pos; -in vec3 c; /* active color */ +in vec3 ac; /* active color */ out vec3 finalColor; @@ -17,7 +17,7 @@ void main() vec3 world_pos = point_object_to_world(pos); gl_Position = point_world_to_ndc(world_pos); - finalColor = srgb_to_linear_attr(c); + finalColor = srgb_to_linear_attr(ac); #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); diff --git a/source/blender/draw/modes/shaders/paint_wire_vert.glsl b/source/blender/draw/modes/shaders/paint_wire_vert.glsl index 371c3120811..5857ffc9960 100644 --- a/source/blender/draw/modes/shaders/paint_wire_vert.glsl +++ b/source/blender/draw/modes/shaders/paint_wire_vert.glsl @@ -32,17 +32,21 @@ void main() #ifdef USE_SELECT finalColor = (is_select) ? colSel : colorWire; + finalColor.a = nor.w; #else # ifdef VERTEX_MODE - finalColor = colorWire; + finalColor.xyz = colorWire.xyz; + finalColor.a = 1.0; # else /* Weight paint needs a light color to contrasts with dark weights. */ - finalColor.xyz = vec3(0.8, 0.8, 0.8); + finalColor = vec4(1, 1, 1, 0.2); # endif #endif - finalColor.a = nor.w; + /* Needed for Radeon (TM) RX 480 Graphics. */ +#if defined(GPU_ATI) gl_PointSize = sizeVertex * 2.0; +#endif #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); diff --git a/source/blender/draw/modes/shaders/particle_strand_vert.glsl b/source/blender/draw/modes/shaders/particle_strand_vert.glsl index c3f8fb89c17..45fadb4ed5e 100644 --- a/source/blender/draw/modes/shaders/particle_strand_vert.glsl +++ b/source/blender/draw/modes/shaders/particle_strand_vert.glsl @@ -55,16 +55,17 @@ void main() #endif #ifdef USE_POINTS - gl_PointSize = sizeVertex; + float size = sizeVertex * 2.0; + gl_PointSize = size; /* calculate concentric radii in pixels */ - float radius = 0.5 * sizeVertex; + float radius = sizeVertex; /* start at the outside and progress toward the center */ radii[0] = radius; radii[1] = radius - 1.0; /* convert to PointCoord units */ - radii /= sizeVertex; + radii /= size; #endif } diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 21b9c7252d2..b93d52a1b2d 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -1711,8 +1711,7 @@ static void update_dependencies_on_delete(bAnimListElem *ale) AnimData *adt = BKE_animdata_from_id(id); /* TODO(sergey): Technically, if the animation element is being deleted * from a driver we don't have to tag action. This is something we can check - * for in the future. For now just do most reliable tag whic hwas always - * happening. */ + * for in the future. For now just do most reliable tag which was always happening. */ if (adt != NULL) { DEG_id_tag_update(id, ID_RECALC_ANIMATION); if (adt->action != NULL) { diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 8d30076103b..2d16ce30d31 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -2231,7 +2231,7 @@ static size_t animdata_filter_ds_textures( } } - /* Firstly check that we actuallly have some textures, + /* Firstly check that we actually have some textures, * by gathering all textures in a temp list. */ for (a = 0; a < MAX_MTEX; a++) { Tex *tex = (mtex[a]) ? mtex[a]->tex : NULL; @@ -3151,7 +3151,9 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, } /* movie clip's animation */ - items += animdata_filter_dopesheet_movieclips(ac, anim_data, ads, filter_mode); + if (!(ads->filterflag2 & ADS_FILTER_NOMOVIECLIPS) && !(ads->filterflag & ADS_FILTER_ONLYSEL)) { + items += animdata_filter_dopesheet_movieclips(ac, anim_data, ads, filter_mode); + } /* Scene-linked animation - e.g. world, compositing nodes, scene anim * (including sequencer currently). */ diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c index d3c6109afcd..7a5b57b1ce6 100644 --- a/source/blender/editors/animation/anim_motion_paths.c +++ b/source/blender/editors/animation/anim_motion_paths.c @@ -322,8 +322,8 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph, /* reset original environment */ /* NOTE: We don't always need to reevaluate the main scene, as the depsgraph - * may be a temporary one that works on a subset of the data. We always have - * to resoture the current frame though. */ + * may be a temporary one that works on a subset of the data. + * We always have to restore the current frame though. */ CFRA = cfra; if (!current_frame_only && restore) { motionpaths_calc_update_scene(bmain, depsgraph); diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 31f7a337d57..2e7ed7eae34 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -532,7 +532,7 @@ int insert_vert_fcurve( * introduced discontinuities in how the param worked. */ beztr.back = 1.70158f; - /* "elastic" easing - values here were hand-optimised for a default duration of + /* "elastic" easing - values here were hand-optimized for a default duration of * ~10 frames (typical mograph motion length) */ beztr.amplitude = 0.8f; beztr.period = 4.1f; @@ -2249,10 +2249,16 @@ static int delete_key_v3d_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); float cfra = (float)CFRA; + int selected_objects_len = 0; + int selected_objects_success_len = 0; + int success_multi = 0; + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { ID *id = &ob->id; int success = 0; + selected_objects_len += 1; + /* just those in active action... */ if ((ob->adt) && (ob->adt->action)) { AnimData *adt = ob->adt; @@ -2317,22 +2323,29 @@ static int delete_key_v3d_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&ob->adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); } - /* report success (or failure) */ + /* Only for reporting. */ if (success) { - BKE_reportf(op->reports, - RPT_INFO, - "Object '%s' successfully had %d keyframes removed", - id->name + 2, - success); - } - else { - BKE_reportf(op->reports, RPT_ERROR, "No keyframes removed from Object '%s'", id->name + 2); + selected_objects_success_len += 1; + success_multi += success; } DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); } CTX_DATA_END; + /* report success (or failure) */ + if (selected_objects_success_len) { + BKE_reportf(op->reports, + RPT_INFO, + "%d object(s) successfully had %d keyframes removed", + selected_objects_success_len, + success_multi); + } + else { + BKE_reportf( + op->reports, RPT_ERROR, "No keyframes removed from %d object(s)", selected_objects_len); + } + /* send updates */ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index d02e58d48a9..d2fa77f90be 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -1121,6 +1121,8 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z } + ED_armature_edit_refresh_layer_used(obedit->data); + /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index c5430e06b6e..4e6661b1d15 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -862,6 +862,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) } /* updates */ + ED_armature_edit_refresh_layer_used(arm); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); /* free points */ @@ -1053,6 +1054,7 @@ static int armature_merge_exec(bContext *C, wmOperator *op) /* updates */ ED_armature_edit_sync_selection(arm->edbo); + ED_armature_edit_refresh_layer_used(arm); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); } MEM_freeN(objects); @@ -1460,8 +1462,8 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) changed_multi = true; ED_armature_edit_sync_selection(arm->edbo); + ED_armature_edit_refresh_layer_used(arm); BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose); - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); } } @@ -1635,6 +1637,7 @@ static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op)) if (changed) { changed_multi = true; ED_armature_edit_sync_selection(arm->edbo); + ED_armature_edit_refresh_layer_used(arm); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); } } diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 2c61818d902..8722e575d15 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -38,6 +38,7 @@ #include "BKE_action.h" #include "BKE_animsys.h" +#include "BKE_armature.h" #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_fcurve.h" @@ -426,6 +427,7 @@ int join_armature_exec(bContext *C, wmOperator *op) ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); + BKE_armature_refresh_layer_used(arm); DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); @@ -671,6 +673,9 @@ static int separate_armature_exec(bContext *C, wmOperator *op) ED_armature_to_edit(obedit->data); + ED_armature_edit_refresh_layer_used(obedit->data); + BKE_armature_refresh_layer_used(newob->data); + /* parents tips remain selected when connected children are removed. */ ED_armature_edit_deselect_all(obedit); diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 5d424594229..d8777b7e0b7 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -85,6 +85,18 @@ void ED_armature_edit_validate_active(struct bArmature *arm) } } +/* Update the layers_used variable after bones are moved between layer + * NOTE: Used to be done in drawing code in 2.7, but that won't work with + * Copy-on-Write, as drawing uses evaluated copies. + */ +void ED_armature_edit_refresh_layer_used(bArmature *arm) +{ + arm->layer_used = 0; + for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) { + arm->layer_used |= ebo->layer; + } +} + /* *************************************************************** */ /* Bone Operations */ diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c index 3a2440af2da..4a82a8fccee 100644 --- a/source/blender/editors/armature/editarmature_undo.c +++ b/source/blender/editors/armature/editarmature_undo.c @@ -174,7 +174,8 @@ static bool armature_undosys_step_encode(struct bContext *C, static void armature_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, - int UNUSED(dir)) + int UNUSED(dir), + bool UNUSED(is_final)) { ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 745af06c7af..5daf6b584e5 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -872,6 +872,8 @@ static int pose_bone_layers_exec(bContext *C, wmOperator *op) RNA_boolean_set_array(&ptr, "layers", layers); if (prev_ob != ob) { + BKE_armature_refresh_layer_used(ob->data); + /* Note, notifier might evolve. */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); DEG_id_tag_update((ID *)ob->data, ID_RECALC_COPY_ON_WRITE); @@ -949,6 +951,8 @@ static int armature_bone_layers_exec(bContext *C, wmOperator *op) } CTX_DATA_END; + ED_armature_edit_refresh_layer_used(ob->data); + /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index e9ea49aaf03..8434fee6e78 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -40,6 +40,7 @@ #include "BKE_object.h" #include "BKE_report.h" #include "BKE_layer.h" +#include "BKE_modifier.h" #include "DEG_depsgraph.h" @@ -181,10 +182,17 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer, if (!extend && !deselect && !toggle) { { - uint bases_len = 0; - Base **bases = BKE_object_pose_base_array_get_unique(view_layer, v3d, &bases_len); - ED_pose_deselect_all_multi_ex(bases, bases_len, SEL_DESELECT, true); - MEM_freeN(bases); + /* Don't use 'BKE_object_pose_base_array_get_unique' + * because we may be selecting from object mode. */ + FOREACH_VISIBLE_BASE_BEGIN (view_layer, v3d, base_iter) { + Object *ob_iter = base_iter->object; + if ((ob_iter->type == OB_ARMATURE) && (ob_iter->mode & OB_MODE_POSE)) { + if (ED_pose_deselect_all(ob_iter, SEL_DESELECT, true)) { + ED_pose_bone_select_tag_update(ob_iter); + } + } + } + FOREACH_VISIBLE_BASE_END; } nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); arm->act_bone = nearBone; @@ -240,6 +248,38 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer, return nearBone != NULL; } +/** + * While in weight-paint mode, a single pose may be active as well. + * While not common, it's possible we have multiple armatures deforming a mesh. + * + * This function de-selects all other objects, and selects the new base. + * It can't be set to the active object because we need + * to keep this set to the weight paint object. + */ +void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_select) +{ + BLI_assert(base_select && (base_select->object->type == OB_ARMATURE)); + Object *ob_active = OBACT(view_layer); + BLI_assert(ob_active && (ob_active->mode & OB_MODE_WEIGHT_PAINT)); + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob_active, &virtualModifierData); + for (; md; md = md->next) { + if (md->type == eModifierType_Armature) { + ArmatureModifierData *amd = (ArmatureModifierData *)md; + Object *ob_arm = amd->object; + if (ob_arm != NULL) { + Base *base_arm = BKE_view_layer_base_find(view_layer, ob_arm); + if ((base_arm != NULL) && (base_arm != base_select) && (base_arm->flag & BASE_SELECTED)) { + ED_object_base_select(base_arm, BA_DESELECT); + } + } + } + } + if ((base_select->flag & BASE_SELECTED) == 0) { + ED_object_base_select(base_select, BA_SELECT); + } +} + /* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT. * When true, 'ignore_visibility' makes this func also affect invisible bones * (hidden or on hidden layers). */ diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 97317a86104..4c5a42cade6 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -584,7 +584,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) /* perform blending */ if (pso->mode == POSESLIDE_BREAKDOWN) { - /* Just perform the interpol between quat_prev and + /* Just perform the interpolation between quat_prev and * quat_next using pso->percentage as a guide. */ interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage); } diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c index d0c2afcb1d2..835abd1a630 100644 --- a/source/blender/editors/curve/editcurve_undo.c +++ b/source/blender/editors/curve/editcurve_undo.c @@ -238,10 +238,8 @@ static bool curve_undosys_step_encode(struct bContext *C, return true; } -static void curve_undosys_step_decode(struct bContext *C, - struct Main *bmain, - UndoStep *us_p, - int UNUSED(dir)) +static void curve_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final)) { CurveUndoStep *us = (CurveUndoStep *)us_p; diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index ffbfb692ca9..db3d5ad401d 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -73,9 +73,9 @@ static int kill_selection(Object *obedit, int ins); /************************* utilities ******************************/ -static char findaccent(char char1, unsigned int code) +static wchar_t findaccent(wchar_t char1, unsigned int code) { - char new = 0; + wchar_t new = 0; if (char1 == 'a') { if (code == '`') { @@ -170,7 +170,7 @@ static char findaccent(char char1, unsigned int code) new = 186; } else if (code == 'e') { - new = 143; + new = 339; } else if (code == 'c') { new = 169; @@ -191,7 +191,7 @@ static char findaccent(char char1, unsigned int code) } else if (char1 == 't') { if (code == 'm') { - new = 153; + new = 8482; } } else if (char1 == 'u') { @@ -342,7 +342,7 @@ static char findaccent(char char1, unsigned int code) new = 247; } if (code == '|') { - new = 135; + new = 8224; } if (code == '+') { new = 177; @@ -350,15 +350,15 @@ static char findaccent(char char1, unsigned int code) } else if (char1 == '|') { if (code == '-') { - new = 135; + new = 8224; } if (code == '=') { - new = 136; + new = 8225; } } else if (char1 == '=') { if (code == '|') { - new = 136; + new = 8225; } } else if (char1 == '+') { diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c index 82c19db7a4a..2f8f15bc6c7 100644 --- a/source/blender/editors/curve/editfont_undo.c +++ b/source/blender/editors/curve/editfont_undo.c @@ -62,7 +62,7 @@ typedef struct UndoFont { wchar_t *textbuf; struct CharInfo *textbufinfo; - int len, pos; + int len, pos, selstart, selend; #ifdef USE_ARRAY_STORE struct { @@ -241,10 +241,10 @@ static void undofont_to_editfont(UndoFont *uf, Curve *cu) memcpy(ef->textbufinfo, uf->textbufinfo, final_size); ef->pos = uf->pos; + ef->selstart = uf->selstart; + ef->selend = uf->selend; ef->len = uf->len; - ef->selstart = ef->selend = 0; - #ifdef USE_ARRAY_STORE uf_arraystore_expand_clear(uf); #endif @@ -269,6 +269,8 @@ static void *undofont_from_editfont(UndoFont *uf, Curve *cu) memcpy(uf->textbufinfo, ef->textbufinfo, final_size); uf->pos = ef->pos; + uf->selstart = ef->selstart; + uf->selend = ef->selend; uf->len = ef->len; #ifdef USE_ARRAY_STORE @@ -356,7 +358,8 @@ static bool font_undosys_step_encode(struct bContext *C, static void font_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, - int UNUSED(dir)) + int UNUSED(dir), + bool UNUSED(is_final)) { /* TODO(campbell): undo_system: use low-level API to set mode. */ ED_object_mode_set(C, OB_MODE_EDIT); diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c index 780cca66fb9..ba3b8c2602e 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c @@ -101,6 +101,7 @@ static bool gizmo_calc_rect_view_margin(const wmGizmo *gz, const float dims[2], handle_size *= gz->scale_final; float scale_xy[2]; if (!gizmo_calc_rect_view_scale(gz, dims, scale_xy)) { + zero_v2(margin); return false; } margin[0] = ((handle_size * scale_xy[0])); diff --git a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c index 31e30a0dd1a..6d8ab096a26 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c @@ -129,7 +129,26 @@ static void dial_geom_draw(const float color[4], immUniformColor4fv(color); if (filled) { - imm_draw_circle_fill_2d(pos, 0, 0, 1.0, DIAL_RESOLUTION); + if (arc_partial_angle == 0.0f) { + if (arc_inner_factor == 0.0f) { + imm_draw_circle_fill_2d(pos, 0, 0, 1.0, DIAL_RESOLUTION); + } + else { + imm_draw_disk_partial_fill_2d( + pos, 0, 0, arc_inner_factor, 1.0f, DIAL_RESOLUTION, 0, RAD2DEGF(M_PI * 2)); + } + } + else { + float arc_partial_deg = RAD2DEGF((M_PI * 2) - arc_partial_angle); + imm_draw_disk_partial_fill_2d(pos, + 0, + 0, + arc_inner_factor, + 1.0f, + DIAL_RESOLUTION, + -arc_partial_deg / 2, + arc_partial_deg); + } } else { if (arc_partial_angle == 0.0f) { diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 5f08035a56b..809acc3b322 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -888,7 +888,7 @@ static void gp_draw_strokes(tGPDdraw *tgpw) /* if disable fill, the colors with fill must be omitted too except fill boundary strokes */ if ((tgpw->disable_fill == 1) && (gp_style->fill_rgba[3] > 0.0f) && - ((gps->flag & GP_STROKE_NOFILL) == 0)) { + ((gps->flag & GP_STROKE_NOFILL) == 0) && (gp_style->flag & GP_STYLE_FILL_SHOW)) { continue; } diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index f5b27d8268d..7d866aedd87 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -579,6 +579,7 @@ static bool gp_brush_push_apply( mul_v3_v3fl(delta, gso->dvec, inf); /* apply */ + mul_mat3_m4_v3(gso->object->obmat, delta); /* only rotation component */ add_v3_v3(&pt->x, delta); /* compute lock axis */ @@ -646,7 +647,9 @@ static bool gp_brush_pinch_apply( inf = gp_brush_influence_calc(gso, radius, co) / 5.0f; /* 1) Make this point relative to the cursor/midpoint (dvec) */ - sub_v3_v3v3(vec, &pt->x, gso->dvec); + float fpt[3]; + mul_v3_m4v3(fpt, gso->object->obmat, &pt->x); + sub_v3_v3v3(vec, fpt, gso->dvec); /* 2) Shrink the distance by pulling the point towards the midpoint * (0.0 = at midpoint, 1 = at edge of brush region) @@ -664,7 +667,8 @@ static bool gp_brush_pinch_apply( mul_v3_fl(vec, fac); /* 3) Translate back to original space, with the shrinkage applied */ - add_v3_v3v3(&pt->x, gso->dvec, vec); + add_v3_v3v3(fpt, gso->dvec, vec); + mul_v3_m4v3(&pt->x, gso->object->imat, fpt); /* compute lock axis */ gpsculpt_compute_lock_axis(gso, pt, save_pt); @@ -713,11 +717,14 @@ static bool gp_brush_twist_apply( axis_angle_normalized_to_mat3(rmat, axis, angle); - /* Rotate point (no matrix-space transforms needed, as GP points are in world space) */ - sub_v3_v3v3(vec, &pt->x, gso->dvec); /* make relative to center - * (center is stored in dvec) */ + /* Rotate point */ + float fpt[3]; + mul_v3_m4v3(fpt, gso->object->obmat, &pt->x); + sub_v3_v3v3(vec, fpt, gso->dvec); /* make relative to center + * (center is stored in dvec) */ mul_m3_v3(rmat, vec); - add_v3_v3v3(&pt->x, vec, gso->dvec); /* restore */ + add_v3_v3v3(fpt, vec, gso->dvec); /* restore */ + mul_v3_m4v3(&pt->x, gso->object->imat, fpt); /* compute lock axis */ gpsculpt_compute_lock_axis(gso, pt, save_pt); @@ -1090,8 +1097,12 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso) * get pasted relative to where the cursor is now */ for (i = 0, pt = new_stroke->points; i < new_stroke->totpoints; i++, pt++) { + /* Rotate around center new position */ + mul_mat3_m4_v3(gso->object->obmat, &pt->x); /* only rotation component */ + /* assume that the delta can just be applied, and then everything works */ add_v3_v3(&pt->x, delta); + mul_m4_v3(gso->object->imat, &pt->x); } /* Store ref for later */ diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 941c7645dc0..90a2b2d613c 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -1521,8 +1521,10 @@ static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op)) /* first lock all colors */ for (short i = 0; i < *totcol; i++) { Material *tmp_ma = give_current_material(ob, i + 1); - tmp_ma->gp_style->flag |= GP_STYLE_COLOR_LOCKED; - DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE); + if (tmp_ma) { + tmp_ma->gp_style->flag |= GP_STYLE_COLOR_LOCKED; + DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE); + } } /* loop all selected strokes and unlock any color */ @@ -2433,10 +2435,12 @@ static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op)) for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); - gp_style = ma->gp_style; - gp_style->flag |= GP_STYLE_COLOR_LOCKED; - gp_style->flag |= GP_STYLE_COLOR_HIDE; - DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + if (ma) { + gp_style = ma->gp_style; + gp_style->flag |= GP_STYLE_COLOR_LOCKED; + gp_style->flag |= GP_STYLE_COLOR_HIDE; + DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + } } /* loop all selected strokes and unlock any color used in active layer */ @@ -2515,7 +2519,7 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op) for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); /* Skip if this is the active one */ - if (ma == active_ma) { + if ((ma == NULL) || (ma == active_ma)) { continue; } @@ -2534,6 +2538,9 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op) /* Set flags on all "other" colors */ for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); + if (ma == NULL) { + continue; + } gp_style = ma->gp_style; if (gp_style == active_color) { continue; @@ -2548,6 +2555,9 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op) /* Clear flags - Restore everything else */ for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); + if (ma == NULL) { + continue; + } gp_style = ma->gp_style; gp_style->flag &= ~flags; DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); @@ -2610,10 +2620,12 @@ static int gpencil_color_hide_exec(bContext *C, wmOperator *op) MaterialGPencilStyle *color = NULL; for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); - color = ma->gp_style; - if (active_color != color) { - color->flag |= GP_STYLE_COLOR_HIDE; - DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + if (ma) { + color = ma->gp_style; + if (active_color != color) { + color->flag |= GP_STYLE_COLOR_HIDE; + DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + } } } } @@ -2671,9 +2683,11 @@ static int gpencil_color_reveal_exec(bContext *C, wmOperator *UNUSED(op)) for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); - gp_style = ma->gp_style; - gp_style->flag &= ~GP_STYLE_COLOR_HIDE; - DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + if (ma) { + gp_style = ma->gp_style; + gp_style->flag &= ~GP_STYLE_COLOR_HIDE; + DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + } } /* updates */ @@ -2722,9 +2736,11 @@ static int gpencil_color_lock_all_exec(bContext *C, wmOperator *UNUSED(op)) for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); - gp_style = ma->gp_style; - gp_style->flag |= GP_STYLE_COLOR_LOCKED; - DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + if (ma) { + gp_style = ma->gp_style; + gp_style->flag |= GP_STYLE_COLOR_LOCKED; + DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + } } /* updates */ @@ -2773,9 +2789,11 @@ static int gpencil_color_unlock_all_exec(bContext *C, wmOperator *UNUSED(op)) for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); - gp_style = ma->gp_style; - gp_style->flag &= ~GP_STYLE_COLOR_LOCKED; - DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + if (ma) { + gp_style = ma->gp_style; + gp_style->flag &= ~GP_STYLE_COLOR_LOCKED; + DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + } } /* updates */ diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 5459cd09e53..0c1c24a9432 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -883,7 +883,7 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps) } gps->flag |= GP_STROKE_RECALC_GEOMETRY; - /* if first point, add new point at the begining */ + /* If first point, add new point at the beginning. */ if (do_first) { copy_move_point(gps, temp_points, temp_dverts, 0, 0, true); /* deselect old */ @@ -2804,6 +2804,9 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) Object *ob = CTX_data_active_object(C); const int type = RNA_enum_get(op->ptr, "type"); + const bool geometry = RNA_boolean_get(op->ptr, "geometry"); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + bGPDstroke *gps = NULL; /* sanity checks */ if (ELEM(NULL, gpd)) { @@ -2812,39 +2815,55 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) /* loop all selected strokes */ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - if (gpl->actframe == NULL) { - continue; - } + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; - for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) { - MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { + continue; + } - /* skip strokes that are not selected or invalid for current view */ - if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false) { - continue; - } - /* skip hidden or locked colors */ - if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) || - (gp_style->flag & GP_STYLE_COLOR_LOCKED)) { - continue; - } + for (gps = gpf->strokes.first; gps; gps = gps->next) { + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + /* skip strokes that are not selected or invalid for current view */ + if (((gps->flag & GP_STROKE_SELECT) == 0) || + ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + /* skip hidden or locked colors */ + if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) || + (gp_style->flag & GP_STYLE_COLOR_LOCKED)) { + continue; + } - switch (type) { - case GP_STROKE_CYCLIC_CLOSE: - /* Close all (enable) */ - gps->flag |= GP_STROKE_CYCLIC; - break; - case GP_STROKE_CYCLIC_OPEN: - /* Open all (disable) */ - gps->flag &= ~GP_STROKE_CYCLIC; - break; - case GP_STROKE_CYCLIC_TOGGLE: - /* Just toggle flag... */ - gps->flag ^= GP_STROKE_CYCLIC; - break; - default: - BLI_assert(0); + switch (type) { + case GP_STROKE_CYCLIC_CLOSE: + /* Close all (enable) */ + gps->flag |= GP_STROKE_CYCLIC; + break; + case GP_STROKE_CYCLIC_OPEN: + /* Open all (disable) */ + gps->flag &= ~GP_STROKE_CYCLIC; + break; + case GP_STROKE_CYCLIC_TOGGLE: + /* Just toggle flag... */ + gps->flag ^= GP_STROKE_CYCLIC; + break; + default: + BLI_assert(0); + break; + } + + /* Create new geometry. */ + if ((gps->flag & GP_STROKE_CYCLIC) && (geometry)) { + BKE_gpencil_close_stroke(gps); + } + } + + /* if not multiedit, exit loop*/ + if (!is_multiedit) { break; + } } } } @@ -2863,6 +2882,8 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) */ void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot) { + PropertyRNA *prop; + static const EnumPropertyItem cyclic_type[] = { {GP_STROKE_CYCLIC_CLOSE, "CLOSE", 0, "Close all", ""}, {GP_STROKE_CYCLIC_OPEN, "OPEN", 0, "Open all", ""}, @@ -2884,6 +2905,9 @@ void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot) /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", ""); + prop = RNA_def_boolean( + ot->srna, "geometry", false, "Create Geometry", "Create new geometry for closing stroke"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* ******************* Flat Stroke Caps ************************** */ diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 8a9f7c1224a..4d5548dcdf3 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -996,8 +996,9 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) float factor; /* get interpolation factor */ - factor = (float)(cframe - prevFrame->framenum) / - (nextFrame->framenum - prevFrame->framenum + 1); + float framerange = nextFrame->framenum - prevFrame->framenum; + CLAMP_MIN(framerange, 1.0f); + factor = (float)(cframe - prevFrame->framenum) / framerange; if (ipo_settings->type == GP_IPO_CURVEMAP) { /* custom curvemap */ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index f6691f4813b..b49094c4fd6 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -3708,7 +3708,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* handle drawing event */ /* printf("\t\tGP - add point\n"); */ - if (((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0)) { + if (((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) && (p->paintmode != GP_PAINTMODE_ERASER)) { gpencil_add_missing_events(C, op, event, p); } diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 21bee0a9d4e..cca94925e6e 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -225,8 +225,8 @@ static void gp_primitive_update_cps(tGPDprimitive *tgpi) } else if (tgpi->type == GP_STROKE_CURVE) { mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end); - copy_v2_v2(tgpi->cp1, tgpi->midpoint); - copy_v2_v2(tgpi->cp2, tgpi->cp1); + interp_v2_v2v2(tgpi->cp1, tgpi->midpoint, tgpi->start, 0.33f); + interp_v2_v2v2(tgpi->cp2, tgpi->midpoint, tgpi->end, 0.33f); } else if (tgpi->type == GP_STROKE_ARC) { if (tgpi->flip) { @@ -1284,6 +1284,11 @@ static void gpencil_primitive_interaction_end(bContext *C, } } + /* Close stroke with geometry */ + if ((tgpi->type == GP_STROKE_BOX) || (tgpi->type == GP_STROKE_CIRCLE)) { + BKE_gpencil_close_stroke(gps); + } + DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_COPY_ON_WRITE); DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index 7d4b6dbeea2..101a65d151a 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -172,8 +172,6 @@ int ED_draw_imbuf_method(struct ImBuf *ibuf); /* OpenGL drawing utility functions. Do not use these in new code, these * are intended to be moved or removed in the future. */ -void set_inverted_drawing(int enable); - /* own working polygon offset */ float bglPolygonOffsetCalc(const float winmat[16], float viewdist, float dist); void bglPolygonOffset(float viewdist, float dist); diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index aca59e2868f..6629eed8328 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -170,6 +170,10 @@ bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer, bool deselect, bool toggle, bool do_nearest); + +void ED_armature_pose_select_in_wpaint_mode(struct ViewLayer *view_layer, + struct Base *base_select); + bool ED_armature_edit_select_pick( struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); @@ -184,6 +188,8 @@ EditBone *ED_armature_ebone_get_mirrored(const struct ListBase *edbo, EditBone * void ED_armature_edit_sync_selection(struct ListBase *edbo); void ED_armature_edit_validate_active(struct bArmature *arm); +void ED_armature_edit_refresh_layer_used(struct bArmature *arm); + struct Base *ED_armature_base_and_ebone_from_select_buffer(struct Base **bases, uint bases_len, int hit, diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 5d8038d0b28..d2613facd83 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -393,6 +393,9 @@ bool ED_mesh_color_remove_named(struct Mesh *me, const char *name); void ED_mesh_report_mirror(struct wmOperator *op, int totmirr, int totfail); void ED_mesh_report_mirror_ex(struct wmOperator *op, int totmirr, int totfail, char selectmode); +/* Returns the pinned mesh, the mesh from the pinned object, or the mesh from the active object. */ +struct Mesh *ED_mesh_context(struct bContext *C); + /* mesh backup */ typedef struct BMBackup { struct BMesh *bmcopy; diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index a4c68c2c5ad..038f1bf52a6 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -121,6 +121,9 @@ void ED_object_parent_clear(struct Object *ob, const int type); void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode); void ED_object_base_activate(struct bContext *C, struct Base *base); +void ED_object_base_active_refresh(struct Main *bmain, + struct Scene *scene, + struct ViewLayer *view_layer); void ED_object_base_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Object *ob); bool ED_object_base_deselect_all_ex(struct ViewLayer *view_layer, struct View3D *v3d, diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index 7689a9f97cd..d36d2559f26 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -93,7 +93,8 @@ void ED_preview_icon_job(const struct bContext *C, struct ID *id, unsigned int *rect, int sizex, - int sizey); + int sizey, + const bool delay); void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain); void ED_preview_draw(const struct bContext *C, void *idp, void *parentp, void *slot, rcti *rect); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index fc43144417a..e67a3b003fc 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -337,6 +337,7 @@ bool ED_operator_object_active(struct bContext *C); bool ED_operator_object_active_editable(struct bContext *C); bool ED_operator_object_active_editable_mesh(struct bContext *C); bool ED_operator_object_active_editable_font(struct bContext *C); +bool ED_operator_editable_mesh(struct bContext *C); bool ED_operator_editmesh(struct bContext *C); bool ED_operator_editmesh_view3d(struct bContext *C); bool ED_operator_editmesh_region_view3d(struct bContext *C); diff --git a/source/blender/editors/include/ED_text.h b/source/blender/editors/include/ED_text.h index 7638249d49a..ed71439bd37 100644 --- a/source/blender/editors/include/ED_text.h +++ b/source/blender/editors/include/ED_text.h @@ -26,7 +26,7 @@ struct ARegion; struct SpaceText; -struct TextUndoBuf; +struct UndoStep; struct UndoType; bool ED_text_region_location_from_cursor(struct SpaceText *st, @@ -37,6 +37,6 @@ bool ED_text_region_location_from_cursor(struct SpaceText *st, /* text_undo.c */ void ED_text_undosys_type(struct UndoType *ut); -struct TextUndoBuf *ED_text_undo_push_init(struct bContext *C); +struct UndoStep *ED_text_undo_push_init(struct bContext *C); #endif /* __ED_TEXT_H__ */ 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 75564ddd947..f27523bb1f8 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -121,16 +121,16 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx, bool sort, struct ListBase *r_hit_list); -bool ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx, - const unsigned short snap_to, - const struct SnapObjectParams *params, - const float mval[2], - float *dist_px, - float r_loc[3], - float r_no[3], - int *r_index, - struct Object **r_ob, - float r_obmat[4][4]); +short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx, + const unsigned short snap_to, + const struct SnapObjectParams *params, + const float mval[2], + float *dist_px, + float r_loc[3], + float r_no[3], + int *r_index, + struct Object **r_ob, + float r_obmat[4][4]); bool ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx, const unsigned short snap_to, const struct SnapObjectParams *params, diff --git a/source/blender/editors/include/ED_undo.h b/source/blender/editors/include/ED_undo.h index ebc50e186a2..fa2630ba726 100644 --- a/source/blender/editors/include/ED_undo.h +++ b/source/blender/editors/include/ED_undo.h @@ -54,6 +54,9 @@ bool ED_undo_is_valid(const struct bContext *C, const char *undoname); bool ED_undo_is_memfile_compatible(const struct bContext *C); +/* Unfortunate workaround for limits mixing undo systems. */ +bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, struct ID *id); + void ED_undo_object_editmode_restore_helper(struct bContext *C, struct Object **object_array, uint object_array_len, diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 3d2052f1fa9..47cf827ed66 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -45,6 +45,9 @@ #ifndef DEF_ICON_COLOR # define DEF_ICON_COLOR DEF_ICON #endif +#ifndef DEF_ICON_FUND +# define DEF_ICON_FUND DEF_ICON +#endif /* ICON_ prefix added */ DEF_ICON_COLOR(NONE) @@ -289,7 +292,7 @@ DEF_ICON(DECORATE_LIBRARY_OVERRIDE) DEF_ICON(DECORATE_UNLOCKED) DEF_ICON(DECORATE_LOCKED) DEF_ICON(DECORATE_OVERRIDE) -DEF_ICON_BLANK(111) +DEF_ICON_FUND(FUND) DEF_ICON(TRACKER_DATA) DEF_ICON(HEART) DEF_ICON(ORPHAN_DATA) @@ -1033,4 +1036,5 @@ DEF_ICON_COLOR(EVENT_RETURN) #undef DEF_ICON_SHADING #undef DEF_ICON_VECTOR #undef DEF_ICON_COLOR +#undef DEF_ICON_FUND #undef DEF_ICON_BLANK diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index bf728ec7772..3b2a80c1e05 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -723,7 +723,7 @@ bool UI_block_active_only_flagged_buttons(const struct bContext *C, struct ARegion *ar, struct uiBlock *block); -void UI_but_execute(const struct bContext *C, uiBut *but); +void UI_but_execute(const struct bContext *C, struct ARegion *ar, uiBut *but); bool UI_but_online_manual_id(const uiBut *but, char *r_str, diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index db6bb35560d..3b080b6df95 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -272,6 +272,7 @@ typedef enum ThemeColorID { TH_ICON_OBJECT_DATA, TH_ICON_MODIFIER, TH_ICON_SHADING, + TH_ICON_FUND, TH_SCROLL_TEXT, diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 137c431e3bf..0dbf3c710d6 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -71,7 +71,7 @@ enum eView2D_CommonViewTypes { #define V2D_SCROLL_HANDLE_SIZE_HOTSPOT (0.6f * U.widget_unit) /** Don't allow scroll thumb to show below this size (so it's never too small to click on). */ -#define V2D_SCROLL_THUMB_SIZE_MIN (50.0 * UI_DPI_FAC) +#define V2D_SCROLL_THUMB_SIZE_MIN (30.0 * UI_DPI_FAC) /* ------ Define for UI_view2d_sync ----- */ diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 697c289491a..a2138a1b3a5 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -896,9 +896,8 @@ bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *ar, uiBloc } /* simulate button click */ -void UI_but_execute(const bContext *C, uiBut *but) +void UI_but_execute(const bContext *C, ARegion *ar, uiBut *but) { - ARegion *ar = CTX_wm_region(C); void *active_back; ui_but_execute_begin((bContext *)C, ar, but, &active_back); /* Value is applied in begin. No further action required. */ diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c index be02def1693..cc68e303e4a 100644 --- a/source/blender/editors/interface/interface_align.c +++ b/source/blender/editors/interface/interface_align.c @@ -251,7 +251,7 @@ static void block_align_proximity_compute(ButAlign *butal, ButAlign *butal_other } } /* We assume two buttons can only share one side at most - for until - * we have sperical UI... */ + * we have spherical UI. */ return; } } diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 36e197a0591..7cec8af46de 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -1030,23 +1030,6 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) 0, ""); UI_but_func_set(but2, popup_change_shortcut_func, but, NULL); - - but2 = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - ICON_BLANK1, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"), - 0, - 0, - w, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - ""); - UI_but_func_set(but2, remove_shortcut_func, but, NULL); } else { but2 = uiDefIconTextBut(block, @@ -1067,6 +1050,23 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) "please use User Preferences otherwise")); UI_but_flag_enable(but2, UI_BUT_DISABLED); } + + but2 = uiDefIconTextBut(block, + UI_BTYPE_BUT, + 0, + ICON_BLANK1, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"), + 0, + 0, + w, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + ""); + UI_but_func_set(but2, remove_shortcut_func, but, NULL); } /* only show 'assign' if there's a suitable key map for it to go in */ else if (WM_keymap_guess_opname(C, idname)) { diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c index 67e5a6c806c..ffe93e48936 100644 --- a/source/blender/editors/interface/interface_eyedropper_colorband.c +++ b/source/blender/editors/interface/interface_eyedropper_colorband.c @@ -84,22 +84,40 @@ static bool eyedropper_colorband_init(bContext *C, wmOperator *op) uiBut *but = UI_context_active_but_get(C); + PointerRNA rna_update_ptr = PointerRNA_NULL; + PropertyRNA *rna_update_prop = NULL; + bool is_undo = true; + if (but == NULL) { /* pass */ } - else if (but->type == UI_BTYPE_COLORBAND) { - /* When invoked with a hotkey, we can find the band in 'but->poin'. */ - band = (ColorBand *)but->poin; - } else { - /* When invoked from a button it's in custom_data field. */ - band = (ColorBand *)but->custom_data; + if (but->type == UI_BTYPE_COLORBAND) { + /* When invoked with a hotkey, we can find the band in 'but->poin'. */ + band = (ColorBand *)but->poin; + } + else { + /* When invoked from a button it's in custom_data field. */ + band = (ColorBand *)but->custom_data; + } + + if (band) { + rna_update_ptr = ((Colorband_RNAUpdateCb *)but->func_argN)->ptr; + rna_update_prop = ((Colorband_RNAUpdateCb *)but->func_argN)->prop; + is_undo = UI_but_flag_is_set(but, UI_BUT_UNDO); + } } if (!band) { PointerRNA ptr = CTX_data_pointer_get_type(C, "color_ramp", &RNA_ColorRamp); if (ptr.data != NULL) { band = ptr.data; + + /* Set this to a sub-member of the property to trigger an update. */ + extern PropertyRNA rna_ColorRamp_color_mode; + rna_update_ptr = ptr; + rna_update_prop = &rna_ColorRamp_color_mode; + is_undo = RNA_struct_undo_check(ptr.type); } } @@ -113,9 +131,9 @@ static bool eyedropper_colorband_init(bContext *C, wmOperator *op) eye->color_buffer_len = 0; eye->color_band = band; eye->init_color_band = *eye->color_band; - eye->ptr = ((Colorband_RNAUpdateCb *)but->func_argN)->ptr; - eye->prop = ((Colorband_RNAUpdateCb *)but->func_argN)->prop; - eye->is_undo = UI_but_flag_is_set(but, UI_BUT_UNDO); + eye->ptr = rna_update_ptr; + eye->prop = rna_update_prop; + eye->is_undo = is_undo; op->customdata = eye; @@ -186,7 +204,9 @@ static void eyedropper_colorband_apply(bContext *C, wmOperator *op) BKE_colorband_init_from_table_rgba( eye->color_band, eye->color_buffer, eye->color_buffer_len, filter_samples); eye->is_set = true; - RNA_property_update(C, &eye->ptr, eye->prop); + if (eye->prop) { + RNA_property_update(C, &eye->ptr, eye->prop); + } } static void eyedropper_colorband_cancel(bContext *C, wmOperator *op) @@ -194,7 +214,9 @@ static void eyedropper_colorband_cancel(bContext *C, wmOperator *op) EyedropperColorband *eye = op->customdata; if (eye->is_set) { *eye->color_band = eye->init_color_band; - RNA_property_update(C, &eye->ptr, eye->prop); + if (eye->prop) { + RNA_property_update(C, &eye->ptr, eye->prop); + } } eyedropper_colorband_exit(C, op); } @@ -267,7 +289,9 @@ static int eyedropper_colorband_point_modal(bContext *C, wmOperator *op, const w break; case EYE_MODAL_SAMPLE_RESET: *eye->color_band = eye->init_color_band; - RNA_property_update(C, &eye->ptr, eye->prop); + if (eye->prop) { + RNA_property_update(C, &eye->ptr, eye->prop); + } eye->color_buffer_len = 0; break; } diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c index adb317f488c..fc60fc06ac0 100644 --- a/source/blender/editors/interface/interface_eyedropper_depth.c +++ b/source/blender/editors/interface/interface_eyedropper_depth.c @@ -31,6 +31,7 @@ #include "DNA_space_types.h" #include "DNA_screen_types.h" #include "DNA_object_types.h" +#include "DNA_camera_types.h" #include "DNA_view3d_types.h" #include "BLI_string.h" @@ -102,8 +103,9 @@ static int depthdropper_init(bContext *C, wmOperator *op) if (rv3d && rv3d->persp == RV3D_CAMOB) { View3D *v3d = CTX_wm_view3d(C); if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) { - RNA_id_pointer_create(v3d->camera->data, &ddr->ptr); - ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance"); + Camera *camera = (Camera *)v3d->camera->data; + RNA_pointer_create(&camera->id, &RNA_CameraDOFSettings, &camera->dof, &ddr->ptr); + ddr->prop = RNA_struct_find_property(&ddr->ptr, "focus_distance"); ddr->is_undo = true; } } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index e59431d265d..a7fc0cfec25 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -551,12 +551,15 @@ static bool ui_but_dragedit_update_mval(uiHandleButtonData *data, int mx) return true; } -static void ui_but_update_preferences_dirty(uiBut *but) +static void ui_rna_update_preferences_dirty(PointerRNA *ptr, PropertyRNA *prop) { /* Not very elegant, but ensures preference changes force re-save. */ bool tag = false; - if (but->rnaprop) { - StructRNA *base = RNA_struct_base(but->rnapoin.type); + if (prop && !(RNA_property_flag(prop) & PROP_NO_DEG_UPDATE)) { + StructRNA *base = RNA_struct_base(ptr->type); + if (base == NULL) { + base = ptr->type; + } if (ELEM(base, &RNA_AddonPreferences, &RNA_KeyConfigPreferences, &RNA_KeyMapItem)) { tag = true; } @@ -568,6 +571,16 @@ static void ui_but_update_preferences_dirty(uiBut *but) } } +static void ui_but_update_preferences_dirty(uiBut *but) +{ + ui_rna_update_preferences_dirty(&but->rnapoin, but->rnaprop); +} + +static void ui_afterfunc_update_preferences_dirty(uiAfterFunc *after) +{ + ui_rna_update_preferences_dirty(&after->rnapoin, after->rnaprop); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -743,6 +756,22 @@ static void ui_apply_but_undo(uiBut *but) str = "Unknown Action"; } + /* Optionally override undo when undo system doesn't support storing properties. */ + if (but->rnapoin.id.data) { + /* Exception for renaming ID data, we always need undo pushes in this case, + * because undo systems track data by their ID, see: T67002. */ + extern PropertyRNA rna_ID_name; + if (but->rnaprop == &rna_ID_name) { + /* pass */ + } + else { + ID *id = but->rnapoin.id.data; + if (!ED_undo_is_legacy_compatible_for_property(but->block->evil_C, id)) { + str = ""; + } + } + } + /* delayed, after all other funcs run, popups are closed, etc */ after = ui_afterfunc_new(); BLI_strncpy(after->undostr, str, sizeof(after->undostr)); @@ -843,6 +872,8 @@ static void ui_apply_but_funcs_after(bContext *C) MEM_freeN(after.rename_orig); } + ui_afterfunc_update_preferences_dirty(&after); + if (after.undostr[0]) { ED_undo_push(C, after.undostr); } @@ -1347,7 +1378,7 @@ static bool ui_drag_toggle_set_xy_xy( /* is it pressed? */ int pushed_state_but = ui_drag_toggle_but_pushed_state(C, but); if (pushed_state_but != pushed_state) { - UI_but_execute(C, but); + UI_but_execute(C, ar, but); if (do_check) { ui_but_update_edited(but); } @@ -7278,7 +7309,11 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s button_tooltip_timer_reset(C, but); /* automatic open pulldown block timer */ - if (ELEM(but->type, UI_BTYPE_BLOCK, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER)) { + if (ELEM(but->type, UI_BTYPE_BLOCK, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER) || + /* Menu button types may draw as popovers, check for this case + * ignoring other kinds of menus (mainly enums). (see T66538). */ + ((but->type == UI_BTYPE_MENU) && + (UI_but_paneltype_get(but) || ui_but_menu_draw_as_popover(but)))) { if (data->used_mouse && !data->autoopentimer) { int time; @@ -7939,6 +7974,8 @@ void ui_but_execute_begin(struct bContext *UNUSED(C), uiBut *but, void **active_back) { + BLI_assert(ar != NULL); + BLI_assert(BLI_findindex(&ar->uiblocks, but->block) != -1); /* note: ideally we would not have to change 'but->active' however * some functions we call don't use data (as they should be doing) */ uiHandleButtonData *data; @@ -9269,7 +9306,7 @@ static int ui_handle_menu_event(bContext *C, for (but = block->buttons.first; but; but = but->next) { if (!(but->flag & UI_BUT_DISABLED) && but->menu_key == event->type) { if (but->type == UI_BTYPE_BUT) { - UI_but_execute(C, but); + UI_but_execute(C, ar, but); } else { ui_handle_button_activate_by_type(C, ar, but); @@ -9350,7 +9387,7 @@ static int ui_handle_menu_event(bContext *C, ar, UI_BUT_ACTIVE_DEFAULT, UI_HIDDEN); if ((but_default != NULL) && (but_default->active == NULL)) { if (but_default->type == UI_BTYPE_BUT) { - UI_but_execute(C, but_default); + UI_but_execute(C, ar, but_default); } else { ui_handle_button_activate_by_type(C, ar, but_default); @@ -10100,9 +10137,10 @@ static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSE if ((data->state == BUTTON_STATE_MENU_OPEN) && /* make sure mouse isn't inside another menu (see T43247) */ - (is_inside_menu == false) && (ELEM(but->type, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER)) && + (is_inside_menu == false) && + (ELEM(but->type, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER, UI_BTYPE_MENU)) && (but_other = ui_but_find_mouse_over(ar, event)) && (but != but_other) && - (ELEM(but_other->type, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER))) { + (ELEM(but_other->type, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER, UI_BTYPE_MENU))) { /* if mouse moves to a different root-level menu button, * open it to replace the current menu */ if ((but_other->flag & UI_BUT_DISABLED) == 0) { diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 6f1f4dde1ab..ea5ef94d90d 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -169,6 +169,7 @@ static const IconType icontypes[] = { # define DEF_ICON_OBJECT_DATA(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_OBJECT_DATA}, # define DEF_ICON_MODIFIER(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_MODIFIER}, # define DEF_ICON_SHADING(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_SHADING}, +# define DEF_ICON_FUND(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_FUND}, # define DEF_ICON_VECTOR(name) {ICON_TYPE_VECTOR, 0}, # define DEF_ICON_COLOR(name) {ICON_TYPE_COLOR_TEXTURE, 0}, # define DEF_ICON_BLANK(name) {ICON_TYPE_BLANK, 0}, @@ -1417,11 +1418,13 @@ static void icon_set_image(const bContext *C, return; } + const bool delay = prv_img->rect[size] != NULL; icon_create_rect(prv_img, size); if (use_job) { /* Job (background) version */ - ED_preview_icon_job(C, prv_img, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]); + ED_preview_icon_job( + C, prv_img, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size], delay); } else { if (!scene) { diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index aa7e7f97478..f2b2a478ba9 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1052,8 +1052,7 @@ static int reports_to_text_exec(bContext *C, wmOperator *UNUSED(op)) str = BKE_reports_string(reports, (G.debug & G_DEBUG) ? RPT_DEBUG : RPT_INFO); if (str) { - TextUndoBuf *utxt = NULL; // FIXME - BKE_text_write(txt, utxt, str); + BKE_text_write(txt, str); MEM_freeN(str); return OPERATOR_FINISHED; @@ -1507,29 +1506,21 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot) /** \name Press Button Operator * \{ */ -static ARegion *region_event_inside_for_screen(bContext *C, const int xy[2]) -{ - bScreen *sc = CTX_wm_screen(C); - if (sc) { - for (ARegion *ar = sc->regionbase.first; ar; ar = ar->next) { - if (BLI_rcti_isect_pt_v(&ar->winrct, xy)) { - return ar; - } - } - } - return NULL; -} - static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + bScreen *sc = CTX_wm_screen(C); const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed"); ARegion *ar_prev = CTX_wm_region(C); - ARegion *ar = region_event_inside_for_screen(C, &event->x); + ARegion *ar = sc ? BKE_screen_find_region_xy(sc, RGN_TYPE_ANY, event->x, event->y) : NULL; if (ar == NULL) { ar = ar_prev; } + if (ar == NULL) { + return OPERATOR_PASS_THROUGH; + } + CTX_wm_region_set(C, ar); uiBut *but = UI_context_active_but_get(C); CTX_wm_region_set(C, ar_prev); @@ -1545,7 +1536,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev * having this avoids a minor drawing glitch. */ void *but_optype = but->optype; - UI_but_execute(C, but); + UI_but_execute(C, ar, but); but->optype = but_optype; diff --git a/source/blender/editors/interface/interface_region_color_picker.c b/source/blender/editors/interface/interface_region_color_picker.c index 5c231f5e51a..917c35f0135 100644 --- a/source/blender/editors/interface/interface_region_color_picker.c +++ b/source/blender/editors/interface/interface_region_color_picker.c @@ -63,6 +63,21 @@ enum ePickerType { /** \name Color Conversion * \{ */ +static void ui_color_picker_rgb_round(float rgb[3]) +{ + /* Handle small rounding errors in color space conversions. Doing these for + * all color space conversions would be expensive, but for the color picker + * we can do the extra work. */ + for (int i = 0; i < 3; i++) { + if (fabsf(rgb[i]) < 1e-6f) { + rgb[i] = 0.0f; + } + else if (fabsf(1.0f - rgb[i]) < 1e-6f) { + rgb[i] = 1.0f; + } + } +} + void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]) { switch (U.color_picker_type) { @@ -131,6 +146,7 @@ void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3]) * space for intuitive color picking. */ if (!ui_but_is_color_gamma(but)) { IMB_colormanagement_scene_linear_to_color_picking_v3(rgb); + ui_color_picker_rgb_round(rgb); } } @@ -138,6 +154,7 @@ void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3]) { if (!ui_but_is_color_gamma(but)) { IMB_colormanagement_color_picking_to_scene_linear_v3(rgb); + ui_color_picker_rgb_round(rgb); } } @@ -201,6 +218,7 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but, copy_v3_v3(rgb_hex, rgb); if (from_but && !ui_but_is_color_gamma(from_but)) { IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex); + ui_color_picker_rgb_round(rgb_hex); } rgb_float_to_uchar(rgb_hex_uchar, rgb_hex); @@ -287,6 +305,7 @@ static void ui_colorpicker_hex_rna_cb(bContext *UNUSED(C), void *bt1, void *hexc /* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */ if (!ui_but_is_color_gamma(but)) { IMB_colormanagement_srgb_to_scene_linear_v3(rgb); + ui_color_picker_rgb_round(rgb); } ui_update_color_picker_buts_rgb(but, but->block, cpicker, rgb); @@ -765,6 +784,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], if (!ui_but_is_color_gamma(from_but)) { IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex); + ui_color_picker_rgb_round(rgb_hex); } rgb_float_to_uchar(rgb_hex_uchar, rgb_hex); diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c index 6d1b2baeff9..43afdc534ad 100644 --- a/source/blender/editors/interface/interface_region_hud.c +++ b/source/blender/editors/interface/interface_region_hud.c @@ -27,6 +27,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_screen_types.h" #include "DNA_userdef_types.h" #include "BLI_string.h" @@ -231,6 +232,11 @@ ARegionType *ED_area_type_hud(int space_type) art->init = hud_region_init; art->free = hud_region_free; + /* We need to indicate a preferred size to avoid false `RGN_FLAG_TOO_SMALL` + * the first time the region is created. */ + art->prefsizex = AREAMINX; + art->prefsizey = HEADERY; + hud_panels_register(art, space_type, art->regionid); art->lock = 1; /* can become flag, see BKE_spacedata_draw_locks */ diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c index 22c62ecd6f7..53c96fb72a7 100644 --- a/source/blender/editors/interface/interface_region_popover.c +++ b/source/blender/editors/interface/interface_region_popover.c @@ -355,7 +355,7 @@ uiPopover *UI_popover_begin(bContext *C, int ui_size_x) } pup->ui_size_x = ui_size_x; - /* Opertor context default same as menus, change if needed. */ + /* Operator context default same as menus, change if needed. */ ui_popover_create_block(C, pup, WM_OP_EXEC_REGION_WIN); /* create in advance so we can let buttons point to retval already */ @@ -404,7 +404,7 @@ void UI_popover_end(bContext *C, uiPopover *pup, wmKeyMap *keymap) /* TODO(campbell): we may want to make this configurable. * The begin/end stype of calling popups doesn't allow to 'can_refresh' to be set. - * For now close this style of popvers when accessed. */ + * For now close this style of popovers when accessed. */ UI_block_flag_disable(pup->block, UI_BLOCK_KEEP_OPEN); /* panels are created flipped (from event handling pov) */ diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 5d3ef5c625e..1fc1af9815f 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -952,7 +952,7 @@ static void template_ID(bContext *C, /* Due to space limit in UI - skip the "open" icon for packed data, and allow to unpack. * Only for images, sound and fonts */ - if (id && BKE_pack_check(id)) { + if (id && BKE_packedfile_id_check(id)) { but = uiDefIconButO(block, UI_BTYPE_BUT, "FILE_OT_unpack_item", diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index ec0b01d4341..0bf8247dc17 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -2636,7 +2636,7 @@ static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag) wt->wcol.item[0] = wt->wcol.item[1] = wt->wcol.item[2] = rgb_to_grayscale_byte( (const uchar *)wt->wcol.item); widget_state_blend(wt->wcol.item, color_blend, wcol_state->blend); - rgb_ensure_contrast(wt->wcol.item, wt->wcol.inner, 20); + rgb_ensure_contrast(wt->wcol.item, wt->wcol.inner, 30); } if (state & UI_SELECT) { diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index e281c6c9e9c..25116934b06 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -901,6 +901,12 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) case TH_ICON_SHADING: cp = btheme->tui.icon_shading; break; + case TH_ICON_FUND: { + /* Development fund icon color is not part of theme. */ + static const char red[4] = {204, 48, 72, 255}; + cp = red; + break; + } case TH_SCROLL_TEXT: cp = btheme->tui.wcol_scroll.text; @@ -1377,12 +1383,14 @@ bool UI_GetIconThemeColor4ubv(int colorid, uchar col[4]) if (colorid == 0) { return false; } - - /* Only colored icons in outliner and popups, overall UI is intended - * to stay monochrome and out of the way except a few places where it - * is important to communicate different data types. */ - if (!((theme_spacetype == SPACE_OUTLINER && theme_regionid == RGN_TYPE_WINDOW) || - (theme_spacetype == SPACE_PROPERTIES && theme_regionid == RGN_TYPE_NAV_BAR))) { + else if (colorid == TH_ICON_FUND) { + /* Always color development fund icon. */ + } + else if (!((theme_spacetype == SPACE_OUTLINER && theme_regionid == RGN_TYPE_WINDOW) || + (theme_spacetype == SPACE_PROPERTIES && theme_regionid == RGN_TYPE_NAV_BAR))) { + /* Only colored icons in outliner and popups, overall UI is intended + * to stay monochrome and out of the way except a few places where it + * is important to communicate different data types. */ return false; } diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index 1f844961d19..dad84c87fd7 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -593,8 +593,8 @@ void WM_OT_collada_export(wmOperatorType *ot) "apply_global_orientation", false, "Apply Global Orientation", - "enabled: Rotate all root objects to match the global orientation " - "settings.\ndisabled: set global orientation in Collada assets"); + "Rotate all root objects to match the global orientation settings " + "otherwise set the global orientation per Collada asset"); RNA_def_boolean(func, "selected", false, "Selection Only", "Export only selected elements"); @@ -726,8 +726,8 @@ void WM_OT_collada_export(wmOperatorType *ot) INT_MIN, INT_MAX, "Transform", - "Transformation type for translation, scale and rotation\n" - "Note: The Animation transformation type in the Anim Tab\n" + "Transformation type for translation, scale and rotation. " + "Note: The Animation transformation type in the Anim Tab " "is always equal to the Object transformation type in the Geom tab", INT_MIN, INT_MAX); @@ -737,8 +737,8 @@ void WM_OT_collada_export(wmOperatorType *ot) prop_bc_export_transformation_type, 0, "Transform", - "Transformation type for translation, scale and rotation\n" - "Note: The Animation transformation type in the Anim Tab\n" + "Transformation type for translation, scale and rotation. " + "Note: The Animation transformation type in the Anim Tab " "is always equal to the Object transformation type in the Geom tab"); RNA_def_boolean(func, diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c index 166201adc15..abc5224c4d6 100644 --- a/source/blender/editors/lattice/editlattice_undo.c +++ b/source/blender/editors/lattice/editlattice_undo.c @@ -68,9 +68,19 @@ typedef struct UndoLattice { static void undolatt_to_editlatt(UndoLattice *ult, EditLatt *editlatt) { - int len = editlatt->latt->pntsu * editlatt->latt->pntsv * editlatt->latt->pntsw; + const int len_src = ult->pntsu * ult->pntsv * ult->pntsw; + const int len_dst = editlatt->latt->pntsu * editlatt->latt->pntsv * editlatt->latt->pntsw; + if (len_src != len_dst) { + MEM_freeN(editlatt->latt->def); + editlatt->latt->def = MEM_dupallocN(ult->def); + } + else { + memcpy(editlatt->latt->def, ult->def, sizeof(BPoint) * len_src); + } - memcpy(editlatt->latt->def, ult->def, sizeof(BPoint) * len); + editlatt->latt->pntsu = ult->pntsu; + editlatt->latt->pntsv = ult->pntsv; + editlatt->latt->pntsw = ult->pntsw; editlatt->latt->actbp = ult->actbp; } @@ -176,7 +186,8 @@ static bool lattice_undosys_step_encode(struct bContext *C, static void lattice_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, - int UNUSED(dir)) + int UNUSED(dir), + bool UNUSED(is_final)) { LatticeUndoStep *us = (LatticeUndoStep *)us_p; diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index fc85eab6e66..883dfe9ad7c 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -869,7 +869,7 @@ static int primitive_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS return op->type->exec(C, op); } -static void define_prinitive_add_properties(wmOperatorType *ot) +static void define_primitive_add_properties(wmOperatorType *ot) { RNA_def_float( ot->srna, "size", 100, -FLT_MAX, FLT_MAX, "Size", "Size of new circle", -FLT_MAX, FLT_MAX); @@ -913,7 +913,7 @@ void MASK_OT_primitive_circle_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - define_prinitive_add_properties(ot); + define_primitive_add_properties(ot); } /******************** primitive add suqare *********************/ @@ -944,5 +944,5 @@ void MASK_OT_primitive_square_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - define_prinitive_add_properties(ot); + define_primitive_add_properties(ot); } diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index a205f6878e3..8e4efddd8a7 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -441,6 +441,7 @@ static int masklay_new_exec(bContext *C, wmOperator *op) mask->masklay_act = mask->masklay_tot - 1; WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); + DEG_id_tag_update(&mask->id, ID_RECALC_COPY_ON_WRITE); return OPERATOR_FINISHED; } @@ -474,6 +475,7 @@ static int masklay_remove_exec(bContext *C, wmOperator *UNUSED(op)) BKE_mask_layer_remove(mask, masklay); WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); + DEG_id_tag_update(&mask->id, ID_RECALC_COPY_ON_WRITE); } return OPERATOR_FINISHED; @@ -2206,6 +2208,7 @@ static int mask_layer_move_exec(bContext *C, wmOperator *op) } WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); + DEG_id_tag_update(&mask->id, ID_RECALC_COPY_ON_WRITE); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 78b4cfe38d4..b4ef2620895 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -263,14 +263,14 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) initNumInput(&opdata->num_input[i]); opdata->num_input[i].idx_max = 0; opdata->num_input[i].val_flag[0] |= NUM_NO_NEGATIVE; + opdata->num_input[i].unit_type[0] = B_UNIT_NONE; if (i == SEGMENTS_VALUE) { opdata->num_input[i].val_flag[0] |= NUM_NO_FRACTION | NUM_NO_ZERO; } if (i == OFFSET_VALUE) { opdata->num_input[i].unit_sys = scene->unit.system; + opdata->num_input[i].unit_type[0] = B_UNIT_LENGTH; } - /* Not sure this is a factor or a unit? */ - opdata->num_input[i].unit_type[0] = B_UNIT_NONE; } /* avoid the cost of allocating a bm copy */ diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 26d830ccaec..919de4cdb20 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -534,6 +534,9 @@ static int edbm_delete_exec(bContext *C, wmOperator *op) EDBM_flag_disable_all(em, BM_ELEM_SELECT); EDBM_update_generic(em, true, true); + + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } MEM_freeN(objects); @@ -7415,7 +7418,7 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot) #ifdef WITH_FREESTYLE /* -------------------------------------------------------------------- */ -/** \name Mark Edge (FreeStyle) Operator +/** \name Mark Edge (Freestyle) Operator * \{ */ static int edbm_mark_freestyle_edge_exec(bContext *C, wmOperator *op) @@ -7495,7 +7498,7 @@ void MESH_OT_mark_freestyle_edge(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Mark Face (FreeStyle) Operator +/** \name Mark Face (Freestyle) Operator * \{ */ static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op) @@ -8015,6 +8018,7 @@ static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent return OPERATOR_RUNNING_MODAL; } +/* TODO: make this work on multiple objects at once */ static int edbm_point_normals_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -8237,44 +8241,54 @@ static void normals_split(BMesh *bm) static int normals_split_merge(bContext *C, const bool do_merge) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMEdge *e; - BMIter eiter; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - BKE_editmesh_ensure_autosmooth(em); - BKE_editmesh_lnorspace_update(em); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMEdge *e; + BMIter eiter; - /* Note that we need temp lnor editing data for all loops of all affected vertices, since by - * setting some faces/edges as smooth we are going to change clnors spaces... See also T65809. */ - BMLoopNorEditDataArray *lnors_ed_arr = do_merge ? BM_loop_normal_editdata_array_init(bm, true) : - NULL; + BKE_editmesh_ensure_autosmooth(em); + BKE_editmesh_lnorspace_update(em); - mesh_set_smooth_faces(em, do_merge); + /* Note that we need temp lnor editing data for all loops of all affected vertices, since by + * setting some faces/edges as smooth we are going to change clnors spaces... See also T65809. + */ + BMLoopNorEditDataArray *lnors_ed_arr = do_merge ? + BM_loop_normal_editdata_array_init(bm, true) : + NULL; - BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - BM_elem_flag_set(e, BM_ELEM_SMOOTH, do_merge); + mesh_set_smooth_faces(em, do_merge); + + BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + BM_elem_flag_set(e, BM_ELEM_SMOOTH, do_merge); + } } - } - bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; - BKE_editmesh_lnorspace_update(em); + bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; + BKE_editmesh_lnorspace_update(em); - if (do_merge) { - normals_merge(bm, lnors_ed_arr); - } - else { - normals_split(bm); - } + if (do_merge) { + normals_merge(bm, lnors_ed_arr); + } + else { + normals_split(bm); + } - if (lnors_ed_arr) { - BM_loop_normal_editdata_array_free(lnors_ed_arr); - } + if (lnors_ed_arr) { + BM_loop_normal_editdata_array_free(lnors_ed_arr); + } - EDBM_update_generic(em, true, false); + EDBM_update_generic(em, true, false); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -8343,131 +8357,140 @@ static EnumPropertyItem average_method_items[] = { static int edbm_average_normals_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMFace *f; - BMLoop *l, *l_curr, *l_first; - BMIter fiter; - - BKE_editmesh_ensure_autosmooth(em); - bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; - BKE_editmesh_lnorspace_update(em); - + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); const int average_type = RNA_enum_get(op->ptr, "average_type"); - const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); const float absweight = (float)RNA_int_get(op->ptr, "weight"); const float threshold = RNA_float_get(op->ptr, "threshold"); - float weight = absweight / 50.0f; - if (absweight == 100.0f) { - weight = (float)SHRT_MAX; - } - else if (absweight == 1.0f) { - weight = 1 / (float)SHRT_MAX; - } - else if ((weight - 1) * 25 > 1) { - weight = (weight - 1) * 25; - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMLoop *l, *l_curr, *l_first; + BMIter fiter; - BM_normals_loops_edges_tag(bm, true); + BKE_editmesh_ensure_autosmooth(em); + bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; + BKE_editmesh_lnorspace_update(em); - HeapSimple *loop_weight = BLI_heapsimple_new(); + const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); - BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - l_curr = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) && - (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) || - (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_curr)))) { - if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && - !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) { - const int loop_index = BM_elem_index_get(l_curr); - short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset); - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors); - } - else { - BMVert *v_pivot = l_curr->v; - UNUSED_VARS_NDEBUG(v_pivot); - BMEdge *e_next; - const BMEdge *e_org = l_curr->e; - BMLoop *lfan_pivot, *lfan_pivot_next; + float weight = absweight / 50.0f; + if (absweight == 100.0f) { + weight = (float)SHRT_MAX; + } + else if (absweight == 1.0f) { + weight = 1 / (float)SHRT_MAX; + } + else if ((weight - 1) * 25 > 1) { + weight = (weight - 1) * 25; + } - lfan_pivot = l_curr; - e_next = lfan_pivot->e; + BM_normals_loops_edges_tag(bm, true); - while (true) { - lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); - if (lfan_pivot_next) { - BLI_assert(lfan_pivot_next->v == v_pivot); - } - else { - e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e; - } + HeapSimple *loop_weight = BLI_heapsimple_new(); - float val = 1.0f; - if (average_type == EDBM_CLNOR_AVERAGE_FACE_AREA) { - val = 1.0f / BM_face_calc_area(lfan_pivot->f); - } - else if (average_type == EDBM_CLNOR_AVERAGE_ANGLE) { - val = 1.0f / BM_loop_calc_face_angle(lfan_pivot); - } + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + l_curr = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) && + (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) || + (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) && + BM_loop_check_cyclic_smooth_fan(l_curr)))) { + if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && + !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) { + const int loop_index = BM_elem_index_get(l_curr); + short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors); + } + else { + BMVert *v_pivot = l_curr->v; + UNUSED_VARS_NDEBUG(v_pivot); + BMEdge *e_next; + const BMEdge *e_org = l_curr->e; + BMLoop *lfan_pivot, *lfan_pivot_next; + + lfan_pivot = l_curr; + e_next = lfan_pivot->e; + + while (true) { + lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); + if (lfan_pivot_next) { + BLI_assert(lfan_pivot_next->v == v_pivot); + } + else { + e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e; + } - BLI_heapsimple_insert(loop_weight, val, lfan_pivot); + float val = 1.0f; + if (average_type == EDBM_CLNOR_AVERAGE_FACE_AREA) { + val = 1.0f / BM_face_calc_area(lfan_pivot->f); + } + else if (average_type == EDBM_CLNOR_AVERAGE_ANGLE) { + val = 1.0f / BM_loop_calc_face_angle(lfan_pivot); + } - if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { - break; - } - lfan_pivot = lfan_pivot_next; - } + BLI_heapsimple_insert(loop_weight, val, lfan_pivot); - BLI_SMALLSTACK_DECLARE(loops, BMLoop *); - float wnor[3], avg_normal[3] = {0.0f}, count = 0; - float val = BLI_heapsimple_top_value(loop_weight); - - while (!BLI_heapsimple_is_empty(loop_weight)) { - const float cur_val = BLI_heapsimple_top_value(loop_weight); - if (!compare_ff(val, cur_val, threshold)) { - count++; - val = cur_val; + if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { + break; + } + lfan_pivot = lfan_pivot_next; } - l = BLI_heapsimple_pop_min(loop_weight); - BLI_SMALLSTACK_PUSH(loops, l); - const float n_weight = pow(weight, count); + BLI_SMALLSTACK_DECLARE(loops, BMLoop *); + float wnor[3], avg_normal[3] = {0.0f}, count = 0; + float val = BLI_heapsimple_top_value(loop_weight); + + while (!BLI_heapsimple_is_empty(loop_weight)) { + const float cur_val = BLI_heapsimple_top_value(loop_weight); + if (!compare_ff(val, cur_val, threshold)) { + count++; + val = cur_val; + } + l = BLI_heapsimple_pop_min(loop_weight); + BLI_SMALLSTACK_PUSH(loops, l); + + const float n_weight = pow(weight, count); + + if (average_type == EDBM_CLNOR_AVERAGE_LOOP) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_data_to_normal( + bm->lnor_spacearr->lspacearr[l_index], clnors, wnor); + } + else { + copy_v3_v3(wnor, l->f->no); + } + mul_v3_fl(wnor, (1.0f / cur_val) * (1.0f / n_weight)); + add_v3_v3(avg_normal, wnor); + } - if (average_type == EDBM_CLNOR_AVERAGE_LOOP) { + if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) { + /* If avg normal is nearly 0, set clnor to default value. */ + zero_v3(avg_normal); + } + while ((l = BLI_SMALLSTACK_POP(loops))) { const int l_index = BM_elem_index_get(l); short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); - BKE_lnor_space_custom_data_to_normal( - bm->lnor_spacearr->lspacearr[l_index], clnors, wnor); - } - else { - copy_v3_v3(wnor, l->f->no); + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors); } - mul_v3_fl(wnor, (1.0f / cur_val) * (1.0f / n_weight)); - add_v3_v3(avg_normal, wnor); - } - - if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) { - /* If avg normal is nearly 0, set clnor to default value. */ - zero_v3(avg_normal); - } - while ((l = BLI_SMALLSTACK_POP(loops))) { - const int l_index = BM_elem_index_get(l); - short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors); } } - } - } while ((l_curr = l_curr->next) != l_first); - } + } while ((l_curr = l_curr->next) != l_first); + } - BLI_heapsimple_free(loop_weight, NULL); - EDBM_update_generic(em, true, false); + BLI_heapsimple_free(loop_weight, NULL); + EDBM_update_generic(em, true, false); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -8566,135 +8589,151 @@ static EnumPropertyItem normal_vector_tool_items[] = { static int edbm_normals_tools_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); Scene *scene = CTX_data_scene(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - if (bm->totloop == 0) { - return OPERATOR_CANCELLED; - } - + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); const int mode = RNA_enum_get(op->ptr, "mode"); const bool absolute = RNA_boolean_get(op->ptr, "absolute"); + float *normal_vector = scene->toolsettings->normal_vector; + bool done_copy = false; - BKE_editmesh_ensure_autosmooth(em); - BKE_editmesh_lnorspace_update(em); - BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false); - BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; - float *normal_vector = scene->toolsettings->normal_vector; + if (bm->totloop == 0) { + continue; + } - switch (mode) { - case EDBM_CLNOR_TOOLS_COPY: - if (bm->totfacesel != 1 && lnors_ed_arr->totloop != 1 && bm->totvertsel != 1) { - BKE_report(op->reports, - RPT_ERROR, - "Can only copy one custom normal, vertex normal or face normal"); - BM_loop_normal_editdata_array_free(lnors_ed_arr); - return OPERATOR_CANCELLED; - } - if (lnors_ed_arr->totloop == 1) { - copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc); - } - else if (bm->totfacesel == 1) { - BMFace *f; - BMIter fiter; - BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - copy_v3_v3(scene->toolsettings->normal_vector, f->no); - } + BKE_editmesh_ensure_autosmooth(em); + BKE_editmesh_lnorspace_update(em); + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false); + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + + switch (mode) { + case EDBM_CLNOR_TOOLS_COPY: + if (bm->totfacesel == 0 || bm->totvertsel == 0) { + BM_loop_normal_editdata_array_free(lnors_ed_arr); + continue; } - } - else { - /* 'Vertex' normal, i.e. common set of loop normals on the same vertex, - * only if they are all the same. */ - bool are_same_lnors = true; - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - if (!compare_v3v3(lnors_ed_arr->lnor_editdata->nloc, lnor_ed->nloc, 1e-4f)) { - are_same_lnors = false; - } + + if (done_copy || + (bm->totfacesel != 1 && lnors_ed_arr->totloop != 1 && bm->totvertsel != 1)) { + BKE_report(op->reports, + RPT_ERROR, + "Can only copy one custom normal, vertex normal or face normal"); + BM_loop_normal_editdata_array_free(lnors_ed_arr); + continue; } - if (are_same_lnors) { + if (lnors_ed_arr->totloop == 1) { copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc); } - } - break; + else if (bm->totfacesel == 1) { + BMFace *f; + BMIter fiter; + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + copy_v3_v3(scene->toolsettings->normal_vector, f->no); + } + } + } + else { + /* 'Vertex' normal, i.e. common set of loop normals on the same vertex, + * only if they are all the same. */ + bool are_same_lnors = true; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + if (!compare_v3v3(lnors_ed_arr->lnor_editdata->nloc, lnor_ed->nloc, 1e-4f)) { + are_same_lnors = false; + } + } + if (are_same_lnors) { + copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc); + } + } + done_copy = true; + break; - case EDBM_CLNOR_TOOLS_PASTE: - if (!absolute) { - if (normalize_v3(normal_vector) < CLNORS_VALID_VEC_LEN) { - /* If normal is nearly 0, do nothing. */ - break; + case EDBM_CLNOR_TOOLS_PASTE: + if (!absolute) { + if (normalize_v3(normal_vector) < CLNORS_VALID_VEC_LEN) { + /* If normal is nearly 0, do nothing. */ + break; + } } - } - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - if (absolute) { - float abs_normal[3]; - copy_v3_v3(abs_normal, lnor_ed->loc); - negate_v3(abs_normal); - add_v3_v3(abs_normal, normal_vector); + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + if (absolute) { + float abs_normal[3]; + copy_v3_v3(abs_normal, lnor_ed->loc); + negate_v3(abs_normal); + add_v3_v3(abs_normal, normal_vector); + + if (normalize_v3(abs_normal) < CLNORS_VALID_VEC_LEN) { + /* If abs normal is nearly 0, set clnor to initial value. */ + copy_v3_v3(abs_normal, lnor_ed->niloc); + } + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], + abs_normal, + lnor_ed->clnors_data); + } + else { + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], + normal_vector, + lnor_ed->clnors_data); + } + } + break; - if (normalize_v3(abs_normal) < CLNORS_VALID_VEC_LEN) { + case EDBM_CLNOR_TOOLS_MULTIPLY: + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + mul_v3_v3(lnor_ed->nloc, normal_vector); + + if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) { /* If abs normal is nearly 0, set clnor to initial value. */ - copy_v3_v3(abs_normal, lnor_ed->niloc); + copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); } - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], abs_normal, lnor_ed->clnors_data); - } - else { BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], - normal_vector, + lnor_ed->nloc, lnor_ed->clnors_data); } - } - break; + break; - case EDBM_CLNOR_TOOLS_MULTIPLY: - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - mul_v3_v3(lnor_ed->nloc, normal_vector); + case EDBM_CLNOR_TOOLS_ADD: + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + add_v3_v3(lnor_ed->nloc, normal_vector); - if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) { - /* If abs normal is nearly 0, set clnor to initial value. */ - copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); + if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) { + /* If abs normal is nearly 0, set clnor to initial value. */ + copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); + } + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], + lnor_ed->nloc, + lnor_ed->clnors_data); } - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], - lnor_ed->nloc, - lnor_ed->clnors_data); - } - break; - - case EDBM_CLNOR_TOOLS_ADD: - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - add_v3_v3(lnor_ed->nloc, normal_vector); + break; - if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) { - /* If abs normal is nearly 0, set clnor to initial value. */ - copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); + case EDBM_CLNOR_TOOLS_RESET: + zero_v3(normal_vector); + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], + normal_vector, + lnor_ed->clnors_data); } - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], - lnor_ed->nloc, - lnor_ed->clnors_data); - } - break; + break; - case EDBM_CLNOR_TOOLS_RESET: - zero_v3(normal_vector); - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], - normal_vector, - lnor_ed->clnors_data); - } - break; + default: + BLI_assert(0); + break; + } - default: - BLI_assert(0); - break; - } + BM_loop_normal_editdata_array_free(lnors_ed_arr); - BM_loop_normal_editdata_array_free(lnors_ed_arr); + EDBM_update_generic(em, true, false); + } - EDBM_update_generic(em, true, false); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -8841,8 +8880,8 @@ static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op) MEM_freeN(vnors); EDBM_update_generic(em, true, false); } - MEM_freeN(objects); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -8865,77 +8904,86 @@ void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot) static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMFace *f; - BMLoop *l; - BMIter fiter, liter; - - BKE_editmesh_ensure_autosmooth(em); - BKE_editmesh_lnorspace_update(em); - BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false); - - float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop, __func__); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - /* This is weird choice of operation, taking all loops of faces of current vertex. - * Could lead to some rather far away loops weighting as much as very close ones - * (topologically speaking), with complex polygons. - * Using topological distance here (rather than geometrical one) - * makes sense imho, but would rather go with a more consistent and flexible code, - * we could even add max topological distance to take into account, * and a weighting curve. - * Would do that later though, think for now we can live with that choice. --mont29. */ - BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - l = lnor_ed->loop; - float loop_normal[3]; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMLoop *l; + BMIter fiter, liter; - BM_ITER_ELEM (f, &fiter, l->v, BM_FACES_OF_VERT) { - BMLoop *l_other; - BM_ITER_ELEM (l_other, &liter, f, BM_LOOPS_OF_FACE) { - const int l_index_other = BM_elem_index_get(l_other); - short *clnors = BM_ELEM_CD_GET_VOID_P(l_other, lnors_ed_arr->cd_custom_normal_offset); - BKE_lnor_space_custom_data_to_normal( - bm->lnor_spacearr->lspacearr[l_index_other], clnors, loop_normal); - add_v3_v3(smooth_normal[i], loop_normal); + BKE_editmesh_ensure_autosmooth(em); + BKE_editmesh_lnorspace_update(em); + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false); + + float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop, + __func__); + + /* This is weird choice of operation, taking all loops of faces of current vertex. + * Could lead to some rather far away loops weighting as much as very close ones + * (topologically speaking), with complex polygons. + * Using topological distance here (rather than geometrical one) + * makes sense imho, but would rather go with a more consistent and flexible code, + * we could even add max topological distance to take into account, * and a weighting curve. + * Would do that later though, think for now we can live with that choice. --mont29. */ + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + l = lnor_ed->loop; + float loop_normal[3]; + + BM_ITER_ELEM (f, &fiter, l->v, BM_FACES_OF_VERT) { + BMLoop *l_other; + BM_ITER_ELEM (l_other, &liter, f, BM_LOOPS_OF_FACE) { + const int l_index_other = BM_elem_index_get(l_other); + short *clnors = BM_ELEM_CD_GET_VOID_P(l_other, lnors_ed_arr->cd_custom_normal_offset); + BKE_lnor_space_custom_data_to_normal( + bm->lnor_spacearr->lspacearr[l_index_other], clnors, loop_normal); + add_v3_v3(smooth_normal[i], loop_normal); + } } } - } - const float factor = RNA_float_get(op->ptr, "factor"); + const float factor = RNA_float_get(op->ptr, "factor"); - lnor_ed = lnors_ed_arr->lnor_editdata; - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - float current_normal[3]; + lnor_ed = lnors_ed_arr->lnor_editdata; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + float current_normal[3]; - if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) { - /* Skip in case smoothen normal is invalid... */ - continue; - } + if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) { + /* Skip in case smoothen normal is invalid... */ + continue; + } - BKE_lnor_space_custom_data_to_normal( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->clnors_data, current_normal); + BKE_lnor_space_custom_data_to_normal( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->clnors_data, current_normal); - /* Note: again, this is not true spherical interpolation that normals would need... - * But it's probably good enough for now. */ - mul_v3_fl(current_normal, 1.0f - factor); - mul_v3_fl(smooth_normal[i], factor); - add_v3_v3(current_normal, smooth_normal[i]); + /* Note: again, this is not true spherical interpolation that normals would need... + * But it's probably good enough for now. */ + mul_v3_fl(current_normal, 1.0f - factor); + mul_v3_fl(smooth_normal[i], factor); + add_v3_v3(current_normal, smooth_normal[i]); - if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) { - /* Skip in case smoothen normal is invalid... */ - continue; - } + if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) { + /* Skip in case smoothen normal is invalid... */ + continue; + } - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], current_normal, lnor_ed->clnors_data); - } + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], current_normal, lnor_ed->clnors_data); + } - BM_loop_normal_editdata_array_free(lnors_ed_arr); - MEM_freeN(smooth_normal); + BM_loop_normal_editdata_array_free(lnors_ed_arr); + MEM_freeN(smooth_normal); - EDBM_update_generic(em, true, false); + EDBM_update_generic(em, true, false); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -8968,50 +9016,59 @@ void MESH_OT_smoothen_normals(struct wmOperatorType *ot) static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMFace *f; - BMIter fiter; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - BM_select_history_clear(bm); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMIter fiter; + const int face_strength = RNA_enum_get(op->ptr, "face_strength"); + const bool set = RNA_boolean_get(op->ptr, "set"); - const char *layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID; - int cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id); - if (cd_prop_int_index == -1) { - BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, layer_id); - cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id); - } - cd_prop_int_index -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT); - const int cd_prop_int_offset = CustomData_get_n_offset( - &bm->pdata, CD_PROP_INT, cd_prop_int_index); + BM_select_history_clear(bm); - const int face_strength = RNA_enum_get(op->ptr, "face_strength"); - const bool set = RNA_boolean_get(op->ptr, "set"); - BM_mesh_elem_index_ensure(bm, BM_FACE); + const char *layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID; + int cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id); + if (cd_prop_int_index == -1) { + BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, layer_id); + cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id); + } + cd_prop_int_index -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT); + const int cd_prop_int_offset = CustomData_get_n_offset( + &bm->pdata, CD_PROP_INT, cd_prop_int_index); - if (set) { - BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset); - *strength = face_strength; + BM_mesh_elem_index_ensure(bm, BM_FACE); + + if (set) { + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset); + *strength = face_strength; + } } } - } - else { - BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset); - if (*strength == face_strength) { - BM_face_select_set(bm, f, true); - BM_select_history_store(bm, f); - } - else { - BM_face_select_set(bm, f, false); + else { + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset); + if (*strength == face_strength) { + BM_face_select_set(bm, f, true); + BM_select_history_store(bm, f); + } + else { + BM_face_select_set(bm, f, false); + } } } + + EDBM_update_generic(em, false, false); } - EDBM_update_generic(em, false, false); + MEM_freeN(objects); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 28b14b0060d..e823fb46140 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -741,7 +741,8 @@ static bool mesh_undosys_step_encode(struct bContext *C, static void mesh_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, - int UNUSED(dir)) + int UNUSED(dir), + bool UNUSED(is_final)) { MeshUndoStep *us = (MeshUndoStep *)us_p; diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index a6934326d68..ee8de9d8ea9 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -41,6 +41,7 @@ #include "DEG_depsgraph.h" +#include "RNA_access.h" #include "RNA_define.h" #include "WM_api.h" @@ -629,8 +630,7 @@ void MESH_OT_vertex_color_remove(wmOperatorType *ot) static int mesh_customdata_clear_exec__internal(bContext *C, char htype, int type) { - Object *obedit = ED_object_context(C); - Mesh *me = obedit->data; + Mesh *me = ED_mesh_context(C); int tot; CustomData *data = mesh_customdata_get_type(me, htype, &tot); @@ -788,8 +788,7 @@ void MESH_OT_customdata_skin_clear(wmOperatorType *ot) /* Clear custom loop normals */ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - Mesh *me = ob->data; + Mesh *me = ED_mesh_context(C); if (!BKE_mesh_has_custom_loop_normals(me)) { CustomData *data = GET_CD_DATA(me, ldata); @@ -853,7 +852,7 @@ void MESH_OT_customdata_custom_splitnormals_add(wmOperatorType *ot) /* api callbacks */ ot->exec = mesh_customdata_custom_splitnormals_add_exec; - ot->poll = ED_operator_object_active_editable_mesh; + ot->poll = ED_operator_editable_mesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -861,8 +860,7 @@ void MESH_OT_customdata_custom_splitnormals_add(wmOperatorType *ot) static int mesh_customdata_custom_splitnormals_clear_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - Mesh *me = ob->data; + Mesh *me = ED_mesh_context(C); if (BKE_mesh_has_custom_loop_normals(me)) { return mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_CUSTOMLOOPNORMAL); @@ -879,7 +877,7 @@ void MESH_OT_customdata_custom_splitnormals_clear(wmOperatorType *ot) /* api callbacks */ ot->exec = mesh_customdata_custom_splitnormals_clear_exec; - ot->poll = ED_operator_object_active_editable_mesh; + ot->poll = ED_operator_editable_mesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1289,3 +1287,23 @@ void ED_mesh_report_mirror(wmOperator *op, int totmirr, int totfail) { ED_mesh_report_mirror_ex(op, totmirr, totfail, SCE_SELECT_VERTEX); } + +Mesh *ED_mesh_context(struct bContext *C) +{ + Mesh *mesh = CTX_data_pointer_get_type(C, "mesh", &RNA_Mesh).data; + if (mesh != NULL) { + return mesh; + } + + Object *ob = ED_object_active_context(C); + if (ob == NULL) { + return NULL; + } + + ID *data = (ID *)ob->data; + if (data == NULL || GS(data->name) != ID_ME) { + return NULL; + } + + return (Mesh *)data; +} diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c index d255fac26ad..9a95560ccdd 100644 --- a/source/blender/editors/metaball/editmball_undo.c +++ b/source/blender/editors/metaball/editmball_undo.c @@ -185,7 +185,8 @@ static bool mball_undosys_step_encode(struct bContext *C, static void mball_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, - int UNUSED(dir)) + int UNUSED(dir), + bool UNUSED(is_final)) { MBallUndoStep *us = (MBallUndoStep *)us_p; diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 0fdb1cec16f..f8cf55933aa 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1658,54 +1658,80 @@ static void copy_object_set_idnew(bContext *C) /** \name Make Instanced Objects Real Operator * \{ */ +/* XXX TODO That whole hierarchy handling based on persistent_id tricks is + * very confusing and convoluted, and it will fail in many cases besides basic ones. + * Think this should be replaced by a proper tree-like representation of the instantiations, + * should help a lot in both readability, and precise consistent rebuilding of hierarchy. + */ + /** - * \note regarding hashing dupli-objects when using OB_DUPLICOLLECTION, + * \note regarding hashing dupli-objects which come from OB_DUPLICOLLECTION, * skip the first member of #DupliObject.persistent_id * since its a unique index and we only want to know if the group objects are from the same * dupli-group instance. + * + * \note regarding hashing dupli-objects which come from non-OB_DUPLICOLLECTION, + * include the first member of #DupliObject.persistent_id + * since its the index of the vertex/face the object is instantiated on and we want to identify + * objects on the same vertex/face. + * In other words, we consider each group of objects from a same item as being + * the 'local group' where to check for parents. */ -static unsigned int dupliobject_group_hash(const void *ptr) +static unsigned int dupliobject_hash(const void *ptr) { const DupliObject *dob = ptr; unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); - unsigned int i; - for (i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) { - hash ^= (dob->persistent_id[i] ^ i); + + if (dob->type == OB_DUPLICOLLECTION) { + for (int i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) { + hash ^= (dob->persistent_id[i] ^ i); + } + } + else { + hash ^= (dob->persistent_id[0] ^ 0); } return hash; } /** - * \note regarding hashing dupli-objects when NOT using OB_DUPLICOLLECTION, - * include the first member of #DupliObject.persistent_id - * since its the index of the vertex/face the object is instantiated on and we want to identify - * objects on the same vertex/face. + * \note regarding hashing dupli-objects when using OB_DUPLICOLLECTION, + * skip the first member of #DupliObject.persistent_id + * since its a unique index and we only want to know if the group objects are from the same + * dupli-group instance. */ -static unsigned int dupliobject_hash(const void *ptr) +static unsigned int dupliobject_instancer_hash(const void *ptr) { const DupliObject *dob = ptr; - unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); - hash ^= (dob->persistent_id[0] ^ 0); + unsigned int hash = BLI_ghashutil_inthash(dob->persistent_id[0]); + for (int i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) { + hash ^= (dob->persistent_id[i] ^ i); + } return hash; } -/* Compare function that matches dupliobject_group_hash */ -static bool dupliobject_group_cmp(const void *a_, const void *b_) +/* Compare function that matches dupliobject_hash */ +static bool dupliobject_cmp(const void *a_, const void *b_) { const DupliObject *a = a_; const DupliObject *b = b_; - unsigned int i; if (a->ob != b->ob) { return true; } - for (i = 1; (i < MAX_DUPLI_RECUR); i++) { - if (a->persistent_id[i] != b->persistent_id[i]) { - return true; + if (ELEM(a->type, b->type, OB_DUPLICOLLECTION)) { + for (int i = 1; (i < MAX_DUPLI_RECUR); i++) { + if (a->persistent_id[i] != b->persistent_id[i]) { + return true; + } + else if (a->persistent_id[i] == INT_MAX) { + break; + } } - else if (a->persistent_id[i] == INT_MAX) { - break; + } + else { + if (a->persistent_id[0] != b->persistent_id[0]) { + return true; } } @@ -1713,18 +1739,19 @@ static bool dupliobject_group_cmp(const void *a_, const void *b_) return false; } -/* Compare function that matches dupliobject_hash */ -static bool dupliobject_cmp(const void *a_, const void *b_) +/* Compare function that matches dupliobject_instancer_hash. */ +static bool dupliobject_instancer_cmp(const void *a_, const void *b_) { const DupliObject *a = a_; const DupliObject *b = b_; - if (a->ob != b->ob) { - return true; - } - - if (a->persistent_id[0] != b->persistent_id[0]) { - return true; + for (int i = 0; (i < MAX_DUPLI_RECUR); i++) { + if (a->persistent_id[i] != b->persistent_id[i]) { + return true; + } + else if (a->persistent_id[i] == INT_MAX) { + break; + } } /* matching */ @@ -1739,7 +1766,7 @@ static void make_object_duplilist_real( Depsgraph *depsgraph = CTX_data_depsgraph(C); ListBase *lb_duplis; DupliObject *dob; - GHash *dupli_gh, *parent_gh = NULL; + GHash *dupli_gh, *parent_gh = NULL, *instancer_gh = NULL; if (!(base->object->transflag & OB_DUPLI)) { return; @@ -1750,11 +1777,11 @@ static void make_object_duplilist_real( dupli_gh = BLI_ghash_ptr_new(__func__); if (use_hierarchy) { - if (base->object->transflag & OB_DUPLICOLLECTION) { - parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__); - } - else { - parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + + if (use_base_parent) { + instancer_gh = BLI_ghash_new( + dupliobject_instancer_hash, dupliobject_instancer_cmp, __func__); } } @@ -1788,7 +1815,12 @@ static void make_object_duplilist_real( ob_dst->parent = NULL; BKE_constraints_free(&ob_dst->constraints); ob_dst->runtime.curve_cache = NULL; + const bool is_dupli_instancer = (ob_dst->transflag & OB_DUPLI) != 0; ob_dst->transflag &= ~OB_DUPLI; + /* Remove instantiated collection, it's annoying to keep it here + * (and get potentially a lot of usages of it then...). */ + id_us_min((ID *)ob_dst->instance_collection); + ob_dst->instance_collection = NULL; copy_m4_m4(ob_dst->obmat, dob->mat); BKE_object_apply_mat4(ob_dst, ob_dst->obmat, false, false); @@ -1802,6 +1834,13 @@ static void make_object_duplilist_real( if (!BLI_ghash_ensure_p(parent_gh, dob, &val)) { *val = ob_dst; } + + if (is_dupli_instancer && instancer_gh) { + /* Same as above, we may have several 'hits'. */ + if (!BLI_ghash_ensure_p(instancer_gh, dob, &val)) { + *val = ob_dst; + } + } } } @@ -1825,7 +1864,8 @@ static void make_object_duplilist_real( * they won't be read, this is simply for a hash lookup. */ DupliObject dob_key; dob_key.ob = ob_src_par; - if (base->object->transflag & OB_DUPLICOLLECTION) { + dob_key.type = dob->type; + if (dob->type == OB_DUPLICOLLECTION) { memcpy(&dob_key.persistent_id[1], &dob->persistent_id[1], sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); @@ -1848,15 +1888,30 @@ static void make_object_duplilist_real( ob_dst->parent = ob_dst_par; } - else if (use_base_parent) { - ob_dst->parent = base->object; - ob_dst->partype = PAROBJECT; - } } - else if (use_base_parent) { - /* since we are ignoring the internal hierarchy - parent all to the - * base object */ - ob_dst->parent = base->object; + if (use_base_parent && ob_dst->parent == NULL) { + Object *ob_dst_par = NULL; + + if (instancer_gh != NULL) { + /* OK to keep most of the members uninitialized, + * they won't be read, this is simply for a hash lookup. */ + DupliObject dob_key; + /* We are looking one step upper in hierarchy, so we need to 'shift' the persitent_id, + * ignoring the first item. + * We only check on persistent_id here, since we have no idea what object it might be. */ + memcpy(&dob_key.persistent_id[0], + &dob->persistent_id[1], + sizeof(dob_key.persistent_id[0]) * (MAX_DUPLI_RECUR - 1)); + ob_dst_par = BLI_ghash_lookup(instancer_gh, &dob_key); + } + + if (ob_dst_par == NULL) { + /* Default to parenting to root object... + * Always the case when use_hierarchy is false. */ + ob_dst_par = base->object; + } + + ob_dst->parent = ob_dst_par; ob_dst->partype = PAROBJECT; } @@ -1878,12 +1933,16 @@ static void make_object_duplilist_real( DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); } } + base->object->instance_collection = NULL; } BLI_ghash_free(dupli_gh, NULL, NULL); if (parent_gh) { BLI_ghash_free(parent_gh, NULL, NULL); } + if (instancer_gh) { + BLI_ghash_free(instancer_gh, NULL, NULL); + } free_object_duplilist(lb_duplis); @@ -1977,7 +2036,13 @@ static void curvetomesh(Main *bmain, Depsgraph *depsgraph, Object *ob) { Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); Curve *curve = ob->data; + Mesh *mesh = BKE_mesh_new_from_object_to_bmain(bmain, depsgraph, object_eval, true); + if (mesh == NULL) { + /* Unable to convert the curve to a mesh. */ + return; + } + BKE_object_free_modifiers(ob, 0); /* Replace curve used by the object itself. */ ob->data = mesh; @@ -2066,7 +2131,7 @@ static Base *duplibase_for_convert( static int convert_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); + Depsgraph *depsgraph = CTX_data_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); Base *basen = NULL, *basact = NULL; @@ -2285,8 +2350,9 @@ static int convert_exec(bContext *C, wmOperator *op) BKE_curve_curve_dimension_update(cu); if (target == OB_MESH) { + /* No assumption should be made that the resulting objects is a mesh, as conversion can + * fail. */ curvetomesh(bmain, depsgraph, newob); - /* meshes doesn't use displist */ BKE_object_free_curve_cache(newob); } @@ -2309,8 +2375,9 @@ static int convert_exec(bContext *C, wmOperator *op) newob = ob; } + /* No assumption should be made that the resulting objects is a mesh, as conversion can + * fail. */ curvetomesh(bmain, depsgraph, newob); - /* meshes doesn't use displist */ BKE_object_free_curve_cache(newob); } @@ -2826,7 +2893,7 @@ void OBJECT_OT_join_shapes(wmOperatorType *ot) { /* identifiers */ ot->name = "Join as Shapes"; - ot->description = "Merge selected objects to shapes of active object"; + ot->description = "Copy the current resulting shape of another selected object to this one"; ot->idname = "OBJECT_OT_join_shapes"; /* api callbacks */ diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 6164958bf2c..410ccccbd0d 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -707,7 +707,7 @@ static size_t initialize_internal_images(BakeImages *bake_images, ReportList *re /* create new mesh with edit mode changes and modifiers applied */ static Mesh *bake_mesh_new_from_object(Object *object) { - Mesh *me = BKE_object_to_mesh(NULL, object, false); + Mesh *me = BKE_mesh_new_from_object(NULL, object, false); if (me->flag & ME_AUTOSMOOTH) { BKE_mesh_split_faces(me, true); @@ -927,7 +927,7 @@ static int bake(Render *re, } } else if (is_cage) { - BKE_object_eval_reset(ob_low_eval); + bool is_changed = false; ModifierData *md = ob_low_eval->modifiers.first; while (md) { @@ -942,11 +942,23 @@ static int bake(Render *re, if (md->type == eModifierType_EdgeSplit) { BLI_remlink(&ob_low_eval->modifiers, md); modifier_free(md); + is_changed = true; } md = md_next; } - me_cage = BKE_object_to_mesh(NULL, ob_low_eval, false); + if (is_changed) { + /* Make sure object is evaluated with the new modifier settings. + * + * NOTE: Since the dependency graph was fully evaluated prior to bake, and we only made + * single modification to this object all the possible dependencies for evaluation are + * already up to date. This means we can do a cheap single object update + * (as an opposite of full depsgraph update). */ + BKE_object_eval_reset(ob_low_eval); + BKE_object_handle_data_update(depsgraph, scene, ob_low_eval); + } + + me_cage = BKE_mesh_new_from_object(NULL, ob_low_eval, false); RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); } @@ -965,7 +977,7 @@ static int bake(Render *re, highpoly[i].ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter); highpoly[i].ob_eval->restrictflag &= ~OB_RESTRICT_RENDER; highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE | BASE_ENABLED_RENDER); - highpoly[i].me = BKE_object_to_mesh(NULL, highpoly[i].ob_eval, false); + highpoly[i].me = BKE_mesh_new_from_object(NULL, highpoly[i].ob_eval, false); /* lowpoly to highpoly transformation matrix */ copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); @@ -1088,7 +1100,7 @@ static int bake(Render *re, } /* Evaluate modifiers again. */ - me_nores = BKE_object_to_mesh(NULL, ob_low_eval, false); + me_nores = BKE_mesh_new_from_object(NULL, ob_low_eval, false); RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer); RE_bake_normal_world_to_tangent(pixel_array_low, @@ -1098,7 +1110,7 @@ static int bake(Render *re, me_nores, normal_swizzle, ob_low_eval->obmat); - BKE_object_to_mesh_clear(ob_low_eval); + BKE_id_free(NULL, &me_nores->id); if (md) { md->mode = mode; @@ -1221,8 +1233,8 @@ cleanup: if (highpoly) { int i; for (i = 0; i < tot_highpoly; i++) { - if (highpoly[i].ob_eval) { - BKE_object_to_mesh_clear(highpoly[i].ob_eval); + if (highpoly[i].me != NULL) { + BKE_id_free(NULL, &highpoly[i].me->id); } } MEM_freeN(highpoly); @@ -1252,12 +1264,12 @@ cleanup: MEM_freeN(result); } - if (ob_low_eval) { - BKE_object_to_mesh_clear(ob_low_eval); + if (me_low != NULL) { + BKE_id_free(NULL, &me_low->id); } - if (ob_cage_eval) { - BKE_object_to_mesh_clear(ob_cage_eval); + if (me_cage != NULL) { + BKE_id_free(NULL, &me_cage->id); } DEG_graph_free(depsgraph); diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 53bc037c736..5ef133e87de 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -34,6 +34,7 @@ #include "BLT_translation.h" #include "DNA_anim_types.h" +#include "DNA_armature_types.h" #include "DNA_constraint_types.h" #include "DNA_curve_types.h" #include "DNA_scene_types.h" @@ -53,6 +54,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #ifdef WITH_PYTHON # include "BPY_extern.h" @@ -861,94 +863,107 @@ void CONSTRAINT_OT_limitdistance_reset(wmOperatorType *ot) /* ------------- Child-Of Constraint ------------------ */ -static void child_get_inverse_matrix(const bContext *C, - Scene *scene, - Object *ob, - bConstraint *con, - float invmat[4][4], - const int owner) +static void child_get_inverse_matrix_owner_bone( + const bContext *C, wmOperator *op, Scene *scene, Object *ob, float invmat[4][4]) { + /* For bone owner we want to do this in evaluated domain. + * BKE_pose_where_is / BKE_pose_where_is_bone relies on (re)evaluating parts of the scene + * and copying new evaluated stuff back to original. + */ Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + bConstraint *con_eval = edit_constraint_property_get(op, ob_eval, CONSTRAINT_TYPE_CHILDOF); /* nullify inverse matrix first */ unit_m4(invmat); - if (owner == EDIT_CONSTRAINT_OWNER_BONE) { - bPoseChannel *pchan; - /* try to find a pose channel - assume that this is the constraint owner */ - /* TODO: get from context instead? */ - if (ob && ob->pose && (pchan = BKE_pose_channel_active(ob))) { - bConstraint *con_last; - /* calculate/set inverse matrix: - * We just calculate all transform-stack eval up to but not including this constraint. - * This is because inverse should just inverse correct for just the constraint's influence - * when it gets applied; that is, at the time of application, we don't know anything about - * what follows. - */ - float imat[4][4], tmat[4][4]; - float pmat[4][4]; + bPoseChannel *pchan_eval = BKE_pose_channel_active(ob_eval); - /* make sure we passed the correct constraint */ - BLI_assert(BLI_findindex(&pchan->constraints, con) != -1); + /* try to find a pose channel - assume that this is the constraint owner */ + /* TODO: get from context instead? */ + if (ob_eval && ob_eval->pose && pchan_eval) { + bConstraint *con_last; - /* 1. calculate posemat where inverse doesn't exist yet (inverse was cleared above), - * to use as baseline ("pmat") to derive delta from. This extra calc saves users - * from having pressing "Clear Inverse" first - */ - BKE_pose_where_is(depsgraph, scene, ob); - copy_m4_m4(pmat, pchan->pose_mat); + /* calculate/set inverse matrix: + * We just calculate all transform-stack eval up to but not including this constraint. + * This is because inverse should just inverse correct for just the constraint's influence + * when it gets applied; that is, at the time of application, we don't know anything about + * what follows. + */ + float imat[4][4], tmat[4][4]; + float pmat[4][4]; - /* 2. knock out constraints starting from this one */ - con_last = pchan->constraints.last; - pchan->constraints.last = con->prev; + /* make sure we passed the correct constraint */ + BLI_assert(BLI_findindex(&pchan_eval->constraints, con_eval) != -1); - if (con->prev) { - /* new end must not point to this one, else this chain cutting is useless */ - con->prev->next = NULL; - } - else { - /* constraint was first */ - pchan->constraints.first = NULL; - } + /* 1. calculate posemat where inverse doesn't exist yet (inverse was cleared above), + * to use as baseline ("pmat") to derive delta from. This extra calc saves users + * from having pressing "Clear Inverse" first + */ + BKE_pose_where_is(depsgraph, scene, ob_eval); + copy_m4_m4(pmat, pchan_eval->pose_mat); - /* 3. solve pose without disabled constraints */ - BKE_pose_where_is(depsgraph, scene, ob); + /* 2. knock out constraints starting from this one */ + con_last = pchan_eval->constraints.last; + pchan_eval->constraints.last = con_eval->prev; - /* 4. determine effect of constraint by removing the newly calculated - * pchan->pose_mat from the original pchan->pose_mat, thus determining - * the effect of the constraint - */ - invert_m4_m4(imat, pchan->pose_mat); - mul_m4_m4m4(tmat, pmat, imat); - invert_m4_m4(invmat, tmat); + if (con_eval->prev) { + /* new end must not point to this one, else this chain cutting is useless */ + con_eval->prev->next = NULL; + } + else { + /* constraint was first */ + pchan_eval->constraints.first = NULL; + } - /* 5. restore constraints */ - pchan->constraints.last = con_last; + /* 3. solve pose without disabled constraints */ + BKE_pose_where_is(depsgraph, scene, ob_eval); - if (con->prev) { - /* hook up prev to this one again */ - con->prev->next = con; - } - else { - /* set as first again */ - pchan->constraints.first = con; - } + /* 4. determine effect of constraint by removing the newly calculated + * pchan->pose_mat from the original pchan->pose_mat, thus determining + * the effect of the constraint + */ + invert_m4_m4(imat, pchan_eval->pose_mat); + mul_m4_m4m4(tmat, pmat, imat); + invert_m4_m4(invmat, tmat); + + /* 5. restore constraints */ + pchan_eval->constraints.last = con_last; - /* 6. recalculate pose with new inv-mat applied */ - BKE_pose_where_is(depsgraph, scene, ob); + if (con_eval->prev) { + /* hook up prev to this one again */ + con_eval->prev->next = con_eval; } + else { + /* set as first again */ + pchan_eval->constraints.first = con_eval; + } + + /* 6. recalculate pose with new inv-mat applied */ + /* this one is unnecessary? (DEG seems to update correctly without) + + if we leave this in, we have to click "Set Inverse" twice to see updates... + BKE_pose_where_is(depsgraph, scene, ob_eval); */ } - if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) { - if (ob) { - Object workob; +} - /* make sure we passed the correct constraint */ - BLI_assert(BLI_findindex(&ob->constraints, con) != -1); +static void child_get_inverse_matrix_owner_object( + const bContext *C, Scene *scene, Object *ob, bConstraint *con, float invmat[4][4]) +{ + Depsgraph *depsgraph = CTX_data_depsgraph(C); - /* use BKE_object_workob_calc_parent to find inverse - just like for normal parenting */ - BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(invmat, workob.obmat); - } + /* nullify inverse matrix first */ + unit_m4(invmat); + + if (ob) { + Object workob; + + /* make sure we passed the correct constraint */ + BLI_assert(BLI_findindex(&ob->constraints, con) != -1); + UNUSED_VARS_NDEBUG(con); + + /* use BKE_object_workob_calc_parent to find inverse - just like for normal parenting */ + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); + invert_m4_m4(invmat, workob.obmat); } } @@ -969,7 +984,12 @@ static int childof_set_inverse_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - child_get_inverse_matrix(C, scene, ob, con, data->invmat, owner); + if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) { + child_get_inverse_matrix_owner_object(C, scene, ob, con, data->invmat); + } + else if (owner == EDIT_CONSTRAINT_OWNER_BONE) { + child_get_inverse_matrix_owner_bone(C, op, scene, ob, data->invmat); + } ED_object_constraint_update(bmain, ob); WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); @@ -1203,6 +1223,7 @@ void CONSTRAINT_OT_followpath_path_animate(wmOperatorType *ot) static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *ob = ED_object_active_context(C); bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER); @@ -1216,8 +1237,14 @@ static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - child_get_inverse_matrix(C, scene, ob, con, data->invmat, owner); + if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) { + child_get_inverse_matrix_owner_object(C, scene, ob, con, data->invmat); + } + else if (owner == EDIT_CONSTRAINT_OWNER_BONE) { + child_get_inverse_matrix_owner_bone(C, op, scene, ob, data->invmat); + } + ED_object_constraint_update(bmain, ob); WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); return OPERATOR_FINISHED; @@ -1789,10 +1816,15 @@ static bool get_new_constraint_target( */ if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) && (!only_curve && !only_mesh)) { - /* just use the active bone, and assume that it is visible + usable */ - *tar_ob = ob; - *tar_pchan = BKE_pose_channel_active(ob); - found = true; + + /* Only use the object & bone if the bone is visible & selected + * since we may have multiple objects in pose mode at once. */ + bPoseChannel *pchan = BKE_pose_channel_active_or_first_selected(ob); + if (pchan != NULL) { + *tar_pchan = pchan; + *tar_ob = ob; + found = true; + } break; } diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index afdda8d6b7f..da06707ebac 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -119,18 +119,27 @@ void ED_object_base_select(Base *base, eObjectSelect_Mode mode) } /** + * Call when the active base has changed. + */ +void ED_object_base_active_refresh(Main *bmain, Scene *scene, ViewLayer *view_layer) +{ + WM_main_add_notifier(NC_SCENE | ND_OB_ACTIVE, scene); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + struct wmMsgBus *mbus = ((wmWindowManager *)bmain->wm.first)->message_bus; + if (mbus != NULL) { + WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); + } +} + +/** * Change active base, it includes the notifier */ void ED_object_base_activate(bContext *C, Base *base) { - struct wmMsgBus *mbus = CTX_wm_message_bus(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); view_layer->basact = base; - - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); - DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_SELECT); + ED_object_base_active_refresh(CTX_data_main(C), scene, view_layer); } bool ED_object_base_deselect_all_ex(ViewLayer *view_layer, diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 394fea2cf27..9c98fdc2a2e 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -466,6 +466,8 @@ static void ignore_parent_tx(Main *bmain, Depsgraph *depsgraph, Scene *scene, Ob Object workob; Object *ob_child; + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + /* a change was made, adjust the children to compensate */ for (ob_child = bmain->objects.first; ob_child; ob_child = ob_child->id.next) { if (ob_child->parent == ob) { @@ -475,6 +477,14 @@ static void ignore_parent_tx(Main *bmain, Depsgraph *depsgraph, Scene *scene, Ob invert_m4_m4(ob_child->parentinv, workob.obmat); /* Copy result of BKE_object_apply_mat4(). */ BKE_object_transform_copy(ob_child, ob_child_eval); + /* Make sure evaluated object is in a consistent state with the original one. + * It might be needed for applying transform on its children. */ + copy_m4_m4(ob_child_eval->parentinv, ob_child->parentinv); + BKE_object_eval_transform_all(depsgraph, scene_eval, ob_child_eval); + /* Tag for update. + * This is because parent matrix did change, so in theory the child object might now be + * evaluated to a different location in another editing context. */ + DEG_id_tag_update(&ob_child->id, ID_RECALC_TRANSFORM); } } } @@ -537,7 +547,7 @@ static int apply_objects_internal(bContext *C, { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); + Depsgraph *depsgraph = CTX_data_evaluated_depsgraph(C); float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale; bool changed = true; @@ -965,7 +975,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Object *obact = CTX_data_active_object(C); Object *obedit = CTX_data_edit_object(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); + Depsgraph *depsgraph = CTX_data_evaluated_depsgraph(C); Object *tob; float cent[3], cent_neg[3], centn[3]; const float *cursor = scene->cursor.location; @@ -1052,7 +1062,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) /* move active first */ if (ob == obact) { - memmove(&objects[1], objects, object_index); + memmove(&objects[1], objects, object_index * sizeof(Object *)); objects[0] = ob; } } @@ -1217,8 +1227,10 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) arm->id.tag |= LIB_TAG_DOIT; /* do_inverse_offset = true; */ /* docenter_armature() handles this */ - BKE_object_where_is_calc(depsgraph, scene, ob); - BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */ + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + BKE_object_transform_copy(ob_eval, ob); + BKE_object_where_is_calc(depsgraph, scene, ob_eval); + BKE_pose_where_is(depsgraph, scene, ob_eval); /* needed for bone parents */ ignore_parent_tx(bmain, depsgraph, scene, ob); @@ -1353,9 +1365,12 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) add_v3_v3(ob->loc, centn); - BKE_object_where_is_calc(depsgraph, scene, ob); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + BKE_object_transform_copy(ob_eval, ob); + BKE_object_where_is_calc(depsgraph, scene, ob_eval); if (ob->type == OB_ARMATURE) { - BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */ + /* needed for bone parents */ + BKE_pose_where_is(depsgraph, scene, ob_eval); } ignore_parent_tx(bmain, depsgraph, scene, ob); @@ -1378,10 +1393,12 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */ add_v3_v3(ob_other->loc, centn); - BKE_object_where_is_calc(depsgraph, scene, ob_other); + Object *ob_other_eval = DEG_get_evaluated_object(depsgraph, ob_other); + BKE_object_transform_copy(ob_other_eval, ob_other); + BKE_object_where_is_calc(depsgraph, scene, ob_other_eval); if (ob_other->type == OB_ARMATURE) { /* needed for bone parents */ - BKE_pose_where_is(depsgraph, scene, ob_other); + BKE_pose_where_is(depsgraph, scene, ob_other_eval); } ignore_parent_tx(bmain, depsgraph, scene, ob_other); } @@ -1490,7 +1507,7 @@ void OBJECT_OT_origin_set(wmOperatorType *ot) /* -------------------------------------------------------------------- */ /** \name Transform Axis Target * - * Note this is an experemental operator to point lights/cameras at objects. + * Note this is an experimental operator to point lights/cameras at objects. * We may re-work how this behaves based on user feedback. * - campbell. * \{ */ diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 678f6f50096..4f61443ac54 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -3278,9 +3278,18 @@ static int vertex_group_smooth_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob_ctx = ED_object_context(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data( - view_layer, CTX_wm_view3d(C), &objects_len, ob_ctx->mode); + uint objects_len; + Object **objects; + if (ob_ctx->mode == OB_MODE_WEIGHT_PAINT) { + /* Until weight paint supports multi-edit, use only the active. */ + objects_len = 1; + objects = &ob_ctx; + } + else { + objects = BKE_view_layer_array_from_objects_in_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len, ob_ctx->mode); + } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *ob = objects[ob_index]; @@ -3296,7 +3305,9 @@ static int vertex_group_smooth_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); } - MEM_freeN(objects); + if (objects != &ob_ctx) { + MEM_freeN(objects); + } return OPERATOR_FINISHED; } diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index dc634865a0a..4e6022cf18c 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -97,23 +97,38 @@ bool PE_poll(bContext *C) Object *ob = CTX_data_active_object(C); if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) { - return 0; + return false; + } + + PTCacheEdit *edit = PE_get_current(scene, ob); + if (edit == NULL) { + return false; } - return (PE_get_current(scene, ob) != NULL); + if (edit->psmd_eval == NULL || edit->psmd_eval->mesh_final == NULL) { + return false; + } + + return true; } bool PE_hair_poll(bContext *C) { Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - PTCacheEdit *edit; if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) { - return 0; + return false; } - edit = PE_get_current(scene, ob); - return (edit && edit->psys); + PTCacheEdit *edit = PE_get_current(scene, ob); + if (edit == NULL || edit->psys == NULL) { + return false; + } + if (edit->psmd_eval == NULL || edit->psmd_eval->mesh_final == NULL) { + return false; + } + + return true; } bool PE_poll_view3d(bContext *C) @@ -322,10 +337,13 @@ static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *o } } - if (edit) { + /* Don't consider inactive or render dependency graphs, since they might be evaluated for a + * different number of childrem. or have different pointer to evaluated particle system or + * modifier which will also cause troubles. */ + if (edit && DEG_is_active(depsgraph)) { edit->pid = *pid; if (edit->flags & PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL) { - if (edit->psys != NULL) { + if (edit->psys != NULL && edit->psys_eval != NULL) { psys_copy_particles(edit->psys, edit->psys_eval); pe_update_hair_particle_edit_pointers(edit); } @@ -1085,7 +1103,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys) edit = psys->edit; psmd_eval = edit->psmd_eval; - if (!psmd_eval->mesh_final) { + if (psmd_eval == NULL || psmd_eval->mesh_final == NULL) { return; } @@ -1217,7 +1235,7 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit) psys = edit->psys; - if (!edit->psmd_eval->mesh_final) { + if (edit->psmd_eval == NULL || edit->psmd_eval->mesh_final == NULL) { return; } @@ -1489,7 +1507,7 @@ void update_world_cos(Depsgraph *UNUSED(depsgraph), Object *ob, PTCacheEdit *edi KEY_K; float hairmat[4][4]; - if (psys == 0 || psys->edit == 0 || psmd_eval->mesh_final == NULL) { + if (psys == 0 || psys->edit == 0 || psmd_eval == NULL || psmd_eval->mesh_final == NULL) { return; } diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c index be625eb939f..40d90676487 100644 --- a/source/blender/editors/physics/particle_edit_undo.c +++ b/source/blender/editors/physics/particle_edit_undo.c @@ -252,7 +252,8 @@ static bool particle_undosys_step_encode(struct bContext *C, static void particle_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, - int UNUSED(dir)) + int UNUSED(dir), + bool UNUSED(is_final)) { /* TODO(campbell): undo_system: use low-level API to set mode. */ ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT); diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index dc4ce138d9d..dc3673c972f 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -46,6 +46,7 @@ #include "DEG_depsgraph.h" #include "ED_screen.h" +#include "ED_object.h" #include "WM_types.h" #include "WM_api.h" @@ -1216,7 +1217,7 @@ static int fluid_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED( return OPERATOR_CANCELLED; } - if (!fluidsimBake(C, op->reports, CTX_data_active_object(C), true)) { + if (!fluidsimBake(C, op->reports, ED_object_context(C), true)) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 352593a15ad..9ac93f07300 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -914,7 +914,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even wmJob *wm_job; RenderJob *rj; Image *ima; - int jobflag; const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); const bool use_viewport = RNA_boolean_get(op->ptr, "use_viewport"); @@ -973,12 +972,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even /* ensure at least 1 area shows result */ sa = render_view_open(C, event->x, event->y, op->reports); - jobflag = WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS; - - if (RNA_struct_property_is_set(op->ptr, "layer")) { - jobflag |= WM_JOB_SUSPEND; - } - /* job custom data */ rj = MEM_callocN(sizeof(RenderJob), "render job"); rj->main = bmain; @@ -1038,12 +1031,20 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even name = "Render"; } - wm_job = WM_jobs_get( - CTX_wm_manager(C), CTX_wm_window(C), scene, name, jobflag, WM_JOB_TYPE_RENDER); + wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + scene, + name, + WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS, + WM_JOB_TYPE_RENDER); WM_jobs_customdata_set(wm_job, rj, render_freejob); WM_jobs_timer(wm_job, 0.2, NC_SCENE | ND_RENDER_RESULT, 0); WM_jobs_callbacks(wm_job, render_startjob, NULL, NULL, render_endjob); + if (RNA_struct_property_is_set(op->ptr, "layer")) { + WM_jobs_delay_start(wm_job, 0.2); + } + /* get a render result image, and make sure it is empty */ ima = BKE_image_verify_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(rj->main, ima, NULL, IMA_SIGNAL_FREE); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 35130988aba..fbabdc2f3c1 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -1208,19 +1208,13 @@ static void icon_preview_startjob_all_sizes(void *customdata, IconPreview *ip = (IconPreview *)customdata; IconPreviewSize *cur_size; - /* Wait 2s to start rendering icon previews, to not bog down user interaction. - * Particularly important for heavy scenes and Eevee using OpenGL that blocks - * the user interface drawing. */ - for (int i = 0; i < 20; i++) { - PIL_sleep_ms(100); - if (*stop) { - return; - } - } - for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) { PreviewImage *prv = ip->owner; + if (*stop) { + break; + } + if (prv->tag & PRV_TAG_DEFFERED_DELETE) { /* Non-thread-protected reading is not an issue here. */ continue; @@ -1265,10 +1259,6 @@ static void icon_preview_startjob_all_sizes(void *customdata, common_preview_startjob(sp, stop, do_update, progress); shader_preview_free(sp); - - if (*stop) { - break; - } } } @@ -1350,8 +1340,13 @@ void ED_preview_icon_render( BLI_freelistN(&ip.sizes); } -void ED_preview_icon_job( - const bContext *C, void *owner, ID *id, unsigned int *rect, int sizex, int sizey) +void ED_preview_icon_job(const bContext *C, + void *owner, + ID *id, + unsigned int *rect, + int sizex, + int sizey, + const bool delay) { wmJob *wm_job; IconPreview *ip, *old_ip; @@ -1363,7 +1358,7 @@ void ED_preview_icon_job( CTX_wm_window(C), owner, "Icon Preview", - WM_JOB_EXCL_RENDER | WM_JOB_SUSPEND, + WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); ip = MEM_callocN(sizeof(IconPreview), "icon preview"); @@ -1396,6 +1391,10 @@ void ED_preview_icon_job( /* setup job */ WM_jobs_customdata_set(wm_job, ip, icon_preview_free); WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW); + /* Wait 2s to start rendering icon previews, to not bog down user interaction. + * Particularly important for heavy scenes and Eevee using OpenGL that blocks + * the user interface drawing. */ + WM_jobs_delay_start(wm_job, (delay) ? 2.0 : 0.0); WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index fc771e0db77..af1e0eeed79 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -47,17 +47,6 @@ /* ******************************************** */ -/* Invert line handling */ - -#define GL_TOGGLE(mode, onoff) (((onoff) ? glEnable : glDisable)(mode)) - -void set_inverted_drawing(int enable) -{ - glLogicOp(enable ? GL_INVERT : GL_COPY); - GL_TOGGLE(GL_COLOR_LOGIC_OP, enable); - GL_TOGGLE(GL_DITHER, !enable); -} - static int get_cached_work_texture(int *r_w, int *r_h) { static GLint texid = -1; @@ -486,6 +475,9 @@ void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state, float bglPolygonOffsetCalc(const float winmat[16], float viewdist, float dist) { + /* Seems like we have a factor of 2 more offset than 2.79 for some reason. Correct for this. */ + dist *= 0.5f; + if (winmat[15] > 0.5f) { #if 1 return 0.00001f * dist * viewdist; // ortho tweaking diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index ef99d39f990..c9a45728bc2 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -74,6 +74,7 @@ #include "ED_clip.h" #include "ED_image.h" #include "ED_keyframes_draw.h" +#include "ED_mesh.h" #include "ED_object.h" #include "ED_screen.h" #include "ED_screen_types.h" @@ -371,6 +372,12 @@ bool ED_operator_object_active_editable_font(bContext *C) return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob) && (ob->type == OB_FONT)); } +bool ED_operator_editable_mesh(bContext *C) +{ + Mesh *mesh = ED_mesh_context(C); + return (mesh != NULL) && !ID_IS_LINKED(mesh); +} + bool ED_operator_editmesh(bContext *C) { Object *obedit = CTX_data_edit_object(C); @@ -4200,6 +4207,7 @@ static int match_region_with_redraws(int spacetype, static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { bScreen *screen = CTX_wm_screen(C); + wmWindow *win = CTX_wm_window(C); #ifdef PROFILE_AUDIO_SYNCH static int old_frame = 0; @@ -4209,8 +4217,9 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv if (screen->animtimer && screen->animtimer == event->customdata) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + ViewLayer *view_layer = WM_window_get_active_view_layer(win); + Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false); + Scene *scene_eval = (depsgraph != NULL) ? DEG_get_evaluated_scene(depsgraph) : NULL; wmTimer *wt = screen->animtimer; ScreenAnimData *sad = wt->customdata; wmWindowManager *wm = CTX_wm_manager(C); @@ -4230,7 +4239,11 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv sync = (scene->flag & SCE_FRAME_DROP); } - if (scene_eval->id.recalc & ID_RECALC_AUDIO_SEEK) { + if (scene_eval == NULL) { + /* Happens when undo/redo system is used during playback, nothing meaningful we can do here. + */ + } + else if (scene_eval->id.recalc & ID_RECALC_AUDIO_SEEK) { /* Ignore seek here, the audio will be updated to the scene frame after jump during next * dependency graph update. */ } @@ -4335,7 +4348,9 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv } /* since we follow drawflags, we can't send notifier but tag regions ourselves */ - ED_update_for_newframe(bmain, depsgraph); + if (depsgraph != NULL) { + ED_update_for_newframe(bmain, depsgraph); + } for (window = wm->windows.first; window; window = window->next) { const bScreen *win_screen = WM_window_get_active_screen(window); diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c index 86be939d41b..26849edeb44 100644 --- a/source/blender/editors/screen/screen_user_menu.c +++ b/source/blender/editors/screen/screen_user_menu.c @@ -298,7 +298,7 @@ void ED_screen_user_menu_register(void) { MenuType *mt = MEM_callocN(sizeof(MenuType), __func__); strcpy(mt->idname, "SCREEN_MT_user_menu"); - strcpy(mt->label, "Quick Favorites"); + strcpy(mt->label, N_("Quick Favorites")); strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); mt->draw = screen_user_menu_draw; WM_menutype_add(mt); diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index e5552314a6e..005c76d26b0 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -110,24 +110,6 @@ static void screenshot_data_free(wmOperator *op) } } -static void screenshot_crop(ImBuf *ibuf, rcti crop) -{ - unsigned int *to = ibuf->rect; - unsigned int *from = ibuf->rect + crop.ymin * ibuf->x + crop.xmin; - int crop_x = BLI_rcti_size_x(&crop); - int crop_y = BLI_rcti_size_y(&crop); - int y; - - if (crop_x > 0 && crop_y > 0) { - for (y = 0; y < crop_y; y++, to += crop_x, from += ibuf->x) { - memmove(to, from, sizeof(unsigned int) * crop_x); - } - - ibuf->x = crop_x; - ibuf->y = crop_y; - } -} - static int screenshot_exec(bContext *C, wmOperator *op) { ScreenshotData *scd = op->customdata; @@ -153,7 +135,8 @@ static int screenshot_exec(bContext *C, wmOperator *op) /* crop to show only single editor */ if (!RNA_boolean_get(op->ptr, "full")) { - screenshot_crop(ibuf, scd->crop); + IMB_rect_crop(ibuf, &scd->crop); + scd->dumprect = ibuf->rect; } if (scd->im_format.planes == R_IMF_PLANES_BW) { diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index f4138dd7847..61b737589c8 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -331,30 +331,6 @@ static void WORKSPACE_OT_delete(wmOperatorType *ot) ot->exec = workspace_delete_exec; } -static bool workspace_append_activate_poll(bContext *C) -{ - wmOperatorType *ot = WM_operatortype_find("WM_OT_append", false); - return WM_operator_poll(C, ot); -} - -static int workspace_append(bContext *C, const char *directory, const char *idname) -{ - wmOperatorType *ot = WM_operatortype_find("WM_OT_append", false); - PointerRNA opptr; - int retval; - - WM_operator_properties_create_ptr(&opptr, ot); - RNA_string_set(&opptr, "directory", directory); - RNA_string_set(&opptr, "filename", idname); - RNA_boolean_set(&opptr, "autoselect", false); - - retval = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &opptr); - - WM_operator_properties_free(&opptr); - - return retval; -} - static int workspace_append_activate_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -367,23 +343,20 @@ static int workspace_append_activate_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "idname", idname); RNA_string_get(op->ptr, "filepath", filepath); - if (workspace_append(C, filepath, idname) != OPERATOR_CANCELLED) { - WorkSpace *appended_workspace = BLI_findstring( - &bmain->workspaces, idname, offsetof(ID, name) + 2); - BLI_assert(appended_workspace != NULL); + WorkSpace *appended_workspace = (WorkSpace *)WM_file_append_datablock( + C, filepath, ID_WS, idname); - if (appended_workspace) { - /* Set defaults. */ - BLO_update_defaults_workspace(appended_workspace, NULL); + if (appended_workspace) { + /* Set defaults. */ + BLO_update_defaults_workspace(appended_workspace, NULL); - /* Reorder to last position. */ - BKE_id_reorder(&bmain->workspaces, &appended_workspace->id, NULL, true); + /* Reorder to last position. */ + BKE_id_reorder(&bmain->workspaces, &appended_workspace->id, NULL, true); - /* Changing workspace changes context. Do delayed! */ - WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace); + /* Changing workspace changes context. Do delayed! */ + WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace); - return OPERATOR_FINISHED; - } + return OPERATOR_FINISHED; } return OPERATOR_CANCELLED; @@ -398,7 +371,6 @@ static void WORKSPACE_OT_append_activate(wmOperatorType *ot) /* api callbacks */ ot->exec = workspace_append_activate_exec; - ot->poll = workspace_append_activate_poll; RNA_def_string(ot->srna, "idname", @@ -449,25 +421,21 @@ static void workspace_append_button(uiLayout *layout, { const ID *id = (ID *)workspace; PointerRNA opptr; - char lib_path[FILE_MAX_LIBEXTRA]; const char *filepath = from_main->name; if (strlen(filepath) == 0) { filepath = BLO_EMBEDDED_STARTUP_BLEND; } - BLI_path_join(lib_path, sizeof(lib_path), filepath, BKE_idcode_to_name(GS(id->name)), NULL); - BLI_assert(STREQ(ot_append->idname, "WORKSPACE_OT_append_activate")); uiItemFullO_ptr( layout, ot_append, workspace->id.name + 2, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); RNA_string_set(&opptr, "idname", id->name + 2); - RNA_string_set(&opptr, "filepath", lib_path); + RNA_string_set(&opptr, "filepath", filepath); } -static void workspace_add_menu(bContext *C, uiLayout *layout, void *template_v) +static void workspace_add_menu(bContext *UNUSED(C), uiLayout *layout, void *template_v) { - Main *bmain = CTX_data_main(C); const char *app_template = template_v; bool has_startup_items = false; @@ -479,10 +447,6 @@ static void workspace_add_menu(bContext *C, uiLayout *layout, void *template_v) for (WorkSpace *workspace = startup_config->workspaces.first; workspace; workspace = workspace->id.next) { uiLayout *row = uiLayoutRow(layout, false); - if (BLI_findstring(&bmain->workspaces, workspace->id.name, offsetof(ID, name))) { - uiLayoutSetActive(row, false); - } - workspace_append_button(row, ot_append, workspace, startup_config->main); has_startup_items = true; } @@ -506,10 +470,6 @@ static void workspace_add_menu(bContext *C, uiLayout *layout, void *template_v) } uiLayout *row = uiLayoutRow(layout, false); - if (BLI_findstring(&bmain->workspaces, workspace->id.name, offsetof(ID, name))) { - uiLayoutSetActive(row, false); - } - workspace_append_button(row, ot_append, workspace, builtin_config->main); } } diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 65e24cecf82..ac74afce79e 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -964,9 +964,9 @@ static void paint_draw_curve_cursor(Brush *brush, ViewContext *vc) immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); float selec_col[4], handle_col[4], pivot_col[4]; - UI_GetThemeColor4fv(TH_VERTEX_SELECT, selec_col); - UI_GetThemeColor4fv(TH_PAINT_CURVE_HANDLE, handle_col); - UI_GetThemeColor4fv(TH_PAINT_CURVE_PIVOT, pivot_col); + UI_GetThemeColorType4fv(TH_VERTEX_SELECT, SPACE_VIEW3D, selec_col); + UI_GetThemeColorType4fv(TH_PAINT_CURVE_HANDLE, SPACE_VIEW3D, handle_col); + UI_GetThemeColorType4fv(TH_PAINT_CURVE_PIVOT, SPACE_VIEW3D, pivot_col); for (i = 0; i < pc->tot_points - 1; i++, cp++) { int j; diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c index c03cb69df88..7e283274383 100644 --- a/source/blender/editors/sculpt_paint/paint_curve_undo.c +++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c @@ -122,7 +122,8 @@ static bool paintcurve_undosys_step_encode(struct bContext *C, static void paintcurve_undosys_step_decode(struct bContext *UNUSED(C), struct Main *UNUSED(bmain), UndoStep *us_p, - int UNUSED(dir)) + int UNUSED(dir), + bool UNUSED(is_final)) { PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p; undocurve_to_paintcurve(&us->data, us->pc); diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index dded9fcf45a..d7e1b47d973 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -126,7 +126,8 @@ static void partialvis_update_mesh(Object *ob, /* Hide or show elements in multires grids with a special GridFlags * customdata layer. */ -static void partialvis_update_grids(Object *ob, +static void partialvis_update_grids(Depsgraph *depsgraph, + Object *ob, PBVH *pbvh, PBVHNode *node, PartialVisAction action, @@ -208,7 +209,7 @@ static void partialvis_update_grids(Object *ob, if (any_changed) { BKE_pbvh_node_mark_rebuild_draw(node); BKE_pbvh_node_fully_hidden_set(node, !any_visible); - multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED); + multires_mark_as_modified(depsgraph, ob, MULTIRES_HIDDEN_MODIFIED); } } @@ -378,7 +379,7 @@ static int hide_show_exec(bContext *C, wmOperator *op) partialvis_update_mesh(ob, pbvh, nodes[i], action, area, clip_planes); break; case PBVH_GRIDS: - partialvis_update_grids(ob, pbvh, nodes[i], action, area, clip_planes); + partialvis_update_grids(depsgraph, ob, pbvh, nodes[i], action, area, clip_planes); break; case PBVH_BMESH: partialvis_update_bmesh(ob, pbvh, nodes[i], action, area, clip_planes); diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 79731a6752d..22de22e8e59 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -1554,9 +1554,8 @@ static void screen_px_from_persp(const float uv[2], w_int[2] *= wtot_inv; } else { - w[0] = w[1] = w[2] = - /* dummy values for zero area face */ - w_int[0] = w_int[1] = w_int[2] = 1.0f / 3.0f; + /* Dummy values for zero area face. */ + w[0] = w[1] = w[2] = w_int[0] = w_int[1] = w_int[2] = 1.0f / 3.0f; } /* done re-weighting */ diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c index bb73d424152..e7f100ebacb 100644 --- a/source/blender/editors/sculpt_paint/paint_image_undo.c +++ b/source/blender/editors/sculpt_paint/paint_image_undo.c @@ -540,10 +540,8 @@ static void image_undosys_step_decode_redo(ImageUndoStep *us) } } -static void image_undosys_step_decode(struct bContext *C, - struct Main *bmain, - UndoStep *us_p, - int dir) +static void image_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir, bool UNUSED(is_final)) { ImageUndoStep *us = (ImageUndoStep *)us_p; #if 0 diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 0dd2e8ee968..f60ea8410ef 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -167,7 +167,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) 0, totnode, &data, mask_flood_fill_task_cb, &settings); if (multires) { - multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); + multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); } sculpt_undo_push_end(); @@ -341,7 +341,7 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti * } if (multires) { - multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); + multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); } sculpt_undo_push_end(); @@ -528,7 +528,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) } if (multires) { - multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); + multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); } sculpt_undo_push_end(); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 316ae6189f0..980b043bf8b 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -56,6 +56,7 @@ #include "BKE_paint.h" #include "BKE_report.h" #include "BKE_subsurf.h" +#include "BKE_layer.h" #include "DEG_depsgraph.h" @@ -1305,18 +1306,47 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) BKE_paint_toolslots_brush_validate(bmain, &ts->wpaint->paint); } - /* When locked, it's almost impossible to select the pose - * then the object to enter weight paint mode. + /* When locked, it's almost impossible to select the pose-object + * then the mesh-object to enter weight paint mode. + * Even when the object mode is not locked this is inconvenient - so allow in either case. + * * In this case move our pose object in/out of pose mode. - * This is in fits with the convention of selecting multiple objects and entering a mode. */ - if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) { - Object *ob_arm = modifiers_isDeformedByArmature(ob); - if (ob_arm && (ob_arm->base_flag & BASE_SELECTED)) { - if (ob_arm->mode & OB_MODE_POSE) { - ED_object_posemode_exit_ex(bmain, ob_arm); - } - else { - ED_object_posemode_enter_ex(bmain, ob_arm); + * This is in fits with the convention of selecting multiple objects and entering a mode. + */ + { + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + if (md != NULL) { + /* Can be NULL. */ + View3D *v3d = CTX_wm_view3d(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + for (; md; md = md->next) { + if (md->type == eModifierType_Armature) { + ArmatureModifierData *amd = (ArmatureModifierData *)md; + Object *ob_arm = amd->object; + if (ob_arm != NULL) { + const Base *base_arm = BKE_view_layer_base_find(view_layer, ob_arm); + if (base_arm && BASE_VISIBLE(v3d, base_arm)) { + if (is_mode_set) { + if ((ob_arm->mode & OB_MODE_POSE) != 0) { + ED_object_posemode_exit_ex(bmain, ob_arm); + } + } + else { + /* Only check selected status when entering weight-paint mode + * because we may have multiple armature objects. + * Selecting one will de-select the other, which would leave it in pose-mode + * when exiting weight paint mode. While usable, this looks like inconsistent + * behavior from a user perspective. */ + if (base_arm->flag & BASE_SELECTED) { + if ((ob_arm->mode & OB_MODE_POSE) == 0) { + ED_object_posemode_enter_ex(bmain, ob_arm); + } + } + } + } + } + } } } } @@ -2271,7 +2301,6 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P vwpaint_update_cache_variants(C, wp, ob, itemptr); float mat[4][4]; - float mval[2]; const float brush_alpha_value = BKE_brush_alpha_get(scene, brush); @@ -2321,7 +2350,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P /* calculate pivot for rotation around seletion if needed */ /* also needed for "View Selected" on last stroke */ - paint_last_stroke_update(scene, vc->ar, mval); + paint_last_stroke_update(scene, vc->ar, ss->cache->mouse); BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); @@ -3273,12 +3302,12 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P VPaint *vp = ts->vpaint; ViewContext *vc = &vpd->vc; Object *ob = vc->obact; + SculptSession *ss = ob->sculpt; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; vwpaint_update_cache_variants(C, vp, ob, itemptr); float mat[4][4]; - float mval[2]; ED_view3d_init_mats_rv3d(ob, vc->rv3d); @@ -3300,7 +3329,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P /* calculate pivot for rotation around seletion if needed */ /* also needed for "View Selected" on last stroke */ - paint_last_stroke_update(scene, vc->ar, mval); + paint_last_stroke_update(scene, vc->ar, ss->cache->mouse); ED_region_tag_redraw(vc->ar); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index ec7cb410f2c..173d6ed5085 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -5186,15 +5186,13 @@ static void sculpt_flush_update_step(bContext *C) { Depsgraph *depsgraph = CTX_data_depsgraph(C); Object *ob = CTX_data_active_object(C); - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); SculptSession *ss = ob->sculpt; ARegion *ar = CTX_wm_region(C); MultiresModifierData *mmd = ss->multires; View3D *v3d = CTX_wm_view3d(C); if (mmd != NULL) { - /* NOTE: SubdivCCG is living in the evaluated object. */ - multires_mark_as_modified(ob_eval, MULTIRES_COORDS_MODIFIED); + multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); } DEG_id_tag_update(&ob->id, ID_RECALC_SHADING); diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 8c8d4487ada..81bb9c35817 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -554,10 +554,10 @@ static void sculpt_undo_restore_list(bContext *C, ListBase *lb) if (BKE_sculpt_multires_active(scene, ob)) { if (rebuild) { - multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED); + multires_mark_as_modified(depsgraph, ob, MULTIRES_HIDDEN_MODIFIED); } else { - multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); + multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); } } @@ -1109,10 +1109,8 @@ static void sculpt_undosys_step_decode_redo(struct bContext *C, SculptUndoStep * } } -static void sculpt_undosys_step_decode(struct bContext *C, - struct Main *bmain, - UndoStep *us_p, - int dir) +static void sculpt_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir, bool UNUSED(is_final)) { /* Ensure sculpt mode. */ { diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 30ddd8c7d33..0241a2fbe88 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -104,7 +104,7 @@ static int sound_open_exec(bContext *C, wmOperator *op) } if (RNA_boolean_get(op->ptr, "cache")) { - BKE_sound_cache(sound); + sound->flags |= SOUND_FLAGS_CACHING; } /* hook into UI */ @@ -765,7 +765,8 @@ static int sound_pack_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - sound->packedfile = newPackedFile(op->reports, sound->name, ID_BLEND_PATH(bmain, &sound->id)); + sound->packedfile = BKE_packedfile_new( + op->reports, sound->name, ID_BLEND_PATH(bmain, &sound->id)); BKE_sound_load(bmain, sound); return OPERATOR_FINISHED; @@ -811,7 +812,7 @@ static int sound_unpack_exec(bContext *C, wmOperator *op) "AutoPack is enabled, so image will be packed again on file save"); } - unpackSound(bmain, op->reports, sound, method); + BKE_packedfile_unpack_sound(bmain, op->reports, sound, method); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 99f9a91775e..e3fa8edd714 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -1378,10 +1378,11 @@ static void draw_plane_marker_ex(SpaceClip *sc, immEnd(); } } + immUnbindProgram(); /* Draw sliders. */ if (is_selected_track) { - immUniform1f("dash_factor", 2.0f); /* Solid line */ + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); if (draw_outline) { immUniformThemeColor(TH_MARKER_OUTLINE); @@ -1400,9 +1401,8 @@ static void draw_plane_marker_ex(SpaceClip *sc, px, shdr_pos); } + immUnbindProgram(); } - - immUnbindProgram(); } } diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 83d8133a99e..45479c4253d 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -1515,6 +1515,11 @@ static int mode_set_exec(bContext *C, wmOperator *op) sc->mode = mode; + if (sc->mode == SC_MODE_MASKEDIT && sc->view != SC_VIEW_CLIP) { + /* Make sure we are in the right view for mask editing */ + sc->view = SC_VIEW_CLIP; + } + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CLIP, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index c290e3a21d1..7e19ac255f0 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -420,6 +420,14 @@ static void clip_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, S ED_area_tag_redraw(sa); } break; + case NC_WM: + switch (wmn->data) { + case ND_FILEREAD: + case ND_UNDO: + clip_area_sync_frame_from_scene(sa, scene); + break; + } + break; } } diff --git a/source/blender/editors/space_clip/tracking_ops_plane.c b/source/blender/editors/space_clip/tracking_ops_plane.c index 89478375658..b1bf88634bc 100644 --- a/source/blender/editors/space_clip/tracking_ops_plane.c +++ b/source/blender/editors/space_clip/tracking_ops_plane.c @@ -74,6 +74,7 @@ static int create_plane_track_tracks_exec(bContext *C, wmOperator *op) BKE_tracking_track_plane_from_existing_motion(plane_track, framenr); } + DEG_id_tag_update(&clip->id, ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); return OPERATOR_FINISHED; @@ -337,8 +338,7 @@ static int slide_plane_marker_modal(bContext *C, wmOperator *op, const wmEvent * data->previous_mval[1] = event->mval[1]; copy_v2_v2(data->previous_corner, data->corner); - DEG_id_tag_update(&sc->clip->id, 0); - + DEG_id_tag_update(&clip->id, ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL); break; @@ -355,7 +355,7 @@ static int slide_plane_marker_modal(bContext *C, wmOperator *op, const wmEvent * clip_tracking_show_cursor(C); - DEG_id_tag_update(&sc->clip->id, 0); + DEG_id_tag_update(&clip->id, ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 15f87235c0d..4e50413513a 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1736,7 +1736,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w ((numfiles % items_block_size) != 0 ? items_block_size : 0)) - (numfiles_layout / 2); /* Actual (physical) scrolling info, in pixels, used to detect whether we are fully at the - * begining/end of the view. */ + * beginning/end of the view. */ /* Note that there is a weird glitch, that sometimes tot rctf is smaller than cur rctf... * that is why we still need to keep the min/max_middle_offset checks too. :( */ const float min_tot_scroll = is_horizontal ? ar->v2d.tot.xmin : -ar->v2d.tot.ymax; @@ -1747,16 +1747,16 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w /* Check if we have reached our final scroll position. */ /* Filelist has to be ready, otherwise it makes no sense to stop scrolling yet. */ const bool is_ready = filelist_is_ready(sfile->files); - /* Edited item must be in the 'middle' of shown area (kind of approximative). + /* Edited item must be in the 'middle' of shown area (kind of approximated). * Note that we have to do the check in 'block space', not in 'item space' here. */ const bool is_centered = (abs(middle_offset / items_block_size - sfile->scroll_offset / items_block_size) == 0); - /* OR edited item must be towards the begining, and we are scrolled fully to the start. */ + /* OR edited item must be towards the beginning, and we are scrolled fully to the start. */ const bool is_full_start = ((sfile->scroll_offset < min_middle_offset) && (min_curr_scroll - min_tot_scroll < 1.0f) && (middle_offset - min_middle_offset < items_block_size)); /* OR edited item must be towards the end, and we are scrolled fully to the end. - * This one is crucial (unlike the one for the begining), because without it we won't scroll + * This one is crucial (unlike the one for the beginning), because without it we won't scroll * fully to the end, and last column or row wil end up only partially drawn. */ const bool is_full_end = ((sfile->scroll_offset > max_middle_offset) && (max_tot_scroll - max_curr_scroll < 1.0f) && diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 86db6d50fcc..97a3c7f2480 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -797,6 +797,11 @@ void draw_image_main(const bContext *C, ARegion *ar) ima = ED_space_image(sima); ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy); + /* Tag image as in active use for garbage collector. */ + if (ima) { + BKE_image_tag_time(ima); + } + show_viewer = (ima && ima->source == IMA_SRC_VIEWER) != 0; show_render = (show_viewer && ima->type == IMA_TYPE_R_RESULT) != 0; show_paint = (ima && (sima->mode == SI_MODE_PAINT) && (show_viewer == false) && diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 96eaa89d175..b79ed1c83c4 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1391,7 +1391,7 @@ static int image_open_exec(bContext *C, wmOperator *op) BKE_image_init_imageuser(ima, iuser); } - /* XXX unpackImage frees image buffers */ + /* XXX BKE_packedfile_unpack_image frees image buffers */ ED_preview_kill_jobs(CTX_wm_manager(C), bmain); BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD); @@ -1601,7 +1601,7 @@ static int image_replace_exec(bContext *C, wmOperator *op) sima->image->source = IMA_SRC_FILE; } - /* XXX unpackImage frees image buffers */ + /* XXX BKE_packedfile_unpack_image frees image buffers */ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); BKE_icon_changed(BKE_icon_id_ensure(&sima->image->id)); @@ -2401,7 +2401,7 @@ static int image_reload_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } - /* XXX unpackImage frees image buffers */ + /* XXX BKE_packedfile_unpack_image frees image buffers */ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD); @@ -2859,10 +2859,10 @@ static int image_unpack_exec(bContext *C, wmOperator *op) "AutoPack is enabled, so image will be packed again on file save"); } - /* XXX unpackImage frees image buffers */ + /* XXX BKE_packedfile_unpack_image frees image buffers */ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - unpackImage(CTX_data_main(C), op->reports, ima, method); + BKE_packedfile_unpack_image(CTX_data_main(C), op->reports, ima, method); WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 6bf79711ae5..e8116193c1f 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -843,6 +843,11 @@ static void image_buttons_region_listener(wmWindow *UNUSED(win), ED_region_tag_redraw(ar); } break; + case NC_BRUSH: + if (wmn->action == NA_EDITED) { + ED_region_tag_redraw(ar); + } + break; } } @@ -946,6 +951,11 @@ static void image_header_region_listener(wmWindow *UNUSED(win), break; } break; + case NC_BRUSH: + if (wmn->action == NA_EDITED) { + ED_region_tag_redraw(ar); + } + break; } } diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c index bf43e493cc5..14817e9ffa1 100644 --- a/source/blender/editors/space_info/info_ops.c +++ b/source/blender/editors/space_info/info_ops.c @@ -65,7 +65,7 @@ static int pack_libraries_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - packLibraries(bmain, op->reports); + BKE_packedfile_pack_all_libraries(bmain, op->reports); return OPERATOR_FINISHED; } @@ -88,7 +88,7 @@ static int unpack_libraries_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - unpackLibraries(bmain, op->reports); + BKE_packedfile_unpack_all_libraries(bmain, op->reports); return OPERATOR_FINISHED; } @@ -124,7 +124,7 @@ static int autopack_toggle_exec(bContext *C, wmOperator *op) G.fileflags &= ~G_FILE_AUTOPACK; } else { - packAll(bmain, op->reports, true); + BKE_packedfile_pack_all(bmain, op->reports, true); G.fileflags |= G_FILE_AUTOPACK; } @@ -151,7 +151,7 @@ static int pack_all_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - packAll(bmain, op->reports, true); + BKE_packedfile_pack_all(bmain, op->reports, true); return OPERATOR_FINISHED; } @@ -221,7 +221,7 @@ static int unpack_all_exec(bContext *C, wmOperator *op) int method = RNA_enum_get(op->ptr, "method"); if (method != PF_KEEP) { - unpackAll(bmain, op->reports, method); /* XXX PF_ASK can't work here */ + BKE_packedfile_unpack_all(bmain, op->reports, method); /* XXX PF_ASK can't work here */ } G.fileflags &= ~G_FILE_AUTOPACK; @@ -236,7 +236,7 @@ static int unpack_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED( char title[64]; int count = 0; - count = countPackedFiles(bmain); + count = BKE_packedfile_count_all(bmain); if (!count) { BKE_report(op->reports, RPT_WARNING, "No packed files to unpack"); @@ -321,7 +321,7 @@ static int unpack_item_exec(bContext *C, wmOperator *op) } if (method != PF_KEEP) { - BKE_unpack_id(bmain, id, op->reports, method); /* XXX PF_ASK can't work here */ + BKE_packedfile_id_unpack(bmain, id, op->reports, method); /* XXX PF_ASK can't work here */ } G.fileflags &= ~G_FILE_AUTOPACK; @@ -545,7 +545,8 @@ static int update_reports_display_invoke(bContext *C, wmOperator *UNUSED(op), co /* escape if not our timer */ if ((reports->reporttimer == NULL) || (reports->reporttimer != event->customdata) || - ((report = BKE_reports_last_displayable(reports)) == NULL) /* may have been deleted */ + ((report = BKE_reports_last_displayable(reports)) == NULL) + /* may have been deleted */ ) { return OPERATOR_PASS_THROUGH; } diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index a5755ae43c6..d31256a1425 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -210,6 +210,7 @@ static void compo_initjob(void *cjv) /* NOTE: Don't update animation to preserve unkeyed changes, this means can not use * evaluate_on_framechange. */ + DEG_graph_flush_update(bmain, cj->compositor_depsgraph); DEG_evaluate_on_refresh(cj->compositor_depsgraph); bNodeTree *ntree_eval = (bNodeTree *)DEG_get_evaluated_id(cj->compositor_depsgraph, @@ -2418,6 +2419,7 @@ static int ntree_socket_move_exec(bContext *C, wmOperator *op) } } + ntree->update |= NTREE_UPDATE_GROUP; ntreeUpdateTree(CTX_data_main(C), ntree); snode_notify(C, snode); diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index b33960bb454..7dec6f5a4ef 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -347,7 +347,7 @@ static int backimage_fit_exec(bContext *C, wmOperator *UNUSED(op)) BKE_image_release_ibuf(ima, ibuf, lock); - snode->zoom *= min_ff(facx, facy); + snode->zoom *= min_ff(facx, facy) * U.dpi_fac; snode->xof = 0; snode->yof = 0; diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 459183ff226..4740c412083 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -593,7 +593,7 @@ static int collection_link_exec(bContext *C, wmOperator *op) if (ID_IS_LINKED(active_collection) || ((active_collection->flag & COLLECTION_IS_MASTER) && ID_IS_LINKED(scene))) { - BKE_report(op->reports, RPT_ERROR, "Cannot add a colection to a linked collection/scene"); + BKE_report(op->reports, RPT_ERROR, "Cannot add a collection to a linked collection/scene"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 86f99555e12..55130ae8894 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -116,6 +116,10 @@ static void outliner_tree_dimensions(SpaceOutliner *soops, int *r_width, int *r_ */ static bool is_object_data_in_editmode(const ID *id, const Object *obact) { + if (id == NULL) { + return false; + } + const short id_type = GS(id->name); if (id_type == ID_GD && obact && obact->data == id) { @@ -929,6 +933,40 @@ static void outliner_restrict_properties_enable_layer_collection_set( } } +static bool outliner_restrict_properties_collection_set(Scene *scene, + TreeElement *te, + PointerRNA *collection_ptr, + PointerRNA *layer_collection_ptr, + RestrictProperties *props, + RestrictPropertiesActive *props_active) +{ + TreeStoreElem *tselem = TREESTORE(te); + LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? te->directdata : + NULL; + Collection *collection = outliner_collection_from_tree_element(te); + + if ((collection->flag & COLLECTION_IS_MASTER) || + (layer_collection && ((layer_collection->flag & LAYER_COLLECTION_EXCLUDE) != 0))) { + return false; + } + + /* Create the PointerRNA. */ + RNA_id_pointer_create(&collection->id, collection_ptr); + if (layer_collection != NULL) { + RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection, layer_collection_ptr); + } + + /* Update the restriction column values for the collection children. */ + if (layer_collection) { + outliner_restrict_properties_enable_layer_collection_set( + layer_collection_ptr, collection_ptr, props, props_active); + } + else { + outliner_restrict_properties_enable_collection_set(collection_ptr, props, props_active); + } + return true; +} + static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ViewLayer *view_layer, @@ -1333,30 +1371,16 @@ static void outliner_draw_restrictbuts(uiBlock *block, } } else if (outliner_is_collection_tree_element(te)) { - LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? - te->directdata : - NULL; - Collection *collection = outliner_collection_from_tree_element(te); - if ((!layer_collection || !(layer_collection->flag & LAYER_COLLECTION_EXCLUDE)) && - !(collection->flag & COLLECTION_IS_MASTER)) { + PointerRNA collection_ptr; + PointerRNA layer_collection_ptr; - PointerRNA collection_ptr; - PointerRNA layer_collection_ptr; - RNA_id_pointer_create(&collection->id, &collection_ptr); - if (layer_collection != NULL) { - RNA_pointer_create( - &scene->id, &RNA_LayerCollection, layer_collection, &layer_collection_ptr); - } + if (outliner_restrict_properties_collection_set( + scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active)) { - /* Update the restriction column values for the collection children. */ - if (layer_collection) { - outliner_restrict_properties_enable_layer_collection_set( - &layer_collection_ptr, &collection_ptr, &props, &props_active); - } - else { - outliner_restrict_properties_enable_collection_set( - &collection_ptr, &props, &props_active); - } + LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? + te->directdata : + NULL; + Collection *collection = outliner_collection_from_tree_element(te); if (layer_collection != NULL) { if (soops->show_restrict_flags & SO_RESTRICT_HIDE) { @@ -1443,7 +1467,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, layer_collection, (char *)"indirect_only"); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - if (!props_active.layer_collection_indirect_only) { + if (props_active.layer_collection_holdout || + !props_active.layer_collection_indirect_only) { UI_but_flag_enable(bt, UI_BUT_INACTIVE); } } @@ -1558,6 +1583,12 @@ static void outliner_draw_restrictbuts(uiBlock *block, } } } + else if (outliner_is_collection_tree_element(te)) { + PointerRNA collection_ptr; + PointerRNA layer_collection_ptr; + outliner_restrict_properties_collection_set( + scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active); + } if (TSELEM_OPEN(tselem, soops)) { outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &te->subtree, props_active); @@ -2202,7 +2233,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) data.icon = ICON_OUTLINER_OB_LIGHTPROBE; break; case OB_EMPTY: - if (ob->instance_collection) { + if (ob->instance_collection && (ob->transflag & OB_DUPLICOLLECTION)) { data.icon = ICON_OUTLINER_OB_GROUP_INSTANCE; } else if (ob->empty_drawtype == OB_EMPTY_IMAGE) { diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index e1e7bf49606..89eb3b9d953 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -109,8 +109,9 @@ static void set_operation_types(SpaceOutliner *soops, } } else { - int idcode = GS(tselem->id->name); - switch (idcode) { + const int idcode = (int)GS(tselem->id->name); + bool is_standard_id = false; + switch ((ID_Type)idcode) { case ID_SCE: *scenelevel = 1; break; @@ -134,21 +135,47 @@ static void set_operation_types(SpaceOutliner *soops, case ID_KE: case ID_WO: case ID_AC: - case ID_NLA: case ID_TXT: case ID_GR: case ID_LS: case ID_LI: - if (*idlevel == 0) { - *idlevel = idcode; - } - else if (*idlevel != idcode) { - *idlevel = -1; - } - if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) { - *datalevel = 0; - } + case ID_VF: + case ID_NT: + case ID_BR: + case ID_PA: + case ID_GD: + case ID_MC: + case ID_MSK: + case ID_PAL: + case ID_PC: + case ID_CF: + case ID_WS: + case ID_LP: + is_standard_id = true; break; + case ID_WM: + case ID_SCR: + /* Those are ignored here. */ + /* Note: while Screens should be manageable here, deleting a screen used by a workspace + * will cause crashes when trying to use that workspace, so for now let's play minimal, + * safe change. */ + break; + } + if (idcode == ID_NLA) { + /* Fake one, not an actual ID type... */ + is_standard_id = true; + } + + if (is_standard_id) { + if (*idlevel == 0) { + *idlevel = idcode; + } + else if (*idlevel != idcode) { + *idlevel = -1; + } + if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) { + *datalevel = 0; + } } } } @@ -288,31 +315,33 @@ static void unlink_object_cb(bContext *C, TreeStoreElem *tselem, void *UNUSED(user_data)) { - Main *bmain = CTX_data_main(C); - Object *ob = (Object *)tselem->id; + if (tsep && tsep->id) { + Main *bmain = CTX_data_main(C); + Object *ob = (Object *)tselem->id; - if (GS(tsep->id->name) == ID_OB) { - /* Parented objects need to find which collection to unlink from. */ - TreeElement *te_parent = te->parent; - while (tsep && GS(tsep->id->name) == ID_OB) { - te_parent = te_parent->parent; - tsep = te_parent ? TREESTORE(te_parent) : NULL; + if (GS(tsep->id->name) == ID_OB) { + /* Parented objects need to find which collection to unlink from. */ + TreeElement *te_parent = te->parent; + while (tsep && GS(tsep->id->name) == ID_OB) { + te_parent = te_parent->parent; + tsep = te_parent ? TREESTORE(te_parent) : NULL; + } } - } - if (tsep) { - if (GS(tsep->id->name) == ID_GR) { - Collection *parent = (Collection *)tsep->id; - BKE_collection_object_remove(bmain, parent, ob, true); - DEG_id_tag_update(&parent->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); - } - else if (GS(tsep->id->name) == ID_SCE) { - Scene *scene = (Scene *)tsep->id; - Collection *parent = BKE_collection_master(scene); - BKE_collection_object_remove(bmain, parent, ob, true); - DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); + if (tsep && tsep->id) { + if (GS(tsep->id->name) == ID_GR) { + Collection *parent = (Collection *)tsep->id; + BKE_collection_object_remove(bmain, parent, ob, true); + DEG_id_tag_update(&parent->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + } + else if (GS(tsep->id->name) == ID_SCE) { + Scene *scene = (Scene *)tsep->id; + Collection *parent = BKE_collection_master(scene); + BKE_collection_object_remove(bmain, parent, ob, true); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + } } } } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index d428a190549..cc062467dbe 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -515,7 +515,7 @@ static void outliner_add_object_contents(SpaceOutliner *soops, } /* duplicated group */ - if (ob->instance_collection) { + if (ob->instance_collection && (ob->transflag & OB_DUPLICOLLECTION)) { outliner_add_element(soops, &te->subtree, ob->instance_collection, te, 0, 0); } } @@ -1545,7 +1545,7 @@ static void outliner_make_object_parent_hierarchy_collections(SpaceOutliner *soo if (!found) { /* We add the child in the tree even if it is not in the collection. - * We deliberately clear its subtree though, to make it less proeminent. */ + * We deliberately clear its sub-tree though, to make it less prominent. */ TreeElement *child_ob_tree_element = outliner_add_element( soops, &parent_ob_tree_element->subtree, child, parent_ob_tree_element, 0, 0); outliner_free_tree(&child_ob_tree_element->subtree); diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index e53a3cb02a7..76c198b3d6b 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -2042,8 +2042,6 @@ void draw_timeline_seq(const bContext *C, ARegion *ar) if (ed) { /* draw the data */ draw_seq_strips(C, ed, ar); - draw_cache_view(C); - /* text draw cached (for sequence names), in pixelspace now */ UI_view2d_text_cache_draw(ar); } @@ -2063,8 +2061,12 @@ void draw_timeline_seq(const bContext *C, ARegion *ar) } ED_markers_draw(C, marker_draw_flag); - /* preview range */ UI_view2d_view_ortho(v2d); + /* draw cache on top of markers area */ + if (ed) { + draw_cache_view(C); + } + /* preview range */ ANIM_draw_previewrange(C, v2d, 1); /* overlap playhead */ diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c index c36175489b3..b6c660ae5b2 100644 --- a/source/blender/editors/space_text/text_autocomplete.c +++ b/source/blender/editors/space_text/text_autocomplete.c @@ -260,7 +260,7 @@ static void get_suggest_prefix(Text *text, int offset) texttool_suggest_prefix(line + i, len); } -static void confirm_suggestion(Text *text, TextUndoBuf *utxt) +static void confirm_suggestion(Text *text) { SuggItem *sel; int i, over = 0; @@ -285,7 +285,7 @@ static void confirm_suggestion(Text *text, TextUndoBuf *utxt) // for (i = 0; i < skipleft; i++) // txt_move_left(text, 0); BLI_assert(memcmp(sel->name, &line[i], over) == 0); - txt_insert_buf(text, utxt, sel->name + over); + txt_insert_buf(text, sel->name + over); // for (i = 0; i < skipleft; i++) // txt_move_right(text, 0); @@ -308,8 +308,8 @@ static int text_autocomplete_invoke(bContext *C, wmOperator *op, const wmEvent * ED_area_tag_redraw(CTX_wm_area(C)); if (texttool_suggest_first() == texttool_suggest_last()) { - TextUndoBuf *utxt = ED_text_undo_push_init(C); - confirm_suggestion(st->text, utxt); + ED_text_undo_push_init(C); + confirm_suggestion(st->text); text_update_line_edited(st->text->curl); text_autocomplete_free(C, op); ED_undo_push(C, op->type->name); @@ -371,8 +371,8 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e case MIDDLEMOUSE: if (event->val == KM_PRESS) { if (text_do_suggest_select(st, ar)) { - TextUndoBuf *utxt = ED_text_undo_push_init(C); - confirm_suggestion(st->text, utxt); + ED_text_undo_push_init(C); + confirm_suggestion(st->text); text_update_line_edited(st->text->curl); ED_undo_push(C, op->type->name); swallow = 1; @@ -410,8 +410,8 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e case PADENTER: if (event->val == KM_PRESS) { if (tools & TOOL_SUGG_LIST) { - TextUndoBuf *utxt = ED_text_undo_push_init(C); - confirm_suggestion(st->text, utxt); + ED_text_undo_push_init(C); + confirm_suggestion(st->text); text_update_line_edited(st->text->curl); ED_undo_push(C, op->type->name); swallow = 1; diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 63d4f3e3119..8f7bd83cbf4 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -241,6 +241,8 @@ static int text_new_exec(bContext *C, wmOperator *UNUSED(op)) PropertyRNA *prop; text = BKE_text_add(bmain, "Text"); + /* Texts have no user by default... Only the 'real' user flag. */ + id_us_min(&text->id); /* hook into UI */ UI_context_active_but_prop_get_templateID(C, &ptr, &prop); @@ -307,6 +309,8 @@ static int text_open_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", str); text = BKE_text_load_ex(bmain, str, BKE_main_blendfile_path(bmain), internal); + /* Texts have no user by default... Only the 'real' user flag. */ + id_us_min(&text->id); if (!text) { if (op->customdata) { @@ -322,8 +326,6 @@ static int text_open_exec(bContext *C, wmOperator *op) /* hook into UI */ pprop = op->customdata; - id_us_ensure_real(&text->id); - if (pprop->prop) { RNA_id_pointer_create(&text->id, &idptr); RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, NULL); @@ -840,7 +842,7 @@ static int text_paste_exec(bContext *C, wmOperator *op) text_drawcache_tag_update(CTX_wm_space_text(C), 0); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); /* Convert clipboard content indentation to spaces if specified */ if (text->flags & TXT_TABSTOSPACES) { @@ -849,7 +851,7 @@ static int text_paste_exec(bContext *C, wmOperator *op) buf = new_buf; } - txt_insert_buf(text, utxt, buf); + txt_insert_buf(text, buf); text_update_edited(text); MEM_freeN(buf); @@ -893,9 +895,9 @@ static int text_duplicate_line_exec(bContext *C, wmOperator *UNUSED(op)) { Text *text = CTX_data_edit_text(C); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); - txt_duplicate_line(text, utxt); + txt_duplicate_line(text); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); @@ -932,7 +934,7 @@ static void txt_copy_clipboard(Text *text) return; } - buf = txt_sel_to_buf(text); + buf = txt_sel_to_buf(text, NULL); if (buf) { WM_clipboard_text_set(buf, 0); @@ -971,8 +973,8 @@ static int text_cut_exec(bContext *C, wmOperator *UNUSED(op)) txt_copy_clipboard(text); - TextUndoBuf *utxt = ED_text_undo_push_init(C); - txt_delete_selected(text, utxt); + ED_text_undo_push_init(C); + txt_delete_selected(text); text_update_cursor_moved(C); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); @@ -1008,14 +1010,14 @@ static int text_indent_exec(bContext *C, wmOperator *UNUSED(op)) text_drawcache_tag_update(CTX_wm_space_text(C), 0); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); if (txt_has_sel(text)) { txt_order_cursors(text, false); - txt_indent(text, utxt); + txt_indent(text); } else { - txt_add_char(text, utxt, '\t'); + txt_add_char(text, '\t'); } text_update_edited(text); @@ -1049,10 +1051,10 @@ static int text_unindent_exec(bContext *C, wmOperator *UNUSED(op)) text_drawcache_tag_update(CTX_wm_space_text(C), 0); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); txt_order_cursors(text, false); - txt_unindent(text, utxt); + txt_unindent(text); text_update_edited(text); @@ -1090,15 +1092,15 @@ static int text_line_break_exec(bContext *C, wmOperator *UNUSED(op)) // double check tabs/spaces before splitting the line curts = txt_setcurr_tab_spaces(text, space); - TextUndoBuf *utxt = ED_text_undo_push_init(C); - txt_split_curline(text, utxt); + ED_text_undo_push_init(C); + txt_split_curline(text); for (a = 0; a < curts; a++) { if (text->flags & TXT_TABSTOSPACES) { - txt_add_char(text, utxt, ' '); + txt_add_char(text, ' '); } else { - txt_add_char(text, utxt, '\t'); + txt_add_char(text, '\t'); } } @@ -1139,10 +1141,10 @@ static int text_comment_exec(bContext *C, wmOperator *UNUSED(op)) if (txt_has_sel(text)) { text_drawcache_tag_update(CTX_wm_space_text(C), 0); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); txt_order_cursors(text, false); - txt_comment(text, utxt); + txt_comment(text); text_update_edited(text); text_update_cursor_moved(C); @@ -1177,10 +1179,10 @@ static int text_uncomment_exec(bContext *C, wmOperator *UNUSED(op)) if (txt_has_sel(text)) { text_drawcache_tag_update(CTX_wm_space_text(C), 0); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); txt_order_cursors(text, false); - txt_uncomment(text, utxt); + txt_uncomment(text); text_update_edited(text); text_update_cursor_moved(C); @@ -1446,9 +1448,9 @@ static int move_lines_exec(bContext *C, wmOperator *op) Text *text = CTX_data_edit_text(C); const int direction = RNA_enum_get(op->ptr, "direction"); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); - txt_move_lines(text, utxt, direction); + txt_move_lines(text, direction); text_update_cursor_moved(C); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); @@ -2230,13 +2232,13 @@ static int text_delete_exec(bContext *C, wmOperator *op) } } - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); if (type == DEL_PREV_WORD) { if (txt_cursor_is_line_start(text)) { - txt_backspace_char(text, utxt); + txt_backspace_char(text); } - txt_backspace_word(text, utxt); + txt_backspace_word(text); } else if (type == DEL_PREV_CHAR) { @@ -2252,13 +2254,13 @@ static int text_delete_exec(bContext *C, wmOperator *op) } } - txt_backspace_char(text, utxt); + txt_backspace_char(text); } else if (type == DEL_NEXT_WORD) { if (txt_cursor_is_line_end(text)) { - txt_delete_char(text, utxt); + txt_delete_char(text); } - txt_delete_word(text, utxt); + txt_delete_word(text); } else if (type == DEL_NEXT_CHAR) { @@ -2274,7 +2276,7 @@ static int text_delete_exec(bContext *C, wmOperator *op) } } - txt_delete_char(text, utxt); + txt_delete_char(text); } text_update_line_edited(text->curl); @@ -2994,7 +2996,7 @@ static void text_cursor_set_exit(bContext *C, wmOperator *op) char *buffer; if (txt_has_sel(text)) { - buffer = txt_sel_to_buf(text); + buffer = txt_sel_to_buf(text, NULL); WM_clipboard_text_set(buffer, 1); MEM_freeN(buffer); } @@ -3190,18 +3192,18 @@ static int text_insert_exec(bContext *C, wmOperator *op) str = RNA_string_get_alloc(op->ptr, "text", NULL, 0); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); if (st && st->overwrite) { while (str[i]) { code = BLI_str_utf8_as_unicode_step(str, &i); - done |= txt_replace_char(text, utxt, code); + done |= txt_replace_char(text, code); } } else { while (str[i]) { code = BLI_str_utf8_as_unicode_step(str, &i); - done |= txt_add_char(text, utxt, code); + done |= txt_add_char(text, code); } } @@ -3308,7 +3310,7 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode) /* Replace current */ if (mode != TEXT_FIND && txt_has_sel(text)) { - tmp = txt_sel_to_buf(text); + tmp = txt_sel_to_buf(text, NULL); if (flags & ST_MATCH_CASE) { found = STREQ(st->findstr, tmp); @@ -3319,8 +3321,8 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode) if (found) { if (mode == TEXT_REPLACE) { - TextUndoBuf *utxt = ED_text_undo_push_init(C); - txt_insert_buf(text, utxt, st->replacestr); + ED_text_undo_push_init(C); + txt_insert_buf(text, st->replacestr); if (text->curl && text->curl->format) { MEM_freeN(text->curl->format); text->curl->format = NULL; @@ -3406,7 +3408,7 @@ static int text_find_set_selected_exec(bContext *C, wmOperator *op) Text *text = CTX_data_edit_text(C); char *tmp; - tmp = txt_sel_to_buf(text); + tmp = txt_sel_to_buf(text, NULL); BLI_strncpy(st->findstr, tmp, ST_MAX_FIND_STR); MEM_freeN(tmp); @@ -3437,7 +3439,7 @@ static int text_replace_set_selected_exec(bContext *C, wmOperator *UNUSED(op)) Text *text = CTX_data_edit_text(C); char *tmp; - tmp = txt_sel_to_buf(text); + tmp = txt_sel_to_buf(text, NULL); BLI_strncpy(st->replacestr, tmp, ST_MAX_FIND_STR); MEM_freeN(tmp); diff --git a/source/blender/editors/space_text/text_undo.c b/source/blender/editors/space_text/text_undo.c index 7db97f15a68..6ecb2b731b0 100644 --- a/source/blender/editors/space_text/text_undo.c +++ b/source/blender/editors/space_text/text_undo.c @@ -25,6 +25,7 @@ #include "DNA_text_types.h" +#include "BLI_array_store.h" #include "BLI_array_utils.h" #include "BLT_translation.h" @@ -35,6 +36,7 @@ #include "BKE_report.h" #include "BKE_text.h" #include "BKE_undo_system.h" +#include "BKE_main.h" #include "WM_api.h" #include "WM_types.h" @@ -53,18 +55,32 @@ #include "text_intern.h" #include "text_format.h" -/* TODO(campbell): undo_system: move text undo out of text block. */ - /* -------------------------------------------------------------------- */ /** \name Implements ED Undo System * \{ */ +#define ARRAY_CHUNK_SIZE 128 + typedef struct TextUndoStep { UndoStep step; UndoRefID_Text text_ref; - TextUndoBuf data; + struct { + BArrayState *state; + int buf_len; + } data; + + struct { + int line, line_select; + int column, column_select; + } cursor; + } TextUndoStep; +static struct { + BArrayStore *buffer_store; + int users; +} g_text_buffers = {NULL}; + static bool text_undosys_poll(bContext *UNUSED(C)) { /* Only use when operators initialized. */ @@ -77,12 +93,8 @@ static void text_undosys_step_encode_init(struct bContext *C, UndoStep *us_p) TextUndoStep *us = (TextUndoStep *)us_p; BLI_assert(BLI_array_is_zeroed(&us->data, 1)); - UNUSED_VARS(C); + UNUSED_VARS(C, us); /* XXX, use to set the undo type only. */ - - us->data.buf = NULL; - us->data.len = 0; - us->data.pos = -1; } static bool text_undosys_step_encode(struct bContext *C, @@ -93,97 +105,71 @@ static bool text_undosys_step_encode(struct bContext *C, Text *text = CTX_data_edit_text(C); - /* No undo data was generated. Hint, use global undo here. */ - if ((us->data.pos == -1) || (us->data.buf == NULL)) { - return false; - } + int buf_len = 0; - us_p->is_applied = true; - - us->text_ref.ptr = text; + uchar *buf = (uchar *)txt_to_buf_for_undo(text, &buf_len); + if (g_text_buffers.buffer_store == NULL) { + g_text_buffers.buffer_store = BLI_array_store_create(1, ARRAY_CHUNK_SIZE); + } + g_text_buffers.users += 1; + const size_t total_size_prev = BLI_array_store_calc_size_compacted_get( + g_text_buffers.buffer_store); - us->step.data_size = us->data.len; + us->data.state = BLI_array_store_state_add(g_text_buffers.buffer_store, buf, buf_len, NULL); + MEM_freeN(buf); - return true; -} + us->cursor.line = txt_get_span(text->lines.first, text->curl); + us->cursor.column = text->curc; -static void text_undosys_step_decode_undo_impl(Text *text, TextUndoStep *us) -{ - BLI_assert(us->step.is_applied == true); - TextUndoBuf data = us->data; - while (data.pos > -1) { - txt_do_undo(text, &data); + if (txt_has_sel(text)) { + us->cursor.line_select = (text->curl == text->sell) ? + us->cursor.line : + txt_get_span(text->lines.first, text->sell); + us->cursor.column_select = text->selc; } - BLI_assert(data.pos == -1); - us->step.is_applied = false; -} - -static void text_undosys_step_decode_redo_impl(Text *text, TextUndoStep *us) -{ - BLI_assert(us->step.is_applied == false); - TextUndoBuf data = us->data; - data.pos = -1; - while (data.pos < us->data.pos) { - txt_do_redo(text, &data); + else { + us->cursor.line_select = us->cursor.line; + us->cursor.column_select = us->cursor.column; } - BLI_assert(data.pos == us->data.pos); - us->step.is_applied = true; -} -static void text_undosys_step_decode_undo(Text *text, TextUndoStep *us) -{ - TextUndoStep *us_iter = us; - while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) { - if (us_iter->step.next->is_applied == false) { - break; - } - us_iter = (TextUndoStep *)us_iter->step.next; - } - while (us_iter != us) { - text_undosys_step_decode_undo_impl(text, us_iter); - us_iter = (TextUndoStep *)us_iter->step.prev; - } -} + us_p->is_applied = true; -static void text_undosys_step_decode_redo(Text *text, TextUndoStep *us) -{ - TextUndoStep *us_iter = us; - while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) { - if (us_iter->step.prev->is_applied == true) { - break; - } - us_iter = (TextUndoStep *)us_iter->step.prev; - } - while (us_iter && (us_iter->step.is_applied == false)) { - text_undosys_step_decode_redo_impl(text, us_iter); - if (us_iter == us) { - break; - } - us_iter = (TextUndoStep *)us_iter->step.next; - } + us->text_ref.ptr = text; + + us->step.data_size = BLI_array_store_calc_size_compacted_get(g_text_buffers.buffer_store) - + total_size_prev; + + return true; } static void text_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, - int dir) + int UNUSED(dir), + bool UNUSED(is_final)) { TextUndoStep *us = (TextUndoStep *)us_p; Text *text = us->text_ref.ptr; + size_t buf_len; - if (dir < 0) { - text_undosys_step_decode_undo(text, us); + { + const uchar *buf = BLI_array_store_state_data_get_alloc(us->data.state, &buf_len); + txt_from_buf_for_undo(text, (const char *)buf, buf_len); + MEM_freeN((void *)buf); } - else { - text_undosys_step_decode_redo(text, us); + + const bool has_select = ((us->cursor.line != us->cursor.line_select) || + (us->cursor.column != us->cursor.column_select)); + if (has_select) { + txt_move_to(text, us->cursor.line_select, us->cursor.column_select, false); } + txt_move_to(text, us->cursor.line, us->cursor.column, has_select); SpaceText *st = CTX_wm_space_text(C); if (st) { /* Not essential, always show text being undo where possible. */ st->text = text; } - text_update_edited(text); text_update_cursor_moved(C); text_drawcache_tag_update(st, 1); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); @@ -192,7 +178,14 @@ static void text_undosys_step_decode(struct bContext *C, static void text_undosys_step_free(UndoStep *us_p) { TextUndoStep *us = (TextUndoStep *)us_p; - MEM_SAFE_FREE(us->data.buf); + + BLI_array_store_state_remove(g_text_buffers.buffer_store, us->data.state); + + g_text_buffers.users -= 1; + if (g_text_buffers.users == 0) { + BLI_array_store_destroy(g_text_buffers.buffer_store); + g_text_buffers.buffer_store = NULL; + } } static void text_undosys_foreach_ID_ref(UndoStep *us_p, @@ -228,12 +221,16 @@ void ED_text_undosys_type(UndoType *ut) * \{ */ /* Use operator system to finish the undo step. */ -TextUndoBuf *ED_text_undo_push_init(bContext *C) +UndoStep *ED_text_undo_push_init(bContext *C) { UndoStack *ustack = ED_undo_stack_get(); - UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, NULL, BKE_UNDOSYS_TYPE_TEXT); - TextUndoStep *us = (TextUndoStep *)us_p; - return &us->data; + Main *bmain = CTX_data_main(C); + wmWindowManager *wm = bmain->wm.first; + if (wm->op_undo_depth <= 1) { + UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, NULL, BKE_UNDOSYS_TYPE_TEXT); + return us_p; + } + return NULL; } /** \} */ diff --git a/source/blender/editors/space_userpref/userpref_ops.c b/source/blender/editors/space_userpref/userpref_ops.c index 04ef2ed8118..1ec459ccfca 100644 --- a/source/blender/editors/space_userpref/userpref_ops.c +++ b/source/blender/editors/space_userpref/userpref_ops.c @@ -26,6 +26,8 @@ #include "DNA_screen_types.h" #include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_main.h" #include "BKE_report.h" #include "RNA_types.h" @@ -45,8 +47,10 @@ static int reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op)) { + Main *bmain = CTX_data_main(C); UI_theme_init_default(); UI_style_init_default(); + WM_reinit_gizmomap_all(bmain); WM_event_add_notifier(C, NC_WINDOW, NULL); U.runtime.is_dirty = true; return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index c1891865d6d..57b98ffeda3 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -662,7 +662,10 @@ static void view3d_widgets(void) WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_camera); WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_camera_view); WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_empty_image); + /* TODO(campbell): Not working well enough, disable for now. */ +#if 0 WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_armature_spline); +#endif WM_gizmogrouptype_append(VIEW3D_GGT_xform_gizmo); WM_gizmogrouptype_append(VIEW3D_GGT_xform_cage); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index d14a6870a6c..eef36dae86a 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -169,7 +169,13 @@ void ED_view3d_update_viewmat(Depsgraph *depsgraph, v2[2] = rv3d->persmat[2][1]; len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2))); - len_sc = (float)MAX2(ar->winx, ar->winy); + + if (rect) { + len_sc = (float)max_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)); + } + else { + len_sc = (float)MAX2(ar->winx, ar->winy); + } rv3d->pixsize = len_px / len_sc; } @@ -798,7 +804,11 @@ void ED_view3d_draw_depth(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, bool a GPU_depth_test(true); GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0); - DRW_draw_depth_loop(depsgraph, ar, v3d, viewport); + /* When Blender is starting, a click event can trigger a depth test while the viewport is not + * yet available. */ + if (viewport != NULL) { + DRW_draw_depth_loop(depsgraph, ar, v3d, viewport); + } if (rv3d->rflag & RV3D_CLIPPING) { ED_view3d_clipping_disable(); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index b6eb57a3c81..7c4b35507b9 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -4661,6 +4661,7 @@ static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEven cam->flag |= CAM_SHOW_BG_IMAGE; WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam); + DEG_id_tag_update(&cam->id, ID_RECALC_COPY_ON_WRITE); return OPERATOR_FINISHED; } @@ -4721,6 +4722,8 @@ static int background_image_remove_exec(bContext *C, wmOperator *op) BKE_camera_background_image_remove(cam, bgpic_rem); WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam); + DEG_id_tag_update(&cam->id, ID_RECALC_COPY_ON_WRITE); + return OPERATOR_FINISHED; } else { @@ -4944,7 +4947,7 @@ void ED_view3d_cursor3d_position_rotation(bContext *C, ray_no, NULL, &ob_dummy, - obmat)) { + obmat) != 0) { if (use_depth) { copy_v3_v3(cursor_co, ray_co); } diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c index 9cbf179ab49..64697a59019 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c @@ -21,7 +21,7 @@ * * Use for tools to hover over data before activation. * - * \note This is a slight mis-use of gizmo's, since clicking performs no action. + * \note This is a slight misuse of gizmo's, since clicking performs no action. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index ebfd66008f7..e781e129540 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -113,6 +113,13 @@ typedef struct RulerInfo { wmWindow *win; ScrArea *sa; ARegion *ar; /* re-assigned every modal update */ + + /* Track changes in state. */ + struct { + bool do_snap; + bool do_thickness; + } drag_state_prev; + } RulerInfo; /* -------------------------------------------------------------------- */ @@ -280,6 +287,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) /* pass */ } else if (state == RULER_STATE_DRAG) { + memset(&ruler_info->drag_state_prev, 0x0, sizeof(ruler_info->drag_state_prev)); ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0, ruler_info->ar, CTX_wm_view3d(C)); } @@ -857,27 +865,43 @@ static int gizmo_ruler_test_select(bContext *UNUSED(C), wmGizmo *gz, const int m static int gizmo_ruler_modal(bContext *C, wmGizmo *gz, const wmEvent *event, - eWM_GizmoFlagTweak UNUSED(tweak_flag)) + eWM_GizmoFlagTweak tweak_flag) { bool do_draw = false; int exit_code = OPERATOR_RUNNING_MODAL; RulerInfo *ruler_info = gz->parent_gzgroup->customdata; RulerItem *ruler_item = (RulerItem *)gz; ARegion *ar = CTX_wm_region(C); + bool do_cursor_update = false; ruler_info->ar = ar; switch (event->type) { case MOUSEMOVE: { - if (ruler_info->state == RULER_STATE_DRAG) { - if (view3d_ruler_item_mousemove( - ruler_info, ruler_item, event->mval, event->shift != 0, event->ctrl != 0)) { - do_draw = true; - } - } + do_cursor_update = true; break; } } + + const bool do_snap = tweak_flag & WM_GIZMO_TWEAK_SNAP; + const bool do_thickness = tweak_flag & WM_GIZMO_TWEAK_PRECISE; + if ((ruler_info->drag_state_prev.do_snap != do_snap) || + (ruler_info->drag_state_prev.do_thickness != do_thickness)) { + do_cursor_update = true; + } + + if (do_cursor_update) { + if (ruler_info->state == RULER_STATE_DRAG) { + if (view3d_ruler_item_mousemove( + ruler_info, ruler_item, event->mval, do_thickness, do_snap)) { + do_draw = true; + } + } + } + + ruler_info->drag_state_prev.do_snap = do_snap; + ruler_info->drag_state_prev.do_thickness = do_thickness; + if (do_draw) { ED_region_tag_redraw(ar); } @@ -920,8 +944,7 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) } /* update the new location */ - view3d_ruler_item_mousemove( - ruler_info, ruler_item_pick, event->mval, event->shift != 0, event->ctrl != 0); + view3d_ruler_item_mousemove(ruler_info, ruler_item_pick, event->mval, false, false); } } else { diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index 6ed0508f09f..2636062ed8b 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -38,6 +38,7 @@ #include "BKE_editmesh.h" #include "BKE_mesh_runtime.h" #include "BKE_mesh_iterators.h" +#include "BKE_modifier.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -293,8 +294,15 @@ void mesh_foreachScreenFace( data.clip_flag = clip_flag; BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE); - BKE_mesh_foreach_mapped_face_center( - me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP); + + if (modifiers_usesSubsurfFacedots(vc->scene, vc->obedit)) { + BKE_mesh_foreach_mapped_subdiv_face_center( + me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP); + } + else { + BKE_mesh_foreach_mapped_face_center( + me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP); + } } /* ------------------------------------------------------------------------ */ diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 3ff97cdd59a..61de61c8e31 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1602,31 +1602,63 @@ static const EnumPropertyItem *object_select_menu_enum_itemf(bContext *C, static int object_select_menu_exec(bContext *C, wmOperator *op) { const int name_index = RNA_enum_get(op->ptr, "name"); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool deselect = RNA_boolean_get(op->ptr, "deselect"); const bool toggle = RNA_boolean_get(op->ptr, "toggle"); bool changed = false; const char *name = object_mouse_select_menu_data[name_index].idname; - if (!toggle) { - CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { - if ((base->flag & BASE_SELECTED) != 0) { - ED_object_base_select(base, BA_DESELECT); - changed = true; - } - } - CTX_DATA_END; - } + View3D *v3d = CTX_wm_view3d(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + const Base *oldbasact = BASACT(view_layer); + Base *basact = NULL; CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { /* This is a bit dodgy, there should only be ONE object with this name, * but library objects can mess this up. */ if (STREQ(name, base->object->id.name + 2)) { - ED_object_base_activate(C, base); - ED_object_base_select(base, BA_SELECT); - changed = true; + basact = base; + break; } } CTX_DATA_END; + if (basact == NULL) { + return OPERATOR_CANCELLED; + } + UNUSED_VARS_NDEBUG(v3d); + BLI_assert(BASE_SELECTABLE(v3d, basact)); + + if (extend) { + ED_object_base_select(basact, BA_SELECT); + changed = true; + } + else if (deselect) { + ED_object_base_select(basact, BA_DESELECT); + changed = true; + } + else if (toggle) { + if (basact->flag & BASE_SELECTED) { + if (basact == oldbasact) { + ED_object_base_select(basact, BA_DESELECT); + changed = true; + } + } + else { + ED_object_base_select(basact, BA_SELECT); + changed = true; + } + } + else { + object_deselect_all_except(view_layer, basact); + ED_object_base_select(basact, BA_SELECT); + changed = true; + } + + if ((oldbasact != basact)) { + ED_object_base_activate(C, basact); + } + /* weak but ensures we activate menu again before using the enum */ memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data)); @@ -1664,12 +1696,19 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE); ot->prop = prop; - RNA_def_boolean( - ot->srna, "toggle", 0, "Toggle", "Toggle selection instead of deselecting everything first"); + RNA_def_boolean(ot->srna, "extend", 0, "Extend", ""); + RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", ""); + RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); } -static Base *object_mouse_select_menu( - bContext *C, ViewContext *vc, uint *buffer, int hits, const int mval[2], bool toggle) +static Base *object_mouse_select_menu(bContext *C, + ViewContext *vc, + uint *buffer, + int hits, + const int mval[2], + bool extend, + bool deselect, + bool toggle) { short baseCount = 0; bool ok; @@ -1739,6 +1778,8 @@ static Base *object_mouse_select_menu( PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); + RNA_boolean_set(&ptr, "extend", extend); + RNA_boolean_set(&ptr, "deselect", deselect); RNA_boolean_set(&ptr, "toggle", toggle); WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); WM_operator_properties_free(&ptr); @@ -2122,7 +2163,7 @@ static bool ed_object_select_pick(bContext *C, /* note; shift+alt goes to group-flush-selecting */ if (enumerate) { - basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, toggle); + basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, extend, deselect, toggle); } else { base = startbase; @@ -2190,7 +2231,7 @@ static bool ed_object_select_pick(bContext *C, /* note; shift+alt goes to group-flush-selecting */ if (enumerate) { - basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, toggle); + basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, extend, deselect, toggle); } else { basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest); @@ -2278,11 +2319,17 @@ static bool ed_object_select_pick(bContext *C, retval = true; WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, basact->object); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - /* in weightpaint, we use selected bone to select vertexgroup, - * so no switch to new active object */ + /* In weight-paint, we use selected bone to select vertex-group, + * so don't switch to new active object. */ if (oldbasact && (oldbasact->object->mode & OB_MODE_WEIGHT_PAINT)) { - /* prevent activating */ + /* Prevent activating. + * Selection causes this to be considered the 'active' pose in weight-paint mode. + * Eventually this limitation may be removed. + * For now, de-select all other pose objects deforming this mesh. */ + ED_armature_pose_select_in_wpaint_mode(view_layer, basact); + basact = NULL; } } @@ -2353,7 +2400,7 @@ static bool ed_object_select_pick(bContext *C, } else { /* When enabled, this puts other objects out of multi pose-mode. */ - if (is_pose_mode == false) { + if (is_pose_mode == false || (basact->object->mode & OB_MODE_POSE) == 0) { object_deselect_all_except(view_layer, basact); ED_object_base_select(basact, BA_SELECT); } @@ -2507,6 +2554,9 @@ static int view3d_select_exec(bContext *C, wmOperator *op) /* pass */ } } + if (retval) { + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } } else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) { retval = PE_mouse_particles(C, location, extend, deselect, toggle); diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index 51dc14f3dff..0103fd0df53 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -634,14 +634,12 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) TransVertStore tvs = {NULL}; TransVert *tv; float bmat[3][3], vec[3], min[3], max[3], centroid[3]; - int count, a; + int count = 0; - count = 0; INIT_MINMAX(min, max); zero_v3(centroid); if (obedit) { - int global_transverts_tot = 0; ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( @@ -662,13 +660,13 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS | TM_SKIP_HANDLES); } - global_transverts_tot += tvs.transverts_tot; + count += tvs.transverts_tot; if (tvs.transverts_tot != 0) { Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit); copy_m3_m4(bmat, obedit_eval->obmat); tv = tvs.transverts; - for (a = 0; a < tvs.transverts_tot; a++, tv++) { + for (int i = 0; i < tvs.transverts_tot; i++, tv++) { copy_v3_v3(vec, tv->loc); mul_m3_v3(bmat, vec); add_v3_v3(vec, obedit_eval->obmat[3]); @@ -679,14 +677,6 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) ED_transverts_free(&tvs); } MEM_freeN(objects); - - if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEDIAN) { - mul_v3_fl(centroid, 1.0f / (float)global_transverts_tot); - copy_v3_v3(cursor, centroid); - } - else { - mid_v3_v3v3(cursor, min, max); - } } else { Object *obact = CTX_data_active_object(C); @@ -725,18 +715,18 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) } FOREACH_SELECTED_OBJECT_END; } + } - if (count == 0) { - return false; - } + if (count == 0) { + return false; + } - if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEDIAN) { - mul_v3_fl(centroid, 1.0f / (float)count); - copy_v3_v3(cursor, centroid); - } - else { - mid_v3_v3v3(cursor, min, max); - } + if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEDIAN) { + mul_v3_fl(centroid, 1.0f / (float)count); + copy_v3_v3(cursor, centroid); + } + else { + mid_v3_v3v3(cursor, min, max); } return true; } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 5865efa0ffa..c0902cd1cd5 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -30,6 +30,7 @@ #include "BLI_math.h" #include "BLI_rect.h" #include "BLI_utildefines.h" +#include "BLI_linklist.h" #include "BKE_action.h" #include "BKE_camera.h" @@ -38,6 +39,7 @@ #include "BKE_global.h" #include "BKE_layer.h" #include "BKE_main.h" +#include "BKE_modifier.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -962,8 +964,8 @@ static bool drw_select_filter_object_mode_lock(Object *ob, void *user_data) * we want to select pose bones (this doesn't switch modes). */ static bool drw_select_filter_object_mode_lock_for_weight_paint(Object *ob, void *user_data) { - const Object *ob_pose = user_data; - return (DEG_get_original_object(ob) == ob_pose); + LinkNode *ob_pose_list = user_data; + return ob_pose_list && (BLI_linklist_index(ob_pose_list, DEG_get_original_object(ob)) != -1); } /** @@ -1044,10 +1046,22 @@ int view3d_opengl_select(ViewContext *vc, case VIEW3D_SELECT_FILTER_WPAINT_POSE_MODE_LOCK: { Object *obact = vc->obact; BLI_assert(obact && (obact->mode & OB_MODE_WEIGHT_PAINT)); - Object *ob_pose = BKE_object_pose_armature_get(obact); + /* While this uses 'alloca' in a loop (which we typically avoid), + * the number of items is nearly always 1, maybe 2..3 in rare cases. */ + LinkNode *ob_pose_list = NULL; + VirtualModifierData virtualModifierData; + const ModifierData *md = modifiers_getVirtualModifierList(obact, &virtualModifierData); + for (; md; md = md->next) { + if (md->type == eModifierType_Armature) { + ArmatureModifierData *amd = (ArmatureModifierData *)md; + if (amd->object && (amd->object->mode & OB_MODE_POSE)) { + BLI_linklist_prepend_alloca(&ob_pose_list, amd->object); + } + } + } object_filter.fn = drw_select_filter_object_mode_lock_for_weight_paint; - object_filter.user_data = ob_pose; + object_filter.user_data = ob_pose_list; break; } case VIEW3D_SELECT_FILTER_NOP: diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 5b3f7d85b43..a316567fc63 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -617,6 +617,8 @@ static void viewRedrawForce(const bContext *C, TransInfo *t) } else if (t->spacetype == SPACE_SEQ) { WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL); + /* Keyframes on strips has been moved, so make sure related editos are informed. */ + WM_event_add_notifier(C, NC_ANIMATION, NULL); } else if (t->spacetype == SPACE_IMAGE) { if (t->options & CTX_MASK) { @@ -6440,6 +6442,8 @@ static void slide_origdata_create_data(TransDataContainer *tc, layer_index_dst = 0; + /* TODO: We don't need `sod->layer_math_map` when there are no loops linked + * to one of the sliding vertices. */ if (CustomData_has_math(&bm->ldata)) { /* over alloc, only 'math' layers are indexed */ sod->layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__); @@ -6583,7 +6587,7 @@ static void slide_origdata_interp_data_vert(SlideOrigData *sod, } } - if (sod->layer_math_map_num) { + if (sod->layer_math_map_num && sv->cd_loop_groups) { if (do_loop_weight) { for (j = 0; j < sod->layer_math_map_num; j++) { BM_vert_loop_groups_data_layer_merge_weights( @@ -6699,9 +6703,28 @@ static void slide_origdata_free_date(SlideOrigData *sod) /** \name Transform Edge Slide * \{ */ +/** + * Get the first valid EdgeSlideData. + * + * Note we cannot trust TRANS_DATA_CONTAINER_FIRST_OK because of multi-object that + * may leave items with invalid custom data in the transform data container. + */ +static EdgeSlideData *edgeSlideFirstGet(TransInfo *t) +{ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + EdgeSlideData *sld = tc->custom.mode.data; + if (sld == NULL) { + continue; + } + return sld; + } + BLI_assert(!"Should never happen, at least one EdgeSlideData should be valid"); + return NULL; +} + static void calcEdgeSlideCustomPoints(struct TransInfo *t) { - EdgeSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; + EdgeSlideData *sld = edgeSlideFirstGet(t); setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start); @@ -7675,10 +7698,14 @@ void projectEdgeSlideData(TransInfo *t, bool is_final) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { EdgeSlideData *sld = tc->custom.mode.data; - SlideOrigData *sod = &sld->orig_data; + if (sld == NULL) { + continue; + } + + SlideOrigData *sod = &sld->orig_data; if (sod->use_origfaces == false) { - return; + continue; } slide_origdata_interp_data(tc->obedit, @@ -7701,7 +7728,7 @@ void freeEdgeSlideVerts(TransInfo *UNUSED(t), { EdgeSlideData *sld = custom_data->data; - if (!sld) { + if (sld == NULL) { return; } @@ -7843,9 +7870,9 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven static void drawEdgeSlide(TransInfo *t) { - if ((t->mode == TFM_EDGE_SLIDE) && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data) { + if ((t->mode == TFM_EDGE_SLIDE) && edgeSlideFirstGet(t)) { const EdgeSlideParams *slp = t->custom.mode.data; - EdgeSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; + EdgeSlideData *sld = edgeSlideFirstGet(t); const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); /* Even mode */ @@ -7964,7 +7991,7 @@ static void drawEdgeSlide(TransInfo *t) static void doEdgeSlide(TransInfo *t, float perc) { EdgeSlideParams *slp = t->custom.mode.data; - EdgeSlideData *sld_active = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; + EdgeSlideData *sld_active = edgeSlideFirstGet(t); slp->perc = perc; @@ -7975,6 +8002,11 @@ static void doEdgeSlide(TransInfo *t, float perc) const float perc_final = fabsf(perc); FOREACH_TRANS_DATA_CONTAINER (t, tc) { EdgeSlideData *sld = tc->custom.mode.data; + + if (sld == NULL) { + continue; + } + TransDataEdgeSlideVert *sv = sld->sv; for (int i = 0; i < sld->totsv; i++, sv++) { madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final); @@ -7988,6 +8020,11 @@ static void doEdgeSlide(TransInfo *t, float perc) const int side_index = sld_active->curr_side_unclamp; FOREACH_TRANS_DATA_CONTAINER (t, tc) { EdgeSlideData *sld = tc->custom.mode.data; + + if (sld == NULL) { + continue; + } + TransDataEdgeSlideVert *sv = sld->sv; for (int i = 0; i < sld->totsv; i++, sv++) { float dir_flip[3]; @@ -8024,6 +8061,11 @@ static void doEdgeSlide(TransInfo *t, float perc) FOREACH_TRANS_DATA_CONTAINER (t, tc) { EdgeSlideData *sld = tc->custom.mode.data; + + if (sld == NULL) { + continue; + } + TransDataEdgeSlideVert *sv = sld->sv; for (int i = 0; i < sld->totsv; i++, sv++) { if (sv->edge_len > FLT_EPSILON) { diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 06851451461..208242d53b3 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -235,8 +235,7 @@ static void axisProjection(const TransInfo *t, normalize_v3_v3_length(out, axis, -factor); } else { - float v[3], i1[3], i2[3]; - float v2[3], v4[3]; + float v[3]; float norm_center[3]; float plane[3]; @@ -261,14 +260,17 @@ static void axisProjection(const TransInfo *t, } } else { - add_v3_v3v3(v2, t_con_center, axis); - add_v3_v3v3(v4, v, norm); - - isect_line_line_v3(t_con_center, v2, v, v4, i1, i2); - - sub_v3_v3v3(v, i2, v); - - sub_v3_v3v3(out, i1, t_con_center); + /* Use ray-ray intersection instead of line-line because this gave + * precision issues adding small values to large numbers. */ + float mul; + if (isect_ray_ray_v3(v, norm, t_con_center, axis, &mul, NULL)) { + madd_v3_v3v3fl(out, t_con_center, axis, mul); + sub_v3_v3(out, t_con_center); + } + else { + /* In practice this should never fail. */ + BLI_assert(0); + } /* possible some values become nan when * viewpoint and object are both zero */ @@ -863,9 +865,9 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformThemeColor(TH_GRID); - set_inverted_drawing(1); + GPU_logic_op_invert_set(true); imm_drawcircball(t->center_global, t->prop_size, imat, pos); - set_inverted_drawing(0); + GPU_logic_op_invert_set(false); immUnbindProgram(); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 1ed0d5e9221..d13c0f8e8f1 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -1289,7 +1289,6 @@ static void createTransPose(TransInfo *t) bPose *pose = ob->pose; bArmature *arm; - short ik_on = 0; /* check validity of state */ arm = BKE_armature_from_object(tc->poseobj); @@ -1315,8 +1314,7 @@ static void createTransPose(TransInfo *t) /* do we need to add temporal IK chains? */ if ((pose->flag & POSE_AUTO_IK) && t->mode == TFM_TRANSLATION) { - ik_on = pose_grab_with_ik(bmain, ob); - if (ik_on) { + if (pose_grab_with_ik(bmain, ob)) { t->flag |= T_AUTOIK; has_translate_rotate[0] = true; } @@ -1359,7 +1357,6 @@ static void createTransPose(TransInfo *t) Object *ob = tc->poseobj; TransData *td; TransDataExtension *tdx; - short ik_on = 0; int i; PoseInitData_Mirror *pid = tc->custom.type.data; @@ -1407,7 +1404,7 @@ static void createTransPose(TransInfo *t) } /* initialize initial auto=ik chainlen's? */ - if (ik_on) { + if (t->flag & T_AUTOIK) { transform_autoik_update(t, 0); } } @@ -2537,6 +2534,7 @@ void flushTransParticles(TransInfo *t) } PE_update_object(t->depsgraph, scene, OBACT(view_layer), 1); + BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL); DEG_id_tag_update(&ob->id, ID_RECALC_PSYS_REDO); } } @@ -2935,11 +2933,16 @@ static void VertsToTransData(TransInfo *t, } else if (t->mode == TFM_SKIN_RESIZE) { MVertSkin *vs = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MVERT_SKIN); - /* skin node size */ - td->ext = tx; - copy_v3_v3(tx->isize, vs->radius); - tx->size = vs->radius; - td->val = vs->radius; + if (vs) { + /* skin node size */ + td->ext = tx; + copy_v3_v3(tx->isize, vs->radius); + tx->size = vs->radius; + td->val = vs->radius; + } + else { + td->flag |= TD_SKIP; + } } else if (t->mode == TFM_SHRINKFATTEN) { td->ext = tx; @@ -3705,50 +3708,48 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize) for (a = 0, td = tc->data; a < tc->data_len; a++, td++) { minmax_v2v2_v2(min, max, td->loc); } + } - if (resize) { - if (min[0] < 0.0f && t->center_global[0] > 0.0f && - t->center_global[0] < t->aspect[0] * 0.5f) { - vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]); - } - else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0]) { - vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]); - } - else { - clipx = 0; - } + if (resize) { + if (min[0] < 0.0f && t->center_global[0] > 0.0f && t->center_global[0] < t->aspect[0] * 0.5f) { + vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]); + } + else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0]) { + vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]); + } + else { + clipx = 0; + } - if (min[1] < 0.0f && t->center_global[1] > 0.0f && - t->center_global[1] < t->aspect[1] * 0.5f) { - vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]); - } - else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1]) { - vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]); - } - else { - clipy = 0; - } + if (min[1] < 0.0f && t->center_global[1] > 0.0f && t->center_global[1] < t->aspect[1] * 0.5f) { + vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]); + } + else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1]) { + vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]); } else { - if (min[0] < 0.0f) { - vec[0] -= min[0]; - } - else if (max[0] > t->aspect[0]) { - vec[0] -= max[0] - t->aspect[0]; - } - else { - clipx = 0; - } + clipy = 0; + } + } + else { + if (min[0] < 0.0f) { + vec[0] -= min[0]; + } + else if (max[0] > t->aspect[0]) { + vec[0] -= max[0] - t->aspect[0]; + } + else { + clipx = 0; + } - if (min[1] < 0.0f) { - vec[1] -= min[1]; - } - else if (max[1] > t->aspect[1]) { - vec[1] -= max[1] - t->aspect[1]; - } - else { - clipy = 0; - } + if (min[1] < 0.0f) { + vec[1] -= min[1]; + } + else if (max[1] > t->aspect[1]) { + vec[1] -= max[1] - t->aspect[1]; + } + else { + clipy = 0; } } @@ -6438,19 +6439,25 @@ static void trans_object_base_deps_flag_prepare(ViewLayer *view_layer) } } -static void set_trans_object_base_deps_flag_cb(ID *id, void *UNUSED(user_data)) +static void set_trans_object_base_deps_flag_cb(ID *id, + eDepsObjectComponentType component, + void *UNUSED(user_data)) { /* Here we only handle object IDs. */ if (GS(id->name) != ID_OB) { return; } + if (!ELEM(component, DEG_OB_COMP_TRANSFORM, DEG_OB_COMP_GEOMETRY)) { + return; + } id->tag |= LIB_TAG_DOIT; } static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object) { object->id.tag |= LIB_TAG_DOIT; - DEG_foreach_dependent_ID(depsgraph, &object->id, set_trans_object_base_deps_flag_cb, NULL); + DEG_foreach_dependent_ID_component( + depsgraph, &object->id, DEG_OB_COMP_TRANSFORM, set_trans_object_base_deps_flag_cb, NULL); } static void trans_object_base_deps_flag_finish(ViewLayer *view_layer) @@ -7093,6 +7100,10 @@ void special_aftertrans_update(bContext *C, TransInfo *t) FOREACH_TRANS_DATA_CONTAINER (t, tc) { EdgeSlideData *sld = tc->custom.mode.data; + if (sld == NULL) { + continue; + } + /* Free temporary faces to avoid auto-merging and deleting * during cleanup - psy-fi. */ freeEdgeSlideTempFaces(sld); diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index 530abe6faff..a883b5b6ba5 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -1489,7 +1489,12 @@ static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup) ggd->gizmos[MAN_AXIS_ROT_T]->flag |= WM_GIZMO_SELECT_BACKGROUND; /* Prevent axis gizmos overlapping the center point, see: T63744. */ - ggd->gizmos[MAN_AXIS_SCALE_C]->select_bias = ggd->gizmos[MAN_AXIS_TRANS_C]->select_bias = 2.0f; + ggd->gizmos[MAN_AXIS_TRANS_C]->select_bias = 2.0f; + + ggd->gizmos[MAN_AXIS_SCALE_C]->select_bias = -2.0f; + + /* Use 1/6 since this is '0.2' if the main scale is 1.2. */ + RNA_float_set(ggd->gizmos[MAN_AXIS_SCALE_C]->ptr, "arc_inner_factor", 1.0 / 6.0); return ggd; } @@ -1591,6 +1596,9 @@ static void gizmogroup_init_properties_from_twtype(wmGizmoGroup *gzgroup) WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_VALUE, true); WM_gizmo_set_scale(axis, 1.2f); } + else if (axis_idx == MAN_AXIS_SCALE_C) { + WM_gizmo_set_scale(axis, 1.2f); + } else { WM_gizmo_set_scale(axis, 0.2f); } @@ -1868,7 +1876,7 @@ static void WIDGETGROUP_gizmo_invoke_prepare(const bContext *C, GizmoGroup *ggd = gzgroup->customdata; - /* Support gizmo spesific orientation. */ + /* Support gizmo specific orientation. */ if (gz != ggd->gizmos[MAN_AXIS_ROT_T]) { Scene *scene = CTX_data_scene(C); wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index f028f2dc506..c6c2a441d94 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -33,6 +33,7 @@ #include "BKE_global.h" #include "BKE_report.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "BKE_scene.h" #include "RNA_access.h" @@ -754,16 +755,6 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot) P_OPTIONS | P_GPENCIL_EDIT | P_CENTER); } -static bool skin_resize_poll(bContext *C) -{ - struct Object *obedit = CTX_data_edit_object(C); - if (obedit && obedit->type == OB_MESH) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - return (em && CustomData_has_layer(&em->bm->vdata, CD_MVERT_SKIN)); - } - return 0; -} - static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot) { /* identifiers */ @@ -777,7 +768,7 @@ static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot) ot->exec = transform_exec; ot->modal = transform_modal; ot->cancel = transform_cancel; - ot->poll = skin_resize_poll; + ot->poll = ED_operator_editmesh; ot->poll_property = transform_poll_property; RNA_def_float_vector( diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 58a50da9846..d45a0588003 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -566,13 +566,8 @@ static void initSnappingMode(TransInfo *t) /* Edit mode */ if (t->tsnap.applySnap != NULL && // A snapping function actually exist ((obedit_type != -1) && - ELEM(obedit_type, - OB_MESH, - OB_ARMATURE, - OB_CURVE, - OB_LATTICE, - OB_MBALL))) // Temporary limited to edit mode meshes, armature, curves, metaballs - { + /* Temporary limited to edit mode meshes, armature, curves, metaballs. */ + ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL))) { /* Exclude editmesh if using proportional edit */ if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) { t->tsnap.modeSelect = SNAP_NOT_ACTIVE; diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 03c43c8d16d..6f06f8639bd 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -2820,16 +2820,16 @@ static short transform_snap_context_project_view3d_mixed_impl( return 0; } -bool ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, - const unsigned short snap_to, - const struct SnapObjectParams *params, - const float mval[2], - float *dist_px, - float r_loc[3], - float r_no[3], - int *r_index, - Object **r_ob, - float r_obmat[4][4]) +short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, + const unsigned short snap_to, + const struct SnapObjectParams *params, + const float mval[2], + float *dist_px, + float r_loc[3], + float r_no[3], + int *r_index, + Object **r_ob, + float r_obmat[4][4]) { return transform_snap_context_project_view3d_mixed_impl( sctx, snap_to, params, mval, dist_px, r_loc, r_no, r_index, r_ob, r_obmat) != 0; @@ -2856,7 +2856,7 @@ bool ED_transform_snap_object_project_view3d(SnapObjectContext *sctx, float r_no[3]) { return ED_transform_snap_object_project_view3d_ex( - sctx, snap_to, params, mval, dist_px, r_loc, r_no, NULL, NULL, NULL); + sctx, snap_to, params, mval, dist_px, r_loc, r_no, NULL, NULL, NULL) != 0; } /** diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c index 6d5f486ebe9..183e140169d 100644 --- a/source/blender/editors/undo/ed_undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -99,6 +99,10 @@ void ED_undo_push(bContext *C, const char *str) BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, 0, memory_limit); } + if (CLOG_CHECK(&LOG, 1)) { + BKE_undosys_print(wm->undo_stack); + } + WM_file_tag_modified(); } @@ -236,6 +240,10 @@ static int ed_undo_step_impl( Main *bmain = CTX_data_main(C); WM_toolsystem_refresh_screen_all(bmain); + if (CLOG_CHECK(&LOG, 1)) { + BKE_undosys_print(wm->undo_stack); + } + return OPERATOR_FINISHED; } @@ -322,6 +330,39 @@ bool ED_undo_is_memfile_compatible(const bContext *C) } /** + * When a property of ID changes, return false. + * + * This is to avoid changes to a property making undo pushes + * which are ignored by the undo-system. + * For example, changing a brush property isn't stored by sculpt-mode undo steps. + * This workaround is needed until the limitation is removed, see: T61948. + */ +bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, ID *id) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + if (view_layer != NULL) { + Object *obact = OBACT(view_layer); + if (obact != NULL) { + if (obact->mode & OB_MODE_ALL_PAINT) { + /* Don't store property changes when painting + * (only do undo pushes on brush strokes which each paint operator handles on it's own). */ + CLOG_INFO(&LOG, 1, "skipping undo for paint-mode"); + return false; + } + else if (obact->mode & OB_MODE_EDIT) { + if ((id == NULL) || (obact->data == NULL) || + (GS(id->name) != GS(((ID *)obact->data)->name))) { + /* No undo push on id type mismatch in edit-mode. */ + CLOG_INFO(&LOG, 1, "skipping undo for edit-mode"); + return false; + } + } + } + } + return true; +} + +/** * Ideally we wont access the stack directly, * this is needed for modes which handle undo themselves (bypassing #ED_undo_push). * diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c index 0f495d64b29..f3e2ee92558 100644 --- a/source/blender/editors/undo/memfile_undo.c +++ b/source/blender/editors/undo/memfile_undo.c @@ -83,10 +83,8 @@ static bool memfile_undosys_step_encode(struct bContext *UNUSED(C), return true; } -static void memfile_undosys_step_decode(struct bContext *C, - struct Main *bmain, - UndoStep *us_p, - int UNUSED(dir)) +static void memfile_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final)) { ED_editors_exit(bmain, false); diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 1ee8ff6966c..c1b6a7b42b2 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -326,15 +326,15 @@ void unpack_menu(bContext *C, BLI_split_file_part(abs_name, fi, sizeof(fi)); BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi); if (!STREQ(abs_name, local_name)) { - switch (checkPackedFile(BKE_main_blendfile_path(bmain), local_name, pf)) { - case PF_NOFILE: + switch (BKE_packedfile_compare_to_file(BKE_main_blendfile_path(bmain), local_name, pf)) { + case PF_CMP_NOFILE: BLI_snprintf(line, sizeof(line), TIP_("Create %s"), local_name); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL); RNA_string_set(&props_ptr, "id", id_name); break; - case PF_EQUAL: + case PF_CMP_EQUAL: BLI_snprintf(line, sizeof(line), TIP_("Use %s (identical)"), local_name); // uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_LOCAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); @@ -342,7 +342,7 @@ void unpack_menu(bContext *C, RNA_string_set(&props_ptr, "id", id_name); break; - case PF_DIFFERS: + case PF_CMP_DIFFERS: BLI_snprintf(line, sizeof(line), TIP_("Use %s (differs)"), local_name); // uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_LOCAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); @@ -359,22 +359,22 @@ void unpack_menu(bContext *C, } } - switch (checkPackedFile(BKE_main_blendfile_path(bmain), abs_name, pf)) { - case PF_NOFILE: + switch (BKE_packedfile_compare_to_file(BKE_main_blendfile_path(bmain), abs_name, pf)) { + case PF_CMP_NOFILE: BLI_snprintf(line, sizeof(line), TIP_("Create %s"), abs_name); // uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL); RNA_string_set(&props_ptr, "id", id_name); break; - case PF_EQUAL: + case PF_CMP_EQUAL: BLI_snprintf(line, sizeof(line), TIP_("Use %s (identical)"), abs_name); // uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_ORIGINAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL); RNA_string_set(&props_ptr, "id", id_name); break; - case PF_DIFFERS: + case PF_CMP_DIFFERS: BLI_snprintf(line, sizeof(line), TIP_("Use %s (differs)"), abs_name); // uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_ORIGINAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); diff --git a/source/blender/editors/util/select_buffer_utils.c b/source/blender/editors/util/select_buffer_utils.c index 130f6819e34..79f0f48830e 100644 --- a/source/blender/editors/util/select_buffer_utils.c +++ b/source/blender/editors/util/select_buffer_utils.c @@ -44,7 +44,7 @@ /** \name Select Bitmap from ID's * * Given a buffer of select ID's, fill in a booleans (true/false) per index. - * #BLI_bitmap is used for memory effeciency. + * #BLI_bitmap is used for memory efficiency. * * \{ */ @@ -215,7 +215,7 @@ uint ED_select_buffer_sample_point(const int center[2]) /** * Find the selection id closest to \a center. - * \param dist[in,out]: Use to initalize the distance, + * \param dist[in,out]: Use to initialize the distance, * when found, this value is set to the distance of the selection thats returned. */ uint ED_select_buffer_find_nearest_to_point(const int center[2], @@ -223,7 +223,7 @@ uint ED_select_buffer_find_nearest_to_point(const int center[2], const uint id_max, uint *dist) { - /* Smart function to sample a rect spiralling outside, nice for selection ID. */ + /* Smart function to sample a rect spiraling outside, nice for selection ID. */ /* Create region around center (typically the mouse cursor). * This must be square and have an odd width, diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index b1d22e12b10..ed8178d1908 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -412,10 +412,10 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph * } } if (verts || facedots) { - float pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE); UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2); if (verts) { - float pinned_col[4] = {1.0f, 0.0f, 0.0f, 1.0f}; /* TODO Theme? */ + const float point_size = UI_GetThemeValuef(TH_VERTEX_SIZE); + const float pinned_col[4] = {1.0f, 0.0f, 0.0f, 1.0f}; /* TODO Theme? */ UI_GetThemeColor4fv(TH_VERTEX, col1); GPU_blend(true); GPU_program_point_size(true); @@ -424,7 +424,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph * GPU_batch_uniform_4f(verts, "vertColor", col1[0], col1[1], col1[2], 1.0f); GPU_batch_uniform_4fv(verts, "selectColor", transparent); GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col); - GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2); + GPU_batch_uniform_1f(verts, "pointSize", (point_size + 1.5f) * M_SQRT2); GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f); GPU_batch_draw(verts); @@ -441,7 +441,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph * GPU_program_point_size(false); } if (facedots) { - GPU_point_size(pointsize); + const float point_size = UI_GetThemeValuef(TH_FACEDOT_SIZE); + GPU_point_size(point_size); UI_GetThemeColor4fv(TH_WIRE, col1); GPU_batch_program_set_builtin(facedots, GPU_SHADER_2D_UV_FACEDOTS); diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 14cdb674698..a42a6eba3ff 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -2282,7 +2282,6 @@ static void uvedit_unwrap_cube_project(BMesh *bm, * component, but clusters all together around the center of map. */ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */ if (use_select && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { continue; } diff --git a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp index b1d44a55fd5..7a5469cd414 100644 --- a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp +++ b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp @@ -428,8 +428,8 @@ static PyObject *FrsMaterial_shininess_get(BPy_FrsMaterial *self, void *UNUSED(c static int FrsMaterial_shininess_set(BPy_FrsMaterial *self, PyObject *value, void *UNUSED(closure)) { float scalar; - if ((scalar = PyFloat_AsDouble(value)) == -1.0f && - PyErr_Occurred()) { /* parsed item not a number */ + if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) { + /* parsed item not a number */ PyErr_SetString(PyExc_TypeError, "value must be a number"); return -1; } diff --git a/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp b/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp index 7d2716a3e71..505566d3515 100644 --- a/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp +++ b/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp @@ -577,8 +577,8 @@ static int StrokeAttribute_alpha_set(BPy_StrokeAttribute *self, void *UNUSED(closure)) { float scalar; - if ((scalar = PyFloat_AsDouble(value)) == -1.0f && - PyErr_Occurred()) { /* parsed item not a number */ + if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) { + /* parsed item not a number */ PyErr_SetString(PyExc_TypeError, "value must be a number"); return -1; } diff --git a/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp index 503dd3bf044..74d8fe4ce60 100644 --- a/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp +++ b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp @@ -282,8 +282,8 @@ static int StrokeVertex_curvilinear_abscissa_set(BPy_StrokeVertex *self, void *UNUSED(closure)) { float scalar; - if ((scalar = PyFloat_AsDouble(value)) == -1.0f && - PyErr_Occurred()) { /* parsed item not a number */ + if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) { + /* parsed item not a number */ PyErr_SetString(PyExc_TypeError, "value must be a number"); return -1; } @@ -328,8 +328,8 @@ static int StrokeVertex_stroke_length_set(BPy_StrokeVertex *self, void *UNUSED(closure)) { float scalar; - if ((scalar = PyFloat_AsDouble(value)) == -1.0f && - PyErr_Occurred()) { /* parsed item not a number */ + if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) { + /* parsed item not a number */ PyErr_SetString(PyExc_TypeError, "value must be a number"); return -1; } diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp index 8ba22b0617a..df80f61a7a6 100644 --- a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp +++ b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp @@ -198,8 +198,10 @@ static PyObject *Stroke_insert_vertex(BPy_Stroke *self, PyObject *args, PyObject &py_sv_it)) { return NULL; } - ((BPy_StrokeVertex *)py_sv)->py_cp.py_if0D.borrowed = - true; /* make the wrapped StrokeVertex internal */ + + /* Make the wrapped StrokeVertex internal. */ + ((BPy_StrokeVertex *)py_sv)->py_cp.py_if0D.borrowed = true; + StrokeVertex *sv = ((BPy_StrokeVertex *)py_sv)->sv; StrokeInternal::StrokeVertexIterator sv_it(*(((BPy_StrokeVertexIterator *)py_sv_it)->sv_it)); self->s->InsertVertex(sv, sv_it); @@ -433,8 +435,8 @@ static PyObject *Stroke_length_2d_get(BPy_Stroke *self, void *UNUSED(closure)) static int Stroke_length_2d_set(BPy_Stroke *self, PyObject *value, void *UNUSED(closure)) { float scalar; - if ((scalar = PyFloat_AsDouble(value)) == -1.0f && - PyErr_Occurred()) { /* parsed item not a number */ + if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) { + /* parsed item not a number */ PyErr_SetString(PyExc_TypeError, "value must be a number"); return -1; } diff --git a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp index 42e96df39ef..fe0fc715e34 100644 --- a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp +++ b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp @@ -16,7 +16,7 @@ /** \file * \ingroup freestyle - * \brief A Set of indexed faces to represent a surfacic object + * \brief A Set of indexed faces to represent a surface object */ #include "IndexedFaceSet.h" diff --git a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h index 2a38e6ffcc6..5163a0af07e 100644 --- a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h +++ b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h @@ -168,7 +168,7 @@ class IndexedFaceSet : public Rep { } /*! Desctructor - * desallocates all the ressources + * desallocates all the resources */ virtual ~IndexedFaceSet(); diff --git a/source/blender/freestyle/intern/winged_edge/WXEdge.h b/source/blender/freestyle/intern/winged_edge/WXEdge.h index e7d5f4ac8f8..20c0bd172ad 100644 --- a/source/blender/freestyle/intern/winged_edge/WXEdge.h +++ b/source/blender/freestyle/intern/winged_edge/WXEdge.h @@ -449,7 +449,7 @@ class WXFaceLayer { unsigned int GetSmoothEdgeIndex() const; /*! retrieves the edges of the triangle for which the signs are different (a null value is not - * considered) for the dotp values at each edge extrimity + * considered) for the dotp values at each edge extremity */ void RetrieveCuspEdgesIndices(vector<int> &oCuspEdges); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c index bdab4c083e9..5b5290dc0ff 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c @@ -192,9 +192,8 @@ void gpencil_apply_modifier_material( BLI_ghash_insert(gh_color, mat->id.name, newmat); DEG_id_tag_update(&newmat->id, ID_RECALC_COPY_ON_WRITE); } - /* Reaasign color index. */ - int idx = BKE_gpencil_object_material_get_index(ob, newmat); - gps->mat_nr = idx - 1; + /* Reassign color index. */ + gps->mat_nr = BKE_gpencil_object_material_get_index(ob, newmat); } else { /* reuse existing color (but update only first time) */ diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h index 7b970786e5e..efea02eb5a4 100644 --- a/source/blender/gpu/GPU_state.h +++ b/source/blender/gpu/GPU_state.h @@ -59,4 +59,6 @@ void GPU_viewport_size_get_i(int coords[4]); void GPU_flush(void); void GPU_finish(void); +void GPU_logic_op_invert_set(bool enable); + #endif /* __GPU_STATE_H__ */ diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h index 43eec55bca2..68608a98a79 100644 --- a/source/blender/gpu/GPU_vertex_format.h +++ b/source/blender/gpu/GPU_vertex_format.h @@ -31,7 +31,7 @@ #include "BLI_assert.h" #define GPU_VERT_ATTR_MAX_LEN 16 -#define GPU_VERT_ATTR_MAX_NAMES 4 +#define GPU_VERT_ATTR_MAX_NAMES 5 #define GPU_VERT_ATTR_NAME_AVERAGE_LEN 11 #define GPU_VERT_ATTR_NAMES_BUF_LEN ((GPU_VERT_ATTR_NAME_AVERAGE_LEN + 1) * GPU_VERT_ATTR_MAX_LEN) diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 241b3bd553f..59b0857c177 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -374,6 +374,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], /* Fill the only the line buffer. */ GPUIndexBufBuilder elb_lines; GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, INT_MAX); + int vert_idx = 0; for (i = 0; i < face_indices_len; ++i) { const MLoopTri *lt = &looptri[face_indices[i]]; @@ -384,9 +385,10 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], } /* TODO skip "non-real" edges. */ - GPU_indexbuf_add_line_verts(&elb_lines, i * 3 + 0, i * 3 + 1); - GPU_indexbuf_add_line_verts(&elb_lines, i * 3 + 1, i * 3 + 2); - GPU_indexbuf_add_line_verts(&elb_lines, i * 3 + 2, i * 3 + 0); + GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 0, vert_idx * 3 + 1); + GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 1, vert_idx * 3 + 2); + GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 2, vert_idx * 3 + 0); + vert_idx++; } buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); } diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index d1d5e1d89a2..be3655648f5 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -475,6 +475,9 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget ima->gpuflag &= ~IMA_GPU_REFRESH; } + /* Tag as in active use for garbage collector. */ + BKE_image_tag_time(ima); + /* Test if we already have a texture. */ GPUTexture **tex = gpu_get_image_gputexture(ima, textarget); if (*tex) { diff --git a/source/blender/gpu/intern/gpu_element.c b/source/blender/gpu/intern/gpu_element.c index 380de4c4e65..50e7df96503 100644 --- a/source/blender/gpu/intern/gpu_element.c +++ b/source/blender/gpu/intern/gpu_element.c @@ -204,7 +204,7 @@ static void squeeze_indices_short(GPUIndexBufBuilder *builder, * converting in place to avoid extra allocation */ GLushort *data = (GLushort *)builder->data; - if (max_index > 0xFFFF) { + if (max_index >= 0xFFFF) { elem->base_index = min_index; for (uint i = 0; i < index_len; ++i) { data[i] = (values[i] == RESTART_INDEX) ? 0xFFFF : (GLushort)(values[i] - min_index); diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 58efe3dc5c4..ba5cf214a42 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -378,7 +378,11 @@ void gpu_extensions_init(void) GG.dfdyfactors[1] = 1.0; } - if (strstr(renderer, "HD Graphics 4000")) { + if (strstr(version, "Build 10.18.10.3379") || strstr(version, "Build 10.18.10.3574") || + strstr(version, "Build 10.18.10.4252") || strstr(version, "Build 10.18.10.4358") || + strstr(version, "Build 10.18.10.4653") || strstr(version, "Build 10.18.10.5069") || + strstr(version, "Build 10.18.14.4264") || strstr(version, "Build 10.18.14.4432") || + strstr(version, "Build 10.18.14.5067")) { GG.context_local_shaders_workaround = true; } } diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index cd63355ff51..7d096058e4c 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -837,7 +837,7 @@ static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs) /* List is full, this should never happen or * it might just slow things down if it happens - * regulary. In this case we just empty the list + * regularly. In this case we just empty the list * and start over. This is most likely never going * to happen under normal usage. */ BLI_assert(0); diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c index 858afdc534e..58ca800a92c 100644 --- a/source/blender/gpu/intern/gpu_matrix.c +++ b/source/blender/gpu/intern/gpu_matrix.c @@ -5,7 +5,7 @@ * 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 ipmlied warranty of + * 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. * diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c index 56f9ef69221..beea25b4171 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.c +++ b/source/blender/gpu/intern/gpu_select_sample_query.c @@ -40,6 +40,8 @@ #include "PIL_time.h" +#include "BKE_global.h" + #include "gpu_select_private.h" /* Ad hoc number of queries to allocate to skip doing many glGenQueries */ @@ -173,15 +175,8 @@ uint gpu_select_query_end(void) for (i = 0; i < g_query_state.active_query; i++) { uint result = 0; - /* Wait until the result is available. */ - while (result == 0) { - glGetQueryObjectuiv(g_query_state.queries[i], GL_QUERY_RESULT_AVAILABLE, &result); - if (result == 0) { - /* (fclem) Not sure if this is better than calling - * glGetQueryObjectuiv() indefinitely. */ - PIL_sleep_ms(1); - } - } + /* We are not using GL_QUERY_RESULT_AVAILABLE and sleep to wait for results, + * because it causes lagging on Windows/NVIDIA, see T61474. */ glGetQueryObjectuiv(g_query_state.queries[i], GL_QUERY_RESULT, &result); if (result > 0) { if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) { diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c index e7483e45312..e34c6e23024 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.c +++ b/source/blender/gpu/intern/gpu_shader_interface.c @@ -180,10 +180,10 @@ static const GPUShaderInput *add_uniform(GPUShaderInterface *shaderface, const c input->location = glGetUniformLocation(shaderface->program, name); - uint name_len = strlen(name); + const uint name_len = strlen(name); + /* Include NULL terminator. */ shaderface->name_buffer = MEM_reallocN(shaderface->name_buffer, - shaderface->name_buffer_offset + name_len + - 1); /* include NULL terminator */ + shaderface->name_buffer_offset + name_len + 1); char *name_buffer = shaderface->name_buffer + shaderface->name_buffer_offset; strcpy(name_buffer, name); diff --git a/source/blender/gpu/intern/gpu_state.c b/source/blender/gpu/intern/gpu_state.c index 7a27fea2f0d..caf97a620ab 100644 --- a/source/blender/gpu/intern/gpu_state.c +++ b/source/blender/gpu/intern/gpu_state.c @@ -175,3 +175,17 @@ void GPU_finish(void) { glFinish(); } + +void GPU_logic_op_invert_set(bool enable) +{ + if (enable) { + glLogicOp(GL_INVERT); + glEnable(GL_COLOR_LOGIC_OP); + glDisable(GL_DITHER); + } + else { + glLogicOp(GL_COPY); + glDisable(GL_COLOR_LOGIC_OP); + glEnable(GL_DITHER); + } +} diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 6a92832d1e5..dab17fcd72a 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -505,7 +505,8 @@ static float *GPU_texture_rescale_3d( static bool gpu_texture_check_capacity( GPUTexture *tex, GLenum proxy, GLenum internalformat, GLenum data_format, GLenum data_type) { - if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_ANY)) { + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_ANY) || + GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OFFICIAL)) { /* Some AMD drivers have a faulty `GL_PROXY_TEXTURE_..` check. * (see T55888, T56185, T59351). * Checking with `GL_PROXY_TEXTURE_..` doesn't prevent `Out Of Memory` issue, @@ -1459,7 +1460,9 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl break; } - void *buf = MEM_mallocN(buf_size, "GPU_texture_read"); + /* AMD Pro driver have a bug that write 8 bytes past buffer size + * if the texture is big. (see T66573) */ + void *buf = MEM_mallocN(buf_size + 8, "GPU_texture_read"); GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag); GLenum data_type = gpu_get_gl_datatype(gpu_data_format); diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.c index 37e1f9cf9da..e745c525df6 100644 --- a/source/blender/gpu/intern/gpu_vertex_format.c +++ b/source/blender/gpu/intern/gpu_vertex_format.c @@ -365,6 +365,11 @@ void GPU_vertformat_from_interface(GPUVertFormat *format, const GPUShaderInterfa input = next; next = input->next; + /* OpenGL attributes such as `gl_VertexID` have a location of -1. */ + if (input->location < 0) { + continue; + } + format->name_len++; /* multiname support */ format->attr_len++; diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl index 946fc752e17..56c9a2bd339 100644 --- a/source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl @@ -22,7 +22,7 @@ uniform sampler2D myTexture; #define SOLID 0 #define GRADIENT 1 #define RADIAL 2 -#define CHESS 3 +#define CHECKER 3 #define TEXTURE 4 in vec2 texCoord_interp; @@ -104,7 +104,7 @@ void main() vec2 rot_tex = (matrot_tex * (texCoord_interp - t_center)) + t_center + t_offset; vec4 tmp_color = texture2D(myTexture, rot_tex * t_scale); vec4 text_color = vec4(tmp_color[0], tmp_color[1], tmp_color[2], tmp_color[3] * t_opacity); - vec4 chesscolor; + vec4 checker_color; /* solid fill */ if (fill_type == SOLID) { @@ -144,32 +144,32 @@ void main() } set_color(color, color2, text_color, mix_factor, intensity, t_mix, t_flip, fragColor); } - /* chessboard */ - if (fill_type == CHESS) { + /* Checkerboard */ + if (fill_type == CHECKER) { vec2 pos = rot / g_boxsize; if ((fract(pos.x) < 0.5 && fract(pos.y) < 0.5) || (fract(pos.x) > 0.5 && fract(pos.y) > 0.5)) { if (t_flip == 0) { - chesscolor = color; + checker_color = color; } else { - chesscolor = color2; + checker_color = color2; } } else { if (t_flip == 0) { - chesscolor = color2; + checker_color = color2; } else { - chesscolor = color; + checker_color = color; } } /* mix with texture */ if (t_mix == 1) { - fragColor = mix(chesscolor, text_color, mix_factor); + fragColor = mix(checker_color, text_color, mix_factor); } else { - fragColor = chesscolor; + fragColor = checker_color; } } /* texture */ diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 1750e124c29..6149409774a 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -2224,7 +2224,7 @@ void node_tex_coord_background(vec3 I, generated = coords; normal = -coords; uv = vec3(attr_uv.xy, 0.0); - object = coords; + object = (obmatinv * vec4(coords, 1.0)).xyz; camera = vec3(co.xy, -co.z); window = vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0); diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 8574f33bce6..fbaa9b06d3b 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -67,6 +67,7 @@ * \attention defined in ??? */ struct ImBuf; +struct rcti; /** * @@ -222,6 +223,8 @@ void IMB_blend_color_byte(unsigned char dst[4], IMB_BlendMode mode); void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_BlendMode mode); +void IMB_rect_crop(struct ImBuf *ibuf, const struct rcti *crop); + void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx, diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index d518406124f..7d2f51af65e 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -493,11 +493,12 @@ bool IMB_initImBuf( ibuf->y = y; ibuf->planes = planes; ibuf->ftype = IMB_FTYPE_PNG; - ibuf->foptions.quality = - 15; /* the 15 means, set compression to low ratio but not time consuming */ - ibuf->channels = 4; /* float option, is set to other values when buffers get assigned */ - ibuf->ppm[0] = ibuf->ppm[1] = IMB_DPI_DEFAULT / - 0.0254f; /* IMB_DPI_DEFAULT -> pixels-per-meter */ + /* The '15' means, set compression to low ratio but not time consuming. */ + ibuf->foptions.quality = 15; + /* float option, is set to other values when buffers get assigned. */ + ibuf->channels = 4; + /* IMB_DPI_DEFAULT -> pixels-per-meter. */ + ibuf->ppm[0] = ibuf->ppm[1] = IMB_DPI_DEFAULT / 0.0254f; if (flags & IB_rect) { if (imb_addrectImBuf(ibuf) == false) { diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp index 7a47d0f7787..d2147f833c3 100644 --- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp +++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp @@ -197,6 +197,7 @@ struct ImBuf *imb_load_photoshop(const char *filename, int flags, char colorspac bool is_float, is_alpha; int basesize; char file_colorspace[IM_MAX_SPACE]; + const bool is_colorspace_manually_set = (colorspace[0] != '\0'); /* load image from file through OIIO */ if (imb_is_a_photoshop(filename) == 0) { @@ -221,17 +222,19 @@ struct ImBuf *imb_load_photoshop(const char *filename, int flags, char colorspac return NULL; } - string ics = spec.get_string_attribute("oiio:ColorSpace"); - BLI_strncpy(file_colorspace, ics.c_str(), IM_MAX_SPACE); + if (!is_colorspace_manually_set) { + string ics = spec.get_string_attribute("oiio:ColorSpace"); + BLI_strncpy(file_colorspace, ics.c_str(), IM_MAX_SPACE); - /* only use colorspaces exis */ - if (colormanage_colorspace_get_named(file_colorspace)) { - strcpy(colorspace, file_colorspace); - } - else { - std::cerr << __func__ << ": The embed colorspace (\"" << file_colorspace - << "\") not supported in existent OCIO configuration file. Fallback " - << "to system default colorspace (\"" << colorspace << "\")." << std::endl; + /* only use colorspaces exis */ + if (colormanage_colorspace_get_named(file_colorspace)) { + strcpy(colorspace, file_colorspace); + } + else { + std::cerr << __func__ << ": The embed colorspace (\"" << file_colorspace + << "\") not supported in existent OCIO configuration file. Fallback " + << "to system default colorspace (\"" << colorspace << "\")." << std::endl; + } } width = spec.width; diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 7b3de4167a2..c9883d5df86 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -969,8 +969,8 @@ int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *heig ExrHandle *data = (ExrHandle *)handle; ExrChannel *echan; - if (BLI_exists(filename) && - BLI_file_size(filename) > 32) { /* 32 is arbitrary, but zero length files crashes exr */ + /* 32 is arbitrary, but zero length files crashes exr. */ + if (BLI_exists(filename) && BLI_file_size(filename) > 32) { /* avoid crash/abort when we don't have permission to write here */ try { data->ifile_stream = new IFileStream(filename); @@ -1762,32 +1762,11 @@ static bool imb_exr_is_multilayer_file(MultiPartInputFile &file) const ChannelList &channels = file.header(0).channels(); std::set<std::string> layerNames; - /* will not include empty layer names */ + /* This will not include empty layer names, so files with just R/G/B/A + * channels without a layer name will be single layer. */ channels.layers(layerNames); - if (layerNames.size() > 1) { - return true; - } - - if (layerNames.size()) { - /* if layerNames is not empty, it means at least one layer is non-empty, - * but it also could be layers without names in the file and such case - * shall be considered a multilayer exr - * - * that's what we do here: test whether they're empty layer names together - * with non-empty ones in the file - */ - for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++) { - std::string layerName = i.name(); - size_t pos = layerName.rfind('.'); - - if (pos == std::string::npos) { - return true; - } - } - } - - return false; + return (layerNames.size() > 0); } static void imb_exr_type_by_channels(ChannelList &channels, @@ -1957,8 +1936,8 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem, } } - if (is_multi && - ((flags & IB_thumbnail) == 0)) { /* only enters with IB_multilayer flag set */ + /* Only enters with IB_multilayer flag set. */ + if (is_multi && ((flags & IB_thumbnail) == 0)) { /* constructs channels for reading, allocates memory in channels */ ExrHandle *handle = imb_exr_begin_read_mem(*membuf, *file, width, height); if (handle) { diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c index 25390b73737..76918c216f7 100644 --- a/source/blender/imbuf/intern/rectop.c +++ b/source/blender/imbuf/intern/rectop.c @@ -25,6 +25,7 @@ #include <stdlib.h> #include "BLI_utildefines.h" +#include "BLI_rect.h" #include "BLI_math_base.h" #include "BLI_math_color.h" #include "BLI_math_color_blend.h" @@ -35,6 +36,8 @@ #include "IMB_colormanagement.h" +#include "MEM_guardedalloc.h" + void IMB_blend_color_byte(unsigned char dst[4], unsigned char src1[4], unsigned char src2[4], @@ -207,6 +210,72 @@ void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_Blend } } +/** Crop */ + +static void rect_crop_4bytes(void **buf_p, const int size_src[2], const rcti *crop) +{ + if (*buf_p == NULL) { + return; + } + const int size_dst[2] = { + BLI_rcti_size_x(crop) + 1, + BLI_rcti_size_y(crop) + 1, + }; + uint *src = *buf_p; + uint *dst = src + crop->ymin * size_src[0] + crop->xmin; + for (int y = 0; y < size_dst[1]; y++, src += size_dst[0], dst += size_src[0]) { + memmove(src, dst, sizeof(uint) * size_dst[0]); + } + *buf_p = MEM_reallocN(*buf_p, sizeof(uint) * size_dst[0] * size_dst[1]); +} + +static void rect_crop_16bytes(void **buf_p, const int size_src[2], const rcti *crop) +{ + if (*buf_p == NULL) { + return; + } + const int size_dst[2] = { + BLI_rcti_size_x(crop) + 1, + BLI_rcti_size_y(crop) + 1, + }; + uint(*src)[4] = *buf_p; + uint(*dst)[4] = src + crop->ymin * size_src[0] + crop->xmin; + for (int y = 0; y < size_dst[1]; y++, src += size_dst[0], dst += size_src[0]) { + memmove(src, dst, sizeof(uint[4]) * size_dst[0]); + } + *buf_p = (void *)MEM_reallocN(*buf_p, sizeof(uint[4]) * size_dst[0] * size_dst[1]); +} + +/** + * In-place image crop. + */ +void IMB_rect_crop(ImBuf *ibuf, const rcti *crop) +{ + const int size_src[2] = { + ibuf->x, + ibuf->y, + }; + const int size_dst[2] = { + BLI_rcti_size_x(crop) + 1, + BLI_rcti_size_y(crop) + 1, + }; + BLI_assert(size_dst[0] > 0 && size_dst[0] > 0); + BLI_assert(crop->xmin >= 0 && crop->ymin >= 0); + BLI_assert(crop->xmax < ibuf->x && crop->ymax < ibuf->y); + + if ((size_dst[0] == ibuf->x) && (size_dst[1] == ibuf->y)) { + return; + } + + rect_crop_4bytes((void **)&ibuf->rect, size_src, crop); + rect_crop_4bytes((void **)&ibuf->zbuf, size_src, crop); + rect_crop_4bytes((void **)&ibuf->zbuf_float, size_src, crop); + rect_crop_16bytes((void **)&ibuf->rect_float, size_src, crop); + + ibuf->x = size_dst[0]; + ibuf->y = size_dst[1]; +} + /* clipping */ void IMB_rectclip(ImBuf *dbuf, diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index c8a76791cef..a4cd31a1357 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -772,6 +772,7 @@ typedef enum eDopeSheet_FilterFlag { /* DopeSheet filter-flags - Overflow (filterflag2) */ typedef enum eDopeSheet_FilterFlag2 { ADS_FILTER_NOCACHEFILES = (1 << 1), + ADS_FILTER_NOMOVIECLIPS = (1 << 2), } eDopeSheet_FilterFlag2; /* DopeSheet general flags */ diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index c38222a3eb3..75a417150c8 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -30,6 +30,8 @@ extern "C" { #endif +#include "DNA_defs.h" + /** descriptor and storage for a custom data layer */ typedef struct CustomDataLayer { /** Type of data in layer. */ @@ -107,9 +109,11 @@ typedef enum CustomDataType { CD_PROP_FLT = 10, CD_PROP_INT = 11, CD_PROP_STR = 12, - CD_ORIGSPACE = 13, /* for modifier stack face location mapping */ - CD_ORCO = 14, /* undeformed vertex coordinates, normalized to 0..1 range */ - /* CD_MTEXPOLY = 15, */ /* deprecated */ + CD_ORIGSPACE = 13, /* for modifier stack face location mapping */ + CD_ORCO = 14, /* undeformed vertex coordinates, normalized to 0..1 range */ +#ifdef DNA_DEPRECATED + CD_MTEXPOLY = 15, /* deprecated */ +#endif CD_MLOOPUV = 16, CD_MLOOPCOL = 17, CD_TANGENT = 18, diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index d65a4896758..42308f54d7a 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -338,7 +338,7 @@ enum { enum { GP_STYLE_FILL_STYLE_SOLID = 0, GP_STYLE_FILL_STYLE_GRADIENT, - GP_STYLE_FILL_STYLE_CHESSBOARD, + GP_STYLE_FILL_STYLE_CHECKER, GP_STYLE_FILL_STYLE_TEXTURE, }; diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 04d060b065d..88eef05f8be 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -394,6 +394,7 @@ enum { /* SELECT = (1 << 0), */ ME_VERT_TMP_TAG = (1 << 2), ME_HIDE = (1 << 4), + ME_VERT_FACEDOT = (1 << 5), /* ME_VERT_MERGED = (1 << 6), */ ME_VERT_PBVH_UPDATE = (1 << 7), }; diff --git a/source/blender/makesdna/DNA_packedFile_types.h b/source/blender/makesdna/DNA_packedFile_types.h index a8afa667158..8196e3098eb 100644 --- a/source/blender/makesdna/DNA_packedFile_types.h +++ b/source/blender/makesdna/DNA_packedFile_types.h @@ -30,20 +30,4 @@ typedef struct PackedFile { void *data; } PackedFile; -enum ePF_FileStatus { - PF_EQUAL = 0, - PF_DIFFERS = 1, - PF_NOFILE = 2, - - PF_WRITE_ORIGINAL = 3, - PF_WRITE_LOCAL = 4, - PF_USE_LOCAL = 5, - PF_USE_ORIGINAL = 6, - PF_KEEP = 7, - PF_REMOVE = 8, - PF_NOOP = 9, - - PF_ASK = 10, -}; - #endif /* PACKEDFILE_TYPES_H */ diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h index 8dfaf95a10a..4eec2c1fde8 100644 --- a/source/blender/makesdna/DNA_text_types.h +++ b/source/blender/makesdna/DNA_text_types.h @@ -55,8 +55,6 @@ typedef struct Text { } Text; #define TXT_TABSIZE 4 -#define TXT_INIT_UNDO 1024 -#define TXT_MAX_UNDO (TXT_INIT_UNDO * TXT_INIT_UNDO) /* text flags */ enum { diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 31ffb3efebd..e7a4f9cbd4e 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -433,6 +433,10 @@ enum { V3D_SHADING_TEXTURE_COLOR = 3, V3D_SHADING_OBJECT_COLOR = 4, V3D_SHADING_VERTEX_COLOR = 5, + + /* Is used to display the object using the error color. For example when in + * solid texture paint mode without any textures configured */ + V3D_SHADING_ERROR_COLOR = 999, }; /** #View3DShading.background_type */ diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index ba5355a8d95..4ad2aa55c75 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -571,6 +571,13 @@ static void rna_def_dopesheet(BlenderRNA *brna) RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_GREASEPENCIL, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + prop = RNA_def_property(srna, "show_movieclips", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag2", ADS_FILTER_NOMOVIECLIPS); + RNA_def_property_ui_text( + prop, "Display Movie Clips", "Include visualization of movie clip related animation data"); + RNA_def_property_ui_icon(prop, ICON_TRACKER, 0); + RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + /* GPencil Mode Settings */ prop = RNA_def_property(srna, "show_gpencil_3d_only", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_GP_3DONLY); diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 99b2c423b44..6737363bae4 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -268,18 +268,6 @@ static IDProperty *rna_EditBone_idprops(PointerRNA *ptr, bool create) return ebone->prop; } -/* Update the layers_used variable after bones are moved between layer - * NOTE: Used to be done in drawing code in 2.7, but that won't work with - * Copy-on-Write, as drawing uses evaluated copies. - */ -static void rna_Armature_layer_used_refresh(bArmature *arm, ListBase *bones) -{ - for (Bone *bone = bones->first; bone; bone = bone->next) { - arm->layer_used |= bone->layer; - rna_Armature_layer_used_refresh(arm, &bone->childbase); - } -} - static void rna_bone_layer_set(int *layer, const bool *values) { int i, tot = 0; @@ -312,8 +300,7 @@ static void rna_Bone_layer_set(PointerRNA *ptr, const bool *values) rna_bone_layer_set(&bone->layer, values); - arm->layer_used = 0; - rna_Armature_layer_used_refresh(arm, &arm->bonebase); + BKE_armature_refresh_layer_used(arm); } static void rna_Armature_layer_set(PointerRNA *ptr, const bool *values) @@ -1355,7 +1342,7 @@ static void rna_def_armature(BlenderRNA *brna) prop = RNA_def_property(srna, "display_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "drawtype"); RNA_def_property_enum_items(prop, prop_drawtype_items); - RNA_def_property_ui_text(prop, "Display Type Type", ""); + RNA_def_property_ui_text(prop, "Display Type", ""); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index fabbc7ca18b..fb60f092d16 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -1426,7 +1426,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); prop = RNA_def_property(srna, "use_occlude_eraser", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GP_BRUSH_OCCLUDE_ERASER); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_OCCLUDE_ERASER); RNA_def_property_ui_text(prop, "Occlude Eraser", "Erase only strokes visible and not occluded"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); } @@ -1807,9 +1807,8 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Topology Rake", "Automatically align edges to the brush direction to " - "to generate cleaner topology and define sharp features " - "dynamic topology. Best used on low-poly meshes as it has " - "a performance impact"); + "generate cleaner topology and define sharp features. " + "Best used on low-poly meshes as it has a performance impact"); RNA_def_property_update(prop, 0, "rna_Brush_update"); prop = RNA_def_property(srna, "stencil_pos", PROP_FLOAT, PROP_XYZ); diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c index c93833ef493..548ed656d7b 100644 --- a/source/blender/makesrna/intern/rna_cloth.c +++ b/source/blender/makesrna/intern/rna_cloth.c @@ -824,7 +824,7 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "use_collision", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_COLLSETTINGS_FLAG_ENABLED); RNA_def_property_ui_text(prop, "Enable Collision", "Enable collisions with other objects"); - RNA_def_property_update(prop, 0, "rna_cloth_update"); + RNA_def_property_update(prop, 0, "rna_cloth_dependency_update"); prop = RNA_def_property(srna, "distance_min", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "epsilon"); diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index b59e97f1991..2671246b589 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -685,6 +685,24 @@ static void rna_GPencil_stroke_remove(bGPDframe *frame, WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); } +static void rna_GPencil_stroke_close(ID *id, + bGPDframe *frame, + ReportList *reports, + PointerRNA *stroke_ptr) +{ + bGPdata *gpd = (bGPdata *)id; + bGPDstroke *stroke = stroke_ptr->data; + if (BLI_findindex(&frame->strokes, stroke) == -1) { + BKE_report(reports, RPT_ERROR, "Stroke not found in grease pencil frame"); + return; + } + + BKE_gpencil_close_stroke(stroke); + + DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); + WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); +} + static void rna_GPencil_stroke_select_set(PointerRNA *ptr, const bool value) { bGPDstroke *gps = ptr->data; @@ -710,7 +728,10 @@ static void rna_GPencil_stroke_select_set(PointerRNA *ptr, const bool value) } } -static bGPDframe *rna_GPencil_frame_new(bGPDlayer *layer, ReportList *reports, int frame_number) +static bGPDframe *rna_GPencil_frame_new(bGPDlayer *layer, + ReportList *reports, + int frame_number, + bool active) { bGPDframe *frame; @@ -720,7 +741,9 @@ static bGPDframe *rna_GPencil_frame_new(bGPDlayer *layer, ReportList *reports, i } frame = BKE_gpencil_frame_addnew(layer, frame_number); - + if (active) { + layer->actframe = BKE_gpencil_layer_getframe(layer, frame_number, GP_GETFRAME_USE_PREV); + } WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); return frame; @@ -1154,6 +1177,13 @@ static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "stroke", "GPencilStroke", "Stroke", "The stroke to remove"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + + func = RNA_def_function(srna, "close", "rna_GPencil_stroke_close"); + RNA_def_function_ui_description(func, "Close a grease pencil stroke adding geometry"); + RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); + parm = RNA_def_pointer(func, "stroke", "GPencilStroke", "Stroke", "The stroke to close"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_gpencil_frame(BlenderRNA *brna) @@ -1222,6 +1252,7 @@ static void rna_def_gpencil_frames_api(BlenderRNA *brna, PropertyRNA *cprop) MINAFRAME, MAXFRAME); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_boolean(func, "active", 0, "Active", ""); parm = RNA_def_pointer(func, "frame", "GPencilFrame", "", "The newly created frame"); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 2dabaeebb09..2b89225d34d 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -663,7 +663,7 @@ static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna) /* Mode */ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_gpencil_simplify_mode_items); - RNA_def_property_ui_text(prop, "Mode", "How simplify the stroke"); + RNA_def_property_ui_text(prop, "Mode", "How to simplify the stroke"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index 933dae70457..d167c650683 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -36,13 +36,14 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "BKE_packedFile.h" + #include "rna_internal.h" /* own include */ #ifdef RNA_RUNTIME # include <errno.h> # include "BKE_image.h" -# include "BKE_packedFile.h" # include "BKE_main.h" # include "IMB_imbuf.h" @@ -55,7 +56,7 @@ static void rna_ImagePackedFile_save(ImagePackedFile *imapf, Main *bmain, ReportList *reports) { - if (writePackedFile( + if (BKE_packedfile_write_to_file( reports, BKE_main_blendfile_path(bmain), imapf->filepath, imapf->packedfile, 0) != RET_OK) { BKE_reportf(reports, RPT_ERROR, "Could not save packed file to disk as '%s'", imapf->filepath); @@ -179,7 +180,7 @@ static void rna_Image_unpack(Image *image, Main *bmain, ReportList *reports, int } else { /* reports its own error on failure */ - unpackImage(bmain, reports, image, method); + BKE_packedfile_unpack_image(bmain, reports, image, method); } } diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index 003faed5b81..1c0ced060d5 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -178,6 +178,13 @@ static void rna_ViewLayer_update_tagged(ID *id_ptr, ViewLayer *view_layer, Main Scene *scene = (Scene *)id_ptr; Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); + /* NOTE: This is similar to CTX_data_depsgraph(). Ideally such access would be de-duplicated + * across all possible cases, but for now this is safest and easiest way to go. + * + * The reason for this is that it's possible to have Python operator which asks view layer to + * be updated. After re-do of such operator view layer's dependency graph will not be marked + * as active. */ + DEG_make_active(depsgraph); BKE_scene_graph_update_tagged(depsgraph, bmain); # ifdef WITH_PYTHON @@ -271,15 +278,18 @@ static void rna_LayerCollection_exclude_update(Main *bmain, Scene *UNUSED(scene) LayerCollection *lc = (LayerCollection *)ptr->data; ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, lc); - /* Set/Unset it recursively to match the behaviour of excluding via the menu or shortcuts. */ - rna_LayerCollection_exclude_update_recursive(&lc->layer_collections, - (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0); + /* Set/Unset it recursively to match the behavior of excluding via the menu or shortcuts. */ + const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0; + rna_LayerCollection_exclude_update_recursive(&lc->layer_collections, exclude); BKE_layer_collection_sync(scene, view_layer); DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); DEG_relations_tag_update(bmain); WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + if (exclude) { + ED_object_base_active_refresh(bmain, scene, view_layer); + } } static void rna_LayerCollection_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) @@ -342,7 +352,6 @@ static void rna_def_layer_collection(BlenderRNA *brna) RNA_def_property_boolean_funcs(prop, NULL, "rna_LayerCollection_exclude_set"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Exclude from View Layer", "Exclude from view layer"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_icon(prop, ICON_CHECKBOX_HLT, -1); RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_exclude_update"); diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index d7acbb40bb8..fec991e16da 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -555,6 +555,8 @@ static Text *rna_Main_texts_load(Main *bmain, errno = 0; txt = BKE_text_load_ex(bmain, filepath, BKE_main_blendfile_path(bmain), is_internal); + /* Texts have no user by default... Only the 'real' user flag. */ + id_us_min(&txt->id); if (!txt) { BKE_reportf(reports, diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 3ff2e884d92..28989d1dd5f 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -433,11 +433,11 @@ static void rna_def_material_greasepencil(BlenderRNA *brna) static EnumPropertyItem fill_style_items[] = { {GP_STYLE_FILL_STYLE_SOLID, "SOLID", 0, "Solid", "Fill area with solid color"}, {GP_STYLE_FILL_STYLE_GRADIENT, "GRADIENT", 0, "Gradient", "Fill area with gradient color"}, - {GP_STYLE_FILL_STYLE_CHESSBOARD, - "CHESSBOARD", + {GP_STYLE_FILL_STYLE_CHECKER, + "CHECKER", 0, "Checker Board", - "Fill area with chessboard pattern"}, + "Fill area with checkerboard pattern"}, {GP_STYLE_FILL_STYLE_TEXTURE, "TEXTURE", 0, "Texture", "Fill area with image texture"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index c51097fc8c3..03173bcb3da 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -3095,8 +3095,7 @@ static void rna_def_mesh(BlenderRNA *brna) prop = RNA_def_property(srna, "use_paint_mask_vertex", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_PAINT_VERT_SEL); - RNA_def_property_ui_text( - prop, "Vertex Selection", "Vertex selection masking for painting (weight paint only)"); + RNA_def_property_ui_text(prop, "Vertex Selection", "Vertex selection masking for painting"); RNA_def_property_ui_icon(prop, ICON_VERTEXSEL, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Mesh_update_vertmask"); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 5f156864479..eec280a5f3e 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1711,6 +1711,12 @@ static void rna_Node_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) ED_node_tag_update_nodetree(bmain, ntree, node); } +static void rna_Node_update_relations(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + rna_Node_update(bmain, scene, ptr); + DEG_relations_tag_update(bmain); +} + static void rna_Node_socket_value_update(ID *id, bNode *node, bContext *C) { ED_node_tag_update_nodetree(CTX_data_main(C), (bNodeTree *)id, node); @@ -4458,7 +4464,7 @@ static void def_sh_tex_coord(StructRNA *srna) 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"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update_relations"); prop = RNA_def_property(srna, "from_instancer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 578097733f2..d3b532dd11d 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -444,7 +444,7 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value, struct Report if ((id->tag & LIB_TAG_NO_MAIN) != (ob->id.tag & LIB_TAG_NO_MAIN)) { BKE_report(reports, RPT_ERROR, - "Can only assign evaluated data to to evaluated object, or original data to " + "Can only assign evaluated data to evaluated object, or original data to " "original object"); return; } @@ -638,7 +638,7 @@ static void rna_Object_dup_collection_set(PointerRNA *ptr, id_us_plus(&ob->instance_collection->id); } else { - BKE_report(NULL, RPT_ERROR, "Only empty objects support group instances"); + BKE_report(NULL, RPT_ERROR, "Only empty objects support collection instances"); } } else { @@ -2358,7 +2358,7 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Data", "Object data"); - RNA_def_property_update(prop, 0, "rna_Object_internal_update_data"); + RNA_def_property_update(prop, 0, "rna_Object_internal_update_data_dependency"); prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index a891e11a944..c91481931a2 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -98,11 +98,13 @@ static void rna_Object_select_set( Base *base = BKE_view_layer_base_find(view_layer, ob); if (!base) { - BKE_reportf(reports, - RPT_ERROR, - "Object '%s' not in View Layer '%s'!", - ob->id.name + 2, - view_layer->name); + if (select) { + BKE_reportf(reports, + RPT_ERROR, + "Object '%s' can't be selected because it is not in View Layer '%s'!", + ob->id.name + 2, + view_layer->name); + } return; } @@ -113,10 +115,7 @@ static void rna_Object_select_set( WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene); } -static bool rna_Object_select_get(Object *ob, - bContext *C, - ReportList *reports, - ViewLayer *view_layer) +static bool rna_Object_select_get(Object *ob, bContext *C, ViewLayer *view_layer) { if (view_layer == NULL) { view_layer = CTX_data_view_layer(C); @@ -124,11 +123,6 @@ static bool rna_Object_select_get(Object *ob, Base *base = BKE_view_layer_base_find(view_layer, ob); if (!base) { - BKE_reportf(reports, - RPT_ERROR, - "Object '%s' not in View Layer '%s'!", - ob->id.name + 2, - view_layer->name); return false; } @@ -144,11 +138,13 @@ static void rna_Object_hide_set( Base *base = BKE_view_layer_base_find(view_layer, ob); if (!base) { - BKE_reportf(reports, - RPT_ERROR, - "Object '%s' not in View Layer '%s'!", - ob->id.name + 2, - view_layer->name); + if (hide) { + BKE_reportf(reports, + RPT_ERROR, + "Object '%s' can't be hidden because it is not in View Layer '%s'!", + ob->id.name + 2, + view_layer->name); + } return; } @@ -165,10 +161,7 @@ static void rna_Object_hide_set( WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } -static bool rna_Object_hide_get(Object *ob, - bContext *C, - ReportList *reports, - ViewLayer *view_layer) +static bool rna_Object_hide_get(Object *ob, bContext *C, ViewLayer *view_layer) { if (view_layer == NULL) { view_layer = CTX_data_view_layer(C); @@ -176,19 +169,13 @@ static bool rna_Object_hide_get(Object *ob, Base *base = BKE_view_layer_base_find(view_layer, ob); if (!base) { - BKE_reportf(reports, - RPT_ERROR, - "Object '%s' not in View Layer '%s'!", - ob->id.name + 2, - view_layer->name); return false; } return ((base->flag & BASE_HIDDEN) != 0); } -static bool rna_Object_visible_get( - Object *ob, bContext *C, ReportList *reports, ViewLayer *view_layer, View3D *v3d) +static bool rna_Object_visible_get(Object *ob, bContext *C, ViewLayer *view_layer, View3D *v3d) { if (view_layer == NULL) { view_layer = CTX_data_view_layer(C); @@ -199,21 +186,13 @@ static bool rna_Object_visible_get( Base *base = BKE_view_layer_base_find(view_layer, ob); if (!base) { - BKE_reportf(reports, - RPT_ERROR, - "Object '%s' not in View Layer '%s'!", - ob->id.name + 2, - view_layer->name); return false; } return BASE_VISIBLE(v3d, base); } -static bool rna_Object_holdout_get(Object *ob, - bContext *C, - ReportList *reports, - ViewLayer *view_layer) +static bool rna_Object_holdout_get(Object *ob, bContext *C, ViewLayer *view_layer) { if (view_layer == NULL) { view_layer = CTX_data_view_layer(C); @@ -221,21 +200,13 @@ static bool rna_Object_holdout_get(Object *ob, Base *base = BKE_view_layer_base_find(view_layer, ob); if (!base) { - BKE_reportf(reports, - RPT_ERROR, - "Object '%s' not in View Layer '%s'!", - ob->id.name + 2, - view_layer->name); return false; } return ((base->flag & BASE_HOLDOUT) != 0); } -static bool rna_Object_indirect_only_get(Object *ob, - bContext *C, - ReportList *reports, - ViewLayer *view_layer) +static bool rna_Object_indirect_only_get(Object *ob, bContext *C, ViewLayer *view_layer) { if (view_layer == NULL) { view_layer = CTX_data_view_layer(C); @@ -243,11 +214,6 @@ static bool rna_Object_indirect_only_get(Object *ob, Base *base = BKE_view_layer_base_find(view_layer, ob); if (!base) { - BKE_reportf(reports, - RPT_ERROR, - "Object '%s' not in View Layer '%s'!", - ob->id.name + 2, - view_layer->name); return false; } @@ -741,7 +707,7 @@ void RNA_api_object(StructRNA *srna) func = RNA_def_function(srna, "select_get", "rna_Object_select_get"); RNA_def_function_ui_description( func, "Test if the object is selected. The selection state is per view layer"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer( func, "view_layer", "ViewLayer", "", "Use this instead of the active view layer"); parm = RNA_def_boolean(func, "result", 0, "", "Object selected"); @@ -760,10 +726,10 @@ void RNA_api_object(StructRNA *srna) RNA_def_function_ui_description( func, "Test if the object is hidden for viewport editing. This hiding state is per view layer"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer( func, "view_layer", "ViewLayer", "", "Use this instead of the active view layer"); - parm = RNA_def_boolean(func, "result", 0, "", "Object hideed"); + parm = RNA_def_boolean(func, "result", 0, "", "Object hidden"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "hide_set", "rna_Object_hide_set"); @@ -779,7 +745,7 @@ void RNA_api_object(StructRNA *srna) RNA_def_function_ui_description(func, "Test if the object is visible in the 3D viewport, taking into " "account all visibility settings"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer( func, "view_layer", "ViewLayer", "", "Use this instead of the active view layer"); parm = RNA_def_pointer( @@ -789,7 +755,7 @@ void RNA_api_object(StructRNA *srna) func = RNA_def_function(srna, "holdout_get", "rna_Object_holdout_get"); RNA_def_function_ui_description(func, "Test if object is masked in the view layer"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer( func, "view_layer", "ViewLayer", "", "Use this instead of the active view layer"); parm = RNA_def_boolean(func, "result", 0, "", "Object holdout"); @@ -799,7 +765,7 @@ void RNA_api_object(StructRNA *srna) RNA_def_function_ui_description(func, "Test if object is set to contribute only indirectly (through " "shadows and reflections) in the view layer"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer( func, "view_layer", "ViewLayer", "", "Use this instead of the active view layer"); parm = RNA_def_boolean(func, "result", 0, "", "Object indirect only"); diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index c97491a92c6..ab6cffe615d 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -523,6 +523,8 @@ static void rna_FieldSettings_shape_update(Main *bmain, Scene *scene, PointerRNA if (!particle_id_check(ptr)) { Object *ob = (Object *)ptr->id.data; ED_object_check_force_modifiers(bmain, scene, ob); + + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob); WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob); } diff --git a/source/blender/makesrna/intern/rna_packedfile.c b/source/blender/makesrna/intern/rna_packedfile.c index 0b1b48b1bd3..dda1c637f39 100644 --- a/source/blender/makesrna/intern/rna_packedfile.c +++ b/source/blender/makesrna/intern/rna_packedfile.c @@ -27,6 +27,8 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "BKE_packedFile.h" + #include "rna_internal.h" const EnumPropertyItem rna_enum_unpack_method_items[] = { diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index c1822b35f28..a96e85473a2 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -2822,11 +2822,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "count", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "totpart"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - /* This limit is for those freaks who have the machine power to handle it. */ - /* 10M particles take around 2.2 Gb of memory / disk space in saved file and */ - /* each cached frame takes around 0.5 Gb of memory / disk space depending on cache mode. */ - RNA_def_property_range(prop, 0, 10000000); - RNA_def_property_ui_range(prop, 0, 100000, 1, -1); + RNA_def_property_ui_range(prop, 0, 1000000, 1, -1); RNA_def_property_ui_text(prop, "Number", "Total number of particles"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 8c3e1a724cf..9834520f952 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -1870,8 +1870,8 @@ int rna_property_override_diff_default(Main *bmain, # undef RNA_PATH_FREE } - equals = equals && !(iter_a.valid || iter_b.valid) && - !abort; /* Not same number of items in both collections... */ + /* Not same number of items in both collections. */ + equals = equals && !(iter_a.valid || iter_b.valid) && !abort; RNA_property_collection_end(&iter_a); RNA_property_collection_end(&iter_b); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index b47454ecd84..dcbbdd67d7b 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1666,6 +1666,13 @@ static void rna_Scene_use_nodes_update(bContext *C, PointerRNA *ptr) DEG_relations_tag_update(CTX_data_main(C)); } +static void rna_Physics_relations_update(Main *bmain, + Scene *UNUSED(scene), + PointerRNA *UNUSED(ptr)) +{ + DEG_relations_tag_update(bmain); +} + static void rna_Physics_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->id.data; @@ -7346,7 +7353,7 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "rigidbody_world"); RNA_def_property_struct_type(prop, "RigidBodyWorld"); RNA_def_property_ui_text(prop, "Rigid Body World", ""); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE, "rna_Physics_relations_update"); /* Tool Settings */ prop = RNA_def_property(srna, "tool_settings", PROP_POINTER, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index 6982b8a7f52..853017e6daf 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -576,7 +576,7 @@ static void rna_def_screen(BlenderRNA *brna) prop = RNA_def_property(srna, "use_play_3d_editors", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "redraws_flag", TIME_ALL_3D_WIN); - RNA_def_property_ui_text(prop, "All 3D View Editors", ""); + RNA_def_property_ui_text(prop, "All 3D Viewports", ""); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, "rna_Screen_redraw_update"); prop = RNA_def_property(srna, "use_follow", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 221d4375970..ac41736451a 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -230,11 +230,12 @@ static void rna_ParticleEdit_redo(bContext *C, PointerRNA *UNUSED(ptr)) BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL); psys_free_path_cache(edit->psys, edit); - DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_COPY_ON_WRITE); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); } static void rna_ParticleEdit_update(bContext *C, PointerRNA *UNUSED(ptr)) { + Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = OBACT(view_layer); @@ -243,7 +244,7 @@ static void rna_ParticleEdit_update(bContext *C, PointerRNA *UNUSED(ptr)) } /* Sync tool setting changes from original to evaluated scenes. */ - DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_COPY_ON_WRITE); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); } static void rna_ParticleEdit_tool_set(PointerRNA *ptr, int value) diff --git a/source/blender/makesrna/intern/rna_sound.c b/source/blender/makesrna/intern/rna_sound.c index e4b120261c6..8402c4a8705 100644 --- a/source/blender/makesrna/intern/rna_sound.c +++ b/source/blender/makesrna/intern/rna_sound.c @@ -40,26 +40,10 @@ static void rna_Sound_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerR DEG_id_tag_update(&sound->id, ID_RECALC_AUDIO); } -static bool rna_Sound_caching_get(PointerRNA *ptr) +static void rna_Sound_caching_update(Main *bmain, Scene *scene, PointerRNA *ptr) { - bSound *sound = (bSound *)(ptr->data); - return (sound->flags & SOUND_FLAGS_CACHING) != 0; -} - -static void rna_Sound_caching_set(PointerRNA *ptr, const bool value) -{ - bSound *sound = (bSound *)(ptr->data); - if (value) { - BKE_sound_cache(sound); - } - else { - BKE_sound_delete_cache(sound); - } -} - -static void rna_Sound_caching_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) -{ - BKE_sequencer_update_sound(scene, (bSound *)(ptr->data)); + rna_Sound_update(bmain, scene, ptr); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); } #else @@ -87,7 +71,7 @@ static void rna_def_sound(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Packed File", ""); prop = RNA_def_property(srna, "use_memory_cache", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_funcs(prop, "rna_Sound_caching_get", "rna_Sound_caching_set"); + RNA_def_property_boolean_sdna(prop, NULL, "flags", SOUND_FLAGS_CACHING); RNA_def_property_ui_text(prop, "Caching", "The sound file is decoded and loaded into RAM"); RNA_def_property_update(prop, 0, "rna_Sound_caching_update"); diff --git a/source/blender/makesrna/intern/rna_sound_api.c b/source/blender/makesrna/intern/rna_sound_api.c index f172c659900..2be0ed966f1 100644 --- a/source/blender/makesrna/intern/rna_sound_api.c +++ b/source/blender/makesrna/intern/rna_sound_api.c @@ -26,15 +26,15 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "BKE_packedFile.h" + #include "rna_internal.h" #ifdef RNA_RUNTIME -# include "BKE_packedFile.h" - static void rna_Sound_pack(bSound *sound, Main *bmain, ReportList *reports) { - sound->packedfile = newPackedFile(reports, sound->name, ID_BLEND_PATH(bmain, &sound->id)); + sound->packedfile = BKE_packedfile_new(reports, sound->name, ID_BLEND_PATH(bmain, &sound->id)); } static void rna_Sound_unpack(bSound *sound, Main *bmain, ReportList *reports, int method) @@ -44,7 +44,7 @@ static void rna_Sound_unpack(bSound *sound, Main *bmain, ReportList *reports, in } else { /* reports its own error on failure */ - unpackSound(bmain, reports, sound, method); + BKE_packedfile_unpack_sound(bmain, reports, sound, method); } } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 2b51b1eee97..6dc0cf045cd 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1058,21 +1058,6 @@ static PointerRNA rna_View3DShading_selected_studio_light_get(PointerRNA *ptr) } /* shading.light */ -static int rna_View3DShading_light_get(PointerRNA *ptr) -{ - View3DShading *shading = (View3DShading *)ptr->data; - return shading->light; -} - -static void rna_View3DShading_light_set(PointerRNA *ptr, int value) -{ - View3DShading *shading = (View3DShading *)ptr->data; - if (value == V3D_LIGHTING_MATCAP && shading->color_type == V3D_SHADING_TEXTURE_COLOR) { - shading->color_type = V3D_SHADING_MATERIAL_COLOR; - } - shading->light = value; -} - static const EnumPropertyItem *rna_View3DShading_color_type_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), @@ -1081,36 +1066,24 @@ static const EnumPropertyItem *rna_View3DShading_color_type_itemf(bContext *UNUS View3DShading *shading = (View3DShading *)ptr->data; int totitem = 0; - EnumPropertyItem *item = NULL; - if (shading->type == OB_SOLID) { - RNA_enum_items_add_value( - &item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_MATERIAL_COLOR); + if (shading->type == OB_WIRE) { + EnumPropertyItem *item = NULL; RNA_enum_items_add_value( &item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_SINGLE_COLOR); RNA_enum_items_add_value( &item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_OBJECT_COLOR); RNA_enum_items_add_value( &item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_RANDOM_COLOR); - RNA_enum_items_add_value( - &item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_VERTEX_COLOR); - if (shading->light != V3D_LIGHTING_MATCAP) { - RNA_enum_items_add_value( - &item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_TEXTURE_COLOR); - } + RNA_enum_item_end(&item, &totitem); + *r_free = true; + return item; } - else if (shading->type == OB_WIRE) { - RNA_enum_items_add_value( - &item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_SINGLE_COLOR); - RNA_enum_items_add_value( - &item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_OBJECT_COLOR); - RNA_enum_items_add_value( - &item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_RANDOM_COLOR); + else { + /* Solid mode, or lookdev mode for workbench engine. */ + r_free = false; + return rna_enum_shading_color_type_items; } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - return item; } /* Studio light */ @@ -2132,6 +2105,13 @@ static void rna_SpaceClipEditor_clip_mode_update(Main *UNUSED(bmain), { SpaceClip *sc = (SpaceClip *)(ptr->data); + if (sc->mode == SC_MODE_MASKEDIT && sc->view != SC_VIEW_CLIP) { + /* Make sure we are in the right view for mask editing */ + sc->view = SC_VIEW_CLIP; + ScrArea *sa = rna_area_from_space(ptr); + ED_area_tag_refresh(sa); + } + sc->scopes.ok = 0; } @@ -2997,8 +2977,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) prop = RNA_def_property(srna, "light", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "light"); RNA_def_property_enum_items(prop, rna_enum_viewport_lighting_items); - RNA_def_property_enum_funcs( - prop, "rna_View3DShading_light_get", "rna_View3DShading_light_set", NULL); RNA_def_property_ui_text(prop, "Lighting", "Lighting Method for Solid/Texture Viewport Shading"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); @@ -3551,7 +3529,8 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) prop = RNA_def_property(srna, "texture_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "overlay.texture_paint_mode_opacity"); RNA_def_property_float_default(prop, 1.0f); - RNA_def_property_ui_text(prop, "Texture Opacity", "Opacity of the texture paint mode overlay"); + RNA_def_property_ui_text( + prop, "Stencil Opacity", "Opacity of the texture paint mode stencil mask overlay"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); diff --git a/source/blender/makesrna/intern/rna_text_api.c b/source/blender/makesrna/intern/rna_text_api.c index ad36a56ac6a..4ca48226ee9 100644 --- a/source/blender/makesrna/intern/rna_text_api.c +++ b/source/blender/makesrna/intern/rna_text_api.c @@ -34,13 +34,13 @@ static void rna_Text_clear(Text *text) { - BKE_text_clear(text, NULL); + BKE_text_clear(text); WM_main_add_notifier(NC_TEXT | NA_EDITED, text); } static void rna_Text_write(Text *text, const char *str) { - BKE_text_write(text, NULL, str); + BKE_text_write(text, str); WM_main_add_notifier(NC_TEXT | NA_EDITED, text); } diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index bfdb55800a2..8a9b8a14563 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -5808,8 +5808,8 @@ void RNA_def_userdef(BlenderRNA *brna) prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "runtime.is_dirty", 0); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Dirty", "Preferences have changed"); + RNA_def_property_update(prop, 0, "rna_userdef_ui_update"); rna_def_userdef_view(brna); rna_def_userdef_edit(brna); diff --git a/source/blender/makesrna/intern/rna_vfont_api.c b/source/blender/makesrna/intern/rna_vfont_api.c index f35a764b1b0..a85dde5d8b1 100644 --- a/source/blender/makesrna/intern/rna_vfont_api.c +++ b/source/blender/makesrna/intern/rna_vfont_api.c @@ -26,15 +26,15 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "BKE_packedFile.h" + #include "rna_internal.h" #ifdef RNA_RUNTIME -# include "BKE_packedFile.h" - static void rna_VectorFont_pack(VFont *vfont, Main *bmain, ReportList *reports) { - vfont->packedfile = newPackedFile(reports, vfont->name, ID_BLEND_PATH(bmain, &vfont->id)); + vfont->packedfile = BKE_packedfile_new(reports, vfont->name, ID_BLEND_PATH(bmain, &vfont->id)); } static void rna_VectorFont_unpack(VFont *vfont, Main *bmain, ReportList *reports, int method) @@ -44,7 +44,7 @@ static void rna_VectorFont_unpack(VFont *vfont, Main *bmain, ReportList *reports } else { /* reports its own error on failure */ - unpackVFont(bmain, reports, vfont, method); + BKE_packedfile_unpack_vfont(bmain, reports, vfont, method); } } diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 81bb550616e..1edda29a556 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -1449,12 +1449,12 @@ static StructRNA *rna_Operator_register(Main *bmain, /* setup dummy operator & operator type to store static properties in */ 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.description; /* only assigne the pointer, string is NULL'd */ + dummyot.idname = temp_buffers.idname; /* only assign the pointer, string is NULL'd */ + dummyot.name = temp_buffers.name; /* only assign the pointer, string is NULL'd */ + dummyot.description = temp_buffers.description; /* only assign 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 */ + temp_buffers.translation_context; /* only assign the pointer, string is NULL'd */ + dummyot.undo_group = temp_buffers.undo_group; /* only assign the pointer, string is NULL'd */ RNA_pointer_create(NULL, &RNA_Operator, &dummyop, &dummyotr); /* clear in case they are left unset */ @@ -1597,12 +1597,12 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, /* setup dummy operator & operator type to store static properties in */ 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.description; /* only assigne the pointer, string is NULL'd */ + dummyot.idname = temp_buffers.idname; /* only assign the pointer, string is NULL'd */ + dummyot.name = temp_buffers.name; /* only assign the pointer, string is NULL'd */ + dummyot.description = temp_buffers.description; /* only assign 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 */ + temp_buffers.translation_context; /* only assign the pointer, string is NULL'd */ + dummyot.undo_group = temp_buffers.undo_group; /* only assign the pointer, string is NULL'd */ RNA_pointer_create(NULL, &RNA_Macro, &dummyop, &dummyotr); /* clear in case they are left unset */ diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c index 41e499471ea..38b6ac9ac52 100644 --- a/source/blender/makesrna/intern/rna_wm_gizmo.c +++ b/source/blender/makesrna/intern/rna_wm_gizmo.c @@ -243,6 +243,12 @@ static void rna_Gizmo_bl_idname_set(PointerRNA *ptr, const char *value) } } +static void rna_Gizmo_update_redraw(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + wmGizmo *gizmo = ptr->data; + gizmo->do_draw = true; +} + static wmGizmo *rna_GizmoProperties_find_operator(PointerRNA *ptr) { # if 0 @@ -1123,7 +1129,7 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_ui_text(prop, "Alpha", ""); RNA_def_property_float_funcs(prop, "rna_Gizmo_alpha_get", "rna_Gizmo_alpha_set", NULL); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* Color & Alpha (highlight) */ prop = RNA_def_property(srna, "color_highlight", PROP_FLOAT, PROP_COLOR); @@ -1134,28 +1140,28 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_ui_text(prop, "Alpha", ""); RNA_def_property_float_funcs(prop, "rna_Gizmo_alpha_hi_get", "rna_Gizmo_alpha_hi_set", NULL); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); prop = RNA_def_property(srna, "matrix_space", PROP_FLOAT, PROP_MATRIX); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); RNA_def_property_ui_text(prop, "Space Matrix", ""); RNA_def_property_float_funcs( prop, "rna_Gizmo_matrix_space_get", "rna_Gizmo_matrix_space_set", NULL); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); prop = RNA_def_property(srna, "matrix_basis", PROP_FLOAT, PROP_MATRIX); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); RNA_def_property_ui_text(prop, "Basis Matrix", ""); RNA_def_property_float_funcs( prop, "rna_Gizmo_matrix_basis_get", "rna_Gizmo_matrix_basis_set", NULL); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); prop = RNA_def_property(srna, "matrix_offset", PROP_FLOAT, PROP_MATRIX); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); RNA_def_property_ui_text(prop, "Offset Matrix", ""); RNA_def_property_float_funcs( prop, "rna_Gizmo_matrix_offset_get", "rna_Gizmo_matrix_offset_set", NULL); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); prop = RNA_def_property(srna, "matrix_world", PROP_FLOAT, PROP_MATRIX); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1168,13 +1174,13 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_float_funcs( prop, "rna_Gizmo_scale_basis_get", "rna_Gizmo_scale_basis_set", NULL); RNA_def_property_range(prop, 0.0f, FLT_MAX); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); prop = RNA_def_property(srna, "line_width", PROP_FLOAT, PROP_PIXEL); RNA_def_property_ui_text(prop, "Line Width", ""); RNA_def_property_float_funcs(prop, "rna_Gizmo_line_width_get", "rna_Gizmo_line_width_set", NULL); RNA_def_property_range(prop, 0.0f, FLT_MAX); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); prop = RNA_def_property(srna, "select_bias", PROP_FLOAT, PROP_NONE); RNA_def_property_ui_text(prop, "Select Bias", "Depth bias used for selection"); @@ -1187,39 +1193,39 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_Gizmo_flag_hide_get", "rna_Gizmo_flag_hide_set"); RNA_def_property_ui_text(prop, "Hide", ""); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_HIDDEN_SELECT */ prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs( prop, "rna_Gizmo_flag_hide_select_get", "rna_Gizmo_flag_hide_select_set"); RNA_def_property_ui_text(prop, "Hide Select", ""); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_MOVE_CURSOR */ prop = RNA_def_property(srna, "use_grab_cursor", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs( prop, "rna_Gizmo_flag_use_grab_cursor_get", "rna_Gizmo_flag_use_grab_cursor_set"); RNA_def_property_ui_text(prop, "Grab Cursor", ""); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_DRAW_HOVER */ prop = RNA_def_property(srna, "use_draw_hover", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs( prop, "rna_Gizmo_flag_use_draw_hover_get", "rna_Gizmo_flag_use_draw_hover_set"); RNA_def_property_ui_text(prop, "Draw Hover", ""); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_DRAW_MODAL */ prop = RNA_def_property(srna, "use_draw_modal", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs( prop, "rna_Gizmo_flag_use_draw_modal_get", "rna_Gizmo_flag_use_draw_modal_set"); RNA_def_property_ui_text(prop, "Draw Active", "Draw while dragging"); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_DRAW_VALUE */ prop = RNA_def_property(srna, "use_draw_value", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs( prop, "rna_Gizmo_flag_use_draw_value_get", "rna_Gizmo_flag_use_draw_value_set"); RNA_def_property_ui_text( prop, "Draw Value", "Show an indicator for the current value while dragging"); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_DRAW_OFFSET_SCALE */ prop = RNA_def_property(srna, "use_draw_offset_scale", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, @@ -1227,20 +1233,20 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) "rna_Gizmo_flag_use_draw_offset_scale_set"); RNA_def_property_ui_text( prop, "Scale Offset", "Scale the offset matrix (use to apply screen-space offset)"); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_DRAW_NO_SCALE (negated) */ prop = RNA_def_property(srna, "use_draw_scale", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs( prop, "rna_Gizmo_flag_use_draw_scale_get", "rna_Gizmo_flag_use_draw_scale_set"); RNA_def_property_ui_text(prop, "Scale", "Use scale when calculating the matrix"); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_SELECT_BACKGROUND */ prop = RNA_def_property(srna, "use_select_background", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_Gizmo_flag_use_select_background_get", "rna_Gizmo_flag_use_select_background_set"); RNA_def_property_ui_text(prop, "Select Background", "Don't write into the depth buffer"); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_OPERATOR_TOOL_INIT */ prop = RNA_def_property(srna, "use_operator_tool_properties", PROP_BOOLEAN, PROP_NONE); @@ -1251,7 +1257,7 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) prop, "Tool Property Init", "Merge active tool properties on activation (does not overwrite existing)"); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_EVENT_HANDLE_ALL */ prop = RNA_def_property(srna, "use_event_handle_all", PROP_BOOLEAN, PROP_NONE); @@ -1261,7 +1267,7 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) "Handle All Events", "When highlighted, " "do not pass events through to be handled by other keymaps"); - RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* wmGizmo.state (readonly) */ /* WM_GIZMO_STATE_HIGHLIGHT */ diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 26b45bbef0d..309af4d4812 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -130,9 +130,6 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes if (vertex_only) { BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (!BM_vert_is_manifold(v)) { - continue; - } if (bmd->lim_flags & MOD_BEVEL_WEIGHT) { weight = BM_elem_float_data_get(&bm->vdata, v, CD_BWEIGHT); if (weight == 0.0f) { @@ -187,7 +184,9 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes } } - if (harden_normals && !(((Mesh *)ctx->object->data)->flag & ME_AUTOSMOOTH)) { + Object *ob = ctx->object; + + if (harden_normals && (ob->type == OB_MESH) && !(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) { modifier_setError(md, "Enable 'Auto Smooth' option in mesh settings for hardening"); harden_normals = false; } diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index 3c4dd9f2c56..1a6d172d2f9 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -125,12 +125,14 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte { ClothModifierData *clmd = (ClothModifierData *)md; if (clmd != NULL) { - DEG_add_collision_relations(ctx->node, - ctx->object, - clmd->coll_parms->group, - eModifierType_Collision, - NULL, - "Cloth Collision"); + if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) { + DEG_add_collision_relations(ctx->node, + ctx->object, + clmd->coll_parms->group, + eModifierType_Collision, + NULL, + "Cloth Collision"); + } DEG_add_forcefield_relations( ctx->node, ctx->object, clmd->sim_parms->effector_weights, true, 0, "Cloth Field"); } diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index c41abfb6eb2..cff700e8d45 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -200,8 +200,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes updateFaceCount(ctx, dmd, bm->totface); result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); - BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && - bm->ftoolflagpool == NULL); /* make sure we never alloc'd these */ + /* make sure we never alloc'd these */ + BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL); BLI_assert(bm->vtable == NULL && bm->etable == NULL && bm->ftable == NULL); BM_mesh_free(bm); diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index ce488a224aa..26ee75140a6 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -112,16 +112,17 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes return mesh; } -static bool is_brush_cb(Object *UNUSED(ob), ModifierData *pmd) +static bool is_brush_cb(Object *UNUSED(ob), ModifierData *md) { - return ((DynamicPaintModifierData *)pmd)->brush != NULL; + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; + return (pmd->brush != NULL && pmd->type == MOD_DYNAMICPAINT_TYPE_BRUSH); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; /* Add relation from canvases to all brush objects. */ - if (pmd->canvas != NULL) { + if (pmd->canvas != NULL && pmd->type == MOD_DYNAMICPAINT_TYPE_CANVAS) { for (DynamicPaintSurface *surface = pmd->canvas->surfaces.first; surface; surface = surface->next) { if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) { diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index 857c69eab50..11f001d7a85 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -335,7 +335,7 @@ static Mesh *doMirrorOnAxis(MirrorModifierData *mmd, } /* handle custom split normals */ - if ((((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) && + if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) && CustomData_has_layer(&result->ldata, CD_CUSTOMLOOPNORMAL)) { const int totloop = result->totloop; const int totpoly = result->totpoly; diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c index 5d7b380a751..021e61bd46d 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.c +++ b/source/blender/modifiers/intern/MOD_particlesystem.c @@ -138,8 +138,16 @@ static void deformVerts(ModifierData *md, } /* TODO(sergey): This is not how particles were working prior to copy on * write, but now evaluation is similar to case when one duplicates the - * object. In that case particles were doing reset here. */ - psys->recalc |= ID_RECALC_PSYS_RESET; + * object. In that case particles were doing reset here. + * + * Don't do reset when entering particle edit mode, as that will destroy the edit mode data. + * Shouldn't be an issue, since particles are supposed to be evaluated once prior to entering + * edit mode anyway. + * Could in theory be an issue when everything is done in a script, but then solution is + * not known to me. */ + if (ctx->object->mode != OB_MODE_PARTICLE_EDIT) { + psys->recalc |= ID_RECALC_PSYS_RESET; + } } /* make new mesh */ @@ -193,10 +201,10 @@ static void deformVerts(ModifierData *md, psmd->mesh_final->totedge != psmd->totdmedge || psmd->mesh_final->totface != psmd->totdmface)) { psys->recalc |= ID_RECALC_PSYS_RESET; - psmd->totdmvert = psmd->mesh_final->totvert; - psmd->totdmedge = psmd->mesh_final->totedge; - psmd->totdmface = psmd->mesh_final->totface; } + psmd->totdmvert = psmd->mesh_final->totvert; + psmd->totdmedge = psmd->mesh_final->totedge; + psmd->totdmface = psmd->mesh_final->totface; if (!(ctx->object->transflag & OB_NO_PSYS_UPDATE)) { struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 79f7e52681b..64f5f14eaa8 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -132,6 +132,9 @@ static Mesh *mesh_remove_doubles_on_axis(Mesh *result, tot_doubles += 1; copy_v3_v3(mvert_new[i].co, axis_co); } + else { + mvert_new[i].flag &= ~ME_VERT_TMP_TAG & 0xFF; + } } if (tot_doubles != 0) { @@ -438,6 +441,10 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes med_new->v2 = med_orig->v2; med_new->crease = med_orig->crease; med_new->flag = med_orig->flag & ~ME_LOOSEEDGE; + /* Tag mvert as not loose. + * NOTE: ME_VERT_TMP_TAG is given to be cleared by BKE_mesh_new_nomain_from_template. */ + mvert_new[med_orig->v1].flag |= ME_VERT_TMP_TAG; + mvert_new[med_orig->v2].flag |= ME_VERT_TMP_TAG; } /* build polygon -> edge map */ @@ -899,6 +906,9 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes med_new->v1 = varray_stride + j; med_new->v2 = med_new->v1 - totvert; med_new->flag = ME_EDGEDRAW | ME_EDGERENDER; + if ((mv_new_base->flag & ME_VERT_TMP_TAG) == 0) { + med_new->flag |= ME_LOOSEEDGE; + } med_new++; } } @@ -917,6 +927,9 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes med_new->v1 = i; med_new->v2 = varray_stride + i; med_new->flag = ME_EDGEDRAW | ME_EDGERENDER; + if ((mvert_new[i].flag & ME_VERT_TMP_TAG) == 0) { + med_new->flag |= ME_LOOSEEDGE; + } med_new++; } } diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index 88135b8790b..05bcc7f695d 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -841,8 +841,10 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes /* notice we use 'mp->totloop' which is later overwritten, * we could lookup the original face but there's no point since this is a copy * and will have the same value, just take care when changing order of assignment */ - k1 = mpoly[pidx].loopstart + - (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop); /* prev loop */ + + /* prev loop */ + k1 = mpoly[pidx].loopstart + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop); + k2 = mpoly[pidx].loopstart + (edge_order[eidx]); mp->totloop = 4; diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index 79db436ec4e..88765f1d165 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -32,6 +32,7 @@ #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_scene.h" @@ -514,6 +515,7 @@ static void node_composit_init_rlayers(const bContext *C, PointerRNA *ptr) int sock_index = 0; node->id = &scene->id; + id_us_plus(node->id); for (bNodeSocket *sock = node->outputs.first; sock; sock = sock->next, sock_index++) { NodeImageLayer *sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer"); diff --git a/source/blender/nodes/composite/nodes/node_composite_movieclip.c b/source/blender/nodes/composite/nodes/node_composite_movieclip.c index e871b764a82..07b339a5b78 100644 --- a/source/blender/nodes/composite/nodes/node_composite_movieclip.c +++ b/source/blender/nodes/composite/nodes/node_composite_movieclip.c @@ -24,6 +24,7 @@ #include "node_composite_util.h" #include "BKE_context.h" +#include "BKE_library.h" static bNodeSocketTemplate cmp_node_movieclip_out[] = { {SOCK_RGBA, 0, N_("Image")}, @@ -42,6 +43,7 @@ static void init(const bContext *C, PointerRNA *ptr) MovieClipUser *user = MEM_callocN(sizeof(MovieClipUser), "node movie clip user"); node->id = (ID *)scene->clip; + id_us_plus(node->id); node->storage = user; user->framenr = 1; } diff --git a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c index dbdd65c5976..d218f7568eb 100644 --- a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c +++ b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c @@ -24,6 +24,7 @@ #include "node_composite_util.h" #include "BKE_context.h" +#include "BKE_library.h" /* **************** Translate ******************** */ @@ -53,6 +54,7 @@ static void init(const bContext *C, PointerRNA *ptr) Scene *scene = CTX_data_scene(C); node->id = (ID *)scene->clip; + id_us_plus(node->id); } static void storage_free(bNode *node) diff --git a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c index 55d4ada0ca1..c13356f72b0 100644 --- a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c +++ b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c @@ -24,6 +24,7 @@ #include "node_composite_util.h" #include "BKE_context.h" +#include "BKE_library.h" /* **************** Translate ******************** */ @@ -43,6 +44,7 @@ static void init(const bContext *C, PointerRNA *ptr) Scene *scene = CTX_data_scene(C); node->id = (ID *)scene->clip; + id_us_plus(node->id); /* default to bilinear, see node_sampler_type_items in rna_nodetree.c */ node->custom1 = 1; diff --git a/source/blender/nodes/composite/nodes/node_composite_switchview.c b/source/blender/nodes/composite/nodes/node_composite_switchview.c index 12401a8bbdf..92e06307afb 100644 --- a/source/blender/nodes/composite/nodes/node_composite_switchview.c +++ b/source/blender/nodes/composite/nodes/node_composite_switchview.c @@ -23,6 +23,8 @@ */ #include "BKE_context.h" +#include "BKE_library.h" + #include "../node_composite_util.h" /* **************** SWITCH VIEW ******************** */ @@ -122,6 +124,7 @@ static void init_switch_view(const bContext *C, PointerRNA *ptr) /* store scene for updates */ node->id = (ID *)scene; + id_us_plus(node->id); if (scene) { RenderData *rd = &scene->r; diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c index 70432e04180..f0cd2273e67 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.c +++ b/source/blender/nodes/shader/nodes/node_shader_math.c @@ -64,9 +64,8 @@ static void node_shader_exec_math(void *UNUSED(data), break; } case NODE_MATH_SIN: { - if (in[0]->hasinput || - !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ - { + /* This one only takes one input, so we've got to choose. */ + if (in[0]->hasinput || !in[1]->hasinput) { r = sinf(a); } else { @@ -75,9 +74,8 @@ static void node_shader_exec_math(void *UNUSED(data), break; } case NODE_MATH_COS: { - if (in[0]->hasinput || - !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ - { + /* This one only takes one input, so we've got to choose. */ + if (in[0]->hasinput || !in[1]->hasinput) { r = cosf(a); } else { @@ -86,9 +84,8 @@ static void node_shader_exec_math(void *UNUSED(data), break; } case NODE_MATH_TAN: { - if (in[0]->hasinput || - !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ - { + /* This one only takes one input, so we've got to choose. */ + if (in[0]->hasinput || !in[1]->hasinput) { r = tanf(a); } else { @@ -97,8 +94,8 @@ static void node_shader_exec_math(void *UNUSED(data), break; } case NODE_MATH_ASIN: { - if (in[0]->hasinput || - !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */ + /* This one only takes one input, so we've got to choose. */ + if (in[0]->hasinput || !in[1]->hasinput) { /* Can't do the impossible... */ if (a <= 1 && a >= -1) { r = asinf(a); @@ -119,8 +116,8 @@ static void node_shader_exec_math(void *UNUSED(data), break; } case NODE_MATH_ACOS: { - if (in[0]->hasinput || - !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */ + /* This one only takes one input, so we've got to choose. */ + if (in[0]->hasinput || !in[1]->hasinput) { /* Can't do the impossible... */ if (a <= 1 && a >= -1) { r = acosf(a); @@ -141,9 +138,8 @@ static void node_shader_exec_math(void *UNUSED(data), break; } case NODE_MATH_ATAN: { - if (in[0]->hasinput || - !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ - { + /* This one only takes one input, so we've got to choose. */ + if (in[0]->hasinput || !in[1]->hasinput) { r = atan(a); } else { @@ -200,9 +196,8 @@ static void node_shader_exec_math(void *UNUSED(data), break; } case NODE_MATH_ROUND: { - if (in[0]->hasinput || - !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ - { + /* This one only takes one input, so we've got to choose. */ + if (in[0]->hasinput || !in[1]->hasinput) { r = (a < 0) ? (int)(a - 0.5f) : (int)(a + 0.5f); } else { @@ -246,9 +241,8 @@ static void node_shader_exec_math(void *UNUSED(data), break; } case NODE_MATH_FLOOR: { - if (in[0]->hasinput || - !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ - { + /* This one only takes one input, so we've got to choose. */ + if (in[0]->hasinput || !in[1]->hasinput) { r = floorf(a); } else { @@ -257,9 +251,8 @@ static void node_shader_exec_math(void *UNUSED(data), break; } case NODE_MATH_CEIL: { - if (in[0]->hasinput || - !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ - { + /* This one only takes one input, so we've got to choose. */ + if (in[0]->hasinput || !in[1]->hasinput) { r = ceilf(a); } else { @@ -268,9 +261,8 @@ static void node_shader_exec_math(void *UNUSED(data), break; } case NODE_MATH_FRACT: { - if (in[0]->hasinput || - !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ - { + /* This one only takes one input, so we've got to choose. */ + if (in[0]->hasinput || !in[1]->hasinput) { r = a - floorf(a); } else { @@ -279,9 +271,8 @@ static void node_shader_exec_math(void *UNUSED(data), break; } case NODE_MATH_SQRT: { - if (in[0]->hasinput || - !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ - { + /* This one only takes one input, so we've got to choose. */ + if (in[0]->hasinput || !in[1]->hasinput) { if (a > 0) { r = sqrt(a); } diff --git a/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c b/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c index 583ec7edcc3..3a47fe3e991 100644 --- a/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c +++ b/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c @@ -38,6 +38,10 @@ static int node_shader_gpu_shadertorgb(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { + /* Because node_shader_to_rgba is using fallback_cubemap() + * we need to tag material as glossy. */ + GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY); + return GPU_stack_link(mat, node, "node_shader_to_rgba", in, out); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vectMath.c b/source/blender/nodes/shader/nodes/node_shader_vectMath.c index c6b74e2a727..41273a6dc1d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vectMath.c +++ b/source/blender/nodes/shader/nodes/node_shader_vectMath.c @@ -78,8 +78,8 @@ static void node_shader_exec_vect_math(void *UNUSED(data), out[1]->vec[0] = normalize_v3(out[0]->vec); } else if (node->custom1 == 5) { /* Normalize */ - if (in[0]->hasinput || - !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */ + /* This one only takes one input, so we've got to choose. */ + if (in[0]->hasinput || !in[1]->hasinput) { out[0]->vec[0] = vec1[0]; out[0]->vec[1] = vec1[1]; out[0]->vec[2] = vec1[2]; diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp index a4f799974e3..33c65a0cf95 100644 --- a/source/blender/physics/intern/hair_volume.cpp +++ b/source/blender/physics/intern/hair_volume.cpp @@ -698,8 +698,8 @@ void BPH_hair_volume_normalize_vertex_grid(HairGrid *grid) } } -static const float density_threshold = - 0.001f; /* cells with density below this are considered empty */ +/* Cells with density below this are considered empty. */ +static const float density_threshold = 0.001f; /* Contribution of target density pressure to the laplacian in the pressure poisson equation. * This is based on the model found in diff --git a/source/blender/python/generic/imbuf_py_api.c b/source/blender/python/generic/imbuf_py_api.c index 26e4e5bcf32..22be0429ea5 100644 --- a/source/blender/python/generic/imbuf_py_api.c +++ b/source/blender/python/generic/imbuf_py_api.c @@ -24,6 +24,7 @@ #include "BLI_utildefines.h" #include "BLI_string.h" +#include "BLI_rect.h" #include "py_capi_utils.h" @@ -105,6 +106,43 @@ static PyObject *py_imbuf_resize(Py_ImBuf *self, PyObject *args, PyObject *kw) Py_RETURN_NONE; } +PyDoc_STRVAR(py_imbuf_crop_doc, + ".. method:: crop(min, max)\n" + "\n" + " Crop the image.\n" + "\n" + " :arg min: X, Y minimum.\n" + " :type min: pair of ints\n" + " :arg max: X, Y maximum.\n" + " :type max: pair of ints\n"); +static PyObject *py_imbuf_crop(Py_ImBuf *self, PyObject *args, PyObject *kw) +{ + PY_IMBUF_CHECK_OBJ(self); + + rcti crop; + + static const char *_keywords[] = {"min", "max", NULL}; + static _PyArg_Parser _parser = {"(II)(II):crop", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, &crop.xmin, &crop.ymin, &crop.xmax, &crop.ymax)) { + return NULL; + } + + if (/* X range. */ + (!(crop.xmin >= 0 && crop.xmax < self->ibuf->x)) || + /* Y range. */ + (!(crop.ymin >= 0 && crop.ymax < self->ibuf->y)) || + /* X order. */ + (!(crop.xmin <= crop.xmax)) || + /* Y order. */ + (!(crop.ymin <= crop.ymax))) { + PyErr_SetString(PyExc_ValueError, "ImBuf crop min/max not in range"); + return NULL; + } + IMB_rect_crop(self->ibuf, &crop); + Py_RETURN_NONE; +} + PyDoc_STRVAR(py_imbuf_copy_doc, ".. method:: copy()\n" "\n" @@ -138,14 +176,12 @@ static PyObject *py_imbuf_free(Py_ImBuf *self) } static struct PyMethodDef Py_ImBuf_methods[] = { - {"resize", - (PyCFunction)py_imbuf_resize, - METH_VARARGS | METH_KEYWORDS, - (char *)py_imbuf_resize_doc}, - {"free", (PyCFunction)py_imbuf_free, METH_NOARGS, (char *)py_imbuf_free_doc}, - {"copy", (PyCFunction)py_imbuf_copy, METH_NOARGS, (char *)py_imbuf_copy_doc}, - {"__copy__", (PyCFunction)py_imbuf_copy, METH_NOARGS, (char *)py_imbuf_copy_doc}, - {"__deepcopy__", (PyCFunction)py_imbuf_deepcopy, METH_VARARGS, (char *)py_imbuf_copy_doc}, + {"resize", (PyCFunction)py_imbuf_resize, METH_VARARGS | METH_KEYWORDS, py_imbuf_resize_doc}, + {"crop", (PyCFunction)py_imbuf_crop, METH_VARARGS | METH_KEYWORDS, (char *)py_imbuf_crop_doc}, + {"free", (PyCFunction)py_imbuf_free, METH_NOARGS, py_imbuf_free_doc}, + {"copy", (PyCFunction)py_imbuf_copy, METH_NOARGS, py_imbuf_copy_doc}, + {"__copy__", (PyCFunction)py_imbuf_copy, METH_NOARGS, py_imbuf_copy_doc}, + {"__deepcopy__", (PyCFunction)py_imbuf_deepcopy, METH_VARARGS, py_imbuf_copy_doc}, {NULL, NULL, 0, NULL}, }; diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 92ba7704b19..b8a83d0588d 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -184,6 +184,49 @@ static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObj return PyC_UnicodeFromByte(path ? path : ""); } +PyDoc_STRVAR(bpy_system_resource_doc, + ".. function:: system_resource(type, path=\"\")\n" + "\n" + " Return a system resource path.\n" + "\n" + " :arg type: string in ['DATAFILES', 'SCRIPTS', 'PYTHON'].\n" + " :type type: string\n" + " :arg path: Optional subdirectory.\n" + " :type path: string\n"); +static PyObject *bpy_system_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + const char *type; + const char *subdir = NULL; + int folder_id; + + const char *path; + + static const char *_keywords[] = {"type", "path", NULL}; + static _PyArg_Parser _parser = {"s|s:system_resource", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &type, &subdir)) { + return NULL; + } + + /* stupid string compare */ + if (STREQ(type, "DATAFILES")) { + folder_id = BLENDER_SYSTEM_DATAFILES; + } + else if (STREQ(type, "SCRIPTS")) { + folder_id = BLENDER_SYSTEM_SCRIPTS; + } + else if (STREQ(type, "PYTHON")) { + folder_id = BLENDER_SYSTEM_PYTHON; + } + else { + PyErr_SetString(PyExc_ValueError, "invalid resource argument"); + return NULL; + } + + path = BKE_appdir_folder_id(folder_id, subdir); + + return PyC_UnicodeFromByte(path ? path : ""); +} + PyDoc_STRVAR( bpy_resource_path_doc, ".. function:: resource_path(type, major=bpy.app.version[0], minor=bpy.app.version[1])\n" @@ -292,6 +335,12 @@ static PyMethodDef meth_bpy_user_resource = { METH_VARARGS | METH_KEYWORDS, NULL, }; +static PyMethodDef meth_bpy_system_resource = { + "system_resource", + (PyCFunction)bpy_system_resource, + METH_VARARGS | METH_KEYWORDS, + bpy_system_resource_doc, +}; static PyMethodDef meth_bpy_resource_path = { "resource_path", (PyCFunction)bpy_resource_path, @@ -398,6 +447,9 @@ void BPy_init_modules(void) meth_bpy_user_resource.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_user_resource, NULL)); PyModule_AddObject(mod, + meth_bpy_system_resource.ml_name, + (PyObject *)PyCFunction_New(&meth_bpy_system_resource, NULL)); + PyModule_AddObject(mod, meth_bpy_resource_path.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_resource_path, NULL)); PyModule_AddObject(mod, diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index b34a41b5af6..71bc01d6b98 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -457,7 +457,7 @@ static bool python_script_exec( fn_dummy_py = PyC_UnicodeFromByte(fn_dummy); - buf = txt_to_buf(text); + buf = txt_to_buf(text, NULL); text->compiled = Py_CompileStringObject(buf, fn_dummy_py, Py_file_input, NULL, -1); MEM_freeN(buf); diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index 29861c56dc0..2c9a25d24bc 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -1386,7 +1386,7 @@ static PyObject *vector_item_internal(VectorObject *self, int i, const bool is_a if (is_attr) { PyErr_Format(PyExc_AttributeError, "Vector.%c: unavailable on %dd vector", - *(((char *)"xyzw") + i), + *(((const char *)"xyzw") + i), self->size); } else { @@ -1415,8 +1415,8 @@ static int vector_ass_item_internal(VectorObject *self, int i, PyObject *value, return -1; } - if ((scalar = PyFloat_AsDouble(value)) == -1.0f && - PyErr_Occurred()) { /* parsed item not a number */ + if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) { + /* parsed item not a number */ PyErr_SetString(PyExc_TypeError, "vector[index] = x: " "assigned value not a number"); @@ -1431,7 +1431,7 @@ static int vector_ass_item_internal(VectorObject *self, int i, PyObject *value, if (is_attr) { PyErr_Format(PyExc_AttributeError, "Vector.%c = x: unavailable on %dd vector", - *(((char *)"xyzw") + i), + *(((const char *)"xyzw") + i), self->size); } else { @@ -1950,8 +1950,8 @@ static PyObject *Vector_div(PyObject *v1, PyObject *v2) return NULL; } - if ((scalar = PyFloat_AsDouble(v2)) == -1.0f && - PyErr_Occurred()) { /* parsed item not a number */ + if ((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) { + /* parsed item not a number */ PyErr_SetString(PyExc_TypeError, "Vector division: " "Vector must be divided by a float"); @@ -1989,8 +1989,8 @@ static PyObject *Vector_idiv(PyObject *v1, PyObject *v2) return NULL; } - if ((scalar = PyFloat_AsDouble(v2)) == -1.0f && - PyErr_Occurred()) { /* parsed item not a number */ + if ((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) { + /* parsed item not a number */ PyErr_SetString(PyExc_TypeError, "Vector division: " "Vector must be divided by a float"); @@ -2392,7 +2392,7 @@ static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(clos * 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)},' % + * print('\t{"%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) * @@ -2544,570 +2544,366 @@ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure /* Python attributes get/set structure: */ /*****************************************************************************/ static PyGetSetDef Vector_getseters[] = { - {(char *)"x", (getter)Vector_axis_get, (setter)Vector_axis_set, Vector_axis_x_doc, (void *)0}, - {(char *)"y", (getter)Vector_axis_get, (setter)Vector_axis_set, Vector_axis_y_doc, (void *)1}, - {(char *)"z", (getter)Vector_axis_get, (setter)Vector_axis_set, Vector_axis_z_doc, (void *)2}, - {(char *)"w", (getter)Vector_axis_get, (setter)Vector_axis_set, Vector_axis_w_doc, (void *)3}, - {(char *)"length", - (getter)Vector_length_get, - (setter)Vector_length_set, - Vector_length_doc, - NULL}, - {(char *)"length_squared", + {"x", (getter)Vector_axis_get, (setter)Vector_axis_set, Vector_axis_x_doc, (void *)0}, + {"y", (getter)Vector_axis_get, (setter)Vector_axis_set, Vector_axis_y_doc, (void *)1}, + {"z", (getter)Vector_axis_get, (setter)Vector_axis_set, Vector_axis_z_doc, (void *)2}, + {"w", (getter)Vector_axis_get, (setter)Vector_axis_set, Vector_axis_w_doc, (void *)3}, + {"length", (getter)Vector_length_get, (setter)Vector_length_set, Vector_length_doc, NULL}, + {"length_squared", (getter)Vector_length_squared_get, (setter)NULL, Vector_length_squared_doc, NULL}, - {(char *)"magnitude", - (getter)Vector_length_get, - (setter)Vector_length_set, - Vector_length_doc, - NULL}, - {(char *)"is_wrapped", + {"magnitude", (getter)Vector_length_get, (setter)Vector_length_set, Vector_length_doc, NULL}, + {"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL}, - {(char *)"is_frozen", + {"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}, + {"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL}, /* 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)}, + {"xx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(0, 0)}, + {"xxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 0)}, + {"xxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 0)}, + {"xxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 1)}, + {"xxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 2)}, + {"xxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 3)}, + {"xxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 1)}, + {"xxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 0)}, + {"xxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 1)}, + {"xxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 2)}, + {"xxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 3)}, + {"xxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 2)}, + {"xxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 0)}, + {"xxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 1)}, + {"xxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 2)}, + {"xxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 3)}, + {"xxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 3)}, + {"xxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 0)}, + {"xxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 1)}, + {"xxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 2)}, + {"xxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 3)}, + {"xy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 1)}, + {"xyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 1, 0)}, + {"xyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 0)}, + {"xyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 1)}, + {"xyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 2)}, + {"xyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 3)}, + {"xyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 1, 1)}, + {"xyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 0)}, + {"xyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 1)}, + {"xyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 2)}, + {"xyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 3)}, + {"xyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 1, 2)}, + {"xyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 0)}, + {"xyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 1)}, + {"xyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 2)}, + {"xyzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 1, 2, 3)}, + {"xyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 1, 3)}, + {"xywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 0)}, + {"xywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 1)}, + {"xywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 1, 3, 2)}, + {"xyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 3)}, + {"xz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 2)}, + {"xzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 2, 0)}, + {"xzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 0)}, + {"xzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 1)}, + {"xzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 2)}, + {"xzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 3)}, + {"xzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 2, 1)}, + {"xzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 0)}, + {"xzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 1)}, + {"xzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 2)}, + {"xzyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 2, 1, 3)}, + {"xzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 2, 2)}, + {"xzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 0)}, + {"xzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 1)}, + {"xzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 2)}, + {"xzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 3)}, + {"xzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 2, 3)}, + {"xzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 0)}, + {"xzwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 2, 3, 1)}, + {"xzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 2)}, + {"xzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 3)}, + {"xw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 3)}, + {"xwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 3, 0)}, + {"xwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 0)}, + {"xwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 1)}, + {"xwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 2)}, + {"xwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 3)}, + {"xwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 3, 1)}, + {"xwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 0)}, + {"xwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 1)}, + {"xwyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 3, 1, 2)}, + {"xwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 3)}, + {"xwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 3, 2)}, + {"xwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 0)}, + {"xwzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 3, 2, 1)}, + {"xwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 2)}, + {"xwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 3)}, + {"xww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 3, 3)}, + {"xwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 0)}, + {"xwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 1)}, + {"xwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 2)}, + {"xwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 3)}, + {"yx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 0)}, + {"yxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 0, 0)}, + {"yxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 0)}, + {"yxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 1)}, + {"yxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 2)}, + {"yxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 3)}, + {"yxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 0, 1)}, + {"yxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 0)}, + {"yxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 1)}, + {"yxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 2)}, + {"yxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 3)}, + {"yxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 0, 2)}, + {"yxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 0)}, + {"yxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 1)}, + {"yxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 2)}, + {"yxzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 0, 2, 3)}, + {"yxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 0, 3)}, + {"yxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 0)}, + {"yxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 1)}, + {"yxwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 0, 3, 2)}, + {"yxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 3)}, + {"yy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(1, 1)}, + {"yyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 0)}, + {"yyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 0)}, + {"yyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 1)}, + {"yyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 2)}, + {"yyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 3)}, + {"yyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 1)}, + {"yyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 0)}, + {"yyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 1)}, + {"yyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 2)}, + {"yyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 3)}, + {"yyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 2)}, + {"yyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 0)}, + {"yyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 1)}, + {"yyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 2)}, + {"yyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 3)}, + {"yyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 3)}, + {"yywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 0)}, + {"yywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 1)}, + {"yywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 2)}, + {"yyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 3)}, + {"yz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 2)}, + {"yzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 2, 0)}, + {"yzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 0)}, + {"yzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 1)}, + {"yzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 2)}, + {"yzxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 2, 0, 3)}, + {"yzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 2, 1)}, + {"yzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 0)}, + {"yzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 1)}, + {"yzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 2)}, + {"yzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 3)}, + {"yzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 2, 2)}, + {"yzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 0)}, + {"yzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 1)}, + {"yzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 2)}, + {"yzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 3)}, + {"yzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 2, 3)}, + {"yzwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 2, 3, 0)}, + {"yzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 1)}, + {"yzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 2)}, + {"yzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 3)}, + {"yw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 3)}, + {"ywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 3, 0)}, + {"ywxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 0)}, + {"ywxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 1)}, + {"ywxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 3, 0, 2)}, + {"ywxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 3)}, + {"ywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 3, 1)}, + {"ywyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 0)}, + {"ywyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 1)}, + {"ywyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 2)}, + {"ywyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 3)}, + {"ywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 3, 2)}, + {"ywzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 3, 2, 0)}, + {"ywzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 1)}, + {"ywzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 2)}, + {"ywzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 3)}, + {"yww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 3, 3)}, + {"ywwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 0)}, + {"ywwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 1)}, + {"ywwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 2)}, + {"ywww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 3)}, + {"zx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 0)}, + {"zxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 0, 0)}, + {"zxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 0)}, + {"zxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 1)}, + {"zxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 2)}, + {"zxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 3)}, + {"zxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 0, 1)}, + {"zxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 0)}, + {"zxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 1)}, + {"zxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 2)}, + {"zxyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 0, 1, 3)}, + {"zxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 0, 2)}, + {"zxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 0)}, + {"zxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 1)}, + {"zxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 2)}, + {"zxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 3)}, + {"zxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 0, 3)}, + {"zxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 0)}, + {"zxwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 0, 3, 1)}, + {"zxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 2)}, + {"zxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 3)}, + {"zy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 1)}, + {"zyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 1, 0)}, + {"zyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 0)}, + {"zyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 1)}, + {"zyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 2)}, + {"zyxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 1, 0, 3)}, + {"zyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 1, 1)}, + {"zyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 0)}, + {"zyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 1)}, + {"zyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 2)}, + {"zyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 3)}, + {"zyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 1, 2)}, + {"zyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 0)}, + {"zyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 1)}, + {"zyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 2)}, + {"zyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 3)}, + {"zyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 1, 3)}, + {"zywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 1, 3, 0)}, + {"zywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 1)}, + {"zywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 2)}, + {"zyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 3)}, + {"zz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(2, 2)}, + {"zzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 0)}, + {"zzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 0)}, + {"zzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 1)}, + {"zzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 2)}, + {"zzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 3)}, + {"zzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 1)}, + {"zzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 0)}, + {"zzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 1)}, + {"zzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 2)}, + {"zzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 3)}, + {"zzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 2)}, + {"zzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 0)}, + {"zzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 1)}, + {"zzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 2)}, + {"zzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 3)}, + {"zzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 3)}, + {"zzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 0)}, + {"zzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 1)}, + {"zzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 2)}, + {"zzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 3)}, + {"zw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 3)}, + {"zwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 3, 0)}, + {"zwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 0)}, + {"zwxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 3, 0, 1)}, + {"zwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 2)}, + {"zwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 3)}, + {"zwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 3, 1)}, + {"zwyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 3, 1, 0)}, + {"zwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 1)}, + {"zwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 2)}, + {"zwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 3)}, + {"zwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 3, 2)}, + {"zwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 0)}, + {"zwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 1)}, + {"zwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 2)}, + {"zwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 3)}, + {"zww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 3, 3)}, + {"zwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 0)}, + {"zwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 1)}, + {"zwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 2)}, + {"zwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 3)}, + {"wx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 0)}, + {"wxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 0, 0)}, + {"wxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 0)}, + {"wxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 1)}, + {"wxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 2)}, + {"wxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 3)}, + {"wxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 0, 1)}, + {"wxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 0)}, + {"wxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 1)}, + {"wxyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 0, 1, 2)}, + {"wxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 3)}, + {"wxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 0, 2)}, + {"wxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 0)}, + {"wxzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 0, 2, 1)}, + {"wxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 2)}, + {"wxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 3)}, + {"wxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 0, 3)}, + {"wxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 0)}, + {"wxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 1)}, + {"wxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 2)}, + {"wxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 3)}, + {"wy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 1)}, + {"wyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 1, 0)}, + {"wyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 0)}, + {"wyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 1)}, + {"wyxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 1, 0, 2)}, + {"wyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 3)}, + {"wyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 1, 1)}, + {"wyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 0)}, + {"wyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 1)}, + {"wyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 2)}, + {"wyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 3)}, + {"wyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 1, 2)}, + {"wyzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 1, 2, 0)}, + {"wyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 1)}, + {"wyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 2)}, + {"wyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 3)}, + {"wyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 1, 3)}, + {"wywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 0)}, + {"wywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 1)}, + {"wywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 2)}, + {"wyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 3)}, + {"wz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 2)}, + {"wzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 2, 0)}, + {"wzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 0)}, + {"wzxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 2, 0, 1)}, + {"wzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 2)}, + {"wzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 3)}, + {"wzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 2, 1)}, + {"wzyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 2, 1, 0)}, + {"wzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 1)}, + {"wzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 2)}, + {"wzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 3)}, + {"wzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 2, 2)}, + {"wzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 0)}, + {"wzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 1)}, + {"wzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 2)}, + {"wzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 3)}, + {"wzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 2, 3)}, + {"wzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 0)}, + {"wzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 1)}, + {"wzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 2)}, + {"wzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 3)}, + {"ww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(3, 3)}, + {"wwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 0)}, + {"wwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 0)}, + {"wwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 1)}, + {"wwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 2)}, + {"wwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 3)}, + {"wwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 1)}, + {"wwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 0)}, + {"wwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 1)}, + {"wwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 2)}, + {"wwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 3)}, + {"wwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 2)}, + {"wwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 0)}, + {"wwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 1)}, + {"wwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 2)}, + {"wwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 3)}, + {"www", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 3)}, + {"wwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 0)}, + {"wwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 1)}, + {"wwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 2)}, + {"wwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 3)}, #undef AXIS_FROM_CHAR #undef SWIZZLE1 diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index cf9bfe99474..b5c2db96c47 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -335,8 +335,10 @@ RenderResult *render_result_new(Render *re, BLI_strncpy(rl->name, view_layer->name, sizeof(rl->name)); rl->layflag = view_layer->layflag; - rl->passflag = - view_layer->passflag; /* for debugging: view_layer->passflag | SCE_PASS_RAYHITS; */ + + /* for debugging: view_layer->passflag | SCE_PASS_RAYHITS; */ + rl->passflag = view_layer->passflag; + rl->rectx = rectx; rl->recty = recty; diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index d4fbbd1ecff..04e3f7e88dc 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -42,6 +42,7 @@ extern "C" { struct ARegion; struct GHashIterator; struct GPUViewport; +struct ID; struct IDProperty; struct ImBuf; struct ImageFormatData; @@ -178,6 +179,10 @@ void WM_autosave_init(struct wmWindowManager *wm); void WM_recover_last_session(struct bContext *C, struct ReportList *reports); void WM_file_tag_modified(void); +struct ID *WM_file_append_datablock(struct bContext *C, + const char *filepath, + const short id_code, + const char *id_name); void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *reports); /* mouse cursors */ @@ -649,7 +654,6 @@ enum { WM_JOB_PRIORITY = (1 << 0), WM_JOB_EXCL_RENDER = (1 << 1), WM_JOB_PROGRESS = (1 << 2), - WM_JOB_SUSPEND = (1 << 3), }; /** Identifying jobs by owner alone is unreliable, this isnt saved, @@ -700,6 +704,7 @@ bool WM_jobs_is_stopped(wmWindowManager *wm, void *owner); void *WM_jobs_customdata_get(struct wmJob *); void WM_jobs_customdata_set(struct wmJob *, void *customdata, void (*free)(void *)); void WM_jobs_timer(struct wmJob *, double timestep, unsigned int note, unsigned int endnote); +void WM_jobs_delay_start(struct wmJob *, double delay_time); void WM_jobs_callbacks(struct wmJob *, void (*startjob)(void *, short *, short *, float *), void (*initjob)(void *), diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index d2a876dfb5e..a0c7e8ef752 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -19,24 +19,35 @@ /** \file * \ingroup wm - */ - -#ifndef __WM_TYPES_H__ -#define __WM_TYPES_H__ - -/** + * + * * Overview of WM structs * ====================== * - * <pre> - * > wmWindowManager (window manager stores a list of windows) - * > > wmWindow (window has an active screen) - * > > > bScreen (link to ScrAreas via 'areabase') - * > > > > ScrArea (stores multiple spaces via space links via 'spacedata') - * > > > > > SpaceLink (base struct for space data for all different space types) - * > > > > ScrArea (stores multiple regions via 'regionbase') - * > > > > > ARegion - * </pre> + * - #wmWindowManager.windows -> #wmWindow <br> + * Window manager stores a list of windows. + * + * - #wmWindow.screen -> #bScreen <br> + * Window has an active screen. + * + * - #bScreen.areabase -> #ScrArea <br> + * Link to #ScrArea. + * + * - #ScrArea.spacedata <br> + * Stores multiple spaces via space links. + * + * - #SpaceLink <br> + * Base struct for space data for all different space types. + * + * - #ScrArea.regionbase -> #ARegion <br> + * Stores multiple regions. + * + * - #bScreen.regionbase -> #ARegion <br> + * Global screen level regions, e.g. popups, popovers, menus. + * + * - #wmWindow.global_areas -> #ScrAreaMap <br> + * Global screen via 'areabase', e.g. top-bar & status-bar. + * * * Window Layout * ============= @@ -95,6 +106,9 @@ * \endcode */ +#ifndef __WM_TYPES_H__ +#define __WM_TYPES_H__ + #ifdef __cplusplus extern "C" { #endif @@ -141,7 +155,7 @@ enum { OPTYPE_REGISTER = (1 << 0), /** Do an undo push after the operator runs. */ OPTYPE_UNDO = (1 << 1), - /** Let Blender grab all input from the WM (X11) */ + /** Let Blender grab all input from the WM (X11). */ OPTYPE_BLOCKING = (1 << 2), OPTYPE_MACRO = (1 << 3), @@ -178,8 +192,10 @@ enum { WM_CURSOR_WRAP_XY, }; -/* context to call operator in for WM_operator_name_call */ -/* rna_ui.c contains EnumPropertyItem's of these, keep in sync */ +/** + * Context to call operator in for #WM_operator_name_call. + * rna_ui.c contains EnumPropertyItem's of these, keep in sync. + */ enum { /* if there's invoke, call it, otherwise exec */ WM_OP_INVOKE_DEFAULT, @@ -448,80 +464,106 @@ typedef struct wmNotifier { #define WM_GESTURE_CIRCLE 5 #define WM_GESTURE_STRAIGHTLINE 6 -/* wmGesture is registered to window listbase, handled by operator callbacks */ -/* tweak gesture is builtin feature */ +/** + * wmGesture is registered to #wmWindow.gesture, handled by operator callbacks. + * Tweak gesture is builtin feature. + */ typedef struct wmGesture { struct wmGesture *next, *prev; - int event_type; /* event->type */ - int type; /* gesture type define */ - rcti winrct; /* bounds of region to draw gesture within */ - int points; /* optional, amount of points stored */ - int points_alloc; /* optional, maximum amount of points stored */ + /** #wmEvent.type */ + int event_type; + /** Gesture type define. */ + int type; + /** bounds of region to draw gesture within. */ + rcti winrct; + /** optional, amount of points stored. */ + int points; + /** optional, maximum amount of points stored. */ + int points_alloc; int modal_state; - /* For modal operators which may be running idle, waiting for an event to activate the gesture. + /** + * For modal operators which may be running idle, waiting for an event to activate the gesture. * Typically this is set when the user is click-dragging the gesture - * (border and circle select for eg). */ + * (box and circle select for eg). + */ uint is_active : 1; - /* Previous value of is-active (use to detect first run & edge cases). */ + /** Previous value of is-active (use to detect first run & edge cases). */ uint is_active_prev : 1; - /* Use for gestures that support both immediate or delayed activation. */ + /** Use for gestures that support both immediate or delayed activation. */ uint wait_for_input : 1; + /** + * customdata + * - for border is a #rcti. + * - for circle is recti, (xmin, ymin) is center, xmax radius. + * - for lasso is short array. + * - for straight line is a recti: (xmin,ymin) is start, (xmax, ymax) is end. + */ void *customdata; - /* customdata for border is a recti */ - /* customdata for circle is recti, (xmin, ymin) is center, xmax radius */ - /* customdata for lasso is short array */ - /* customdata for straight line is a recti: (xmin,ymin) is start, (xmax, ymax) is end */ - /* free pointer to use for operator allocs (if set, its freed on exit)*/ + /** Free pointer to use for operator allocs (if set, its freed on exit). */ wmGenericUserData user_data; } wmGesture; /* ************** wmEvent ************************ */ -/* each event should have full modifier state */ -/* event comes from eventmanager and from keymap */ +/** + * Each event should have full modifier state. + * event comes from event manager and from keymap. + */ typedef struct wmEvent { struct wmEvent *next, *prev; - short type; /* event code itself (short, is also in keymap) */ - short val; /* press, release, scrollvalue */ - int x, y; /* mouse pointer position, screen coord */ - int mval[2]; /* region mouse position, name convention pre 2.5 :) */ - char utf8_buf[6]; /* from, ghost if utf8 is enabled for the platform, - * BLI_str_utf8_size() must _always_ be valid, check - * when assigning s we don't need to check on every access after */ - char ascii; /* from ghost, fallback if utf8 isn't set */ + /** Event code itself (short, is also in keymap). */ + short type; + /** Press, release, scrollvalue. */ + short val; + /** Mouse pointer position, screen coord. */ + int x, y; + /** Region mouse position, name convention pre 2.5 :). */ + int mval[2]; + /** + * From, ghost if utf8 is enabled for the platform, + * #BLI_str_utf8_size() must _always_ be valid, check + * when assigning s we don't need to check on every access after. + */ + char utf8_buf[6]; + /** From ghost, fallback if utf8 isn't set. */ + char ascii; char pad; - /* previous state, used for double click and the 'click' */ + /** Previous state, used for double click and the 'click'. */ short prevtype; short prevval; int prevx, prevy; double prevclicktime; int prevclickx, prevclicky; - /* modifier states */ - short shift, ctrl, alt, oskey; /* oskey is apple or windowskey, value denotes order of pressed */ - short keymodifier; /* rawkey modifier */ + /** Modifier states. */ + /** 'oskey' is apple or windows-key, value denotes order of pressed. */ + short shift, ctrl, alt, oskey; + /** rawkey modifier. */ + short keymodifier; - /* set in case a KM_PRESS went by unhandled */ + /** Set in case a #KM_PRESS went by unhandled. */ char check_click; char check_drag; char is_motion_absolute; - /* keymap item, set by handler (weak?) */ + /** Keymap item, set by handler (weak?). */ const char *keymap_idname; - /* tablet info, only use when the tablet is active */ + /** Tablet info, only use when the tablet is active. */ const struct wmTabletData *tablet_data; /* custom data */ - short custom; /* custom data type, stylus, 6dof, see wm_event_types.h */ + /** Custom data type, stylus, 6dof, see wm_event_types.h */ + short custom; short customdatafree; int pad2; - void *customdata; /* ascii, unicode, mouse coords, angles, vectors, dragdrop info */ + /** Ascii, unicode, mouse coords, angles, vectors, dragdrop info. */ + void *customdata; } wmEvent; @@ -543,32 +585,46 @@ bool WM_event_cursor_click_drag_threshold_met(const wmEvent *event); /* ************** custom wmEvent data ************** */ typedef struct wmTabletData { - int Active; /* 0=EVT_TABLET_NONE, 1=EVT_TABLET_STYLUS, 2=EVT_TABLET_ERASER */ - float Pressure; /* range 0.0 (not touching) to 1.0 (full pressure) */ - float Xtilt; /* range 0.0 (upright) to 1.0 (tilted fully against the tablet surface) */ - float Ytilt; /* as above */ + /** 0=EVT_TABLET_NONE, 1=EVT_TABLET_STYLUS, 2=EVT_TABLET_ERASER. */ + int Active; + /** range 0.0 (not touching) to 1.0 (full pressure). */ + float Pressure; + /** range 0.0 (upright) to 1.0 (tilted fully against the tablet surface). */ + float Xtilt; + /** as above. */ + float Ytilt; } wmTabletData; -typedef enum { /* motion progress, for modal handlers */ - P_NOT_STARTED, - P_STARTING, /* <-- */ - P_IN_PROGRESS, /* <-- only these are sent for NDOF motion*/ - P_FINISHING, /* <-- */ - P_FINISHED, +/** Motion progress, for modal handlers. */ +typedef enum { + P_NOT_STARTED, + P_STARTING, /* <-- */ + P_IN_PROGRESS, /* <-- only these are sent for NDOF motion. */ + P_FINISHING, /* <-- */ + P_FINISHED, } wmProgress; #ifdef WITH_INPUT_NDOF typedef struct wmNDOFMotionData { /* awfully similar to GHOST_TEventNDOFMotionData... */ - /* Each component normally ranges from -1 to +1, but can exceed that. + /** + * Each component normally ranges from -1 to +1, but can exceed that. * These use blender standard view coordinates, - * with positive rotations being CCW about the axis. */ - float tvec[3]; /* translation */ - float rvec[3]; /* rotation: */ - /* axis = (rx,ry,rz).normalized */ - /* amount = (rx,ry,rz).magnitude [in revolutions, 1.0 = 360 deg] */ - float dt; /* time since previous NDOF Motion event */ - wmProgress progress; /* is this the first event, the last, or one of many in between? */ + * with positive rotations being CCW about the axis. + */ + /** Translation. */ + float tvec[3]; + /** Rotation. + * <pre> + * axis = (rx,ry,rz).normalized. + * amount = (rx,ry,rz).magnitude [in revolutions, 1.0 = 360 deg] + * </pre> + */ + float rvec[3]; + /** Time since previous NDOF Motion event. */ + float dt; + /** Is this the first event, the last, or one of many in between? */ + wmProgress progress; } wmNDOFMotionData; #endif /* WITH_INPUT_NDOF */ @@ -581,82 +637,113 @@ typedef enum { typedef struct wmTimer { struct wmTimer *next, *prev; - struct wmWindow *win; /* window this timer is attached to (optional) */ + /** Window this timer is attached to (optional). */ + struct wmWindow *win; - double timestep; /* set by timer user */ - int event_type; /* set by timer user, goes to event system */ - wmTimerFlags flags; /* Various flags controlling timer options, see below. */ - void *customdata; /* set by timer user, to allow custom values */ - - double duration; /* total running time in seconds */ - double delta; /* time since previous step in seconds */ + /** Set by timer user. */ + double timestep; + /** Set by timer user, goes to event system. */ + int event_type; + /** Various flags controlling timer options, see below. */ + wmTimerFlags flags; + /** Set by timer user, to allow custom values. */ + void *customdata; - double ltime; /* internal, last time timer was activated */ - double ntime; /* internal, next time we want to activate the timer */ - double stime; /* internal, when the timer started */ - bool sleep; /* internal, put timers to sleep when needed */ + /** Total running time in seconds. */ + double duration; + /** Time since previous step in seconds. */ + double delta; + + /** Internal, last time timer was activated. */ + double ltime; + /** Internal, next time we want to activate the timer. */ + double ntime; + /** Internal, when the timer started. */ + double stime; + /** Internal, put timers to sleep when needed. */ + bool sleep; } wmTimer; typedef struct wmOperatorType { - const char *name; /* text for ui, undo */ - const char *idname; /* unique identifier */ + /** Text for UI, undo. */ + const char *name; + /** Unique identifier. */ + const char *idname; const char *translation_context; - const char *description; /* tooltips and python docs */ - const char *undo_group; /* identifier to group operators together */ + /** Use for tool-tips and Python docs. */ + const char *description; + /** Identifier to group operators together. */ + const char *undo_group; - /* this callback executes the operator without any interactive input, + /** + * This callback executes the operator without any interactive input, * parameters may be provided through operator properties. cannot use * any interface code or input device state. - * - see defines below for return values */ + * See defines below for return values. + */ int (*exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT; - /* this callback executes on a running operator whenever as property + /** + * This callback executes on a running operator whenever as property * is changed. It can correct its own properties or report errors for * invalid settings in exceptional cases. - * Boolean return value, True denotes a change has been made and to redraw */ + * Boolean return value, True denotes a change has been made and to redraw. + */ bool (*check)(struct bContext *, struct wmOperator *); - /* for modal temporary operators, initially invoke is called. then + /** + * For modal temporary operators, initially invoke is called. then * any further events are handled in modal. if the operation is * canceled due to some external reason, cancel is called - * - see defines below for return values */ + * See defines below for return values. + */ int (*invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT; - /* Called when a modal operator is canceled (not used often). - * Internal cleanup can be done here if needed. */ + /** + * Called when a modal operator is canceled (not used often). + * Internal cleanup can be done here if needed. + */ void (*cancel)(struct bContext *, struct wmOperator *); - /* Modal is used for operators which continuously run, eg: + /** + * Modal is used for operators which continuously run, eg: * fly mode, knife tool, circle select are all examples of modal operators. * Modal operators can handle events which would normally access other operators, - * they keep running until they don't return `OPERATOR_RUNNING_MODAL`. */ + * they keep running until they don't return `OPERATOR_RUNNING_MODAL`. + */ int (*modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT; - /* verify if the operator can be executed in the current context, note - * that the operator might still fail to execute even if this return true */ + /** + * Verify if the operator can be executed in the current context, note + * that the operator might still fail to execute even if this return true. + */ bool (*poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT; - /* Use to check if properties should be displayed in auto-generated UI. - * Use 'check' callback to enforce refreshing. */ + /** + * Use to check if properties should be displayed in auto-generated UI. + * Use 'check' callback to enforce refreshing. + */ bool (*poll_property)(const struct bContext *C, struct wmOperator *op, const PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT; - /* optional panel for redo and repeat, autogenerated if not set */ + /** Optional panel for redo and repeat, auto-generated if not set. */ void (*ui)(struct bContext *, struct wmOperator *); - /* Return a different name to use in the user interface, based on property values. - * The returned string does not need to be freed. */ + /** + * Return a different name to use in the user interface, based on property values. + * The returned string does not need to be freed. + */ const char *(*get_name)(struct wmOperatorType *, struct PointerRNA *); - /* rna for properties */ + /** rna for properties */ struct StructRNA *srna; - /* previous settings - for initializing on re-use */ + /** previous settings - for initializing on re-use */ struct IDProperty *last_properties; /** @@ -668,36 +755,42 @@ typedef struct wmOperatorType { */ PropertyRNA *prop; - /* struct wmOperatorTypeMacro */ + /** struct wmOperatorTypeMacro */ ListBase macro; - /* pointer to modal keymap, do not free! */ + /** pointer to modal keymap, do not free! */ struct wmKeyMap *modalkeymap; - /* python needs the operator type as well */ + /** python needs the operator type as well */ bool (*pyop_poll)(struct bContext *, struct wmOperatorType *ot) ATTR_WARN_UNUSED_RESULT; - /* RNA integration */ + /** RNA integration */ ExtensionRNA ext; - /* Flag last for padding */ + /** Flag last for padding */ short flag; } wmOperatorType; #ifdef WITH_INPUT_IME /* *********** Input Method Editor (IME) *********** */ - -/* similar to GHOST_TEventImeData */ +/** + * \note similar to #GHOST_TEventImeData. + */ typedef struct wmIMEData { size_t result_len, composite_len; - char *str_result; /* utf8 encoding */ - char *str_composite; /* utf8 encoding */ + /** utf8 encoding */ + char *str_result; + /** utf8 encoding */ + char *str_composite; - int cursor_pos; /* cursor position in the IME composition. */ - int sel_start; /* beginning of the selection */ - int sel_end; /* end of the selection */ + /** Cursor position in the IME composition. */ + int cursor_pos; + /** Beginning of the selection. */ + int sel_start; + /** End of the selection. */ + int sel_end; bool is_ime_composing; } wmIMEData; @@ -732,40 +825,52 @@ typedef struct wmDragID { typedef struct wmDrag { struct wmDrag *next, *prev; - int icon, type; /* type, see WM_DRAG defines above */ + int icon; + /** See 'WM_DRAG_' defines above. */ + int type; void *poin; char path[1024]; /* FILE_MAX */ double value; - struct ImBuf *imb; /* if no icon but imbuf should be drawn around cursor */ + /** If no icon but imbuf should be drawn around cursor. */ + struct ImBuf *imb; float scale; int sx, sy; - char opname[200]; /* if set, draws operator name*/ + /** If set, draws operator name. */ + char opname[200]; unsigned int flags; - ListBase ids; /* List of wmDragIDs, all are guaranteed to have the same ID type. */ + /** List of wmDragIDs, all are guaranteed to have the same ID type. */ + ListBase ids; } wmDrag; -/* dropboxes are like keymaps, part of the screen/area/region definition */ -/* allocation and free is on startup and exit */ +/** + * Dropboxes are like keymaps, part of the screen/area/region definition. + * Allocation and free is on startup and exit. + */ typedef struct wmDropBox { struct wmDropBox *next, *prev; - /* test if the dropbox is active, then can print optype name */ + /** Test if the dropbox is active, then can print optype name. */ bool (*poll)(struct bContext *, struct wmDrag *, const wmEvent *, const char **); - /* before exec, this copies drag info to wmDrop properties */ + /** Before exec, this copies drag info to #wmDrop properties. */ void (*copy)(struct wmDrag *, struct wmDropBox *); - /* if poll survives, operator is called */ - wmOperatorType *ot; /* not saved in file, so can be pointer */ + /** + * If poll succeeds, operator is called. + * Not saved in file, so can be pointer. + */ + wmOperatorType *ot; - struct IDProperty - *properties; /* operator properties, assigned to ptr->data and can be written to a file */ - struct PointerRNA *ptr; /* rna pointer to access properties */ + /** Operator properties, assigned to ptr->data and can be written to a file. */ + struct IDProperty *properties; + /** RNA pointer to access properties. */ + struct PointerRNA *ptr; - short opcontext; /* default invoke */ + /** Default invoke. */ + short opcontext; } wmDropBox; diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h index 68ecdeea936..7bb77375934 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h @@ -248,6 +248,9 @@ struct wmGizmo { struct IDProperty *properties; + /** Redraw tag. */ + bool do_draw; + /** Temporary data (assume dirty). */ union { float f; @@ -317,7 +320,7 @@ typedef struct wmGizmoType { wmGizmoFnDrawSelect draw_select; /** Determine if the mouse intersects with the gizmo. - * The calculation should be done in the callback itself, -1 for no seleciton. */ + * The calculation should be done in the callback itself, -1 for no selection. */ wmGizmoFnTestSelect test_select; /** Handler used by the gizmo. Usually handles interaction tied to a gizmo type. */ diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c index 40d99ce8ba6..50c98630a16 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c @@ -927,6 +927,15 @@ wmGizmoGroup *WM_gizmomaptype_group_init_runtime_with_region(wmGizmoMapType *gzm wmGizmoGroup *gzgroup = wm_gizmogroup_new_from_type(gzmap, gzgt); + /* Don't allow duplicates when switching modes for e.g. see: T66229. */ + LISTBASE_FOREACH (wmGizmoGroup *, gzgroup_iter, &gzmap->groups) { + if (gzgroup_iter->type == gzgt) { + if (gzgroup_iter != gzgroup) { + WM_gizmo_group_tag_remove(gzgroup_iter); + } + } + } + wm_gizmomap_highlight_set(gzmap, NULL, NULL, 0); ED_region_tag_redraw(ar); diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index be123bee5df..534474a6221 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -552,6 +552,9 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, bool use_select_bias = false; + /* TODO: waiting for the GPU in the middle of the event loop for every + * mouse move is bad for performance, we need to find a solution to not + * use the GPU or draw something once. (see T61474) */ GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0); /* do the drawing */ gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias); @@ -644,7 +647,7 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C, break; } } - else { + else if (gz->type->draw_select != NULL) { has_3d = true; } } @@ -1239,7 +1242,7 @@ void wm_gizmos_keymap(wmKeyConfig *keyconf) /** \} */ /* wmGizmoMapType */ /* -------------------------------------------------------------------- */ -/** \name Updates for Dynamic Type Registraion +/** \name Updates for Dynamic Type Registration * * \{ */ @@ -1283,32 +1286,6 @@ void WM_gizmoconfig_update(struct Main *bmain) return; } - if (wm_gzmap_type_update_flag & WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE) { - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { - for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { - ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - for (ARegion *ar = regionbase->first; ar; ar = ar->next) { - wmGizmoMap *gzmap = ar->gizmo_map; - if (gzmap != NULL && gzmap->tag_remove_group) { - gzmap->tag_remove_group = false; - - for (wmGizmoGroup *gzgroup = gzmap->groups.first, *gzgroup_next; gzgroup; - gzgroup = gzgroup_next) { - gzgroup_next = gzgroup->next; - if (gzgroup->tag_remove) { - wm_gizmogroup_free(NULL, gzgroup); - ED_region_tag_redraw(ar); - } - } - } - } - } - } - } - wm_gzmap_type_update_flag &= ~WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE; - } - if (wm_gzmap_type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE) { for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type; gzmap_type = gzmap_type->next) { @@ -1352,6 +1329,32 @@ void WM_gizmoconfig_update(struct Main *bmain) wm_gzmap_type_update_flag &= ~WM_GIZMOMAPTYPE_GLOBAL_UPDATE_INIT; } + + if (wm_gzmap_type_update_flag & WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE) { + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + for (ARegion *ar = regionbase->first; ar; ar = ar->next) { + wmGizmoMap *gzmap = ar->gizmo_map; + if (gzmap != NULL && gzmap->tag_remove_group) { + gzmap->tag_remove_group = false; + + for (wmGizmoGroup *gzgroup = gzmap->groups.first, *gzgroup_next; gzgroup; + gzgroup = gzgroup_next) { + gzgroup_next = gzgroup->next; + if (gzgroup->tag_remove) { + wm_gizmogroup_free(NULL, gzgroup); + ED_region_tag_redraw(ar); + } + } + } + } + } + } + } + wm_gzmap_type_update_flag &= ~WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE; + } } /** \} */ diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 56fc38160f0..fc669c9543e 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -188,6 +188,26 @@ static void wm_area_mark_invalid_backbuf(ScrArea *sa) } } +static void wm_region_test_gizmo_do_draw(ARegion *ar, bool tag_redraw) +{ + if (ar->gizmo_map == NULL) { + return; + } + + wmGizmoMap *gzmap = ar->gizmo_map; + for (wmGizmoGroup *gzgroup = WM_gizmomap_group_list(gzmap)->first; gzgroup; + gzgroup = gzgroup->next) { + for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) { + if (gz->do_draw) { + if (tag_redraw) { + ED_region_tag_redraw_no_rebuild(ar); + } + gz->do_draw = false; + } + } + } +} + static void wm_region_test_render_do_draw(const Scene *scene, struct Depsgraph *depsgraph, ScrArea *sa, @@ -817,6 +837,7 @@ static bool wm_draw_update_test_window(wmWindow *win) ED_screen_areas_iter(win, screen, sa) { for (ar = sa->regionbase.first; ar; ar = ar->next) { + wm_region_test_gizmo_do_draw(ar, true); wm_region_test_render_do_draw(scene, depsgraph, sa, ar); if (ar->visible && ar->do_draw) { @@ -848,6 +869,24 @@ static bool wm_draw_update_test_window(wmWindow *win) return false; } +/* Clear drawing flags, after drawing is complete so any draw flags set during + * drawing don't cause any additional redraws. */ +static void wm_draw_update_clear_window(wmWindow *win) +{ + bScreen *screen = WM_window_get_active_screen(win); + + ED_screen_areas_iter(win, screen, sa) + { + for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { + wm_region_test_gizmo_do_draw(ar, false); + } + } + + screen->do_draw_gesture = false; + screen->do_draw_paintcursor = false; + screen->do_draw_drag = false; +} + void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *UNUSED(ar)) { if (win) { @@ -893,10 +932,7 @@ void wm_draw_update(bContext *C) ED_screen_ensure_updated(wm, win, screen); wm_draw_window(C, win); - - screen->do_draw_gesture = false; - screen->do_draw_paintcursor = false; - screen->do_draw_drag = false; + wm_draw_update_clear_window(win); wm_window_swap_buffers(win); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 24040568b7b..76cb78b1e04 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -98,7 +98,7 @@ * Without tools using press events which would prevent click/drag events getting to the gizmos. * * This is not a fool proof solution since since it's possible the gizmo operators would pass - * through thse events when called, see: T65479. + * through these events when called, see: T65479. */ #define USE_GIZMO_MOUSE_PRIORITY_HACK @@ -3235,18 +3235,34 @@ void wm_event_do_handlers(bContext *C) if (scene_eval != NULL) { const int is_playing_sound = BKE_sound_scene_playing(scene_eval); - if (is_playing_sound != -1) { + if (scene_eval->id.recalc & ID_RECALC_AUDIO_SEEK) { + /* Ignore seek here, the audio will be updated to the scene frame after jump during next + * dependency graph update. */ + } + else if (is_playing_sound != -1) { bool is_playing_screen; is_playing_screen = (ED_screen_animation_playing(wm) != NULL); if (((is_playing_sound == 1) && (is_playing_screen == 0)) || ((is_playing_sound == 0) && (is_playing_screen == 1))) { + wmWindow *context_old_win = CTX_wm_window(C); + bScreen *context_screen_win = CTX_wm_screen(C); + Scene *context_scene_win = CTX_data_scene(C); + + CTX_wm_window_set(C, win); + CTX_wm_screen_set(C, screen); + CTX_data_scene_set(C, scene); + ED_screen_animation_play(C, -1, 1); + + CTX_data_scene_set(C, context_scene_win); + CTX_wm_screen_set(C, context_screen_win); + CTX_wm_window_set(C, context_old_win); } if (is_playing_sound == 0) { - const float time = BKE_sound_sync_scene(scene); + const float time = BKE_sound_sync_scene(scene_eval); if (isfinite(time)) { int ncfra = time * (float)FPS + 0.5f; if (ncfra != scene->r.cfra) { diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index fe93e39b085..48b09b0d329 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -623,8 +623,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* we didn't succeed, now try to read Blender file */ if (retval == BKE_READ_EXOTIC_OK_BLEND) { - bool use_data = true; - bool use_userdef = false; const int G_f_orig = G.f; ListBase wmbase; @@ -634,7 +632,17 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* confusing this global... */ G.relbase_valid = 1; - retval = BKE_blendfile_read(C, filepath, &(const struct BlendFileReadParams){0}, reports); + retval = BKE_blendfile_read( + C, + filepath, + /* Loading preferences when the user intended to load a regular file is a security risk, + * because the excluded path list is also loaded. + * Further it's just confusing if a user loads a file and various preferences change. */ + &(const struct BlendFileReadParams){ + .is_startup = false, + .skip_flags = BLO_READ_SKIP_USERDEF, + }, + reports); /* BKE_file_read sets new Main into context. */ Main *bmain = CTX_data_main(C); @@ -660,18 +668,14 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm); WM_check(C); /* opens window(s), checks keymaps */ - if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) { - /* in case a userdef is read from regular .blend */ - wm_init_userdef(bmain, false); - use_userdef = true; - } - if (retval != BKE_BLENDFILE_READ_FAIL) { if (do_history) { wm_history_file_update(); } } + const bool use_data = true; + const bool use_userdef = false; wm_file_read_post(C, false, false, use_data, use_userdef, false); success = true; @@ -1376,7 +1380,7 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo /* operator now handles overwrite checks */ if (G.fileflags & G_FILE_AUTOPACK) { - packAll(bmain, reports, false); + BKE_packedfile_pack_all(bmain, reports, false); } /* don't forget not to return without! */ @@ -1861,7 +1865,9 @@ void WM_OT_read_factory_userpref(wmOperatorType *ot) { ot->name = "Load Factory Preferences"; ot->idname = "WM_OT_read_factory_userpref"; - ot->description = "Load default preferences"; + ot->description = + "Load factory default preferences. " + "To make changes to preferences permanent, use \"Save Preferences\""; ot->invoke = WM_operator_confirm; ot->exec = wm_userpref_read_exec; @@ -2034,7 +2040,9 @@ void WM_OT_read_factory_settings(wmOperatorType *ot) { ot->name = "Load Factory Settings"; ot->idname = "WM_OT_read_factory_settings"; - ot->description = "Load default file and preferences"; + ot->description = + "Load factory default startup file and preferences. " + "To make changes permanent, use \"Save Startup File\" and \"Save Preferences\""; ot->invoke = WM_operator_confirm; ot->exec = wm_homefile_read_exec; @@ -2949,7 +2957,12 @@ static void wm_block_file_close_save(bContext *C, void *arg_block, void *arg_dat UI_popup_block_close(C, win, arg_block); if (save_images_when_file_is_closed) { - if (!ED_image_should_save_modified(C)) { + if (ED_image_should_save_modified(C)) { + ReportList *reports = CTX_wm_reports(C); + ED_image_save_all_modified(C, reports); + WM_report_banner_show(); + } + else { execute_callback = false; } } diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 1a46a4550d9..5a6606984ba 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -464,6 +464,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) if (lapp_data->num_items == 0) { /* Early out in case there is nothing to link. */ wm_link_append_data_free(lapp_data); + /* Clear pre existing tag. */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); return OPERATOR_CANCELLED; } @@ -616,10 +618,50 @@ void WM_OT_append(wmOperatorType *ot) "Localize all appended data, including those indirectly linked from other libraries"); } -/** \name Reload/relocate libraries. +/** \name Append single datablock and return it. + * + * Used for appending workspace from startup files. * * \{ */ +ID *WM_file_append_datablock(bContext *C, + const char *filepath, + const short id_code, + const char *id_name) +{ + Main *bmain = CTX_data_main(C); + + /* Tag everything so we can make local only the new datablock. */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); + + /* Define working data, with just the one item we want to append. */ + WMLinkAppendData *lapp_data = wm_link_append_data_new(0); + + wm_link_append_data_library_add(lapp_data, filepath); + WMLinkAppendDataItem *item = wm_link_append_data_item_add(lapp_data, id_name, id_code, NULL); + BLI_BITMAP_ENABLE(item->libraries, 0); + + /* Link datablock. */ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + wm_link_do(lapp_data, NULL, bmain, scene, view_layer, v3d); + + /* Get linked datablock and free working data. */ + ID *id = item->new_id; + wm_link_append_data_free(lapp_data); + + /* Make datablock local. */ + BKE_library_make_local(bmain, NULL, NULL, true, false); + + /* Clear pre existing tag. */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); + + return id; +} + +/** \} */ + static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Library *lib; diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index e74b3c1ef07..f3c94162786 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -166,7 +166,7 @@ void WM_init_state_start_with_console_set(bool value) /** * Since we cannot know in advance if we will require the draw manager * context when starting blender in background mode (specially true with - * scripts) we deferre the ghost initialization the most as possible + * scripts) we defer the ghost initialization the most as possible * so that it does not break anything that can run in headless mode (as in * without display server attached). */ diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index a63592f7b60..a417d80a9a9 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -92,6 +92,8 @@ struct wmJob { /** Running jobs each have own timer */ double timestep; wmTimer *wt; + /** Only start job after specified time delay */ + double start_delay_time; /** The notifier event timers should send */ unsigned int note, endnote; @@ -356,6 +358,11 @@ void WM_jobs_timer(wmJob *wm_job, double timestep, unsigned int note, unsigned i wm_job->endnote = endnote; } +void WM_jobs_delay_start(wmJob *wm_job, double delay_time) +{ + wm_job->start_delay_time = delay_time; +} + void WM_jobs_callbacks(wmJob *wm_job, void (*startjob)(void *, short *, short *, float *), void (*initjob)(void *), @@ -386,9 +393,9 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test) bool suspend = false; /* job added with suspend flag, we wait 1 timer step before activating it */ - if (test->flag & WM_JOB_SUSPEND) { + if (test->start_delay_time > 0.0) { suspend = true; - test->flag &= ~WM_JOB_SUSPEND; + test->start_delay_time = 0.0; } else { /* check other jobs */ @@ -441,6 +448,8 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job) else { if (wm_job->customdata && wm_job->startjob) { + const double timestep = (wm_job->start_delay_time > 0.0) ? wm_job->start_delay_time : + wm_job->timestep; wm_jobs_test_suspend_stop(wm, wm_job); @@ -467,8 +476,12 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job) } /* restarted job has timer already */ + if (wm_job->wt && (wm_job->wt->timestep > timestep)) { + WM_event_remove_timer(wm, wm_job->win, wm_job->wt); + wm_job->wt = WM_event_add_timer(wm, wm_job->win, TIMERJOBS, timestep); + } if (wm_job->wt == NULL) { - wm_job->wt = WM_event_add_timer(wm, wm_job->win, TIMERJOBS, wm_job->timestep); + wm_job->wt = WM_event_add_timer(wm, wm_job->win, TIMERJOBS, timestep); } wm_job->start_time = PIL_check_seconds_timer(); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 63ca46e05c6..367a5a81098 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1151,38 +1151,27 @@ typedef struct wmOpPopUp { /* Only invoked by OK button in popups created with wm_block_dialog_create() */ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2) { - wmOpPopUp *data = arg1; - uiBlock *block = arg2; + wmOperator *op; + { + /* Execute will free the operator. + * In this case, wm_operator_ui_popup_cancel wont run. */ + wmOpPopUp *data = arg1; + op = data->op; + MEM_freeN(data); + } + uiBlock *block = arg2; /* Explicitly set UI_RETURN_OK flag, otherwise the menu might be canceled * in case WM_operator_call_ex exits/reloads the current file (T49199). */ - UI_popup_menu_retval_set(block, UI_RETURN_OK, true); - - WM_operator_call_ex(C, data->op, true); - /* let execute handle freeing it */ - // data->free_op = false; - // data->op = NULL; - - /* in this case, wm_operator_ui_popup_cancel wont run */ - MEM_freeN(data); + UI_popup_menu_retval_set(block, UI_RETURN_OK, true); /* Get context data *after* WM_operator_call_ex * which might have closed the current file and changed context. */ - wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); + UI_popup_block_close(C, win, block); - /* check window before 'block->handle' incase the - * popup execution closed the window and freed the block. see T44688. - */ - /* Post 2.78 TODO: Check if this fix and others related to T44688 are still - * needed or can be improved now that requesting context data has been corrected - * (see above). We're close to release so not a good time for experiments. - * -- Julian - */ - if (BLI_findindex(&wm->windows, win) != -1) { - UI_popup_block_close(C, win, block); - } + WM_operator_call_ex(C, op, true); } /* Dialogs are popups that require user verification (click OK) before exec */ @@ -1478,43 +1467,113 @@ static void wm_block_splash_refreshmenu(bContext *C, void *UNUSED(arg_block), vo ED_region_tag_refresh_ui(ar_menu); } -static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(arg)) +static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, int *y) { - uiBlock *block; - uiBut *but; + if (!(label && label[0])) { + return; + } + uiStyle *style = UI_style_get(); -#ifndef WITH_HEADLESS - extern char datatoc_splash_png[]; - extern int datatoc_splash_png_size; + BLF_size(style->widgetlabel.uifont_id, style->widgetlabel.points, U.pixelsize * U.dpi); + int label_width = BLF_width(style->widgetlabel.uifont_id, label, strlen(label)); + label_width = label_width + U.widget_unit; - extern char datatoc_splash_2x_png[]; - extern int datatoc_splash_2x_png_size; - ImBuf *ibuf; -#else - ImBuf *ibuf = NULL; -#endif + UI_block_emboss_set(block, UI_EMBOSS_NONE); + + uiBut *but = uiDefBut(block, + UI_BTYPE_LABEL, + 0, + label, + x - label_width, + *y, + label_width, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + NULL); + + /* 1 = UI_SELECT, internal flag to draw in white. */ + UI_but_flag_enable(but, 1); + UI_block_emboss_set(block, UI_EMBOSS); + *y -= 12 * U.dpi_fac; +} + +static void wm_block_splash_add_labels(uiBlock *block, int x, int y) +{ + /* Version number. */ + const char *version_suffix = NULL; + bool show_build_info = true; + + if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) { + version_suffix = " Alpha"; + } + else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) { + version_suffix = " Beta"; + } + else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) { + version_suffix = " Release Candidate"; + show_build_info = false; + } + else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) { + version_suffix = STRINGIFY(BLENDER_VERSION_CHAR); + show_build_info = false; + } + + char version_buf[256] = "\0"; + BLI_snprintf(version_buf, + sizeof(version_buf), + "v %d.%d%s", + BLENDER_VERSION / 100, + BLENDER_VERSION % 100, + version_suffix); + + wm_block_splash_add_label(block, version_buf, x, &y); #ifdef WITH_BUILDINFO - int label_delta = 0; - int hash_width, date_width; - char date_buf[128] = "\0"; - char hash_buf[128] = "\0"; - extern unsigned long build_commit_timestamp; - extern char build_hash[], build_commit_date[], build_commit_time[], build_branch[]; + if (show_build_info) { + extern unsigned long build_commit_timestamp; + extern char build_hash[], build_commit_date[], build_commit_time[], build_branch[]; + + /* Date, hidden for builds made from tag. */ + if (build_commit_timestamp != 0) { + char date_buf[256] = "\0"; + BLI_snprintf( + date_buf, sizeof(date_buf), "Date: %s %s", build_commit_date, build_commit_time); + wm_block_splash_add_label(block, date_buf, x, &y); + } - /* Builds made from tag only shows tag sha */ - BLI_snprintf(hash_buf, sizeof(hash_buf), "Hash: %s", build_hash); - BLI_snprintf(date_buf, sizeof(date_buf), "Date: %s %s", build_commit_date, build_commit_time); + /* Hash. */ + char hash_buf[256] = "\0"; + BLI_snprintf(hash_buf, sizeof(hash_buf), "Hash: %s", build_hash); + wm_block_splash_add_label(block, hash_buf, x, &y); - BLF_size(style->widgetlabel.uifont_id, style->widgetlabel.points, U.pixelsize * U.dpi); - hash_width = (int)BLF_width(style->widgetlabel.uifont_id, hash_buf, sizeof(hash_buf)) + - U.widget_unit; - date_width = (int)BLF_width(style->widgetlabel.uifont_id, date_buf, sizeof(date_buf)) + - U.widget_unit; + /* Branch. */ + if (!STREQ(build_branch, "master")) { + char branch_buf[256] = "\0"; + BLI_snprintf(branch_buf, sizeof(branch_buf), "Branch: %s", build_branch); + + wm_block_splash_add_label(block, branch_buf, x, &y); + } + } +#else + UNUSED_VARS(show_build_info); #endif /* WITH_BUILDINFO */ +} +static ImBuf *wm_block_splash_image(void) +{ #ifndef WITH_HEADLESS + extern char datatoc_splash_png[]; + extern int datatoc_splash_png_size; + extern char datatoc_splash_2x_png[]; + extern int datatoc_splash_2x_png_size; + + ImBuf *ibuf = NULL; + if (U.dpi_fac > 1.0) { ibuf = IMB_ibImageFromMemory((const uchar *)datatoc_splash_2x_png, datatoc_splash_2x_png_size, @@ -1541,7 +1600,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar BLI_join_dirfile(splash_filepath, sizeof(splash_filepath), template_directory, - (U.pixelsize == 2) ? "splash_2x.png" : "splash.png"); + (U.dpi_fac > 1.0) ? "splash_2x.png" : "splash.png"); ibuf_template = IMB_loadiffname(splash_filepath, IB_rect, NULL); if (ibuf_template) { const int x_expect = ibuf->x; @@ -1565,7 +1624,17 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar } } } + return ibuf; +#else + return NULL; #endif +} + +static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(arg)) +{ + uiBlock *block; + uiBut *but; + uiStyle *style = UI_style_get(); block = UI_block_begin(C, ar, "splash", UI_EMBOSS); @@ -1575,6 +1644,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP); UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); + ImBuf *ibuf = wm_block_splash_image(); but = uiDefBut(block, UI_BTYPE_IMAGE, 0, @@ -1592,109 +1662,15 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar UI_but_func_set(but, wm_block_splash_close, block, NULL); UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL); - /* label for 'a' bugfix releases, or 'Release Candidate 1'... - * avoids recreating splash for version updates */ - const char *version_suffix = NULL; - - if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) { - version_suffix = " Alpha"; - } - else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) { - version_suffix = " Beta"; - } - else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) { - version_suffix = " Release Candidate"; - } - else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) { - version_suffix = STRINGIFY(BLENDER_VERSION_CHAR); - } - - char *version = BLI_sprintfN( - "Version %d.%d%s", BLENDER_VERSION / 100, BLENDER_VERSION % 100, version_suffix); - - if (version != NULL && version[0]) { - /* placed after the version number in the image, - * placing y is tricky to match baseline */ - /* hack to have text draw 'text_sel' */ - UI_block_emboss_set(block, UI_EMBOSS_NONE); - int x = 202 * U.dpi_fac; - int y = 130 * U.dpi_fac; - int w = 240 * U.dpi_fac; + int x = U.dpi_fac * 502; + int y = U.dpi_fac * 237; - but = uiDefBut(block, UI_BTYPE_LABEL, 0, version, x, y, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL); - /* XXX, set internal flag - UI_SELECT */ - UI_but_flag_enable(but, 1); - UI_block_emboss_set(block, UI_EMBOSS); - } - - MEM_freeN(version); - -#ifdef WITH_BUILDINFO - if (build_commit_timestamp != 0) { - but = uiDefBut(block, - UI_BTYPE_LABEL, - 0, - date_buf, - U.dpi_fac * 502 - date_width, - U.dpi_fac * 237, - date_width, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - NULL); - /* XXX, set internal flag - UI_SELECT */ - UI_but_flag_enable(but, 0); - label_delta = 12; - } - but = uiDefBut(block, - UI_BTYPE_LABEL, - 0, - hash_buf, - U.dpi_fac * 502 - hash_width, - U.dpi_fac * (237 - label_delta), - hash_width, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - NULL); - /* XXX, set internal flag - UI_SELECT */ - UI_but_flag_enable(but, 0); - - if (!STREQ(build_branch, "master")) { - char branch_buf[128] = "\0"; - int branch_width; - BLI_snprintf(branch_buf, sizeof(branch_buf), "Branch: %s", build_branch); - branch_width = (int)BLF_width(style->widgetlabel.uifont_id, branch_buf, sizeof(branch_buf)) + - U.widget_unit; - but = uiDefBut(block, - UI_BTYPE_LABEL, - 0, - branch_buf, - U.dpi_fac * 502 - branch_width, - U.dpi_fac * (225 - label_delta), - branch_width, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - NULL); - /* XXX, set internal flag - UI_SELECT */ - UI_but_flag_enable(but, 0); - } -#endif /* WITH_BUILDINFO */ + wm_block_splash_add_labels(block, x, y); uiLayout *layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, - U.dpi_fac * 40, + U.dpi_fac * 26, 0, U.dpi_fac * 450, U.dpi_fac * 110, diff --git a/source/blender/windowmanager/intern/wm_utils.c b/source/blender/windowmanager/intern/wm_utils.c index c0ee1ec44db..b227065e3cf 100644 --- a/source/blender/windowmanager/intern/wm_utils.c +++ b/source/blender/windowmanager/intern/wm_utils.c @@ -17,7 +17,7 @@ /** \file * \ingroup wm * - * Generic helper utilies that aren't assosiated with a particular area. + * Generic helper utilities that aren't associated with a particular area. */ #include "WM_types.h" diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index ea3596a2143..d17b8817691 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -714,8 +714,14 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm) wm_window_ghostwindow_add(wm, "Blender", win); } - /* happens after fileread */ - wm_window_ensure_eventstate(win); + + if (win->ghostwin != NULL) { + /* If we have no ghostwin this is a buggy window that should be removed. + * However we still need to initialize it correctly so the screen doesn't hang. */ + + /* happens after fileread */ + wm_window_ensure_eventstate(win); + } /* add keymap handlers (1 handler for all keys in map!) */ keymap = WM_keymap_ensure(wm->defaultconf, "Window", 0, 0); @@ -1201,8 +1207,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr //# define USE_WIN_ACTIVATE #endif - wm->winactive = - win; /* no context change! c->wm->windrawable is drawable, or for area queues */ + /* No context change! C->wm->windrawable is drawable, or for area queues. */ + wm->winactive = win; win->active = 1; // window_handle(win, INPUTCHANGE, win->active); @@ -1454,8 +1460,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr event.prevx = event.x; event.prevy = event.y; - wm->winactive = - win; /* no context change! c->wm->windrawable is drawable, or for area queues */ + /* No context change! C->wm->windrawable is drawable, or for area queues. */ + wm->winactive = win; + win->active = 1; wm_event_add(win, &event); diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index f3550034a2f..0a68d2ce6ef 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -926,7 +926,7 @@ static const char arg_handle_debug_mode_generic_set_doc_ffmpeg[] = # ifdef WITH_FREESTYLE static const char arg_handle_debug_mode_generic_set_doc_freestyle[] = "\n\t" - "Enable debug messages for FreeStyle."; + "Enable debug messages for Freestyle."; # endif static const char arg_handle_debug_mode_generic_set_doc_python[] = "\n\t" diff --git a/source/tools b/source/tools -Subproject 33d3969202b855305a9823a9bc67a1d56e4546c +Subproject aa9cc18913aca559e932d5b7894e3c222ccffae |