diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2018-04-11 18:08:25 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2018-04-11 18:08:25 +0300 |
commit | 8e44c30d7176ecb9da06948ae66d5aa9dbd3a85f (patch) | |
tree | 7fbb35e32b9067ad513d5faf82d723a2cf4d736e /source | |
parent | b4c057f42faa81d490bf785272cce27bc7acc0b9 (diff) | |
parent | 8aa6e4d50bfcc0d83985f783228408586b0f877b (diff) |
Merge branch 'master' into soc-2017-normal-tools
Diffstat (limited to 'source')
236 files changed, 4941 insertions, 3139 deletions
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 60fb79d75d5..f6de39c897e 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -169,41 +169,39 @@ void BKE_splineik_execute_tree(struct Scene *scene, struct Object *ob, struct bP void BKE_pose_eval_init(struct EvaluationContext *eval_ctx, struct Scene *scene, - struct Object *ob, - struct bPose *pose); + struct Object *ob); void BKE_pose_eval_init_ik(struct EvaluationContext *eval_ctx, struct Scene *scene, - struct Object *ob, - struct bPose *pose); + struct Object *ob); void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, - struct bPoseChannel *pchan); + int pchan_index); void BKE_pose_constraints_evaluate(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, - struct bPoseChannel *pchan); + int pchan_index); void BKE_pose_bone_done(struct EvaluationContext *eval_ctx, - struct bPoseChannel *pchan); + struct Object *ob, + int pchan_index); void BKE_pose_iktree_evaluate(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, - struct bPoseChannel *rootchan); + int rootchan_index); void BKE_pose_splineik_evaluate(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, - struct bPoseChannel *rootchan); + int rootchan_index); void BKE_pose_eval_flush(struct EvaluationContext *eval_ctx, struct Scene *scene, - struct Object *ob, - struct bPose *pose); + struct Object *ob); void BKE_pose_eval_proxy_copy(struct EvaluationContext *eval_ctx, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h index 84a6d07be7d..a96f8af1fdb 100644 --- a/source/blender/blenkernel/BKE_blender_undo.h +++ b/source/blender/blenkernel/BKE_blender_undo.h @@ -31,22 +31,13 @@ extern "C" { struct bContext; struct Scene; struct Main; +struct MemFileUndoData; #define BKE_UNDO_STR_MAX 64 -/* global undo */ -extern void BKE_undo_write(struct bContext *C, const char *name); -extern void BKE_undo_step(struct bContext *C, int step); -extern void BKE_undo_name(struct bContext *C, const char *name); -extern bool BKE_undo_is_valid(const char *name); -extern void BKE_undo_reset(void); -extern void BKE_undo_number(struct bContext *C, int nr); -extern const char *BKE_undo_get_name(int nr, bool *r_active); -extern const char *BKE_undo_get_name_last(void); -extern bool BKE_undo_save_file(const char *filename); -extern struct Main *BKE_undo_get_main(struct Scene **r_scene); - -extern void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C)); +struct MemFileUndoData *BKE_memfile_undo_encode(struct Main *bmain, struct MemFileUndoData *mfu_prev); +bool BKE_memfile_undo_decode(struct MemFileUndoData *mfu, struct bContext *C); +void BKE_memfile_undo_free(struct MemFileUndoData *mfu); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 57459412efc..1af123759e6 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -67,6 +67,11 @@ void BKE_image_init(struct Image *image); typedef void (StampCallback)(void *data, const char *propname, char *propvalue, int len); void BKE_render_result_stamp_info(struct Scene *scene, struct Object *camera, struct RenderResult *rr, bool allocate_only); +/** + * Fills in the static stamp data (i.e. everything except things that can change per frame). + * The caller is responsible for freeing the allocated memory. + */ +struct StampData *BKE_stamp_info_from_scene_static(struct Scene *scene); void BKE_imbuf_stamp_info(struct RenderResult *rr, struct ImBuf *ibuf); void BKE_stamp_info_from_imbuf(struct RenderResult *rr, struct ImBuf *ibuf); void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCallback callback, bool noskip); diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index d8318bfcf5d..e224155726f 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -84,10 +84,12 @@ typedef struct Main { short minversionfile, minsubversionfile; uint64_t build_commit_timestamp; /* commit's timestamp from buildinfo */ char build_hash[16]; /* hash from buildinfo */ - short recovered; /* indicate the main->name (file) is the recovered one */ + char recovered; /* indicate the main->name (file) is the recovered one */ + /** All current ID's exist in the last memfile undo step. */ + char is_memfile_undo_written; BlendThumbnail *blen_thumb; - + struct Library *curlib; ListBase scene; ListBase library; diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index b0917e4f6cd..18cde156f5e 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -346,6 +346,7 @@ const ModifierTypeInfo *modifierType_getInfo(ModifierType type); * default values if pointer is optional. */ struct ModifierData *modifier_new(int type); +void modifier_free_ex(struct ModifierData *md, const int flag); void modifier_free(struct ModifierData *md); bool modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 5578290c41a..3fea26e7359 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -73,7 +73,7 @@ void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData * bool BKE_object_support_modifier_type_check(struct Object *ob, int modifier_type); void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src); -void BKE_object_free_modifiers(struct Object *ob); +void BKE_object_free_modifiers(struct Object *ob, const int flag); void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob); void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target); diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index f31ae715539..cc60df1b2d6 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -227,7 +227,6 @@ typedef struct PTCacheEditPoint { } PTCacheEditPoint; typedef struct PTCacheUndo { - struct PTCacheUndo *next, *prev; struct PTCacheEditPoint *points; /* particles stuff */ @@ -240,12 +239,11 @@ typedef struct PTCacheUndo { struct ListBase mem_cache; int totpoint; - char name[64]; + + size_t undo_size; } PTCacheUndo; typedef struct PTCacheEdit { - ListBase undo; - struct PTCacheUndo *curundo; PTCacheEditPoint *points; struct PTCacheID pid; diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index b3b1ad23b32..98db06752c8 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -40,6 +40,7 @@ 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); @@ -55,8 +56,8 @@ struct Text *BKE_text_load (struct Main *bmain, const char *file, const char void BKE_text_copy_data(struct Main *bmain, struct Text *ta_dst, const struct Text *ta_src, const int flag); struct Text *BKE_text_copy (struct Main *bmain, const struct Text *ta); void BKE_text_make_local (struct Main *bmain, struct Text *text, const bool lib_local); -void BKE_text_clear (struct Text *text); -void BKE_text_write (struct Text *text, const char *str); +void BKE_text_clear (struct Text *text, struct TextUndoBuf *utxt); +void BKE_text_write (struct Text *text, struct TextUndoBuf *utxt, const char *str); int BKE_text_file_modified_check(struct Text *text); void BKE_text_file_modified_ignore(struct Text *text); @@ -83,29 +84,29 @@ 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); -void txt_delete_word (struct Text *text); -void txt_delete_selected (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_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, const char *in_buffer); -void txt_undo_add_op (struct Text *text, int op); -void txt_do_undo (struct Text *text); -void txt_do_redo (struct Text *text); -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); +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); 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); @@ -135,6 +136,11 @@ enum { TXT_MOVE_LINE_DOWN = 1 }; +typedef struct TextUndoBuf { + char *buf; + int pos, len; +} TextUndoBuf; + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h new file mode 100644 index 00000000000..9697c7dd8e2 --- /dev/null +++ b/source/blender/blenkernel/BKE_undo_system.h @@ -0,0 +1,196 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_UNDO_SYSTEM_H__ +#define __BKE_UNDO_SYSTEM_H__ + +/** \file BKE_undo_system.h + * \ingroup bke + */ + +struct Main; +struct UndoStep; +struct bContext; + +/* ID's */ +struct Mesh; +struct Object; +struct Scene; +struct Text; + +#include "DNA_ID.h" +#include "DNA_listBase.h" + +typedef struct UndoRefID { struct ID *ptr; char name[MAX_ID_NAME]; } UndoRefID; +/* UndoRefID_Mesh & friends. */ +#define UNDO_REF_ID_TYPE(ptr_ty) \ + typedef struct UndoRefID_##ptr_ty { struct ptr_ty *ptr; char name[MAX_ID_NAME]; } UndoRefID_##ptr_ty +UNDO_REF_ID_TYPE(Mesh); +UNDO_REF_ID_TYPE(Object); +UNDO_REF_ID_TYPE(Scene); +UNDO_REF_ID_TYPE(Text); + +typedef struct UndoStack { + ListBase steps; + struct UndoStep *step_active; + + /** + * Some undo systems require begin/end, see: #UndoType.step_encode_init + * + * \note This is not included in the 'steps' list. + * That is done once end is called. + */ + struct UndoStep *step_init; +} UndoStack; + + +typedef struct UndoStep { + struct UndoStep *next, *prev; + char name[64]; + const struct UndoType *type; + /** Size in bytes of all data in step (not including the step). */ + size_t data_size; + /** Users should never see this step (only use for internal consistency). */ + bool skip; + /* Over alloc 'type->struct_size'. */ +} UndoStep; + +typedef enum eUndoTypeMode { + /** + * Each undo step stores a version of the state. + * This means we can simply load in a previous state at any time. + */ + BKE_UNDOTYPE_MODE_STORE = 1, + /** + * Each undo step is a series of edits. + * This means to change states we need to apply each edit. + * It also means the 'step_decode' callback needs to detect the difference between undo and redo. + * (Currently used for text edit and image & sculpt painting). + */ + BKE_UNDOTYPE_MODE_ACCUMULATE = 2, +} eUndoTypeMode; + +typedef void (*UndoTypeForEachIDRefFn)(void *user_data, struct UndoRefID *id_ref); + +typedef struct UndoType { + struct UndoType *next, *prev; + /** Only for debugging. */ + const char *name; + + /** + * When NULL, we don't consider this undo type for context checks. + * Operators must explicitly set the undo type and handle adding the undo step. + * This is needed when tools operate on data which isn't the primary mode (eg, paint-curve in sculpt mode). + */ + bool (*poll)(struct bContext *C); + + /** + * 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. + */ + void (*step_encode_init)(struct bContext *C, UndoStep *us); + + bool (*step_encode)(struct bContext *C, UndoStep *us); + void (*step_decode)(struct bContext *C, UndoStep *us, int dir); + + /** + * \note When freeing all steps, + * free from the last since #MemFileUndoType will merge with the next undo type in the list. */ + void (*step_free)(UndoStep *us); + + void (*step_foreach_ID_ref)(UndoStep *us, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data); + + eUndoTypeMode mode; + bool use_context; + + int step_size; +} UndoType; + +/* expose since we need to perform operations on spesific undo types (rarely). */ +extern const UndoType *BKE_UNDOSYS_TYPE_IMAGE; +extern const UndoType *BKE_UNDOSYS_TYPE_MEMFILE; +extern const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE; +extern const UndoType *BKE_UNDOSYS_TYPE_PARTICLE; +extern const UndoType *BKE_UNDOSYS_TYPE_SCULPT; +extern const UndoType *BKE_UNDOSYS_TYPE_TEXT; + +UndoStack *BKE_undosys_stack_create(void); +void BKE_undosys_stack_destroy(UndoStack *ustack); +void BKE_undosys_stack_clear(UndoStack *ustack); +bool BKE_undosys_stack_has_undo(UndoStack *ustack, const char *name); +void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain); +UndoStep *BKE_undosys_stack_active_with_type(UndoStack *ustack, const UndoType *ut); +UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut); +void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit); + +/* Only some UndoType's require init. */ +UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack, struct bContext *C, const char *name, const UndoType *ut); +UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, struct bContext *C, const char *name); + +bool BKE_undosys_step_push_with_type(UndoStack *ustack, struct bContext *C, const char *name, const UndoType *ut); +bool BKE_undosys_step_push(UndoStack *ustack, struct bContext *C, const char *name); + +UndoStep *BKE_undosys_step_find_by_name_with_type(UndoStack *ustack, const char *name, const UndoType *ut); +UndoStep *BKE_undosys_step_find_by_name(UndoStack *ustack, const char *name); + +bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack, struct bContext *C, UndoStep *us, bool use_skip); +bool BKE_undosys_step_undo_with_data(UndoStack *ustack, struct bContext *C, UndoStep *us); +bool BKE_undosys_step_undo(UndoStack *ustack, struct bContext *C); + +bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack, struct bContext *C, UndoStep *us, bool use_skip); +bool BKE_undosys_step_redo_with_data(UndoStack *ustack, struct bContext *C, UndoStep *us); +bool BKE_undosys_step_redo(UndoStack *ustack, struct bContext *C); + +bool BKE_undosys_step_load_data(UndoStack *ustack, struct bContext *C, UndoStep *us); + +bool BKE_undosys_step_undo_compat_only(UndoStack *ustack, struct bContext *C, int step); +void BKE_undosys_step_undo_from_index(UndoStack *ustack, struct bContext *C, int index); +UndoStep *BKE_undosys_step_same_type_next(UndoStep *us); +UndoStep *BKE_undosys_step_same_type_prev(UndoStep *us); + +/* Type System */ +UndoType *BKE_undosys_type_append(void (*undosys_fn)(UndoType *)); +void BKE_undosys_type_free_all(void); + +/* ID Accessor */ +#if 0 /* functionality is only used internally for now. */ +void BKE_undosys_foreach_ID_ref(UndoStack *ustack, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data); +#endif + +/* Use when the undo step stores many arbitrary pointers. */ +struct UndoIDPtrMap; +struct UndoIDPtrMap *BKE_undosys_ID_map_create(void); +void BKE_undosys_ID_map_destroy(struct UndoIDPtrMap *map); +void BKE_undosys_ID_map_add(struct UndoIDPtrMap *map, ID *id); +struct ID *BKE_undosys_ID_map_lookup(const struct UndoIDPtrMap *map, const struct ID *id_src); + +void BKE_undosys_ID_map_add_with_prev( + struct UndoIDPtrMap *map, struct ID *id, + struct ID **id_prev); +struct ID *BKE_undosys_ID_map_lookup_with_prev( + const struct UndoIDPtrMap *map, struct ID *id_src, + struct ID *id_prev_match[2]); + +void BKE_undosys_ID_map_foreach_ID_ref( + struct UndoIDPtrMap *map, + UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data); + +#endif /* __BKE_UNDO_SYSTEM_H__ */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 25954f277b8..d789671ab24 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -188,6 +188,7 @@ set(SRC intern/tracking_solver.c intern/tracking_stabilize.c intern/tracking_util.c + intern/undo_system.c intern/unit.c intern/world.c intern/writeavi.c @@ -296,6 +297,7 @@ set(SRC BKE_text.h BKE_texture.h BKE_tracking.h + BKE_undo_system.h BKE_unit.h BKE_world.h BKE_writeavi.h diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 2edbd088334..70a3772f388 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -64,7 +64,6 @@ #include "BKE_DerivedMesh.h" #include "BKE_deform.h" #include "BKE_displist.h" -#include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_library.h" #include "BKE_library_query.h" diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index e6bb0d6b7ce..ee63e618b18 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -48,7 +48,6 @@ #include "BIK_api.h" -#include "BKE_global.h" #include "BKE_main.h" #include "DEG_depsgraph.h" @@ -552,12 +551,21 @@ void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_roo /* *************** Depsgraph evaluation callbacks ************ */ +BLI_INLINE bPoseChannel *pose_pchan_get_indexed(Object *ob, int pchan_index) +{ + bPose *pose = ob->pose; + BLI_assert(pose != NULL); + BLI_assert(pchan_index >= 0); + BLI_assert(pchan_index < MEM_allocN_len(pose->chan_array) / sizeof(bPoseChannel *)); + return pose->chan_array[pchan_index]; +} + void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx), Scene *UNUSED(scene), - Object *ob, - bPose *pose) + Object *ob) { - bPoseChannel *pchan; + bPose *pose = ob->pose; + BLI_assert(pose != NULL); DEG_debug_print_eval(__func__, ob->id.name, ob); @@ -570,16 +578,21 @@ void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx), /* imat is needed for solvers. */ invert_m4_m4(ob->imat, ob->obmat); - /* 1. clear flags */ - for (pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) { + const int num_channels = BLI_listbase_count(&pose->chanbase); + pose->chan_array = MEM_malloc_arrayN( + num_channels, sizeof(bPoseChannel *), "pose->chan_array"); + + /* clear flags */ + int pchan_index = 0; + for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) { pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE); + pose->chan_array[pchan_index++] = pchan; } } void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx), Scene *scene, - Object *ob, - bPose *UNUSED(pose)) + Object *ob) { DEG_debug_print_eval(__func__, ob->id.name, ob); BLI_assert(ob->type == OB_ARMATURE); @@ -588,11 +601,11 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx), if (arm->flag & ARM_RESTPOS) { return; } - /* 2a. construct the IK tree (standard IK) */ + /* construct the IK tree (standard IK) */ BIK_initialize_tree(scene, ob, ctime); - /* 2b. construct the Spline IK trees + /* construct the Spline IK trees * - this is not integrated as an IK plugin, since it should be able - * to function in conjunction with standard IK + * to function in conjunction with standard IK */ BKE_pose_splineik_init_tree(scene, ob, ctime); } @@ -600,8 +613,9 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx), void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *ob, - bPoseChannel *pchan) + int pchan_index) { + bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index); DEG_debug_print_eval_subdata( __func__, ob->id.name, ob, "pchan", pchan->name, pchan); BLI_assert(ob->type == OB_ARMATURE); @@ -636,8 +650,9 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx), void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *ob, - bPoseChannel *pchan) + int pchan_index) { + bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index); DEG_debug_print_eval_subdata( __func__, ob->id.name, ob, "pchan", pchan->name, pchan); bArmature *arm = (bArmature *)ob->data; @@ -656,8 +671,10 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx), } void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx), - bPoseChannel *pchan) + struct Object *ob, + int pchan_index) { + bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index); float imat[4][4]; DEG_debug_print_eval(__func__, pchan->name, pchan); if (pchan->bone) { @@ -669,8 +686,9 @@ void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx), void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *ob, - bPoseChannel *rootchan) + int rootchan_index) { + bPoseChannel *rootchan = pose_pchan_get_indexed(ob, rootchan_index); DEG_debug_print_eval_subdata( __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan); BLI_assert(ob->type == OB_ARMATURE); @@ -685,9 +703,10 @@ void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx), void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *ob, - bPoseChannel *rootchan) + int rootchan_index) { + bPoseChannel *rootchan = pose_pchan_get_indexed(ob, rootchan_index); DEG_debug_print_eval_subdata( __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan); BLI_assert(ob->type == OB_ARMATURE); @@ -701,17 +720,23 @@ void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx), void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx), Scene *scene, - Object *ob, - bPose *UNUSED(pose)) + Object *ob) { + bPose *pose = ob->pose; + BLI_assert(pose != NULL); + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ DEG_debug_print_eval(__func__, ob->id.name, ob); BLI_assert(ob->type == OB_ARMATURE); - /* 6. release the IK tree */ + /* release the IK tree */ BIK_release_tree(scene, ob, ctime); ob->recalc &= ~OB_RECALC_ALL; + + BLI_assert(pose->chan_array != NULL); + MEM_freeN(pose->chan_array); + pose->chan_array = NULL; } void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob) diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index 4efca5bcc41..6b31c8c96f9 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -42,28 +42,19 @@ #include "DNA_scene_types.h" -#include "BLI_fileops.h" -#include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" #include "BLI_utildefines.h" -#include "IMB_imbuf.h" -#include "IMB_moviecache.h" - #include "BKE_blender_undo.h" /* own include */ #include "BKE_blendfile.h" #include "BKE_appdir.h" -#include "BKE_brush.h" #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_global.h" -#include "BKE_image.h" #include "BKE_main.h" -#include "RE_pipeline.h" #include "BLO_undofile.h" -#include "BLO_readfile.h" #include "BLO_writefile.h" /* -------------------------------------------------------------------- */ @@ -73,46 +64,21 @@ #define UNDO_DISK 0 -typedef struct UndoElem { - struct UndoElem *next, *prev; - /* Only for 'UNDO_DISK' */ - char filename[FILE_MAX]; - char name[BKE_UNDO_STR_MAX]; - MemFile memfile; - size_t undo_size; -} UndoElem; - -static ListBase undobase = {NULL, NULL}; -static UndoElem *curundo = NULL; - -/** - * Avoid bad-level call to #WM_jobs_kill_all_except() - */ -static void (*undo_wm_job_kill_callback)(struct bContext *C) = NULL; - -void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C)) -{ - undo_wm_job_kill_callback = callback; -} - -static int read_undosave(bContext *C, UndoElem *uel) +bool BKE_memfile_undo_decode(MemFileUndoData *mfu, bContext *C) { char mainstr[sizeof(G.main->name)]; int success = 0, fileflags; - /* This is needed so undoing/redoing doesn't crash with threaded previews going */ - undo_wm_job_kill_callback(C); - BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */ fileflags = G.fileflags; G.fileflags |= G_FILE_NO_UI; if (UNDO_DISK) { - success = (BKE_blendfile_read(C, uel->filename, NULL, 0) != BKE_BLENDFILE_READ_FAIL); + success = (BKE_blendfile_read(C, mfu->filename, NULL, 0) != BKE_BLENDFILE_READ_FAIL); } else { - success = BKE_blendfile_read_from_memfile(C, &uel->memfile, NULL, 0); + success = BKE_blendfile_read_from_memfile(C, &mfu->memfile, NULL, 0); } /* restore */ @@ -127,51 +93,9 @@ static int read_undosave(bContext *C, UndoElem *uel) return success; } -/* name can be a dynamic string */ -void BKE_undo_write(bContext *C, const char *name) +MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev) { - int nr /*, success */ /* UNUSED */; - UndoElem *uel; - - if ((U.uiflag & USER_GLOBALUNDO) == 0) { - return; - } - - if (U.undosteps == 0) { - return; - } - - /* remove all undos after (also when curundo == NULL) */ - while (undobase.last != curundo) { - uel = undobase.last; - BLI_remlink(&undobase, uel); - BLO_memfile_free(&uel->memfile); - MEM_freeN(uel); - } - - /* make new */ - curundo = uel = MEM_callocN(sizeof(UndoElem), "undo file"); - BLI_strncpy(uel->name, name, sizeof(uel->name)); - BLI_addtail(&undobase, uel); - - /* and limit amount to the maximum */ - nr = 0; - uel = undobase.last; - while (uel) { - nr++; - if (nr == U.undosteps) break; - uel = uel->prev; - } - if (uel) { - while (undobase.first != uel) { - UndoElem *first = undobase.first; - BLI_remlink(&undobase, first); - /* the merge is because of compression */ - BLO_memfile_merge(&first->memfile, &first->next->memfile); - MEM_freeN(first); - } - } - + MemFileUndoData *mfu = MEM_callocN(sizeof(MemFileUndoData), __func__); /* disk save version */ if (UNDO_DISK) { @@ -187,222 +111,25 @@ void BKE_undo_write(bContext *C, const char *name) BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter); BLI_make_file_string("/", filename, BKE_tempdir_session(), numstr); - /* success = */ /* UNUSED */ BLO_write_file(CTX_data_main(C), filename, fileflags, NULL, NULL); + /* success = */ /* UNUSED */ BLO_write_file(bmain, filename, fileflags, NULL, NULL); - BLI_strncpy(curundo->filename, filename, sizeof(curundo->filename)); + BLI_strncpy(mfu->filename, filename, sizeof(mfu->filename)); } else { - MemFile *prevfile = NULL; - - if (curundo->prev) prevfile = &(curundo->prev->memfile); - - /* success = */ /* UNUSED */ BLO_write_file_mem(CTX_data_main(C), prevfile, &curundo->memfile, G.fileflags); - curundo->undo_size = curundo->memfile.size; - } - - if (U.undomemory != 0) { - size_t maxmem, totmem; - /* limit to maximum memory (afterwards, we can't know in advance) */ - totmem = 0; - maxmem = ((size_t)U.undomemory) * 1024 * 1024; - - /* keep at least two (original + other) */ - uel = undobase.last; - while (uel && uel->prev) { - totmem += uel->undo_size; - if (totmem > maxmem) break; - uel = uel->prev; - } - - if (uel) { - if (uel->prev && uel->prev->prev) - uel = uel->prev; - - while (undobase.first != uel) { - UndoElem *first = undobase.first; - BLI_remlink(&undobase, first); - /* the merge is because of compression */ - BLO_memfile_merge(&first->memfile, &first->next->memfile); - MEM_freeN(first); - } - } - } -} - -/* 1 = an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */ -void BKE_undo_step(bContext *C, int step) -{ - - if (step == 0) { - read_undosave(C, curundo); - } - else if (step == 1) { - /* curundo should never be NULL, after restart or load file it should call undo_save */ - if (curundo == NULL || curundo->prev == NULL) { - // XXX error("No undo available"); - } - else { - if (G.debug & G_DEBUG) printf("undo %s\n", curundo->name); - curundo = curundo->prev; - read_undosave(C, curundo); - } - } - else { - /* curundo has to remain current situation! */ - - if (curundo == NULL || curundo->next == NULL) { - // XXX error("No redo available"); - } - else { - read_undosave(C, curundo->next); - curundo = curundo->next; - if (G.debug & G_DEBUG) printf("redo %s\n", curundo->name); - } - } -} - -void BKE_undo_reset(void) -{ - UndoElem *uel; - - uel = undobase.first; - while (uel) { - BLO_memfile_free(&uel->memfile); - uel = uel->next; - } - - BLI_freelistN(&undobase); - curundo = NULL; -} - -/* based on index nr it does a restore */ -void BKE_undo_number(bContext *C, int nr) -{ - curundo = BLI_findlink(&undobase, nr); - BKE_undo_step(C, 0); -} - -/* go back to the last occurance of name in stack */ -void BKE_undo_name(bContext *C, const char *name) -{ - UndoElem *uel = BLI_rfindstring(&undobase, name, offsetof(UndoElem, name)); - - if (uel && uel->prev) { - curundo = uel->prev; - BKE_undo_step(C, 0); - } -} - -/* name optional */ -bool BKE_undo_is_valid(const char *name) -{ - if (name) { - UndoElem *uel = BLI_rfindstring(&undobase, name, offsetof(UndoElem, name)); - return uel && uel->prev; + MemFile *prevfile = (mfu_prev) ? &(mfu_prev->memfile) : NULL; + /* success = */ /* UNUSED */ BLO_write_file_mem(bmain, prevfile, &mfu->memfile, G.fileflags); + mfu->undo_size = mfu->memfile.size; } - return undobase.last != undobase.first; -} - -/* get name of undo item, return null if no item with this index */ -/* if active pointer, set it to 1 if true */ -const char *BKE_undo_get_name(int nr, bool *r_active) -{ - UndoElem *uel = BLI_findlink(&undobase, nr); + bmain->is_memfile_undo_written = true; - if (r_active) *r_active = false; - - if (uel) { - if (r_active && (uel == curundo)) { - *r_active = true; - } - return uel->name; - } - return NULL; + return mfu; } -/* return the name of the last item */ -const char *BKE_undo_get_name_last(void) +void BKE_memfile_undo_free(MemFileUndoData *mfu) { - UndoElem *uel = undobase.last; - return (uel ? uel->name : NULL); -} - -/** - * Saves .blend using undo buffer. - * - * \return success. - */ -bool BKE_undo_save_file(const char *filename) -{ - UndoElem *uel; - MemFileChunk *chunk; - int file, oflags; - - if ((U.uiflag & USER_GLOBALUNDO) == 0) { - return false; - } - - uel = curundo; - if (uel == NULL) { - fprintf(stderr, "No undo buffer to save recovery file\n"); - return false; - } - - /* note: This is currently used for autosave and 'quit.blend', where _not_ following symlinks is OK, - * however if this is ever executed explicitly by the user, we may want to allow writing to symlinks. - */ - - oflags = O_BINARY | O_WRONLY | O_CREAT | O_TRUNC; -#ifdef O_NOFOLLOW - /* use O_NOFOLLOW to avoid writing to a symlink - use 'O_EXCL' (CVE-2008-1103) */ - oflags |= O_NOFOLLOW; -#else - /* TODO(sergey): How to deal with symlinks on windows? */ -# ifndef _MSC_VER -# warning "Symbolic links will be followed on undo save, possibly causing CVE-2008-1103" -# endif -#endif - file = BLI_open(filename, oflags, 0666); - - if (file == -1) { - fprintf(stderr, "Unable to save '%s': %s\n", - filename, errno ? strerror(errno) : "Unknown error opening file"); - return false; - } - - for (chunk = uel->memfile.chunks.first; chunk; chunk = chunk->next) { - if (write(file, chunk->buf, chunk->size) != chunk->size) { - break; - } - } - - close(file); - - if (chunk) { - fprintf(stderr, "Unable to save '%s': %s\n", - filename, errno ? strerror(errno) : "Unknown error writing file"); - return false; - } - return true; -} - -/* sets curscene */ -Main *BKE_undo_get_main(Scene **r_scene) -{ - Main *mainp = NULL; - BlendFileData *bfd = BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL, BLO_READ_SKIP_NONE); - - if (bfd) { - mainp = bfd->main; - if (r_scene) { - *r_scene = bfd->curscene; - } - - MEM_freeN(bfd); - } - - return mainp; + BLO_memfile_free(&mfu->memfile); + MEM_freeN(mfu); } /** \} */ diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 8b7118db151..058394fc1b1 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -42,7 +42,6 @@ #include "BKE_animsys.h" #include "BKE_cachefile.h" -#include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_modifier.h" diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 719125b3317..132cbd07ac3 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -47,7 +47,6 @@ #include "BKE_animsys.h" #include "BKE_camera.h" #include "BKE_object.h" -#include "BKE_global.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 2a300cbe47b..8433634f749 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -297,7 +297,10 @@ bool BKE_displist_surfindex_get(DispList *dl, int a, int *b, int *p1, int *p2, i } /* ****************** make displists ********************* */ - +#ifdef __INTEL_COMPILER +/* ICC with the optimization -02 causes crashes. */ +# pragma intel optimization_level 1 +#endif static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase, const bool for_render, const bool use_render_resolution) { diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c index 30ead3ffbb6..7dc6e3575b2 100644 --- a/source/blender/blenkernel/intern/fluidsim.c +++ b/source/blender/blenkernel/intern/fluidsim.c @@ -54,7 +54,6 @@ #include "BKE_customdata.h" #include "BKE_DerivedMesh.h" #include "BKE_fluidsim.h" -#include "BKE_global.h" #include "BKE_modifier.h" #include "BKE_mesh.h" diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 64f25cdcf53..e8b5ce77613 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -46,6 +46,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_moviecache.h" +#include "IMB_metadata.h" #ifdef WITH_OPENEXR # include "intern/openexr/openexr_multi.h" @@ -151,7 +152,7 @@ static void imagecache_put(Image *image, int index, ImBuf *ibuf) if (image->cache == NULL) { // char cache_name[64]; - // BLI_snprintf(cache_name, sizeof(cache_name), "Image Datablock %s", image->id.name); + // SNPRINTF(cache_name, "Image Datablock %s", image->id.name); image->cache = IMB_moviecache_create("Image Datablock Cache", sizeof(ImageCacheKey), imagecache_hashhash, imagecache_hashcmp); @@ -436,7 +437,7 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src) BLI_listbase_clear(lb_dst); for (imapf_src = lb_src->first; imapf_src; imapf_src = imapf_src->next) { ImagePackedFile *imapf_dst = MEM_mallocN(sizeof(ImagePackedFile), "Image Packed Files (copy)"); - BLI_strncpy(imapf_dst->filepath, imapf_src->filepath, sizeof(imapf_dst->filepath)); + STRNCPY(imapf_dst->filepath, imapf_src->filepath); if (imapf_src->packedfile) imapf_dst->packedfile = dupPackedFile(imapf_src->packedfile); @@ -592,7 +593,7 @@ Image *BKE_image_load(Main *bmain, const char *filepath) int file; char str[FILE_MAX]; - BLI_strncpy(str, filepath, sizeof(str)); + STRNCPY(str, filepath); BLI_path_abs(str, bmain->name); /* exists? */ @@ -602,7 +603,7 @@ Image *BKE_image_load(Main *bmain, const char *filepath) close(file); ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE); - BLI_strncpy(ima->name, filepath, sizeof(ima->name)); + STRNCPY(ima->name, filepath); if (BLI_testextensie_array(filepath, imb_ext_movie)) ima->source = IMA_SRC_MOVIE; @@ -621,13 +622,13 @@ Image *BKE_image_load_exists_ex(const char *filepath, bool *r_exists) Image *ima; char str[FILE_MAX], strtest[FILE_MAX]; - BLI_strncpy(str, filepath, sizeof(str)); + STRNCPY(str, filepath); BLI_path_abs(str, G.main->name); /* first search an identical filepath */ for (ima = G.main->image.first; ima; ima = ima->id.next) { if (ima->source != IMA_SRC_VIEWER && ima->source != IMA_SRC_GENERATED) { - BLI_strncpy(strtest, ima->name, sizeof(ima->name)); + STRNCPY(strtest, ima->name); BLI_path_abs(strtest, ID_BLEND_PATH(G.main, &ima->id)); if (BLI_path_cmp(strtest, str) == 0) { @@ -668,7 +669,7 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char if (colorspace_settings->name[0] == '\0') { const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_FLOAT); - BLI_strncpy(colorspace_settings->name, colorspace, sizeof(colorspace_settings->name)); + STRNCPY(colorspace_settings->name, colorspace); } if (ibuf != NULL) { @@ -682,7 +683,7 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char if (colorspace_settings->name[0] == '\0') { const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE); - BLI_strncpy(colorspace_settings->name, colorspace, sizeof(colorspace_settings->name)); + STRNCPY(colorspace_settings->name, colorspace); } if (ibuf != NULL) { @@ -695,7 +696,7 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char return NULL; } - BLI_strncpy(ibuf->name, name, sizeof(ibuf->name)); + STRNCPY(ibuf->name, name); ibuf->userflags |= IB_BITMAPDIRTY; switch (gen_type) { @@ -725,7 +726,7 @@ Image *BKE_image_add_generated( int view_id; const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; - /* BLI_strncpy(ima->name, name, FILE_MAX); */ /* don't do this, this writes in ain invalid filepath! */ + /* STRNCPY(ima->name, name); */ /* don't do this, this writes in ain invalid filepath! */ ima->gen_x = width; ima->gen_y = height; ima->gen_type = gen_type; @@ -766,7 +767,7 @@ Image *BKE_image_add_from_imbuf(ImBuf *ibuf, const char *name) ima = image_alloc(G.main, name, IMA_SRC_FILE, IMA_TYPE_IMAGE); if (ima) { - BLI_strncpy(ima->name, ibuf->name, FILE_MAX); + STRNCPY(ima->name, ibuf->name); image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); ima->ok = IMA_OK_LOADED; } @@ -812,7 +813,7 @@ static void image_memorypack_multiview(Image *ima) pf->size = ibuf->encodedsize; imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile"); - BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath)); + STRNCPY(imapf->filepath, iv->filepath); imapf->packedfile = pf; BLI_addtail(&ima->packedfiles, imapf); @@ -862,7 +863,7 @@ void BKE_image_memorypack(Image *ima) pf->size = ibuf->encodedsize; imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile"); - BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath)); + STRNCPY(imapf->filepath, ima->name); imapf->packedfile = pf; BLI_addtail(&ima->packedfiles, imapf); @@ -888,7 +889,7 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath) BLI_addtail(&ima->packedfiles, imapf); imapf->packedfile = newPackedFile(reports, ima->name, basepath); if (imapf->packedfile) { - BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath)); + STRNCPY(imapf->filepath, ima->name); } else { BLI_freelinkN(&ima->packedfiles, imapf); @@ -902,7 +903,7 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath) imapf->packedfile = newPackedFile(reports, iv->filepath, basepath); if (imapf->packedfile) { - BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath)); + STRNCPY(imapf->filepath, iv->filepath); } else { BLI_freelinkN(&ima->packedfiles, imapf); @@ -922,7 +923,7 @@ void BKE_image_packfiles_from_mem(ReportList *reports, Image *ima, char *data, c ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), __func__); BLI_addtail(&ima->packedfiles, imapf); imapf->packedfile = newPackedFileMemory(data, data_len); - BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath)); + STRNCPY(imapf->filepath, ima->name); } } @@ -1622,6 +1623,7 @@ typedef struct StampData { char marker[512]; char time[512]; char frame[512]; + char frame_range[512]; char camera[STAMP_NAME_SIZE]; char cameralens[STAMP_NAME_SIZE]; char scene[STAMP_NAME_SIZE]; @@ -1638,14 +1640,19 @@ typedef struct StampData { } StampData; #undef STAMP_NAME_SIZE -static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int do_prefix) +/** + * \param do_prefix: Include a label like "File ", "Date ", etc. in the stamp data strings. + * \param use_dynamic: Also include data that can change on a per-frame basis. + */ +static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int do_prefix, + bool use_dynamic) { char text[256]; struct tm *tl; time_t t; if (scene->r.stamp & R_STAMP_FILENAME) { - BLI_snprintf(stamp_data->file, sizeof(stamp_data->file), do_prefix ? "File %s" : "%s", G.relbase_valid ? G.main->name : "<untitled>"); + SNPRINTF(stamp_data->file, do_prefix ? "File %s" : "%s", G.relbase_valid ? G.main->name : "<untitled>"); } else { stamp_data->file[0] = '\0'; @@ -1653,7 +1660,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d if (scene->r.stamp & R_STAMP_NOTE) { /* Never do prefix for Note */ - BLI_snprintf(stamp_data->note, sizeof(stamp_data->note), "%s", scene->r.stamp_udata); + SNPRINTF(stamp_data->note, "%s", scene->r.stamp_udata); } else { stamp_data->note[0] = '\0'; @@ -1662,83 +1669,93 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d if (scene->r.stamp & R_STAMP_DATE) { t = time(NULL); tl = localtime(&t); - BLI_snprintf(text, sizeof(text), "%04d/%02d/%02d %02d:%02d:%02d", tl->tm_year + 1900, tl->tm_mon + 1, tl->tm_mday, tl->tm_hour, tl->tm_min, tl->tm_sec); - BLI_snprintf(stamp_data->date, sizeof(stamp_data->date), do_prefix ? "Date %s" : "%s", text); + SNPRINTF(text, "%04d/%02d/%02d %02d:%02d:%02d", + tl->tm_year + 1900, tl->tm_mon + 1, tl->tm_mday, tl->tm_hour, tl->tm_min, tl->tm_sec); + SNPRINTF(stamp_data->date, do_prefix ? "Date %s" : "%s", text); } else { stamp_data->date[0] = '\0'; } - if (scene->r.stamp & R_STAMP_MARKER) { + if (use_dynamic && scene->r.stamp & R_STAMP_MARKER) { const char *name = BKE_scene_find_last_marker_name(scene, CFRA); - if (name) BLI_strncpy(text, name, sizeof(text)); - else BLI_strncpy(text, "<none>", sizeof(text)); + if (name) STRNCPY(text, name); + else STRNCPY(text, "<none>"); - BLI_snprintf(stamp_data->marker, sizeof(stamp_data->marker), do_prefix ? "Marker %s" : "%s", text); + SNPRINTF(stamp_data->marker, do_prefix ? "Marker %s" : "%s", text); } else { stamp_data->marker[0] = '\0'; } - if (scene->r.stamp & R_STAMP_TIME) { + if (use_dynamic && scene->r.stamp & R_STAMP_TIME) { const short timecode_style = USER_TIMECODE_SMPTE_FULL; BLI_timecode_string_from_time(text, sizeof(text), 0, FRA2TIME(scene->r.cfra), FPS, timecode_style); - BLI_snprintf(stamp_data->time, sizeof(stamp_data->time), do_prefix ? "Timecode %s" : "%s", text); + SNPRINTF(stamp_data->time, do_prefix ? "Timecode %s" : "%s", text); } else { stamp_data->time[0] = '\0'; } - if (scene->r.stamp & R_STAMP_FRAME) { + if (use_dynamic && scene->r.stamp & R_STAMP_FRAME) { char fmtstr[32]; int digits = 1; if (scene->r.efra > 9) digits = integer_digits_i(scene->r.efra); - BLI_snprintf(fmtstr, sizeof(fmtstr), do_prefix ? "Frame %%0%di" : "%%0%di", digits); - BLI_snprintf(stamp_data->frame, sizeof(stamp_data->frame), fmtstr, scene->r.cfra); + SNPRINTF(fmtstr, do_prefix ? "Frame %%0%di" : "%%0%di", digits); + SNPRINTF(stamp_data->frame, fmtstr, scene->r.cfra); } else { stamp_data->frame[0] = '\0'; } - if (scene->r.stamp & R_STAMP_CAMERA) { - BLI_snprintf(stamp_data->camera, sizeof(stamp_data->camera), do_prefix ? "Camera %s" : "%s", camera ? camera->id.name + 2 : "<none>"); + if (scene->r.stamp & R_STAMP_FRAME_RANGE) { + SNPRINTF(stamp_data->frame_range, + do_prefix ? "Frame Range %d:%d" : "%d:%d", + scene->r.sfra, scene->r.efra); + } + else { + stamp_data->frame_range[0] = '\0'; + } + + if (use_dynamic && scene->r.stamp & R_STAMP_CAMERA) { + SNPRINTF(stamp_data->camera, do_prefix ? "Camera %s" : "%s", camera ? camera->id.name + 2 : "<none>"); } else { stamp_data->camera[0] = '\0'; } - if (scene->r.stamp & R_STAMP_CAMERALENS) { + if (use_dynamic && scene->r.stamp & R_STAMP_CAMERALENS) { if (camera && camera->type == OB_CAMERA) { - BLI_snprintf(text, sizeof(text), "%.2f", ((Camera *)camera->data)->lens); + SNPRINTF(text, "%.2f", ((Camera *)camera->data)->lens); } else { - BLI_strncpy(text, "<none>", sizeof(text)); + STRNCPY(text, "<none>"); } - BLI_snprintf(stamp_data->cameralens, sizeof(stamp_data->cameralens), do_prefix ? "Lens %s" : "%s", text); + SNPRINTF(stamp_data->cameralens, do_prefix ? "Lens %s" : "%s", text); } else { stamp_data->cameralens[0] = '\0'; } if (scene->r.stamp & R_STAMP_SCENE) { - BLI_snprintf(stamp_data->scene, sizeof(stamp_data->scene), do_prefix ? "Scene %s" : "%s", scene->id.name + 2); + SNPRINTF(stamp_data->scene, do_prefix ? "Scene %s" : "%s", scene->id.name + 2); } else { stamp_data->scene[0] = '\0'; } - if (scene->r.stamp & R_STAMP_SEQSTRIP) { + if (use_dynamic && scene->r.stamp & R_STAMP_SEQSTRIP) { Sequence *seq = BKE_sequencer_foreground_frame_get(scene, scene->r.cfra); - if (seq) BLI_strncpy(text, seq->name + 2, sizeof(text)); - else BLI_strncpy(text, "<none>", sizeof(text)); + if (seq) STRNCPY(text, seq->name + 2); + else STRNCPY(text, "<none>"); - BLI_snprintf(stamp_data->strip, sizeof(stamp_data->strip), do_prefix ? "Strip %s" : "%s", text); + SNPRINTF(stamp_data->strip, do_prefix ? "Strip %s" : "%s", text); } else { stamp_data->strip[0] = '\0'; @@ -1748,22 +1765,29 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d Render *re = RE_GetSceneRender(scene); RenderStats *stats = re ? RE_GetStats(re) : NULL; - if (stats && (scene->r.stamp & R_STAMP_RENDERTIME)) { + if (use_dynamic && stats && (scene->r.stamp & R_STAMP_RENDERTIME)) { BLI_timecode_string_from_time_simple(text, sizeof(text), stats->lastframetime); - BLI_snprintf(stamp_data->rendertime, sizeof(stamp_data->rendertime), do_prefix ? "RenderTime %s" : "%s", text); + SNPRINTF(stamp_data->rendertime, do_prefix ? "RenderTime %s" : "%s", text); } else { stamp_data->rendertime[0] = '\0'; } - if (stats && (scene->r.stamp & R_STAMP_MEMORY)) { - BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), do_prefix ? "Peak Memory %.2fM" : "%.2fM", stats->mem_peak); + if (use_dynamic && stats && (scene->r.stamp & R_STAMP_MEMORY)) { + SNPRINTF(stamp_data->memory, do_prefix ? "Peak Memory %.2fM" : "%.2fM", stats->mem_peak); } else { stamp_data->memory[0] = '\0'; } } + if (scene->r.stamp & R_STAMP_FRAME_RANGE) { + SNPRINTF(stamp_data->frame_range, + do_prefix ? "Frame Range %d:%d" : "%d:%d", scene->r.sfra, scene->r.efra); + } + else { + stamp_data->frame_range[0] = '\0'; + } } /* Will always add prefix. */ @@ -1772,73 +1796,73 @@ static void stampdata_from_template(StampData *stamp_data, const StampData *stamp_data_template) { if (scene->r.stamp & R_STAMP_FILENAME) { - BLI_snprintf(stamp_data->file, sizeof(stamp_data->file), "File %s", stamp_data_template->file); + SNPRINTF(stamp_data->file, "File %s", stamp_data_template->file); } else { stamp_data->file[0] = '\0'; } if (scene->r.stamp & R_STAMP_NOTE) { - BLI_snprintf(stamp_data->note, sizeof(stamp_data->note), "%s", stamp_data_template->note); + SNPRINTF(stamp_data->note, "%s", stamp_data_template->note); } else { stamp_data->note[0] = '\0'; } if (scene->r.stamp & R_STAMP_DATE) { - BLI_snprintf(stamp_data->date, sizeof(stamp_data->date), "Date %s", stamp_data_template->date); + SNPRINTF(stamp_data->date, "Date %s", stamp_data_template->date); } else { stamp_data->date[0] = '\0'; } if (scene->r.stamp & R_STAMP_MARKER) { - BLI_snprintf(stamp_data->marker, sizeof(stamp_data->marker), "Marker %s", stamp_data_template->marker); + SNPRINTF(stamp_data->marker, "Marker %s", stamp_data_template->marker); } else { stamp_data->marker[0] = '\0'; } if (scene->r.stamp & R_STAMP_TIME) { - BLI_snprintf(stamp_data->time, sizeof(stamp_data->time), "Timecode %s", stamp_data_template->time); + SNPRINTF(stamp_data->time, "Timecode %s", stamp_data_template->time); } else { stamp_data->time[0] = '\0'; } if (scene->r.stamp & R_STAMP_FRAME) { - BLI_snprintf(stamp_data->frame, sizeof(stamp_data->frame), "Frame %s", stamp_data_template->frame); + SNPRINTF(stamp_data->frame, "Frame %s", stamp_data_template->frame); } else { stamp_data->frame[0] = '\0'; } if (scene->r.stamp & R_STAMP_CAMERA) { - BLI_snprintf(stamp_data->camera, sizeof(stamp_data->camera), "Camera %s", stamp_data_template->camera); + SNPRINTF(stamp_data->camera, "Camera %s", stamp_data_template->camera); } else { stamp_data->camera[0] = '\0'; } if (scene->r.stamp & R_STAMP_CAMERALENS) { - BLI_snprintf(stamp_data->cameralens, sizeof(stamp_data->cameralens), "Lens %s", stamp_data_template->cameralens); + SNPRINTF(stamp_data->cameralens, "Lens %s", stamp_data_template->cameralens); } else { stamp_data->cameralens[0] = '\0'; } if (scene->r.stamp & R_STAMP_SCENE) { - BLI_snprintf(stamp_data->scene, sizeof(stamp_data->scene), "Scene %s", stamp_data_template->scene); + SNPRINTF(stamp_data->scene, "Scene %s", stamp_data_template->scene); } else { stamp_data->scene[0] = '\0'; } if (scene->r.stamp & R_STAMP_SEQSTRIP) { - BLI_snprintf(stamp_data->strip, sizeof(stamp_data->strip), "Strip %s", stamp_data_template->strip); + SNPRINTF(stamp_data->strip, "Strip %s", stamp_data_template->strip); } else { stamp_data->strip[0] = '\0'; } if (scene->r.stamp & R_STAMP_RENDERTIME) { - BLI_snprintf(stamp_data->rendertime, sizeof(stamp_data->rendertime), "RenderTime %s", stamp_data_template->rendertime); + SNPRINTF(stamp_data->rendertime, "RenderTime %s", stamp_data_template->rendertime); } else { stamp_data->rendertime[0] = '\0'; } if (scene->r.stamp & R_STAMP_MEMORY) { - BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), "Peak Memory %s", stamp_data_template->memory); + SNPRINTF(stamp_data->memory, "Peak Memory %s", stamp_data_template->memory); } else { stamp_data->memory[0] = '\0'; @@ -1884,7 +1908,7 @@ void BKE_image_stamp_buf( display = IMB_colormanagement_display_get_named(display_device); if (stamp_data_template == NULL) { - stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0); + stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0, true); } else { stampdata_from_template(&stamp_data, scene, stamp_data_template); @@ -2105,13 +2129,28 @@ void BKE_render_result_stamp_info(Scene *scene, Object *camera, struct RenderRes } if (!allocate_only) - stampdata(scene, camera, stamp_data, 0); + stampdata(scene, camera, stamp_data, 0, true); if (!rr->stamp_data) { rr->stamp_data = stamp_data; } } +struct StampData *BKE_stamp_info_from_scene_static(Scene *scene) +{ + struct StampData *stamp_data; + + if (!(scene && (scene->r.stamp & R_STAMP_ALL))) + return NULL; + + /* Memory is allocated here (instead of by the caller) so that the caller + * doesn't have to know the size of the StampData struct. */ + stamp_data = MEM_callocN(sizeof(StampData), __func__); + stampdata(scene, NULL, stamp_data, 0, false); + + return stamp_data; +} + void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCallback callback, bool noskip) { if ((callback == NULL) || (stamp_data == NULL)) { @@ -2129,6 +2168,7 @@ void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCall CALL(marker, "Marker"); CALL(time, "Time"); CALL(frame, "Frame"); + CALL(frame_range, "FrameRange"); CALL(camera, "Camera"); CALL(cameralens, "Lens"); CALL(scene, "Scene"); @@ -2157,8 +2197,8 @@ void BKE_render_result_stamp_data(RenderResult *rr, const char *key, const char stamp_data = rr->stamp_data; StampDataCustomField *field = MEM_mallocN(sizeof(StampDataCustomField), "StampData Custom Field"); - BLI_strncpy(field->key, key, sizeof(field->key)); - BLI_strncpy(field->value, value, sizeof(field->value)); + STRNCPY(field->key, key); + STRNCPY(field->value, value); BLI_addtail(&stamp_data->custom_fields, field); } @@ -2172,27 +2212,31 @@ void BKE_stamp_data_free(struct StampData *stamp_data) } /* wrap for callback only */ -static void metadata_change_field(void *data, const char *propname, char *propvalue, int UNUSED(len)) +static void metadata_set_field(void *data, const char *propname, char *propvalue, int UNUSED(len)) { - IMB_metadata_change_field(data, propname, propvalue); + /* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */ + struct ImBuf *imbuf = data; + IMB_metadata_set_field(imbuf->metadata, propname, propvalue); } static void metadata_get_field(void *data, const char *propname, char *propvalue, int len) { - IMB_metadata_get_field(data, propname, propvalue, len); + /* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */ + struct ImBuf *imbuf = data; + IMB_metadata_get_field(imbuf->metadata, propname, propvalue, len); } void BKE_imbuf_stamp_info(RenderResult *rr, struct ImBuf *ibuf) { struct StampData *stamp_data = rr->stamp_data; - - BKE_stamp_info_callback(ibuf, stamp_data, metadata_change_field, false); + IMB_metadata_ensure(&ibuf->metadata); + BKE_stamp_info_callback(ibuf, stamp_data, metadata_set_field, false); } void BKE_stamp_info_from_imbuf(RenderResult *rr, struct ImBuf *ibuf) { struct StampData *stamp_data = rr->stamp_data; - + IMB_metadata_ensure(&ibuf->metadata); BKE_stamp_info_callback(ibuf, stamp_data, metadata_get_field, true); } @@ -2739,7 +2783,7 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) if (BKE_image_has_packedfile(ima)) { const int totfiles = image_num_files(ima); - if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) { + if (totfiles != BLI_listbase_count_at_most(&ima->packedfiles, totfiles + 1)) { /* in case there are new available files to be loaded */ image_free_packedfiles(ima); BKE_image_packfiles(NULL, ima, ID_BLEND_PATH(G.main, &ima->id)); @@ -2894,7 +2938,7 @@ void BKE_image_multiview_index(Image *ima, ImageUser *iuser) iuser->multi_index = iuser->multiview_eye; } else { - if ((iuser->view < 0) || (iuser->view >= BLI_listbase_count_ex(&ima->views, iuser->view + 1))) { + if ((iuser->view < 0) || (iuser->view >= BLI_listbase_count_at_most(&ima->views, iuser->view + 1))) { iuser->multi_index = iuser->view = 0; } else { @@ -2957,7 +3001,7 @@ static void image_init_multilayer_multiview(Image *ima, RenderResult *rr) if (rr) { for (RenderView *rv = rr->views.first; rv; rv = rv->next) { ImageView *iv = MEM_callocN(sizeof(ImageView), "Viewer Image View"); - BLI_strncpy(iv->name, rv->name, sizeof(iv->name)); + STRNCPY(iv->name, rv->name); BLI_addtail(&ima->views, iv); } } @@ -3038,8 +3082,8 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat ImageView *iv; iv = MEM_mallocN(sizeof(ImageView), "Viewer Image View"); - BLI_strncpy(iv->name, viewname, sizeof(iv->name)); - BLI_strncpy(iv->filepath, filepath, sizeof(iv->filepath)); + STRNCPY(iv->name, viewname); + STRNCPY(iv->filepath, filepath); /* For stereo drawing we need to ensure: * STEREO_LEFT_NAME == STEREO_LEFT_ID and @@ -3361,7 +3405,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) const int totfiles = image_num_files(ima); int i; - if (totfiles != BLI_listbase_count_ex(&ima->anims, totfiles + 1)) { + if (totfiles != BLI_listbase_count_at_most(&ima->anims, totfiles + 1)) { image_free_anims(ima); for (i = 0; i < totfiles; i++) { @@ -3489,7 +3533,7 @@ static ImBuf *load_image_single( ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packefile"); BLI_addtail(&ima->packedfiles, imapf); - BLI_strncpy(imapf->filepath, filepath, sizeof(imapf->filepath)); + STRNCPY(imapf->filepath, filepath); imapf->packedfile = newPackedFile(NULL, filepath, ID_BLEND_PATH(G.main, &ima->id)); } } @@ -3517,7 +3561,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) /* this should never happen, but just playing safe */ if (has_packed) { - if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) { + if (totfiles != BLI_listbase_count_at_most(&ima->packedfiles, totfiles + 1)) { image_free_packedfiles(ima); has_packed = false; } @@ -4644,7 +4688,7 @@ static void image_update_views_format(Image *ima, ImageUser *iuser) for (srv = scene->r.views.first; srv; srv = srv->next) { if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) { char filepath[FILE_MAX]; - BLI_snprintf(filepath, sizeof(filepath), "%s%s%s", prefix, srv->suffix, ext); + SNPRINTF(filepath, "%s%s%s", prefix, srv->suffix, ext); image_add_view(ima, srv->name, filepath); } } @@ -4655,7 +4699,7 @@ static void image_update_views_format(Image *ima, ImageUser *iuser) int file; char str[FILE_MAX]; - BLI_strncpy(str, iv->filepath, sizeof(str)); + STRNCPY(str, iv->filepath); BLI_path_abs(str, G.main->name); /* exists? */ diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 3a4c920d8fb..2714c4f43a1 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -47,7 +47,6 @@ #include "BKE_animsys.h" #include "BKE_colortools.h" #include "BKE_icons.h" -#include "BKE_global.h" #include "BKE_lamp.h" #include "BKE_library.h" #include "BKE_library_query.h" diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index ea4c3f380ff..4b9748133d7 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -55,7 +55,6 @@ #include "BKE_curve.h" #include "BKE_depsgraph.h" #include "BKE_displist.h" -#include "BKE_global.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_library.h" diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 99423ee26a6..10b724f9f69 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -757,6 +757,7 @@ void BKE_libblock_management_main_add(Main *bmain, void *idv) new_id(lb, id, NULL); /* alphabetic insertion: is in new_id */ id->tag &= ~(LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT); + bmain->is_memfile_undo_written = false; BKE_main_unlock(bmain); } @@ -776,6 +777,7 @@ void BKE_libblock_management_main_remove(Main *bmain, void *idv) BKE_main_lock(bmain); BLI_remlink(lb, id); id->tag |= LIB_TAG_NO_MAIN; + bmain->is_memfile_undo_written = false; BKE_main_unlock(bmain); } @@ -1138,6 +1140,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl BKE_main_lock(bmain); BLI_addtail(lb, id); new_id(lb, id, name); + bmain->is_memfile_undo_written = false; /* alphabetic insertion: is in new_id */ BKE_main_unlock(bmain); diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index 878f38256b4..e00884c8a9d 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -47,7 +47,6 @@ #include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_freestyle.h" -#include "BKE_global.h" #include "BKE_library.h" #include "BKE_linestyle.h" #include "BKE_node.h" diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index ff4e7f36018..b5742dbdbb7 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -52,7 +52,6 @@ #include "BKE_animsys.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" -#include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_mask.h" diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c index 889f65da689..e2a9691e577 100644 --- a/source/blender/blenkernel/intern/mask_evaluate.c +++ b/source/blender/blenkernel/intern/mask_evaluate.c @@ -43,7 +43,6 @@ #include "BKE_curve.h" #include "BKE_depsgraph.h" -#include "BKE_global.h" #include "BKE_mask.h" #include "DEG_depsgraph.h" diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index c8b44511edd..6a45432e863 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -2429,7 +2429,7 @@ Mesh *BKE_mesh_new_from_object( /* if getting the original caged mesh, delete object modifiers */ if (cage) - BKE_object_free_modifiers(tmpobj); + BKE_object_free_modifiers(tmpobj, 0); /* copies the data */ copycu = tmpobj->data = BKE_curve_copy(bmain, (Curve *) ob->data); diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index d7a24f90dbe..ce04f3c31e2 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -136,16 +136,38 @@ ModifierData *modifier_new(int type) return md; } -void modifier_free(ModifierData *md) +static void modifier_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag) +{ + ID *id = *idpoin; + if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) { + id_us_min(id); + } +} + +void modifier_free_ex(ModifierData *md, const int flag) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + if (mti->foreachIDLink) { + mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL); + } + else if (mti->foreachObjectLink) { + mti->foreachObjectLink(md, NULL, (ObjectWalkFunc)modifier_free_data_id_us_cb, NULL); + } + } + if (mti->freeData) mti->freeData(md); if (md->error) MEM_freeN(md->error); MEM_freeN(md); } +void modifier_free(ModifierData *md) +{ + modifier_free_ex(md, 0); +} + bool modifier_unique_name(ListBase *modifiers, ModifierData *md) { if (modifiers && md) { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index acc652fb1be..751cd733ae1 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -201,12 +201,12 @@ void BKE_object_free_curve_cache(Object *ob) } } -void BKE_object_free_modifiers(Object *ob) +void BKE_object_free_modifiers(Object *ob, const int flag) { ModifierData *md; while ((md = BLI_pophead(&ob->modifiers))) { - modifier_free(md); + modifier_free_ex(md, flag); } /* particle modifiers were freed, so free the particlesystems as well */ @@ -268,7 +268,7 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type) void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src) { ModifierData *md; - BKE_object_free_modifiers(ob_dst); + BKE_object_free_modifiers(ob_dst, 0); if (!ELEM(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { /* only objects listed above can have modifiers and linking them to objects @@ -410,7 +410,8 @@ void BKE_object_free(Object *ob) { BKE_animdata_free((ID *)ob, false); - BKE_object_free_modifiers(ob); + /* BKE_<id>_free shall never touch to ID->us. Never ever. */ + BKE_object_free_modifiers(ob, LIB_ID_CREATE_NO_USER_REFCOUNT); MEM_SAFE_FREE(ob->mat); MEM_SAFE_FREE(ob->matbits); diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index d0bf1bed4f4..bee6e7d3df0 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -373,7 +373,7 @@ void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, const int add_inde /* remove colour from palette. Must be certain color is inside the palette! */ void BKE_palette_color_remove(Palette *palette, PaletteColor *color) { - if (BLI_listbase_count_ex(&palette->colors, palette->active_color) == palette->active_color) { + if (BLI_listbase_count_at_most(&palette->colors, palette->active_color) == palette->active_color) { palette->active_color--; } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index d7e08233601..04c365eee76 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3165,7 +3165,7 @@ ModifierData *object_add_particle_system(Scene *scene, Object *ob, const char *n psys->part = BKE_particlesettings_add(NULL, DATA_("ParticleSettings")); - if (BLI_listbase_count_ex(&ob->particlesystem, 2) > 1) + if (BLI_listbase_count_at_most(&ob->particlesystem, 2) > 1) BLI_snprintf(psys->name, sizeof(psys->name), DATA_("ParticleSystem %i"), BLI_listbase_count(&ob->particlesystem)); else BLI_strncpy(psys->name, DATA_("ParticleSystem"), sizeof(psys->name)); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 1a18528ba84..8aeeee5a1ad 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -76,7 +76,6 @@ #include "BKE_effect.h" #include "BKE_library_query.h" #include "BKE_particle.h" -#include "BKE_global.h" #include "BKE_DerivedMesh.h" #include "BKE_object.h" diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 6b6f2605dc3..e32a5d0681e 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -555,9 +555,9 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v) #endif #define pbvh_bmesh_node_vert_use_count_is_equal(bvh, node, v, n) \ - (pbvh_bmesh_node_vert_use_count_ex(bvh, node, v, (n) + 1) == n) + (pbvh_bmesh_node_vert_use_count_at_most(bvh, node, v, (n) + 1) == n) -static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max) +static int pbvh_bmesh_node_vert_use_count_at_most(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max) { int count = 0; BMFace *f; diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index c10f54a99eb..b8873cca0fb 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -700,6 +700,39 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool /* --------------------- */ +static void rigidbody_constraint_set_limits(RigidBodyCon *rbc, void (*set_limits)(rbConstraint*,int,float,float)) +{ + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Y) + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->limit_lin_y_lower, rbc->limit_lin_y_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Y, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Z) + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->limit_lin_z_lower, rbc->limit_lin_z_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Z, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X) + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->limit_ang_x_lower, rbc->limit_ang_x_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_X, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Y) + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->limit_ang_y_lower, rbc->limit_ang_y_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Y, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z) + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Z, 0.0f, -1.0f); +} + /** * Create physics sim representation of constraint given rigid body constraint settings * @@ -818,40 +851,13 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z); RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint); - ATTR_FALLTHROUGH; - case RBC_TYPE_6DOF: - if (rbc->type == RBC_TYPE_6DOF) /* a litte awkward but avoids duplicate code for limits */ - rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2); - - if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper); - else - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_X, 0.0f, -1.0f); - - if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Y) - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->limit_lin_y_lower, rbc->limit_lin_y_upper); - else - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Y, 0.0f, -1.0f); - - if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Z) - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->limit_lin_z_lower, rbc->limit_lin_z_upper); - else - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Z, 0.0f, -1.0f); - - if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X) - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->limit_ang_x_lower, rbc->limit_ang_x_upper); - else - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_X, 0.0f, -1.0f); - if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Y) - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->limit_ang_y_lower, rbc->limit_ang_y_upper); - else - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Y, 0.0f, -1.0f); + rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof_spring); + break; + case RBC_TYPE_6DOF: + rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2); - if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z) - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper); - else - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Z, 0.0f, -1.0f); + rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof); break; case RBC_TYPE_MOTOR: rbc->physics_constraint = RB_constraint_new_motor(loc, rot, rb1, rb2); diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index ee80438db64..49f120de250 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -52,6 +52,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_colormanagement.h" +#include "IMB_metadata.h" #include "BLI_math_color_blend.h" diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 67a64ab1433..0cc151c3645 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -84,6 +84,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_colormanagement.h" +#include "IMB_metadata.h" #include "BKE_context.h" #include "BKE_sound.h" @@ -942,6 +943,8 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r return; } + IMB_anim_load_metadata(sanim->anim); + seq->len = IMB_anim_get_duration(sanim->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN); seq->anim_preseek = IMB_anim_get_preseek(sanim->anim); @@ -2955,7 +2958,7 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context, Sequence *seq int totviews; int i; - if (totfiles != BLI_listbase_count_ex(&seq->anims, totfiles + 1)) + if (totfiles != BLI_listbase_count_at_most(&seq->anims, totfiles + 1)) goto monoview_movie; totviews = BKE_scene_multiview_num_views_get(&context->scene->r); @@ -5381,6 +5384,8 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad } } + IMB_anim_load_metadata(anim_arr[0]); + seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]); BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2); BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index bf473603c0e..e12b981a8f9 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -72,7 +72,6 @@ #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_DerivedMesh.h" -#include "BKE_global.h" #include "BKE_effect.h" #include "BKE_main.h" #include "BKE_modifier.h" diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index 9d604a9382a..1d2e12f34ac 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -32,7 +32,6 @@ #include "BLI_utildefines.h" #include "BKE_animsys.h" -#include "BKE_global.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index b8307031920..c7588a4ed48 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -168,9 +168,9 @@ enum { static void txt_pop_first(Text *text); static void txt_pop_last(Text *text); -static void txt_undo_add_blockop(Text *text, int op, const char *buf); +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); +static void txt_delete_sel(Text *text, TextUndoBuf *utxt); static void txt_make_dirty(Text *text); /***/ @@ -188,13 +188,6 @@ int txt_get_undostate(void) return undoing; } -static void init_undo_text(Text *text) -{ - text->undo_pos = -1; - text->undo_len = 0; - text->undo_buf = NULL; -} - /** * \note caller must handle `undo_buf` and `compiled` members. */ @@ -222,7 +215,6 @@ void BKE_text_free(Text *text) BKE_text_free_lines(text); MEM_SAFE_FREE(text->name); - MEM_SAFE_FREE(text->undo_buf); #ifdef WITH_PYTHON BPY_text_free_code(text); #endif @@ -236,8 +228,6 @@ void BKE_text_init(Text *ta) ta->name = NULL; - init_undo_text(ta); - ta->nlines = 1; ta->flags = TXT_ISDIRTY | TXT_ISMEM; if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE) == 0) @@ -419,10 +409,6 @@ bool BKE_text_reload(Text *text) txt_make_dirty(text); /* clear undo buffer */ - MEM_freeN(text->undo_buf); - init_undo_text(text); - - if (BLI_stat(filepath_abs, &st) != -1) { text->mtime = st.st_mtime; } @@ -471,8 +457,6 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const } /* clear undo buffer */ - init_undo_text(ta); - if (BLI_stat(filepath_abs, &st) != -1) { ta->mtime = st.st_mtime; } @@ -526,8 +510,6 @@ void BKE_text_copy_data(Main *UNUSED(bmain), Text *ta_dst, const Text *ta_src, c ta_dst->curl = ta_dst->sell = ta_dst->lines.first; ta_dst->curc = ta_dst->selc = 0; - - init_undo_text(ta_dst); } Text *BKE_text_copy(Main *bmain, const Text *ta) @@ -542,25 +524,29 @@ 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) /* called directly from rna */ +void BKE_text_clear(Text *text, TextUndoBuf *utxt) /* called directly from rna */ { int oldstate; - oldstate = txt_get_undostate(); - txt_set_undostate(1); + if (utxt) { + oldstate = txt_get_undostate(); + } + txt_set_undostate(utxt != NULL); + txt_sel_all(text); - txt_delete_sel(text); + txt_delete_sel(text, utxt); + txt_set_undostate(oldstate); txt_make_dirty(text); } -void BKE_text_write(Text *text, const char *str) /* called directly from rna */ +void BKE_text_write(Text *text, TextUndoBuf *utxt, const char *str) /* called directly from rna */ { int oldstate; oldstate = txt_get_undostate(); - txt_insert_buf(text, str); + txt_insert_buf(text, utxt, str); txt_move_eof(text, 0); txt_set_undostate(oldstate); @@ -1153,7 +1139,7 @@ bool txt_has_sel(Text *text) return ((text->curl != text->sell) || (text->curc != text->selc)); } -static void txt_delete_sel(Text *text) +static void txt_delete_sel(Text *text, TextUndoBuf *utxt) { TextLine *tmpl; char *buf; @@ -1167,7 +1153,7 @@ static void txt_delete_sel(Text *text) if (!undoing) { buf = txt_sel_to_buf(text); - txt_undo_add_blockop(text, UNDO_DBLOCK, buf); + txt_undo_add_blockop(text, utxt, UNDO_DBLOCK, buf); MEM_freeN(buf); } @@ -1408,7 +1394,7 @@ char *txt_sel_to_buf(Text *text) return buf; } -void txt_insert_buf(Text *text, const char *in_buffer) +void txt_insert_buf(Text *text, TextUndoBuf *utxt, const char *in_buffer) { int l = 0, u, len; size_t i = 0, j; @@ -1417,22 +1403,22 @@ void txt_insert_buf(Text *text, const char *in_buffer) if (!in_buffer) return; - txt_delete_sel(text); + txt_delete_sel(text, utxt); len = strlen(in_buffer); buffer = BLI_strdupn(in_buffer, len); len += txt_extended_ascii_as_utf8(&buffer); - if (!undoing) txt_undo_add_blockop(text, UNDO_IBLOCK, buffer); + if (!undoing) txt_undo_add_blockop(text, utxt, UNDO_IBLOCK, buffer); u = undoing; undoing = 1; /* Read the first line (or as close as possible */ while (buffer[i] && buffer[i] != '\n') - txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &i)); + txt_add_raw_char(text, utxt, BLI_str_utf8_as_unicode_step(buffer, &i)); - if (buffer[i] == '\n') txt_split_curline(text); + if (buffer[i] == '\n') txt_split_curline(text, utxt); else { undoing = u; MEM_freeN(buffer); return; } i++; @@ -1450,7 +1436,7 @@ void txt_insert_buf(Text *text, const char *in_buffer) } else { for (j = i - l; j < i && j < len; ) - txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &j)); + txt_add_raw_char(text, utxt, BLI_str_utf8_as_unicode_step(buffer, &j)); break; } } @@ -1464,7 +1450,7 @@ void txt_insert_buf(Text *text, const char *in_buffer) /* Undo functions */ /******************/ -static bool max_undo_test(Text *text, int x) +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 @@ -1474,25 +1460,24 @@ static bool max_undo_test(Text *text, int x) */ /* Add one for the null terminator. */ - text->undo_len = text->undo_pos + x + 1; - if (text->undo_len > TXT_MAX_UNDO) { + utxt->len = utxt->pos + x + 1; + if (utxt->len > TXT_MAX_UNDO) { /* XXX error("Undo limit reached, buffer cleared\n"); */ - MEM_freeN(text->undo_buf); - init_undo_text(text); + MEM_freeN(utxt->buf); return false; } else { /* Small reallocations on each undo step is fine. */ - text->undo_buf = MEM_recallocN(text->undo_buf, text->undo_len); + utxt->buf = MEM_recallocN(utxt->buf, utxt->len); } return true; } -static void txt_undo_end(Text *text) +static void txt_undo_end(Text *UNUSED(text), TextUndoBuf *utxt) { - int undo_pos_end = text->undo_pos + 1; - BLI_assert(undo_pos_end + 1 == text->undo_len); - text->undo_buf[undo_pos_end] = '\0'; + 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. */ @@ -1501,11 +1486,11 @@ static void txt_undo_end(Text *text) #endif #if 0 /* UNUSED */ -static void dump_buffer(Text *text) +static void dump_buffer(TextUndoBuf *utxt) { int i = 0; - - while (i++ < text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]); + + 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 */ @@ -1520,10 +1505,10 @@ void txt_print_undo(Text *text) printf("---< Undo Buffer >---\n"); - printf("UndoPosition is %d\n", text->undo_pos); + printf("UndoPosition is %d\n", utxt->pos); - while (i <= text->undo_pos) { - op = text->undo_buf[i]; + while (i <= utxt->pos) { + op = utxt->buf[i]; if (op == UNDO_INSERT_1) { ops = "Insert ascii "; @@ -1589,15 +1574,15 @@ void txt_print_undo(Text *text) printf(" - Char is "); switch (op) { case UNDO_INSERT_1: case UNDO_BS_1: case UNDO_DEL_1: - printf("%c", text->undo_buf[i]); + printf("%c", utxt->buf[i]); i++; break; case UNDO_INSERT_2: case UNDO_BS_2: case UNDO_DEL_2: - printf("%c%c", text->undo_buf[i], text->undo_buf[i + 1]); + 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", text->undo_buf[i], text->undo_buf[i + 1], text->undo_buf[i + 2]); + 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: @@ -1605,10 +1590,10 @@ void txt_print_undo(Text *text) unsigned int uc; char c[BLI_UTF8_MAX + 1]; size_t c_len; - uc = text->undo_buf[i]; i++; - uc = uc + (text->undo_buf[i] << 8); i++; - uc = uc + (text->undo_buf[i] << 16); i++; - uc = uc + (text->undo_buf[i] << 24); i++; + 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); @@ -1619,44 +1604,44 @@ void txt_print_undo(Text *text) else if (op == UNDO_DBLOCK || op == UNDO_IBLOCK) { i++; - linep = text->undo_buf[i]; i++; - linep = linep + (text->undo_buf[i] << 8); i++; - linep = linep + (text->undo_buf[i] << 16); i++; - linep = linep + (text->undo_buf[i] << 24); 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(text->undo_buf[i]); + putchar(utxt->buf[i]); linep--; i++; } - linep = text->undo_buf[i]; i++; - linep = linep + (text->undo_buf[i] << 8); i++; - linep = linep + (text->undo_buf[i] << 16); i++; - linep = linep + (text->undo_buf[i] << 24); 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 = text->undo_buf[i]; i++; - charp = charp + (text->undo_buf[i] << 8); i++; + charp = utxt->buf[i]; i++; + charp = charp + (utxt->buf[i] << 8); i++; - linep = text->undo_buf[i]; i++; - linep = linep + (text->undo_buf[i] << 8); i++; - linep = linep + (text->undo_buf[i] << 16); i++; - linep = linep + (text->undo_buf[i] << 24); 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 = text->undo_buf[i]; i++; - charp = charp + (text->undo_buf[i] << 8); i++; + charp = utxt->buf[i]; i++; + charp = charp + (utxt->buf[i] << 8); i++; - linep = text->undo_buf[i]; i++; - linep = linep + (text->undo_buf[i] << 8); i++; - linep = linep + (text->undo_buf[i] << 16); i++; - linep = linep + (text->undo_buf[i] << 24); 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); } @@ -1688,113 +1673,113 @@ static void txt_undo_store_uint32(char *undo_buf, int *undo_pos, unsigned int va } /* store the cur cursor to the undo buffer (6 bytes)*/ -static void txt_undo_store_cur(Text *text) +static void txt_undo_store_cur(Text *text, TextUndoBuf *utxt) { - txt_undo_store_uint16(text->undo_buf, &text->undo_pos, text->curc); - txt_undo_store_uint32(text->undo_buf, &text->undo_pos, txt_get_span(text->lines.first, text->curl)); + 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) +static void txt_undo_store_sel(Text *text, TextUndoBuf *utxt) { - txt_undo_store_uint16(text->undo_buf, &text->undo_pos, text->selc); - txt_undo_store_uint32(text->undo_buf, &text->undo_pos, txt_get_span(text->lines.first, text->sell)); + 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) +static void txt_undo_store_cursors(Text *text, TextUndoBuf *utxt) { - txt_undo_store_cur(text); - txt_undo_store_sel(text); + 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, int op, const char *buf) +static void txt_undo_add_blockop(Text *text, TextUndoBuf *utxt, int op, const char *buf) { unsigned int length = strlen(buf); - if (!max_undo_test(text, 2 + 12 + 4 + length + 4 + 1)) { + if (!max_undo_test(utxt, 2 + 12 + 4 + length + 4 + 1)) { return; } /* 2 bytes */ - text->undo_pos++; - text->undo_buf[text->undo_pos] = op; - text->undo_pos++; + utxt->pos++; + utxt->buf[utxt->pos] = op; + utxt->pos++; /* 12 bytes */ - txt_undo_store_cursors(text); + txt_undo_store_cursors(text, utxt); /* 4 bytes */ - txt_undo_store_uint32(text->undo_buf, &text->undo_pos, length); + txt_undo_store_uint32(utxt->buf, &utxt->pos, length); /* 'length' bytes */ - strncpy(text->undo_buf + text->undo_pos, buf, length); - text->undo_pos += length; + strncpy(utxt->buf + utxt->pos, buf, length); + utxt->pos += length; /* 4 bytes */ - txt_undo_store_uint32(text->undo_buf, &text->undo_pos, length); + txt_undo_store_uint32(utxt->buf, &utxt->pos, length); /* 1 byte */ - text->undo_buf[text->undo_pos] = op; + utxt->buf[utxt->pos] = op; - txt_undo_end(text); + txt_undo_end(text, utxt); } /* store a regular operator */ -void txt_undo_add_op(Text *text, int op) +void txt_undo_add_op(Text *text, TextUndoBuf *utxt, int op) { - if (!max_undo_test(text, 2 + 12 + 1)) { + if (!max_undo_test(utxt, 2 + 12 + 1)) { return; } /* 2 bytes */ - text->undo_pos++; - text->undo_buf[text->undo_pos] = op; - text->undo_pos++; + utxt->pos++; + utxt->buf[utxt->pos] = op; + utxt->pos++; /* 12 bytes */ - txt_undo_store_cursors(text); + txt_undo_store_cursors(text, utxt); /* 1 byte */ - text->undo_buf[text->undo_pos] = op; + utxt->buf[utxt->pos] = op; - txt_undo_end(text); + txt_undo_end(text, utxt); } /* store an operator for a single character */ -static void txt_undo_add_charop(Text *text, int op_start, unsigned int c) +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(text, 2 + 6 + utf8_size + 1)) { + if (!max_undo_test(utxt, 2 + 6 + utf8_size + 1)) { return; } /* 2 bytes */ - text->undo_pos++; - text->undo_buf[text->undo_pos] = op_start + utf8_size - 1; - text->undo_pos++; + utxt->pos++; + utxt->buf[utxt->pos] = op_start + utf8_size - 1; + utxt->pos++; /* 6 bytes */ - txt_undo_store_cur(text); + txt_undo_store_cur(text, utxt); /* 'utf8_size' bytes */ for (i = 0; i < utf8_size; i++) { - text->undo_buf[text->undo_pos] = utf8[i]; - text->undo_pos++; + utxt->buf[utxt->pos] = utf8[i]; + utxt->pos++; } /* 1 byte */ - text->undo_buf[text->undo_pos] = op_start + utf8_size - 1; + utxt->buf[utxt->pos] = op_start + utf8_size - 1; } else { - if (!max_undo_test(text, 2 + 6 + 4 + 1)) { + if (!max_undo_test(utxt, 2 + 6 + 4 + 1)) { return; } /* 2 bytes */ - text->undo_pos++; - text->undo_buf[text->undo_pos] = op_start + 3; - text->undo_pos++; + utxt->pos++; + utxt->buf[utxt->pos] = op_start + 3; + utxt->pos++; /* 6 bytes */ - txt_undo_store_cur(text); + txt_undo_store_cur(text, utxt); /* 4 bytes */ - txt_undo_store_uint32(text->undo_buf, &text->undo_pos, c); + txt_undo_store_uint32(utxt->buf, &utxt->pos, c); /* 1 byte */ - text->undo_buf[text->undo_pos] = op_start + 3; + utxt->buf[utxt->pos] = op_start + 3; } - txt_undo_end(text); + txt_undo_end(text, utxt); } /* extends Link */ @@ -1808,7 +1793,7 @@ struct LinkInt { * of the lines that should not be indented back. */ static void txt_undo_add_unprefix_op( - Text *text, char undo_op, + Text *text, TextUndoBuf *utxt, char undo_op, const ListBase *line_index_mask, const int line_index_mask_len) { struct LinkInt *idata; @@ -1816,35 +1801,35 @@ static void txt_undo_add_unprefix_op( BLI_assert(BLI_listbase_count(line_index_mask) == line_index_mask_len); /* OP byte + UInt32 count + counted UInt32 line numbers + UInt32 count + 12-bytes selection + OP byte */ - if (!max_undo_test(text, 2 + 4 + (line_index_mask_len * 4) + 4 + 12 + 1)) { + if (!max_undo_test(utxt, 2 + 4 + (line_index_mask_len * 4) + 4 + 12 + 1)) { return; } /* 2 bytes */ - text->undo_pos++; - text->undo_buf[text->undo_pos] = undo_op; - text->undo_pos++; + utxt->pos++; + utxt->buf[utxt->pos] = undo_op; + utxt->pos++; /* Adding number of line numbers to read * 4 bytes */ - txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len); + txt_undo_store_uint32(utxt->buf, &utxt->pos, line_index_mask_len); /* Adding linenumbers 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(text->undo_buf, &text->undo_pos, idata->value); + txt_undo_store_uint32(utxt->buf, &utxt->pos, idata->value); } /* Adding number of line numbers to read again. * 4 bytes */ - txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len); + txt_undo_store_uint32(utxt->buf, &utxt->pos, line_index_mask_len); /* Adding current selection. * 12 bytes */ - txt_undo_store_cursors(text); + txt_undo_store_cursors(text, utxt); /* Closing with OP (same as above). * 1 byte */ - text->undo_buf[text->undo_pos] = undo_op; + utxt->buf[utxt->pos] = undo_op; /* Marking as last undo operation */ - txt_undo_end(text); + txt_undo_end(text, utxt); } static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos) @@ -1999,9 +1984,9 @@ static unsigned int txt_redo_read_unicode(const char *undo_buf, int *undo_pos, s return unicode; } -void txt_do_undo(Text *text) +void txt_do_undo(Text *text, TextUndoBuf *utxt) { - int op = text->undo_buf[text->undo_pos]; + int op = utxt->buf[utxt->pos]; int prev_flags; unsigned int linep; unsigned int uni_char; @@ -2010,11 +1995,11 @@ void txt_do_undo(Text *text) unsigned short charp; char *buf; - if (text->undo_pos < 0) { + if (utxt->pos < 0) { return; } - text->undo_pos--; + utxt->pos--; undoing = 1; @@ -2023,16 +2008,16 @@ void txt_do_undo(Text *text) case UNDO_INSERT_2: case UNDO_INSERT_3: case UNDO_INSERT_4: - text->undo_pos -= op - UNDO_INSERT_1 + 1; + utxt->pos -= op - UNDO_INSERT_1 + 1; /* get and restore the cursors */ - txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); + 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); + txt_delete_char(text, utxt); - text->undo_pos--; + utxt->pos--; break; case UNDO_BS_1: @@ -2040,16 +2025,16 @@ void txt_do_undo(Text *text) case UNDO_BS_3: case UNDO_BS_4: charp = op - UNDO_BS_1 + 1; - uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp); + uni_char = txt_undo_read_unicode(utxt->buf, &utxt->pos, charp); /* get and restore the cursors */ - txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); + 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, uni_char); + txt_add_char(text, utxt, uni_char); - text->undo_pos--; + utxt->pos--; break; case UNDO_DEL_1: @@ -2057,50 +2042,50 @@ void txt_do_undo(Text *text) case UNDO_DEL_3: case UNDO_DEL_4: charp = op - UNDO_DEL_1 + 1; - uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp); + uni_char = txt_undo_read_unicode(utxt->buf, &utxt->pos, charp); /* get and restore the cursors */ - txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); + 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, uni_char); + txt_add_char(text, utxt, uni_char); txt_move_left(text, 0); - text->undo_pos--; + utxt->pos--; break; case UNDO_DBLOCK: { int i; /* length of the string in the buffer */ - linep = txt_undo_read_uint32(text->undo_buf, &text->undo_pos); + 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] = text->undo_buf[text->undo_pos]; - text->undo_pos--; + buf[(linep - 1) - i] = utxt->buf[utxt->pos]; + utxt->pos--; } buf[i] = 0; /* skip over the length that was stored again */ - text->undo_pos -= 4; + utxt->pos -= 4; /* Get the cursor positions */ - txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + 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, buf); + 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); - text->undo_pos--; + utxt->pos--; break; } @@ -2108,23 +2093,23 @@ void txt_do_undo(Text *text) { int i; /* length of the string in the buffer */ - linep = txt_undo_read_uint32(text->undo_buf, &text->undo_pos); + 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] = text->undo_buf[text->undo_pos]; - text->undo_pos--; + 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 */ - text->undo_pos -= 4; + utxt->pos -= 4; /* get and restore the cursors */ - txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + 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); @@ -2140,9 +2125,9 @@ void txt_do_undo(Text *text) text->flags = prev_flags; } - txt_delete_selected(text); + txt_delete_selected(text, utxt); - text->undo_pos--; + utxt->pos--; break; } case UNDO_INDENT: @@ -2151,37 +2136,37 @@ void txt_do_undo(Text *text) case UNDO_MOVE_LINES_UP: case UNDO_MOVE_LINES_DOWN: /* get and restore the cursors */ - txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + 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); + txt_unindent(text, utxt); } else if (op == UNDO_COMMENT) { - txt_uncomment(text); + 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, TXT_MOVE_LINE_DOWN); + txt_move_lines(text, utxt, TXT_MOVE_LINE_DOWN); } else if (op == UNDO_MOVE_LINES_DOWN) { - txt_move_lines(text, TXT_MOVE_LINE_UP); + txt_move_lines(text, utxt, TXT_MOVE_LINE_UP); } - text->undo_pos--; + utxt->pos--; break; case UNDO_UNINDENT: case UNDO_UNCOMMENT: { - void (*txt_prefix_fn)(Text *); - void (*txt_unprefix_fn)(Text *); + 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(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + 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); @@ -2195,30 +2180,30 @@ void txt_do_undo(Text *text) txt_unprefix_fn = txt_uncomment; } - txt_prefix_fn(text); + txt_prefix_fn(text, utxt); /* Get the count */ - count = txt_undo_read_uint32(text->undo_buf, &text->undo_pos); + 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(text->undo_buf, &text->undo_pos), 0, 0); + txt_move_to(text, txt_undo_read_uint32(utxt->buf, &utxt->pos), 0, 0); /* Un-un-unindent/comment */ - txt_unprefix_fn(text); + 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(text->undo_buf, &text->undo_pos); + txt_undo_read_uint32(utxt->buf, &utxt->pos); /* Jump over closing OP byte */ - text->undo_pos--; + utxt->pos--; break; } default: //XXX error("Undo buffer error - resetting"); - text->undo_pos = -1; + utxt->pos = -1; break; } @@ -2226,7 +2211,7 @@ void txt_do_undo(Text *text) undoing = 0; } -void txt_do_redo(Text *text) +void txt_do_redo(Text *text, TextUndoBuf *utxt) { char op; char *buf; @@ -2236,11 +2221,11 @@ void txt_do_redo(Text *text) unsigned int curln, selln; unsigned short curc, selc; - text->undo_pos++; - op = text->undo_buf[text->undo_pos]; + utxt->pos++; + op = utxt->buf[utxt->pos]; if (!op) { - text->undo_pos--; + utxt->pos--; return; } @@ -2251,35 +2236,35 @@ void txt_do_redo(Text *text) case UNDO_INSERT_2: case UNDO_INSERT_3: case UNDO_INSERT_4: - text->undo_pos++; + utxt->pos++; /* get and restore the cursors */ - txt_redo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); + 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(text->undo_buf, &text->undo_pos, charp); + uni_uchar = txt_redo_read_unicode(utxt->buf, &utxt->pos, charp); - txt_add_char(text, uni_uchar); + txt_add_char(text, utxt, uni_uchar); break; case UNDO_BS_1: case UNDO_BS_2: case UNDO_BS_3: case UNDO_BS_4: - text->undo_pos++; + utxt->pos++; /* get and restore the cursors */ - txt_redo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); + txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc); txt_move_to(text, curln, curc, 0); txt_move_to(text, curln, curc, 1); - text->undo_pos += op - UNDO_BS_1 + 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); + txt_backspace_char(text, utxt); break; @@ -2287,60 +2272,60 @@ void txt_do_redo(Text *text) case UNDO_DEL_2: case UNDO_DEL_3: case UNDO_DEL_4: - text->undo_pos++; + utxt->pos++; /* get and restore the cursors */ - txt_redo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); + txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc); txt_move_to(text, curln, curc, 0); txt_move_to(text, curln, curc, 1); - text->undo_pos += op - UNDO_DEL_1 + 1; + utxt->pos += op - UNDO_DEL_1 + 1; - txt_delete_char(text); + txt_delete_char(text, utxt); break; case UNDO_DBLOCK: - text->undo_pos++; + utxt->pos++; /* get and restore the cursors */ - txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + 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(text->undo_buf, &text->undo_pos); + linep = txt_redo_read_uint32(utxt->buf, &utxt->pos); - text->undo_pos += linep; + utxt->pos += linep; /* skip over the length that was stored again */ - text->undo_pos += 4; + utxt->pos += 4; - txt_delete_sel(text); + txt_delete_sel(text, utxt); break; case UNDO_IBLOCK: - text->undo_pos++; + utxt->pos++; /* get and restore the cursors */ - txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + 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(text->undo_buf, &text->undo_pos); + linep = txt_redo_read_uint32(utxt->buf, &utxt->pos); buf = MEM_mallocN(linep + 1, "iblock buffer"); - memcpy(buf, &text->undo_buf[text->undo_pos], linep); - text->undo_pos += linep; + memcpy(buf, &utxt->buf[utxt->pos], linep); + utxt->pos += linep; buf[linep] = 0; - txt_insert_buf(text, buf); + txt_insert_buf(text, utxt, buf); MEM_freeN(buf); /* skip over the length that was stored again */ - text->undo_pos += 4; + utxt->pos += 4; break; @@ -2350,38 +2335,38 @@ void txt_do_redo(Text *text) case UNDO_DUPLICATE: case UNDO_MOVE_LINES_UP: case UNDO_MOVE_LINES_DOWN: - text->undo_pos++; + utxt->pos++; /* get and restore the cursors */ - txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + 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); + txt_indent(text, utxt); } else if (op == UNDO_COMMENT) { - txt_comment(text); + txt_comment(text, utxt); } else if (op == UNDO_UNCOMMENT) { - txt_uncomment(text); + txt_uncomment(text, utxt); } else if (op == UNDO_DUPLICATE) { - txt_duplicate_line(text); + 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, TXT_MOVE_LINE_UP); + 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, TXT_MOVE_LINE_DOWN); + txt_move_lines(text, utxt, TXT_MOVE_LINE_DOWN); } /* re-restore the cursors since they got moved when redoing */ @@ -2394,24 +2379,24 @@ void txt_do_redo(Text *text) int count; int i; - text->undo_pos++; + utxt->pos++; /* Scan all the stuff described in txt_undo_add_unindent_op */ - count = txt_redo_read_uint32(text->undo_buf, &text->undo_pos); + count = txt_redo_read_uint32(utxt->buf, &utxt->pos); for (i = 0; i < count; i++) { - txt_redo_read_uint32(text->undo_buf, &text->undo_pos); + txt_redo_read_uint32(utxt->buf, &utxt->pos); } /* Count again */ - txt_redo_read_uint32(text->undo_buf, &text->undo_pos); + txt_redo_read_uint32(utxt->buf, &utxt->pos); /* Get the selection and re-unindent */ - txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + 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); + txt_unindent(text, utxt); break; } default: //XXX error("Undo buffer error - resetting"); - text->undo_pos = -1; + utxt->pos = -1; break; } @@ -2423,16 +2408,16 @@ void txt_do_redo(Text *text) /* Line editing functions */ /**************************/ -void txt_split_curline(Text *text) +void txt_split_curline(Text *text, TextUndoBuf *utxt) { TextLine *ins; char *left, *right; if (!text->curl) return; - txt_delete_sel(text); + txt_delete_sel(text, utxt); - if (!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, '\n'); + if (!undoing) txt_undo_add_charop(text, utxt, UNDO_INSERT_1, '\n'); /* Make the two half strings */ @@ -2504,7 +2489,7 @@ static void txt_combine_lines(Text *text, TextLine *linea, TextLine *lineb) txt_clean_text(text); } -void txt_duplicate_line(Text *text) +void txt_duplicate_line(Text *text, TextUndoBuf *utxt) { TextLine *textline; @@ -2517,18 +2502,18 @@ void txt_duplicate_line(Text *text) txt_make_dirty(text); txt_clean_text(text); - if (!undoing) txt_undo_add_op(text, UNDO_DUPLICATE); + if (!undoing) txt_undo_add_op(text, utxt, UNDO_DUPLICATE); } } -void txt_delete_char(Text *text) +void txt_delete_char(Text *text, TextUndoBuf *utxt) { unsigned int c = '\n'; if (!text->curl) return; if (txt_has_sel(text)) { /* deleting a selection */ - txt_delete_sel(text); + txt_delete_sel(text, utxt); txt_make_dirty(text); return; } @@ -2554,24 +2539,24 @@ void txt_delete_char(Text *text) txt_make_dirty(text); txt_clean_text(text); - if (!undoing) txt_undo_add_charop(text, UNDO_DEL_1, c); + if (!undoing) txt_undo_add_charop(text, utxt, UNDO_DEL_1, c); } -void txt_delete_word(Text *text) +void txt_delete_word(Text *text, TextUndoBuf *utxt) { txt_jump_right(text, true, true); - txt_delete_sel(text); + txt_delete_sel(text, utxt); txt_make_dirty(text); } -void txt_backspace_char(Text *text) +void txt_backspace_char(Text *text, TextUndoBuf *utxt) { unsigned int c = '\n'; if (!text->curl) return; if (txt_has_sel(text)) { /* deleting a selection */ - txt_delete_sel(text); + txt_delete_sel(text, utxt); txt_make_dirty(text); return; } @@ -2603,13 +2588,13 @@ void txt_backspace_char(Text *text) txt_make_dirty(text); txt_clean_text(text); - if (!undoing) txt_undo_add_charop(text, UNDO_BS_1, c); + if (!undoing) txt_undo_add_charop(text, utxt, UNDO_BS_1, c); } -void txt_backspace_word(Text *text) +void txt_backspace_word(Text *text, TextUndoBuf *utxt) { txt_jump_left(text, true, true); - txt_delete_sel(text); + txt_delete_sel(text, utxt); txt_make_dirty(text); } @@ -2618,17 +2603,17 @@ void txt_backspace_word(Text *text) * Remember to change this string according to max tab size */ static char tab_to_spaces[] = " "; -static void txt_convert_tab_to_spaces(Text *text) +static void txt_convert_tab_to_spaces(Text *text, TextUndoBuf *utxt) { /* 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, sb); + txt_insert_buf(text, utxt, sb); } -static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs) +static bool txt_add_char_intern(Text *text, TextUndoBuf *utxt, unsigned int add, bool replace_tabs) { char *tmp, ch[BLI_UTF8_MAX]; size_t add_len; @@ -2636,19 +2621,19 @@ static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs) if (!text->curl) return 0; if (add == '\n') { - txt_split_curline(text); + txt_split_curline(text, utxt); return true; } /* insert spaces rather than tabs */ if (add == '\t' && replace_tabs) { - txt_convert_tab_to_spaces(text); + txt_convert_tab_to_spaces(text, utxt); return true; } - txt_delete_sel(text); + txt_delete_sel(text, utxt); - if (!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, add); + if (!undoing) txt_undo_add_charop(text, utxt, UNDO_INSERT_1, add); add_len = BLI_str_utf8_from_unicode(add, ch); @@ -2670,23 +2655,23 @@ static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs) return 1; } -bool txt_add_char(Text *text, unsigned int add) +bool txt_add_char(Text *text, TextUndoBuf *utxt, unsigned int add) { - return txt_add_char_intern(text, add, (text->flags & TXT_TABSTOSPACES) != 0); + return txt_add_char_intern(text, utxt, add, (text->flags & TXT_TABSTOSPACES) != 0); } -bool txt_add_raw_char(Text *text, unsigned int add) +bool txt_add_raw_char(Text *text, TextUndoBuf *utxt, unsigned int add) { - return txt_add_char_intern(text, add, 0); + return txt_add_char_intern(text, utxt, add, 0); } -void txt_delete_selected(Text *text) +void txt_delete_selected(Text *text, TextUndoBuf *utxt) { - txt_delete_sel(text); + txt_delete_sel(text, utxt); txt_make_dirty(text); } -bool txt_replace_char(Text *text, unsigned int add) +bool txt_replace_char(Text *text, TextUndoBuf *utxt, unsigned int add) { unsigned int del; size_t del_size = 0, add_size; @@ -2696,7 +2681,7 @@ bool txt_replace_char(Text *text, 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, add); + return txt_add_char(text, utxt, add); } del = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &del_size); @@ -2724,10 +2709,10 @@ bool txt_replace_char(Text *text, unsigned int add) /* Should probably create a new op for this */ if (!undoing) { - txt_undo_add_charop(text, UNDO_INSERT_1, add); + txt_undo_add_charop(text, utxt, UNDO_INSERT_1, add); text->curc -= add_size; txt_pop_sel(text); - txt_undo_add_charop(text, UNDO_DEL_1, del); + txt_undo_add_charop(text, utxt, UNDO_DEL_1, del); text->curc += add_size; txt_pop_sel(text); } @@ -2867,7 +2852,7 @@ static void txt_select_unprefix( /* caller must handle undo */ } -void txt_comment(Text *text) +void txt_comment(Text *text, TextUndoBuf *utxt) { const char *prefix = "#"; @@ -2878,11 +2863,11 @@ void txt_comment(Text *text) txt_select_prefix(text, prefix); if (!undoing) { - txt_undo_add_op(text, UNDO_COMMENT); + txt_undo_add_op(text, utxt, UNDO_COMMENT); } } -void txt_uncomment(Text *text) +void txt_uncomment(Text *text, TextUndoBuf *utxt) { const char *prefix = "#"; ListBase line_index_mask; @@ -2895,13 +2880,13 @@ void txt_uncomment(Text *text) txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len); if (!undoing) { - txt_undo_add_unprefix_op(text, UNDO_UNCOMMENT, &line_index_mask, line_index_mask_len); + txt_undo_add_unprefix_op(text, utxt, UNDO_UNCOMMENT, &line_index_mask, line_index_mask_len); } BLI_freelistN(&line_index_mask); } -void txt_indent(Text *text) +void txt_indent(Text *text, TextUndoBuf *utxt) { const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t"; @@ -2912,11 +2897,11 @@ void txt_indent(Text *text) txt_select_prefix(text, prefix); if (!undoing) { - txt_undo_add_op(text, UNDO_INDENT); + txt_undo_add_op(text, utxt, UNDO_INDENT); } } -void txt_unindent(Text *text) +void txt_unindent(Text *text, TextUndoBuf *utxt) { const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t"; ListBase line_index_mask; @@ -2929,13 +2914,13 @@ void txt_unindent(Text *text) txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len); if (!undoing) { - txt_undo_add_unprefix_op(text, UNDO_UNINDENT, &line_index_mask, line_index_mask_len); + txt_undo_add_unprefix_op(text, utxt, UNDO_UNINDENT, &line_index_mask, line_index_mask_len); } BLI_freelistN(&line_index_mask); } -void txt_move_lines(struct Text *text, const int direction) +void txt_move_lines(struct Text *text, TextUndoBuf *utxt, const int direction) { TextLine *line_other; @@ -2962,7 +2947,7 @@ void txt_move_lines(struct Text *text, const int direction) txt_clean_text(text); if (!undoing) { - txt_undo_add_op(text, (direction == TXT_MOVE_LINE_DOWN) ? UNDO_MOVE_LINES_DOWN : UNDO_MOVE_LINES_UP); + txt_undo_add_op(text, utxt, (direction == TXT_MOVE_LINE_DOWN) ? UNDO_MOVE_LINES_DOWN : UNDO_MOVE_LINES_UP); } } diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 0e2ac811a41..250408642bb 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -55,7 +55,6 @@ #include "IMB_imbuf.h" -#include "BKE_global.h" #include "BKE_main.h" #include "BKE_colorband.h" diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c new file mode 100644 index 00000000000..760c6a60976 --- /dev/null +++ b/source/blender/blenkernel/intern/undo_system.c @@ -0,0 +1,831 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/undo_system.c + * \ingroup bke + * + * Used by ED_undo.h, internal implementation. + */ + +#include <string.h> + +#include "CLG_log.h" + +#include "BLI_utildefines.h" +#include "BLI_sys_types.h" +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_sort_utils.h" + +#include "DNA_listBase.h" +#include "DNA_windowmanager_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_undo_system.h" + +#include "MEM_guardedalloc.h" + +#define undo_stack _wm_undo_stack_disallow /* pass in as a variable always. */ + +/** Odd requirement of Blender that we always keep a memfile undo in the stack. */ +#define WITH_GLOBAL_UNDO_KEEP_ONE + +/** Make sure all ID's created at the point we add an undo step that uses ID's. */ +#define WITH_GLOBAL_UNDO_ENSURE_UPDATED + +/** We only need this locally. */ +static CLG_LogRef LOG = {"bke.undosys"}; + +/* -------------------------------------------------------------------- */ +/** \name Internal Nested Undo Checks + * + * Make sure we're not running undo operations from 'step_encode', 'step_decode' callbacks. + * bugs caused by this situation aren't _that_ hard to spot but aren't always so obvious. + * Best we have a check which shows the problem immediately. + * + * \{ */ +#define WITH_NESTED_UNDO_CHECK + +#ifdef WITH_NESTED_UNDO_CHECK +static bool g_undo_callback_running = false; +# define UNDO_NESTED_ASSERT(state) BLI_assert(g_undo_callback_running == state) +# define UNDO_NESTED_CHECK_BEGIN { \ + UNDO_NESTED_ASSERT(false); \ + g_undo_callback_running = true; \ +} ((void)0) +# define UNDO_NESTED_CHECK_END { \ + UNDO_NESTED_ASSERT(true); \ + g_undo_callback_running = false; \ +} ((void)0) +#else +# define UNDO_NESTED_ASSERT(state) ((void)0) +# define UNDO_NESTED_CHECK_BEGIN ((void)0) +# define UNDO_NESTED_CHECK_END ((void)0) +#endif +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public Undo Types + * + * Unfortunately we need this for a handful of places. + */ +const UndoType *BKE_UNDOSYS_TYPE_IMAGE = NULL; +const UndoType *BKE_UNDOSYS_TYPE_MEMFILE = NULL; +const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE = NULL; +const UndoType *BKE_UNDOSYS_TYPE_PARTICLE = NULL; +const UndoType *BKE_UNDOSYS_TYPE_SCULPT = NULL; +const UndoType *BKE_UNDOSYS_TYPE_TEXT = NULL; +/** \} */ + +/* UndoType */ + +static ListBase g_undo_types = {NULL, NULL}; + +static const UndoType *BKE_undosys_type_from_context(bContext *C) +{ + for (const UndoType *ut = g_undo_types.first; ut; ut = ut->next) { + /* No poll means we don't check context. */ + if (ut->poll && ut->poll(C)) { + return ut; + } + } + return NULL; +} + +/* -------------------------------------------------------------------- */ +/** \name Internal Callback Wrappers + * + * #UndoRefID is simply a way to avoid inlining name copy and lookups, + * since it's easy to forget a single case when done inline (crashing in some cases). + * + * \{ */ + +static void undosys_id_ref_store(void *UNUSED(user_data), UndoRefID *id_ref) +{ + BLI_assert(id_ref->name[0] == '\0'); + if (id_ref->ptr) { + BLI_strncpy(id_ref->name, id_ref->ptr->name, sizeof(id_ref->name)); + /* Not needed, just prevents stale data access. */ + id_ref->ptr = NULL; + } +} + +static void undosys_id_ref_resolve(void *user_data, UndoRefID *id_ref) +{ + /* Note: we could optimize this, for now it's not too bad since it only runs when we access undo! */ + Main *bmain = user_data; + ListBase *lb = which_libbase(bmain, GS(id_ref->name)); + for (ID *id = lb->first; id; id = id->next) { + if (STREQ(id_ref->name, id->name) && (id->lib == NULL)) { + id_ref->ptr = id; + break; + } + } +} + +static bool undosys_step_encode(bContext *C, UndoStep *us) +{ + CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name); + UNDO_NESTED_CHECK_BEGIN; + bool ok = us->type->step_encode(C, us); + UNDO_NESTED_CHECK_END; + if (ok) { + if (us->type->step_foreach_ID_ref != NULL) { + /* Don't use from context yet because sometimes context is fake and not all members are filled in. */ + Main *bmain = G.main; + us->type->step_foreach_ID_ref(us, undosys_id_ref_store, bmain); + } + } + if (ok == false) { + CLOG_INFO(&LOG, 2, "encode callback didn't create undo step"); + } + return ok; +} + +static void undosys_step_decode(bContext *C, UndoStep *us, int dir) +{ + CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name); + if (us->type->step_foreach_ID_ref) { + /* Don't use from context yet because sometimes context is fake and not all members are filled in. */ + Main *bmain = G.main; + us->type->step_foreach_ID_ref(us, undosys_id_ref_resolve, bmain); + } + + UNDO_NESTED_CHECK_BEGIN; + us->type->step_decode(C, us, dir); + UNDO_NESTED_CHECK_END; +} + +static void undosys_step_free_and_unlink(UndoStack *ustack, UndoStep *us) +{ + CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name); + UNDO_NESTED_CHECK_BEGIN; + us->type->step_free(us); + UNDO_NESTED_CHECK_END; + + BLI_remlink(&ustack->steps, us); + MEM_freeN(us); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Undo Stack + * \{ */ + +#ifndef NDEBUG +static void undosys_stack_validate(UndoStack *ustack, bool expect_non_empty) +{ + if (ustack->step_active != NULL) { + BLI_assert(!BLI_listbase_is_empty(&ustack->steps)); + BLI_assert(BLI_findindex(&ustack->steps, ustack->step_active) != -1); + } + if (expect_non_empty) { + BLI_assert(!BLI_listbase_is_empty(&ustack->steps)); + } +} +#else +static void undosys_stack_validate(UndoStack *ustack, bool expect_non_empty) +{ + UNUSED_VARS(ustack, expect_non_empty); +} +#endif + +UndoStack *BKE_undosys_stack_create(void) +{ + UndoStack *ustack = MEM_callocN(sizeof(UndoStack), __func__); + return ustack; +} + +void BKE_undosys_stack_destroy(UndoStack *ustack) +{ + BKE_undosys_stack_clear(ustack); + MEM_freeN(ustack); +} + +void BKE_undosys_stack_clear(UndoStack *ustack) +{ + UNDO_NESTED_ASSERT(false); + CLOG_INFO(&LOG, 1, "steps=%d", BLI_listbase_count(&ustack->steps)); + for (UndoStep *us = ustack->steps.last, *us_prev; us; us = us_prev) { + us_prev = us->prev; + undosys_step_free_and_unlink(ustack, us); + } + BLI_listbase_clear(&ustack->steps); + ustack->step_active = NULL; +} + +static bool undosys_stack_push_main(UndoStack *ustack, const char *name, struct Main *bmain) +{ + UNDO_NESTED_ASSERT(false); + CLOG_INFO(&LOG, 1, "'%s'", name); + bContext *C_temp = CTX_create(); + CTX_data_main_set(C_temp, bmain); + bool ok = BKE_undosys_step_push_with_type(ustack, C_temp, name, BKE_UNDOSYS_TYPE_MEMFILE); + CTX_free(C_temp); + return ok; +} + +void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain) +{ + UNDO_NESTED_ASSERT(false); + undosys_stack_push_main(ustack, "original", bmain); +} + +/* name optional */ +bool BKE_undosys_stack_has_undo(UndoStack *ustack, const char *name) +{ + if (name) { + UndoStep *us = BLI_rfindstring(&ustack->steps, name, offsetof(UndoStep, name)); + return us && us->prev; + } + + return !BLI_listbase_is_empty(&ustack->steps); +} + +UndoStep *BKE_undosys_stack_active_with_type(UndoStack *ustack, const UndoType *ut) +{ + UndoStep *us = ustack->step_active; + while (us && (us->type != ut)) { + us = us->prev; + } + return us; +} + +UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut) +{ + UNDO_NESTED_ASSERT(false); + CLOG_INFO(&LOG, 1, "type='%s'", ut->name); + if (ustack->step_init && (ustack->step_init->type == ut)) { + return ustack->step_init; + } + return BKE_undosys_stack_active_with_type(ustack, ut); +} + +/** + * \param steps: Limit the number of undo steps. + * \param memory_limit: Limit the amount of memory used by the undo stack. + */ +void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit) +{ + UNDO_NESTED_ASSERT(false); + if (!(steps || memory_limit)) { + return; + } + + 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; + for (us = ustack->steps.last; us && us->prev; us = us->prev) { + if (memory_limit) { + data_size_all += us->data_size; + if (data_size_all > memory_limit) { + break; + } + } + if (steps) { + if (us_count == steps) { + break; + } + if (us->skip == false) { + us_count += 1; + } + } + } + + if (us) { + if (us->prev && us->prev->prev) { + us = us->prev; + } + +#ifdef WITH_GLOBAL_UNDO_KEEP_ONE + /* 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) { + 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). */ + while (ustack->steps.first != us) { + UndoStep *us_first = ustack->steps.first; + BLI_assert(us_first != ustack->step_active); + undosys_step_free_and_unlink(ustack, us_first); + } + +#ifdef WITH_GLOBAL_UNDO_KEEP_ONE + if (us_exclude) { + BLI_addhead(&ustack->steps, us_exclude); + } +#endif + } +} + +/** \} */ + +UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut) +{ + UNDO_NESTED_ASSERT(false); + /* We could detect and clean this up (but it should never happen!). */ + BLI_assert(ustack->step_init == NULL); + if (ut->step_encode_init) { + undosys_stack_validate(ustack, false); + UndoStep *us = MEM_callocN(ut->step_size, __func__); + CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, name, ut->name); + if (name != NULL) { + BLI_strncpy(us->name, name, sizeof(us->name)); + } + us->type = ut; + ustack->step_init = us; + ut->step_encode_init(C, us); + undosys_stack_validate(ustack, true); + return us; + } + else { + return NULL; + } +} + +UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, bContext *C, const char *name) +{ + UNDO_NESTED_ASSERT(false); + /* We could detect and clean this up (but it should never happen!). */ + BLI_assert(ustack->step_init == NULL); + const UndoType *ut = BKE_undosys_type_from_context(C); + if (ut == NULL) { + return NULL; + } + return BKE_undosys_step_push_init_with_type(ustack, C, name, ut); +} + +bool BKE_undosys_step_push_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut) +{ + UNDO_NESTED_ASSERT(false); + undosys_stack_validate(ustack, false); + bool is_not_empty = ustack->step_active != NULL; + + /* Remove all undos after (also when 'ustack->step_active == NULL'). */ + while (ustack->steps.last != ustack->step_active) { + UndoStep *us_iter = ustack->steps.last; + undosys_step_free_and_unlink(ustack, us_iter); + undosys_stack_validate(ustack, is_not_empty); + } + + if (ustack->step_active) { + BLI_assert(BLI_findindex(&ustack->steps, ustack->step_active) != -1); + } + +#ifdef WITH_GLOBAL_UNDO_ENSURE_UPDATED + if (ut->step_foreach_ID_ref != NULL) { + Main *bmain = G.main; + if (bmain->is_memfile_undo_written == false) { + const char *name_internal = "MemFile Internal"; + if (undosys_stack_push_main(ustack, name_internal, bmain)) { + UndoStep *us = ustack->steps.last; + BLI_assert(STREQ(us->name, name_internal)); + us->skip = true; + } + } + } +#endif + + UndoStep *us = ustack->step_init ? ustack->step_init : MEM_callocN(ut->step_size, __func__); + ustack->step_init = NULL; + if (us->name[0] == '\0') { + BLI_strncpy(us->name, name, sizeof(us->name)); + } + us->type = ut; + /* initialized, not added yet. */ + + if (undosys_step_encode(C, us)) { + ustack->step_active = us; + BLI_addtail(&ustack->steps, us); + undosys_stack_validate(ustack, true); + return true; + } + else { + MEM_freeN(us); + undosys_stack_validate(ustack, true); + return false; + } +} + +bool BKE_undosys_step_push(UndoStack *ustack, bContext *C, const char *name) +{ + UNDO_NESTED_ASSERT(false); + const UndoType *ut = ustack->step_init ? ustack->step_init->type : BKE_undosys_type_from_context(C); + if (ut == NULL) { + return false; + } + return BKE_undosys_step_push_with_type(ustack, C, name, ut); +} + + +/** + * Useful when we want to diff against previous undo data but can't be sure the types match. + */ +UndoStep *BKE_undosys_step_same_type_next(UndoStep *us) +{ + if (us) { + const UndoType *ut = us->type; + while ((us = us->next)) { + if (us->type == ut) { + return us; + } + } + + } + return us; +} + +/** + * Useful when we want to diff against previous undo data but can't be sure the types match. + */ +UndoStep *BKE_undosys_step_same_type_prev(UndoStep *us) +{ + if (us) { + const UndoType *ut = us->type; + while ((us = us->prev)) { + if (us->type == ut) { + return us; + } + } + + } + return us; +} + +UndoStep *BKE_undosys_step_find_by_name_with_type(UndoStack *ustack, const char *name, const UndoType *ut) +{ + for (UndoStep *us = ustack->steps.last; us; us = us->prev) { + if (us->type == ut) { + if (STREQ(name, us->name)) { + return us; + } + } + } + return NULL; +} + +UndoStep *BKE_undosys_step_find_by_name(UndoStack *ustack, const char *name) +{ + return BLI_rfindstring(&ustack->steps, name, offsetof(UndoStep, name)); +} + +bool BKE_undosys_step_undo_with_data_ex( + UndoStack *ustack, bContext *C, UndoStep *us, + bool use_skip) +{ + UNDO_NESTED_ASSERT(false); + if (us) { + undosys_stack_validate(ustack, true); + } + UndoStep *us_prev = us ? us->prev : NULL; + if (us && us->type->mode == BKE_UNDOTYPE_MODE_STORE) { + /* The current state is a copy, we need to load the previous state. */ + us = us_prev; + } + + if (us != NULL) { + CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name); + undosys_step_decode(C, us, -1); + ustack->step_active = us_prev; + undosys_stack_validate(ustack, true); + 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); + } + } + return true; + } + return false; +} +bool BKE_undosys_step_undo_with_data(UndoStack *ustack, bContext *C, UndoStep *us) +{ + return BKE_undosys_step_undo_with_data_ex(ustack, C, us, true); +} + +bool BKE_undosys_step_undo(UndoStack *ustack, bContext *C) +{ + return BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active); +} + +void BKE_undosys_step_undo_from_index(UndoStack *ustack, bContext *C, int index) +{ + UndoStep *us = BLI_findlink(&ustack->steps, index); + BLI_assert(us->skip == false); + BKE_undosys_step_load_data(ustack, C, us); +} + +bool BKE_undosys_step_redo_with_data_ex( + UndoStack *ustack, bContext *C, UndoStep *us, + bool use_skip) +{ + UNDO_NESTED_ASSERT(false); + UndoStep *us_next = us ? us->next : NULL; + /* Unlike undo accumulate, we always use the next. */ + us = us_next; + + if (us != NULL) { + CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name); + undosys_step_decode(C, us, 1); + ustack->step_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); + } + } + return true; + } + return false; +} +bool BKE_undosys_step_redo_with_data(UndoStack *ustack, bContext *C, UndoStep *us) +{ + return BKE_undosys_step_redo_with_data_ex(ustack, C, us, true); +} + +bool BKE_undosys_step_redo(UndoStack *ustack, bContext *C) +{ + return BKE_undosys_step_redo_with_data(ustack, C, ustack->step_active); +} + +bool BKE_undosys_step_load_data(UndoStack *ustack, bContext *C, UndoStep *us) +{ + UNDO_NESTED_ASSERT(false); + const int index_active = BLI_findindex(&ustack->steps, ustack->step_active); + const int index_target = BLI_findindex(&ustack->steps, us); + BLI_assert(!ELEM(-1, index_active, index_target)); + bool ok = true; + + if (index_target < index_active) { + uint i = index_active - index_target; + while (i-- && ok) { + ok = BKE_undosys_step_undo_with_data_ex(ustack, C, ustack->step_active, false); + } + } + else if (index_target > index_active) { + uint i = index_target - index_active; + while (i-- && ok) { + ok = BKE_undosys_step_redo_with_data_ex(ustack, C, ustack->step_active, false); + } + } + + if (ok) { + BLI_assert(ustack->step_active == us); + } + + return ok; +} + +bool BKE_undosys_step_undo_compat_only(UndoStack *ustack, bContext *C, int step) +{ + if (step == 0) { + return BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active); + } + else if (step == 1) { + return BKE_undosys_step_undo(ustack, C); + } + else { + return BKE_undosys_step_redo(ustack, C); + } +} +/** + * Similar to #WM_operatortype_append + */ +UndoType *BKE_undosys_type_append(void (*undosys_fn)(UndoType *)) +{ + UndoType *ut; + + ut = MEM_callocN(sizeof(UndoType), __func__); + + undosys_fn(ut); + + BLI_assert(ut->mode != 0); + + BLI_addtail(&g_undo_types, ut); + + return ut; +} + +void BKE_undosys_type_free_all(void) +{ + UndoType *ut; + while ((ut = BLI_pophead(&g_undo_types))) { + MEM_freeN(ut); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ID Reference Utilities + * + * Unfortunately we need this for a handful of places. + */ + +static void UNUSED_FUNCTION(BKE_undosys_foreach_ID_ref( + UndoStack *ustack, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)) +{ + for (UndoStep *us = ustack->steps.first; us; us = us->next) { + const UndoType *ut = us->type; + if (ut->step_foreach_ID_ref != NULL) { + ut->step_foreach_ID_ref(us, foreach_ID_ref_fn, user_data); + } + } +} + +typedef struct UndoIDPtrMapItem { + /** Never changes (matches undo data). Use as sort key for binary search. */ + const void *ptr; + /** Write the new pointers here. */ + uint index; +} UndoIDPtrMapItem; + +typedef struct UndoIDPtrMap { + UndoRefID *refs; + /** + * Pointer map, update 'dst' members before use. + * This is always sorted (adds some overhead when adding, in practice it's acceptable since). + */ + UndoIDPtrMapItem *pmap; + + /** Length for both 'refs' & 'pmap' */ + uint len; + uint len_alloc; +} UndoIDPtrMap; + +#ifdef DEBUG +# define PMAP_DEFAULT_ALLOC 1 +#else +# define PMAP_DEFAULT_ALLOC 32 +#endif + +void BKE_undosys_ID_map_foreach_ID_ref( + UndoIDPtrMap *map, + UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + for (uint i = 0; i < map->len; i++) { + foreach_ID_ref_fn(user_data, &map->refs[i]); + } +} + +/** + * Return true when found, otherwise index is set to the index we should insert. + */ +static bool undosys_ID_map_lookup_index(const UndoIDPtrMap *map, const void *key, uint *r_index) +{ + const UndoIDPtrMapItem *pmap = map->pmap; + const uint len = map->len; + if (len == 0) { + if (*r_index) { + *r_index = 0; + } + return false; + } + int min = 0, max = len - 1; + while (min <= max) { + const uint mid = (min + max) / 2; + if (pmap[mid].ptr < key) { + min = mid + 1; + } + else if (pmap[mid].ptr == key) { + if (r_index) { + *r_index = mid; + } + return true; + } + else if (pmap[mid].ptr > key) { + max = mid - 1; + } + } + if (r_index) { + *r_index = min; + } + return false; +} + +/** + * A set of ID's use for efficient decoding, so we can map pointers back to the newly loaded data + * without performing full look ups each time. + * + * This can be used as an old_pointer -> new_pointer lookup. + */ +UndoIDPtrMap *BKE_undosys_ID_map_create(void) +{ + UndoIDPtrMap *map = MEM_mallocN(sizeof(*map), __func__); + map->len_alloc = PMAP_DEFAULT_ALLOC; + map->refs = MEM_mallocN(sizeof(*map->refs) * map->len_alloc, __func__); + map->pmap = MEM_mallocN(sizeof(*map->pmap) * map->len_alloc, __func__); + map->len = 0; + return map; +} +void BKE_undosys_ID_map_destroy(UndoIDPtrMap *idpmap) +{ + MEM_SAFE_FREE(idpmap->refs); + MEM_SAFE_FREE(idpmap->pmap); + MEM_freeN(idpmap); +} + +void BKE_undosys_ID_map_add(UndoIDPtrMap *map, ID *id) +{ + uint index; + if (id->lib != NULL) { + return; + } + + if (undosys_ID_map_lookup_index(map, id, &index)) { + return; /* exists. */ + } + + const uint len_src = map->len; + const uint len_dst = map->len + 1; + if (len_dst > map->len_alloc) { + map->len_alloc *= 2; + BLI_assert(map->len_alloc >= len_dst); + map->pmap = MEM_reallocN(map->pmap, sizeof(*map->pmap) * map->len_alloc); + map->refs = MEM_reallocN(map->refs, sizeof(*map->refs) * map->len_alloc); + } + +#if 0 /* Will be done automatically in callback. */ + BLI_strncpy(map->refs[len_src].name, id->name, sizeof(id->name)); +#else + map->refs[len_src].name[0] = '\0'; +#endif + map->refs[len_src].ptr = id; + + if (len_src != 0 && index != len_src) { + memmove(&map->pmap[index + 1], &map->pmap[index], sizeof(*map->pmap) * (len_src - index)); + } + map->pmap[index].ptr = id; + map->pmap[index].index = len_src; + + map->len = len_dst; +} + +ID *BKE_undosys_ID_map_lookup(const UndoIDPtrMap *map, const ID *id_src) +{ + /* We should only ever lookup indices which exist! */ + uint index; + if (!undosys_ID_map_lookup_index(map, id_src, &index)) { + BLI_assert(0); + } + index = map->pmap[index].index; + ID *id_dst = map->refs[index].ptr; + BLI_assert(id_dst != NULL); + BLI_assert(STREQ(id_dst->name, map->refs[index].name)); + return id_dst; +} + +void BKE_undosys_ID_map_add_with_prev(UndoIDPtrMap *map, ID *id, ID **id_prev) +{ + if (id == *id_prev) { + return; + } + *id_prev = id; + BKE_undosys_ID_map_add(map, id); +} + +ID *BKE_undosys_ID_map_lookup_with_prev(const UndoIDPtrMap *map, ID *id_src, ID *id_prev_match[2]) +{ + if (id_src == id_prev_match[0]) { + return id_prev_match[1]; + } + else { + ID *id_dst = BKE_undosys_ID_map_lookup(map, id_src); + id_prev_match[0] = id_src; + id_prev_match[1] = id_dst; + return id_dst; + } +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 10fcfaa444f..5736c9331bf 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -43,7 +43,6 @@ #include "BLI_listbase.h" #include "BKE_animsys.h" -#include "BKE_global.h" #include "BKE_icons.h" #include "BKE_library.h" #include "BKE_library_query.h" diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 5415fbb8ae1..d7fcd896e11 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -53,6 +53,7 @@ #include "BKE_global.h" #include "BKE_idprop.h" +#include "BKE_image.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_sound.h" @@ -62,6 +63,8 @@ #include "ffmpeg_compat.h" +struct StampData; + typedef struct FFMpegContext { int ffmpeg_type; int ffmpeg_codec; @@ -94,6 +97,8 @@ typedef struct FFMpegContext { bool audio_deinterleave; int audio_sample_size; + struct StampData *stamp_data; + #ifdef WITH_AUDASPACE AUD_Device *audio_mixdown_device; #endif @@ -577,24 +582,33 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int } if (context->ffmpeg_preset) { - char const *preset_name; + /* 'preset' is used by h.264, 'deadline' is used by webm/vp9. I'm not + * setting those properties conditionally based on the video codec, + * as the FFmpeg encoder simply ignores unknown settings anyway. */ + char const *preset_name = NULL; /* used by h.264 */ + char const *deadline_name = NULL; /* used by webm/vp9 */ switch (context->ffmpeg_preset) { - case FFM_PRESET_ULTRAFAST: preset_name = "ultrafast"; break; - case FFM_PRESET_SUPERFAST: preset_name = "superfast"; break; - case FFM_PRESET_VERYFAST: preset_name = "veryfast"; break; - case FFM_PRESET_FASTER: preset_name = "faster"; break; - case FFM_PRESET_FAST: preset_name = "fast"; break; - case FFM_PRESET_MEDIUM: preset_name = "medium"; break; - case FFM_PRESET_SLOW: preset_name = "slow"; break; - case FFM_PRESET_SLOWER: preset_name = "slower"; break; - case FFM_PRESET_VERYSLOW: preset_name = "veryslow"; break; + case FFM_PRESET_GOOD: + preset_name = "medium"; + deadline_name = "good"; + break; + case FFM_PRESET_BEST: + preset_name = "slower"; + deadline_name = "best"; + break; + case FFM_PRESET_REALTIME: + preset_name = "superfast"; + deadline_name = "realtime"; + break; default: printf("Unknown preset number %i, ignoring.\n", context->ffmpeg_preset); - preset_name = NULL; } if (preset_name != NULL) { av_dict_set(&opts, "preset", preset_name, 0); } + if (deadline_name != NULL) { + av_dict_set(&opts, "deadline", deadline_name, 0); + } } #if 0 @@ -836,6 +850,12 @@ static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float va av_dict_set(dict, key, buffer, 0); } +static void ffmpeg_add_metadata_callback(void *data, const char *propname, char *propvalue, int len) +{ + AVDictionary **metadata = (AVDictionary **)data; + av_dict_set(metadata, propname, propvalue, 0); +} + static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int rectx, int recty, const char *suffix, ReportList *reports) { /* Handle to the output file */ @@ -994,6 +1014,11 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int goto fail; } } + + if (context->stamp_data != NULL) { + BKE_stamp_info_callback(&of->metadata, context->stamp_data, ffmpeg_add_metadata_callback, false); + } + if (avformat_write_header(of, NULL) < 0) { BKE_report(reports, RPT_ERROR, "Could not initialize streams, probably unsupported codec combination"); goto fail; @@ -1168,6 +1193,7 @@ int BKE_ffmpeg_start(void *context_v, struct Scene *scene, RenderData *rd, int r context->ffmpeg_autosplit_count = 0; context->ffmpeg_preview = preview; + context->stamp_data = BKE_stamp_info_from_scene_static(scene); success = start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports); #ifdef WITH_AUDASPACE @@ -1659,7 +1685,7 @@ void BKE_ffmpeg_image_type_verify(RenderData *rd, ImageFormatData *imf) { BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_H264); rd->ffcodecdata.constant_rate_factor = FFM_CRF_MEDIUM; - rd->ffcodecdata.ffmpeg_preset = FFM_PRESET_MEDIUM; + rd->ffcodecdata.ffmpeg_preset = FFM_PRESET_GOOD; rd->ffcodecdata.type = FFMPEG_MKV; } if (rd->ffcodecdata.type == FFMPEG_OGG) { @@ -1734,6 +1760,7 @@ void *BKE_ffmpeg_context_create(void) context->ffmpeg_autosplit = 0; context->ffmpeg_autosplit_count = 0; context->ffmpeg_preview = false; + context->stamp_data = NULL; return context; } @@ -1741,9 +1768,13 @@ void *BKE_ffmpeg_context_create(void) void BKE_ffmpeg_context_free(void *context_v) { FFMpegContext *context = context_v; - if (context) { - MEM_freeN(context); + if (context == NULL) { + return; + } + if (context->stamp_data) { + MEM_freeN(context->stamp_data); } + MEM_freeN(context); } #endif /* WITH_FFMPEG */ diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h index 6be9408ac1e..c4ad5acfe4b 100644 --- a/source/blender/blenlib/BLI_listbase.h +++ b/source/blender/blenlib/BLI_listbase.h @@ -74,7 +74,7 @@ void BLI_listbase_sort(struct ListBase *listbase, int (*cmp)(const void *, const void BLI_listbase_sort_r(ListBase *listbase, int (*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1, 2); bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL(); void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1); -int BLI_listbase_count_ex(const struct ListBase *listbase, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +int BLI_listbase_count_at_most(const struct ListBase *listbase, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1); diff --git a/source/blender/blenlib/BLI_sort_utils.h b/source/blender/blenlib/BLI_sort_utils.h index e08f4e5ac83..f6bd80b30d3 100644 --- a/source/blender/blenlib/BLI_sort_utils.h +++ b/source/blender/blenlib/BLI_sort_utils.h @@ -32,7 +32,7 @@ * \note keep \a sort_value first, * so cmp functions can be reused. */ -struct SortPointerByFloat { +struct SortPtrByFloat { float sort_value; void *data; }; @@ -42,7 +42,7 @@ struct SortIntByFloat { int data; }; -struct SortPointerByInt { +struct SortPtrByInt { int sort_value; void *data; }; @@ -58,4 +58,7 @@ int BLI_sortutil_cmp_float_reverse(const void *a_, const void *b_); int BLI_sortutil_cmp_int(const void *a_, const void *b_); int BLI_sortutil_cmp_int_reverse(const void *a_, const void *b_); +int BLI_sortutil_cmp_ptr(const void *a_, const void *b_); +int BLI_sortutil_cmp_ptr_reverse(const void *a_, const void *b_); + #endif /* __BLI_SORT_UTILS_H__ */ diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index d137806c575..48be9d1842f 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -103,6 +103,20 @@ int BLI_string_find_split_words( const char delim, int r_words[][2], int words_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +/** \name String Copy/Format Macros + * Avoid repeating destination with `sizeof(..)`. + * \note `ARRAY_SIZE` allows pointers on some platforms. + * \{ */ +#define STRNCPY(dst, src) \ + BLI_strncpy(dst, src, ARRAY_SIZE(dst)) +#define STRNCPY_RLEN(dst, src) \ + BLI_strncpy_rlen(dst, src, ARRAY_SIZE(dst)) +#define SNPRINTF(dst, format, ...) \ + BLI_snprintf(dst, ARRAY_SIZE(dst), format, __VA_ARGS__) +#define SNPRINTF_RLEN(dst, format, ...) \ + BLI_snprintf_rlen(dst, ARRAY_SIZE(dst), format, __VA_ARGS__) +/** \} */ + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h index 32504a88b48..21542d0d6e1 100644 --- a/source/blender/blenlib/BLI_string_utf8.h +++ b/source/blender/blenlib/BLI_string_utf8.h @@ -77,6 +77,16 @@ size_t BLI_str_partition_ex_utf8( #define BLI_UTF8_WIDTH_MAX 2 /* columns */ #define BLI_UTF8_ERR ((unsigned int)-1) +/** \name String Copy/Format Macros + * Avoid repeating destination with `sizeof(..)`. + * \note `ARRAY_SIZE` allows pointers on some platforms. + * \{ */ +#define STRNCPY_UTF8(dst, src) \ + BLI_strncpy_utf8(dst, src, ARRAY_SIZE(dst)) +#define STRNCPY_UTF8_RLEN(dst, src) \ + BLI_strncpy_utf8_rlen(dst, src, ARRAY_SIZE(dst)) +/** \} */ + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index 11c8a586784..46b3748c7ce 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -411,7 +411,7 @@ extern "C" { } (void)0 /* assuming a static array */ -#if defined(__GNUC__) && !defined(__cplusplus) && !defined(__clang__) +#if defined(__GNUC__) && !defined(__cplusplus) && !defined(__clang__) && !defined(__INTEL_COMPILER) # define ARRAY_SIZE(arr) \ ((sizeof(struct {int isnt_array : ((const void *)&(arr) == &(arr)[0]);}) * 0) + \ (sizeof(arr) / sizeof(*(arr)))) diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c index 96c3972d802..b87fed571b7 100644 --- a/source/blender/blenlib/intern/listbase.c +++ b/source/blender/blenlib/intern/listbase.c @@ -484,7 +484,7 @@ void BLI_freelistN(ListBase *listbase) * * \note Use to avoid redundant looping. */ -int BLI_listbase_count_ex(const ListBase *listbase, const int count_max) +int BLI_listbase_count_at_most(const ListBase *listbase, const int count_max) { Link *link; int count = 0; diff --git a/source/blender/blenlib/intern/sort_utils.c b/source/blender/blenlib/intern/sort_utils.c index c75e8e7455f..2d55e77b98b 100644 --- a/source/blender/blenlib/intern/sort_utils.c +++ b/source/blender/blenlib/intern/sort_utils.c @@ -37,6 +37,10 @@ struct SortAnyByInt { int sort_value; }; +struct SortAnyByPtr { + const void *sort_value; +}; + int BLI_sortutil_cmp_float(const void *a_, const void *b_) { const struct SortAnyByFloat *a = a_; @@ -72,3 +76,21 @@ int BLI_sortutil_cmp_int_reverse(const void *a_, const void *b_) else if (a->sort_value > b->sort_value) return -1; else return 0; } + +int BLI_sortutil_cmp_ptr(const void *a_, const void *b_) +{ + const struct SortAnyByPtr *a = a_; + const struct SortAnyByPtr *b = b_; + if (a->sort_value > b->sort_value) return 1; + else if (a->sort_value < b->sort_value) return -1; + else return 0; +} + +int BLI_sortutil_cmp_ptr_reverse(const void *a_, const void *b_) +{ + const struct SortAnyByPtr *a = a_; + const struct SortAnyByPtr *b = b_; + if (a->sort_value < b->sort_value) return 1; + else if (a->sort_value > b->sort_value) return -1; + else return 0; +} diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 4fd2e227bc5..0b4ff13c7bd 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -147,6 +147,8 @@ void BLO_update_defaults_startup_blend(struct Main *mainvar); struct BlendThumbnail *BLO_thumbnail_from_file(const char *filepath); +struct Main *BLO_main_from_memfile(struct MemFile *memfile, struct Main *bmain, struct Scene **r_scene); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h index d3c0130a63b..b713b963056 100644 --- a/source/blender/blenloader/BLO_undofile.h +++ b/source/blender/blenloader/BLO_undofile.h @@ -33,6 +33,8 @@ * \ingroup blenloader */ +struct Scene; + typedef struct { void *next, *prev; const char *buf; @@ -47,6 +49,12 @@ typedef struct MemFile { size_t size; } MemFile; +typedef struct MemFileUndoData { + char filename[1024]; /* FILE_MAX */ + MemFile memfile; + size_t undo_size; +} MemFileUndoData; + /* actually only used writefile.c */ extern void memfile_chunk_add(MemFile *compare, MemFile *current, const char *buf, unsigned int size); @@ -54,5 +62,9 @@ extern void memfile_chunk_add(MemFile *compare, MemFile *current, const char *bu extern void BLO_memfile_free(MemFile *memfile); extern void BLO_memfile_merge(MemFile *first, MemFile *second); -#endif +/* utilities */ +extern struct Main *BLO_memfile_main_get(struct MemFile *memfile, struct Main *bmain, struct Scene **r_scene); +extern bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename); + +#endif /* __BLO_UNDOFILE_H__ */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index e85af67b105..a4739240cb4 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2235,6 +2235,10 @@ static void direct_link_id(FileData *fd, ID *id) IDP_DirectLinkGroup_OrFree(&id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); } id->py_instance = NULL; + + /* That way datablock reading not going through main read_libblock() function are still in a clear tag state. + * (glowering at certain nodetree fake datablock here...). */ + id->tag = 0; } /* ************ READ CurveMapping *************** */ @@ -3708,15 +3712,11 @@ static void lib_link_text(FileData *fd, Main *main) static void direct_link_text(FileData *fd, Text *text) { TextLine *ln; - + text->name = newdataadr(fd, text->name); - - text->undo_pos = -1; - text->undo_len = TXT_INIT_UNDO; - text->undo_buf = MEM_mallocN(text->undo_len, "undo buf"); - + text->compiled = NULL; - + #if 0 if (text->flags & TXT_ISEXT) { BKE_text_reload(text); @@ -5076,6 +5076,7 @@ static void direct_link_pose(FileData *fd, bPose *pose) link_list(fd, &pose->agroups); pose->chanhash = NULL; + pose->chan_array = NULL; for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) { pchan->bone = NULL; @@ -6300,7 +6301,8 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm) wm->defaultconf = NULL; wm->addonconf = NULL; wm->userconf = NULL; - + wm->undo_stack = NULL; + BLI_listbase_clear(&wm->jobs); BLI_listbase_clear(&wm->drags); @@ -8236,7 +8238,6 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short if (!id) return blo_nextbhead(fd, bhead); - id->tag = tag | LIB_TAG_NEED_LINK; id->lib = main->curlib; id->us = ID_FAKE_USERS(id); id->icon_id = 0; @@ -8245,12 +8246,12 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short /* this case cannot be direct_linked: it's just the ID part */ if (bhead->code == ID_ID) { + /* That way, we know which datablock needs do_versions (required currently for linking). */ + id->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW; + return blo_nextbhead(fd, bhead); } - /* That way, we know which datablock needs do_versions (required currently for linking). */ - id->tag |= LIB_TAG_NEW; - /* need a name for the mallocN, just for debugging and sane prints on leaks */ allocname = dataname(GS(id->name)); @@ -8259,7 +8260,11 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short /* init pointers direct data */ direct_link_id(fd, id); - + + /* That way, we know which datablock needs do_versions (required currently for linking). */ + /* Note: doing this after driect_link_id(), which resets that field. */ + id->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW; + switch (GS(id->name)) { case ID_WM: direct_link_windowmanager(fd, (wmWindowManager *)id); diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c index ffc7d7c83f5..f6584ecf25f 100644 --- a/source/blender/blenloader/intern/undofile.c +++ b/source/blender/blenloader/intern/undofile.c @@ -34,6 +34,15 @@ #include <string.h> #include <stdio.h> #include <math.h> +#include <fcntl.h> +#include <errno.h> + +/* open/close */ +#ifndef _WIN32 +# include <unistd.h> +#else +# include <io.h> +#endif #include "MEM_guardedalloc.h" @@ -42,6 +51,9 @@ #include "BLI_blenlib.h" #include "BLO_undofile.h" +#include "BLO_readfile.h" + +#include "BKE_main.h" /* keep last */ #include "BLI_strict_flags.h" @@ -124,3 +136,69 @@ void memfile_chunk_add(MemFile *compare, MemFile *current, const char *buf, unsi current->size += size; } } + +struct Main *BLO_memfile_main_get(struct MemFile *memfile, struct Main *oldmain, struct Scene **r_scene) +{ + struct Main *bmain_undo = NULL; + BlendFileData *bfd = BLO_read_from_memfile(oldmain, oldmain->name, memfile, NULL, BLO_READ_SKIP_NONE); + + if (bfd) { + bmain_undo = bfd->main; + if (r_scene) { + *r_scene = bfd->curscene; + } + + MEM_freeN(bfd); + } + + return bmain_undo; +} + + +/** + * Saves .blend using undo buffer. + * + * \return success. + */ +bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename) +{ + MemFileChunk *chunk; + int file, oflags; + + /* note: This is currently used for autosave and 'quit.blend', where _not_ following symlinks is OK, + * however if this is ever executed explicitly by the user, we may want to allow writing to symlinks. + */ + + oflags = O_BINARY | O_WRONLY | O_CREAT | O_TRUNC; +#ifdef O_NOFOLLOW + /* use O_NOFOLLOW to avoid writing to a symlink - use 'O_EXCL' (CVE-2008-1103) */ + oflags |= O_NOFOLLOW; +#else + /* TODO(sergey): How to deal with symlinks on windows? */ +# ifndef _MSC_VER +# warning "Symbolic links will be followed on undo save, possibly causing CVE-2008-1103" +# endif +#endif + file = BLI_open(filename, oflags, 0666); + + if (file == -1) { + fprintf(stderr, "Unable to save '%s': %s\n", + filename, errno ? strerror(errno) : "Unknown error opening file"); + return false; + } + + for (chunk = memfile->chunks.first; chunk; chunk = chunk->next) { + if ((size_t)write(file, chunk->buf, chunk->size) != chunk->size) { + break; + } + } + + close(file); + + if (chunk) { + fprintf(stderr, "Unable to save '%s': %s\n", + filename, errno ? strerror(errno) : "Unknown error writing file"); + return false; + } + return true; +} diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index f1c40aae399..e9de7919d25 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1796,6 +1796,23 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } + + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + int preset = scene->r.ffcodecdata.ffmpeg_preset; + if (preset == FFM_PRESET_NONE || preset >= FFM_PRESET_GOOD) { + continue; + } + if (preset <= FFM_PRESET_FAST) { + preset = FFM_PRESET_REALTIME; + } + else if (preset >= FFM_PRESET_SLOW) { + preset = FFM_PRESET_BEST; + } + else { + preset = FFM_PRESET_GOOD; + } + scene->r.ffcodecdata.ffmpeg_preset = preset; + } } } diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index c4b29e91fb4..7e35866887d 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -685,7 +685,7 @@ int bmesh_elem_check(void *element, const char htype) err |= IS_FACE_LOOP_WRONG_RADIAL_LENGTH; } - if (bmesh_disk_count_ex(l_iter->v, 2) < 2) { + if (bmesh_disk_count_at_most(l_iter->v, 2) < 2) { err |= IS_FACE_LOOP_WRONG_DISK_LENGTH; } } @@ -1785,7 +1785,7 @@ BMEdge *bmesh_kernel_join_edge_kill_vert( return NULL; } - if (bmesh_disk_count_ex(v_kill, 3) == 2) { + if (bmesh_disk_count_at_most(v_kill, 3) == 2) { #ifndef NDEBUG int valence1, valence2; BMLoop *l; diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index 961cc458784..4290f94bba1 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -65,7 +65,7 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v) { /* logic for 3 or more is identical */ - const int len = BM_vert_edge_count_ex(v, 3); + const int len = BM_vert_edge_count_at_most(v, 3); if (len == 1) { BM_vert_kill(bm, v); /* will kill edges too */ diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h index 4dcf97e3f35..daee22ffe76 100644 --- a/source/blender/bmesh/intern/bmesh_private.h +++ b/source/blender/bmesh/intern/bmesh_private.h @@ -55,7 +55,7 @@ int bmesh_elem_check(void *element, const char htype); #endif int bmesh_radial_length(const BMLoop *l); -int bmesh_disk_count_ex(const BMVert *v, const int count_max); +int bmesh_disk_count_at_most(const BMVert *v, const int count_max); int bmesh_disk_count(const BMVert *v); /** diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 3a76f4ca271..ab2f017d103 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -799,9 +799,9 @@ int BM_vert_edge_count(const BMVert *v) return bmesh_disk_count(v); } -int BM_vert_edge_count_ex(const BMVert *v, const int count_max) +int BM_vert_edge_count_at_most(const BMVert *v, const int count_max) { - return bmesh_disk_count_ex(v, count_max); + return bmesh_disk_count_at_most(v, count_max); } int BM_vert_edge_count_nonwire(const BMVert *v) @@ -835,7 +835,7 @@ int BM_edge_face_count(const BMEdge *e) return count; } -int BM_edge_face_count_ex(const BMEdge *e, const int count_max) +int BM_edge_face_count_at_most(const BMEdge *e, const int count_max) { int count = 0; @@ -863,9 +863,9 @@ int BM_vert_face_count(const BMVert *v) return bmesh_disk_facevert_count(v); } -int BM_vert_face_count_ex(const BMVert *v, int count_max) +int BM_vert_face_count_at_most(const BMVert *v, int count_max) { - return bmesh_disk_facevert_count_ex(v, count_max); + return bmesh_disk_facevert_count_at_most(v, count_max); } /** @@ -1044,7 +1044,7 @@ static int bm_loop_region_count__clear(BMLoop *l) /** * The number of loops connected to this loop (not including disconnected regions). */ -int BM_loop_region_loops_count_ex(BMLoop *l, int *r_loop_total) +int BM_loop_region_loops_count_at_most(BMLoop *l, int *r_loop_total) { const int count = bm_loop_region_count__recursive(l->e, l->v); const int count_total = bm_loop_region_count__clear(l); @@ -1059,7 +1059,7 @@ int BM_loop_region_loops_count_ex(BMLoop *l, int *r_loop_total) int BM_loop_region_loops_count(BMLoop *l) { - return BM_loop_region_loops_count_ex(l, NULL); + return BM_loop_region_loops_count_at_most(l, NULL); } /** @@ -1071,7 +1071,7 @@ bool BM_vert_is_manifold_region(const BMVert *v) BMLoop *l_first = BM_vert_find_first_loop((BMVert *)v); if (l_first) { int count, count_total; - count = BM_loop_region_loops_count_ex(l_first, &count_total); + count = BM_loop_region_loops_count_at_most(l_first, &count_total); return (count == count_total); } return true; diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index c9fce96c798..e602c63da94 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -70,17 +70,17 @@ BMFace *BM_edge_pair_share_face_by_len( const bool allow_adjacent) ATTR_NONNULL(); int BM_vert_edge_count_nonwire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -#define BM_vert_edge_count_is_equal(v, n) (BM_vert_edge_count_ex(v, (n) + 1) == n) -#define BM_vert_edge_count_is_over(v, n) (BM_vert_edge_count_ex(v, (n) + 1) == (n) + 1) -int BM_vert_edge_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +#define BM_vert_edge_count_is_equal(v, n) (BM_vert_edge_count_at_most(v, (n) + 1) == n) +#define BM_vert_edge_count_is_over(v, n) (BM_vert_edge_count_at_most(v, (n) + 1) == (n) + 1) +int BM_vert_edge_count_at_most(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BM_vert_edge_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -#define BM_edge_face_count_is_equal(e, n) (BM_edge_face_count_ex(e, (n) + 1) == n) -#define BM_edge_face_count_is_over(e, n) (BM_edge_face_count_ex(e, (n) + 1) == (n) + 1) -int BM_edge_face_count_ex(const BMEdge *e, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +#define BM_edge_face_count_is_equal(e, n) (BM_edge_face_count_at_most(e, (n) + 1) == n) +#define BM_edge_face_count_is_over(e, n) (BM_edge_face_count_at_most(e, (n) + 1) == (n) + 1) +int BM_edge_face_count_at_most(const BMEdge *e, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BM_edge_face_count(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -#define BM_vert_face_count_is_equal(v, n) (BM_vert_face_count_ex(v, (n) + 1) == n) -#define BM_vert_face_count_is_over(v, n) (BM_vert_face_count_ex(v, (n) + 1) == (n) + 1) -int BM_vert_face_count_ex(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +#define BM_vert_face_count_is_equal(v, n) (BM_vert_face_count_at_most(v, (n) + 1) == n) +#define BM_vert_face_count_is_over(v, n) (BM_vert_face_count_at_most(v, (n) + 1) == (n) + 1) +int BM_vert_face_count_at_most(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BM_vert_face_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); @@ -103,7 +103,7 @@ bool BM_edge_is_contiguous_loop_cd( const int cd_loop_type, const int cd_loop_offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -int BM_loop_region_loops_count_ex(BMLoop *l, int *r_loop_total) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +int BM_loop_region_loops_count_at_most(BMLoop *l, int *r_loop_total) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); int BM_loop_region_loops_count(BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); bool BM_loop_is_convex(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c index 8e484841568..8aa9502c0f7 100644 --- a/source/blender/bmesh/intern/bmesh_structure.c +++ b/source/blender/bmesh/intern/bmesh_structure.c @@ -244,7 +244,7 @@ int bmesh_disk_count(const BMVert *v) return count; } -int bmesh_disk_count_ex(const BMVert *v, const int count_max) +int bmesh_disk_count_at_most(const BMVert *v, const int count_max) { int count = 0; if (v->e) { @@ -267,7 +267,7 @@ bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v) if (!BM_vert_in_edge(e, v)) { return false; } - if (len == 0 || bmesh_disk_count_ex(v, len + 1) != len) { + if (len == 0 || bmesh_disk_count_at_most(v, len + 1) != len) { return false; } @@ -307,7 +307,7 @@ int bmesh_disk_facevert_count(const BMVert *v) return count; } -int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) +int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max) { /* is there an edge on this vert at all */ int count = 0; @@ -318,7 +318,7 @@ int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) e_first = e_iter = v->e; do { if (e_iter->l) { - count += bmesh_radial_facevert_count_ex(e_iter->l, v, count_max - count); + count += bmesh_radial_facevert_count_at_most(e_iter->l, v, count_max - count); if (count == count_max) { break; } @@ -560,7 +560,7 @@ int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v) return count; } -int bmesh_radial_facevert_count_ex(const BMLoop *l, const BMVert *v, const int count_max) +int bmesh_radial_facevert_count_at_most(const BMLoop *l, const BMVert *v, const int count_max) { const BMLoop *l_iter; int count = 0; diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h index 0efb25da37c..974b276f8b3 100644 --- a/source/blender/bmesh/intern/bmesh_structure.h +++ b/source/blender/bmesh/intern/bmesh_structure.h @@ -49,7 +49,7 @@ BLI_INLINE BMEdge *bmesh_disk_edge_next_safe(const BMEdge *e, const BMVert *v) A BLI_INLINE BMEdge *bmesh_disk_edge_prev_safe(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); @@ -63,7 +63,7 @@ void bmesh_radial_loop_unlink(BMLoop *l) ATTR_NONNULL(); * bmesh_radial_loop_next(BMLoop *l) / prev. * just use member access l->radial_next, l->radial_prev now */ -int bmesh_radial_facevert_count_ex(const BMLoop *l, const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +int bmesh_radial_facevert_count_at_most(const BMLoop *l, const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c index 69198ff35ab..b1053e6d8c2 100644 --- a/source/blender/bmesh/operators/bmo_join_triangles.c +++ b/source/blender/bmesh/operators/bmo_join_triangles.c @@ -270,7 +270,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) BMFace *f; BMEdge *e; /* data: edge-to-join, sort_value: error weight */ - struct SortPointerByFloat *jedges; + struct SortPtrByFloat *jedges; unsigned i, totedge; uint totedge_tag = 0; diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index 6ae82ddd836..334dff20d52 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -592,6 +592,12 @@ void AnimationImporter:: Assign_color_animations(const COLLADAFW::UniqueId& list BLI_strncpy(rna_path, anim_type, sizeof(rna_path)); const COLLADAFW::AnimationList *animlist = animlist_map[listid]; + if (animlist == NULL) + { + fprintf(stderr, "Collada: No animlist found for ID: %s of type %s\n", listid.toAscii().c_str(), anim_type); + return; + } + const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings(); //all the curves belonging to the current binding std::vector<FCurve *> animcurves; @@ -889,11 +895,22 @@ static const double get_aspect_ratio(const COLLADAFW::Camera *camera) return aspect; } +static ListBase &get_animation_curves(Material *ma) +{ + bAction *act; + if (!ma->adt || !ma->adt->action) + act = verify_adt_action((ID *)&ma->id, 1); + else + act = ma->adt->action; + + return act->curves; +} void AnimationImporter::translate_Animations(COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& root_map, std::multimap<COLLADAFW::UniqueId, Object *>& object_map, - std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map) + std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map, + std::map<COLLADAFW::UniqueId, Material*> uid_material_map) { bool is_joint = node->getType() == COLLADAFW::Node::JOINT; COLLADAFW::UniqueId uid = node->getUniqueId(); @@ -1071,11 +1088,6 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, } } if (animType->material != 0) { - Material *ma = give_current_material(ob, 1); - if (!ma->adt || !ma->adt->action) act = verify_adt_action((ID *)&ma->id, 1); - else act = ma->adt->action; - - ListBase *AnimCurves = &(act->curves); const COLLADAFW::InstanceGeometryPointerArray& nodeGeoms = node->getInstanceGeometries(); for (unsigned int i = 0; i < nodeGeoms.getCount(); i++) { @@ -1084,30 +1096,36 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, const COLLADAFW::UniqueId & matuid = matBinds[j].getReferencedMaterial(); const COLLADAFW::Effect *ef = (COLLADAFW::Effect *) (FW_object_map[matuid]); if (ef != NULL) { /* can be NULL [#28909] */ - const COLLADAFW::CommonEffectPointerArray& commonEffects = ef->getCommonEffects(); + Material *ma = uid_material_map[matuid]; + if (!ma) { + fprintf(stderr, "Collada: Node %s refers to undefined material\n", node->getName().c_str()); + continue; + } + ListBase &AnimCurves = get_animation_curves(ma); + const COLLADAFW::CommonEffectPointerArray& commonEffects = ef->getCommonEffects(); COLLADAFW::EffectCommon *efc = commonEffects[0]; if ((animType->material & MATERIAL_SHININESS) != 0) { const COLLADAFW::FloatOrParam *shin = &(efc->getShininess()); - const COLLADAFW::UniqueId& listid = shin->getAnimationList(); - Assign_float_animations(listid, AnimCurves, "specular_hardness"); + const COLLADAFW::UniqueId& listid = shin->getAnimationList(); + Assign_float_animations(listid, &AnimCurves, "specular_hardness"); } if ((animType->material & MATERIAL_IOR) != 0) { const COLLADAFW::FloatOrParam *ior = &(efc->getIndexOfRefraction()); - const COLLADAFW::UniqueId& listid = ior->getAnimationList(); - Assign_float_animations(listid, AnimCurves, "raytrace_transparency.ior"); + const COLLADAFW::UniqueId& listid = ior->getAnimationList(); + Assign_float_animations(listid, &AnimCurves, "raytrace_transparency.ior"); } if ((animType->material & MATERIAL_SPEC_COLOR) != 0) { const COLLADAFW::ColorOrTexture *cot = &(efc->getSpecular()); - const COLLADAFW::UniqueId& listid = cot->getColor().getAnimationList(); - Assign_color_animations(listid, AnimCurves, "specular_color"); + const COLLADAFW::UniqueId& listid = cot->getColor().getAnimationList(); + Assign_color_animations(listid, &AnimCurves, "specular_color"); } if ((animType->material & MATERIAL_DIFF_COLOR) != 0) { const COLLADAFW::ColorOrTexture *cot = &(efc->getDiffuse()); - const COLLADAFW::UniqueId& listid = cot->getColor().getAnimationList(); - Assign_color_animations(listid, AnimCurves, "diffuse_color"); + const COLLADAFW::UniqueId& listid = cot->getColor().getAnimationList(); + Assign_color_animations(listid, &AnimCurves, "diffuse_color"); } } } diff --git a/source/blender/collada/AnimationImporter.h b/source/blender/collada/AnimationImporter.h index 1f2de2f3162..e25116cac9f 100644 --- a/source/blender/collada/AnimationImporter.h +++ b/source/blender/collada/AnimationImporter.h @@ -156,7 +156,8 @@ public: void translate_Animations(COLLADAFW::Node * Node, std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map, std::multimap<COLLADAFW::UniqueId, Object*>& object_map, - std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map); + std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map, + std::map<COLLADAFW::UniqueId, Material*> uid_material_map); AnimMix* get_animation_type( const COLLADAFW::Node * node, std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map ); diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 08ac6e65c11..ce0d296843b 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -320,7 +320,7 @@ void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW translate_anim_recursive(node, node, parob); } else { - anim_importer.translate_Animations(node, root_map, object_map, FW_object_map); + anim_importer.translate_Animations(node, root_map, object_map, FW_object_map, uid_material_map); COLLADAFW::NodePointerArray &children = node->getChildNodes(); for (i = 0; i < children.getCount(); i++) { translate_anim_recursive(children[i], node, NULL); diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp index 81891d853d2..1399749fc8d 100644 --- a/source/blender/compositor/nodes/COM_ImageNode.cpp +++ b/source/blender/compositor/nodes/COM_ImageNode.cpp @@ -105,7 +105,7 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo } /* returns the image view to use for the current active view */ - if (BLI_listbase_count_ex(&image->rr->views, 2) > 1) { + if (BLI_listbase_count_at_most(&image->rr->views, 2) > 1) { const int view_image = imageuser->view; const bool is_allview = (view_image == 0); /* if view selected == All (0) */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 15e3ea3e10f..7b2914303ce 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -114,39 +114,6 @@ extern "C" { namespace DEG { -namespace { - -struct BuilderWalkUserData { - DepsgraphNodeBuilder *builder; -}; - -static void modifier_walk(void *user_data, - struct Object * /*object*/, - struct Object **obpoin, - int /*cb_flag*/) -{ - BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; - if (*obpoin) { - data->builder->build_object(NULL, *obpoin); - } -} - -void constraint_walk(bConstraint * /*con*/, - ID **idpoin, - bool /*is_reference*/, - void *user_data) -{ - BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; - if (*idpoin) { - ID *id = *idpoin; - if (GS(id->name) == ID_OB) { - data->builder->build_object(NULL, (Object *)id); - } - } -} - -} /* namespace */ - /* ************ */ /* Node Builder */ @@ -342,7 +309,7 @@ void DepsgraphNodeBuilder::build_object(Base *base, Object *object) if (object->modifiers.first != NULL) { BuilderWalkUserData data; data.builder = this; - modifiers_foreachObjectLink(object, modifier_walk, &data); + modifiers_foreachIDLink(object, modifier_walk, &data); } /* Constraints. */ if (object->constraints.first != NULL) { @@ -1053,6 +1020,11 @@ void DepsgraphNodeBuilder::build_texture(Tex *texture) build_image(texture->ima); } } + /* Placeholder so we can add relations and tag ID node for update. */ + add_operation_node(&texture->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_PLACEHOLDER); } void DepsgraphNodeBuilder::build_image(Image *image) { @@ -1131,4 +1103,50 @@ void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) { DEG_OPCODE_MOVIECLIP_EVAL); } +/* **** ID traversal callbacks functions **** */ + +void DepsgraphNodeBuilder::modifier_walk(void *user_data, + struct Object * /*object*/, + struct ID **idpoin, + int /*cb_flag*/) +{ + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + ID *id = *idpoin; + if (id == NULL) { + return; + } + switch (GS(id->name)) { + case ID_OB: + data->builder->build_object(NULL, (Object *)id); + break; + case ID_TE: + data->builder->build_texture((Tex *)id); + break; + default: + /* pass */ + break; + } +} + +void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/, + ID **idpoin, + bool /*is_reference*/, + void *user_data) +{ + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + ID *id = *idpoin; + if (id == NULL) { + return; + } + switch (GS(id->name)) { + case ID_OB: + data->builder->build_object(NULL, (Object *)id); + break; + default: + /* pass */ + break; + } +} + + } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 9d47dc6bced..d64aee11536 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -132,7 +132,7 @@ struct DepsgraphNodeBuilder { void build_object_data(Object *object); void build_object_transform(Object *object); void build_object_constraints(Object *object); - void build_pose_constraints(Object *object, bPoseChannel *pchan); + void build_pose_constraints(Object *object, bPoseChannel *pchan, int pchan_index); void build_rigidbody(Scene *scene); void build_particles(Object *object); void build_cloth(Object *object); @@ -165,6 +165,20 @@ struct DepsgraphNodeBuilder { void build_movieclip(MovieClip *clip); protected: + struct BuilderWalkUserData { + DepsgraphNodeBuilder *builder; + }; + + static void modifier_walk(void *user_data, + struct Object *object, + struct ID **idpoin, + int cb_flag); + + static void constraint_walk(bConstraint *constraint, + ID **idpoin, + bool is_reference, + void *user_data); + /* State which never changes, same for the whole builder time. */ Main *bmain_; Depsgraph *graph_; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index 73bbbcfa0b3..9cfe83e0087 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -49,6 +49,7 @@ extern "C" { #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_constraint.h" } /* extern "C" */ #include "DEG_depsgraph.h" @@ -64,16 +65,28 @@ extern "C" { namespace DEG { -void DepsgraphNodeBuilder::build_pose_constraints(Object *object, bPoseChannel *pchan) +void DepsgraphNodeBuilder::build_pose_constraints(Object *object, + bPoseChannel *pchan, + int pchan_index) { - /* create node for constraint stack */ + /* Pull indirect dependencies via constraints. */ + BuilderWalkUserData data; + data.builder = this; + BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data); + /* Create node for constraint stack. */ add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name, - function_bind(BKE_pose_constraints_evaluate, _1, scene_, object, pchan), + function_bind(BKE_pose_constraints_evaluate, + _1, + scene_, + object, + pchan_index), DEG_OPCODE_BONE_CONSTRAINTS); } /* IK Solver Eval Steps */ -void DepsgraphNodeBuilder::build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con) +void DepsgraphNodeBuilder::build_ik_pose(Object *object, + bPoseChannel *pchan, + bConstraint *con) { bKinematicConstraint *data = (bKinematicConstraint *)con->data; @@ -89,14 +102,22 @@ void DepsgraphNodeBuilder::build_ik_pose(Object *object, bPoseChannel *pchan, bC return; } + int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan); + BLI_assert(rootchan_index != -1); /* Operation node for evaluating/running IK Solver. */ add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name, - function_bind(BKE_pose_iktree_evaluate, _1, scene_, object, rootchan), + function_bind(BKE_pose_iktree_evaluate, + _1, + scene_, + object, + rootchan_index), DEG_OPCODE_POSE_IK_SOLVER); } /* Spline IK Eval Steps */ -void DepsgraphNodeBuilder::build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con) +void DepsgraphNodeBuilder::build_splineik_pose(Object *object, + bPoseChannel *pchan, + bConstraint *con) { bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; @@ -106,8 +127,14 @@ void DepsgraphNodeBuilder::build_splineik_pose(Object *object, bPoseChannel *pch /* Operation node for evaluating/running Spline IK Solver. * Store the "root bone" of this chain in the solver, so it knows where to start. */ + int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan); + BLI_assert(rootchan_index != -1); add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name, - function_bind(BKE_pose_splineik_evaluate, _1, scene_, object, rootchan), + function_bind(BKE_pose_splineik_evaluate, + _1, + scene_, + object, + rootchan_index), DEG_OPCODE_POSE_SPLINE_IK_SOLVER); } @@ -178,22 +205,32 @@ void DepsgraphNodeBuilder::build_rig(Object *object) /* pose eval context */ op_node = add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, - function_bind(BKE_pose_eval_init, _1, scene_, object, object->pose), + function_bind(BKE_pose_eval_init, + _1, + scene_, + object), DEG_OPCODE_POSE_INIT); op_node->set_as_entry(); op_node = add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, - function_bind(BKE_pose_eval_init_ik, _1, scene_, object, object->pose), + function_bind(BKE_pose_eval_init_ik, + _1, + scene_, + object), DEG_OPCODE_POSE_INIT_IK); op_node = add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, - function_bind(BKE_pose_eval_flush, _1, scene_, object, object->pose), + function_bind(BKE_pose_eval_flush, + _1, + scene_, + object), DEG_OPCODE_POSE_DONE); op_node->set_as_exit(); /* bones */ + int pchan_index = 0; LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { /* Node for bone evaluation. */ op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name, NULL, @@ -201,7 +238,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object) op_node->set_as_entry(); add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name, - function_bind(BKE_pose_eval_bone, _1, scene_, object, pchan), + function_bind(BKE_pose_eval_bone, _1, scene_, object, pchan_index), DEG_OPCODE_BONE_POSE_PARENT); add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name, @@ -209,7 +246,10 @@ void DepsgraphNodeBuilder::build_rig(Object *object) DEG_OPCODE_BONE_READY); op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name, - function_bind(BKE_pose_bone_done, _1, pchan), + function_bind(BKE_pose_bone_done, + _1, + object, + pchan_index), DEG_OPCODE_BONE_DONE); op_node->set_as_exit(); /* Custom properties. */ @@ -222,7 +262,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object) } /* Constraints. */ if (pchan->constraints.first != NULL) { - build_pose_constraints(object, pchan); + build_pose_constraints(object, pchan, pchan_index); } /** * IK Solvers. @@ -232,7 +272,8 @@ void DepsgraphNodeBuilder::build_rig(Object *object) * base transforms of a bunch of bones is done) * * Unsolved Issues: - * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building + * - Care is needed to ensure that multi-headed trees work out the same + * as in ik-tree building. * - Animated chain-lengths are a problem... */ LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) { @@ -249,6 +290,13 @@ void DepsgraphNodeBuilder::build_rig(Object *object) break; } } + + /* Custom shape. */ + if (pchan->custom != NULL) { + build_object(NULL, pchan->custom); + } + + pchan_index++; } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 40db9d1b5f1..4ebc0804479 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -114,39 +114,6 @@ extern "C" { namespace DEG { -namespace { - -struct BuilderWalkUserData { - DepsgraphRelationBuilder *builder; -}; - -void modifier_walk(void *user_data, - struct Object * /*object*/, - struct Object **obpoin, - int /*cb_flag*/) -{ - BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; - if (*obpoin) { - data->builder->build_object(*obpoin); - } -} - -void constraint_walk(bConstraint * /*con*/, - ID **idpoin, - bool /*is_reference*/, - void *user_data) -{ - BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; - if (*idpoin) { - ID *id = *idpoin; - if (GS(id->name) == ID_OB) { - data->builder->build_object((Object *)id); - } - } -} - -} /* namespace */ - /* ***************** */ /* Relations Builder */ @@ -459,7 +426,7 @@ void DepsgraphRelationBuilder::build_object(Object *object) if (object->modifiers.first != NULL) { BuilderWalkUserData data; data.builder = this; - modifiers_foreachObjectLink(object, modifier_walk, &data); + modifiers_foreachIDLink(object, modifier_walk, &data); } /* Constraints. */ if (object->constraints.first != NULL) { @@ -1874,4 +1841,43 @@ void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip) build_animdata(&clip->id); } +/* **** ID traversal callbacks functions **** */ + +void DepsgraphRelationBuilder::modifier_walk(void *user_data, + struct Object * /*object*/, + struct ID **idpoin, + int /*cb_flag*/) +{ + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + ID *id = *idpoin; + if (id == NULL) { + return; + } + switch (GS(id->name)) { + case ID_OB: + data->builder->build_object((Object *)id); + break; + case ID_TE: + data->builder->build_texture((Tex *)id); + break; + default: + /* pass */ + break; + } +} + +void DepsgraphRelationBuilder::constraint_walk(bConstraint * /*con*/, + ID **idpoin, + bool /*is_reference*/, + void *user_data) +{ + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + if (*idpoin) { + ID *id = *idpoin; + if (GS(id->name) == ID_OB) { + data->builder->build_object((Object *)id); + } + } +} + } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index c4d77d97232..d1ca0b6c7dd 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -313,6 +313,20 @@ protected: const KeyTo& key_to); private: + struct BuilderWalkUserData { + DepsgraphRelationBuilder *builder; + }; + + static void modifier_walk(void *user_data, + struct Object *object, + struct ID **idpoin, + int cb_flag); + + static void constraint_walk(bConstraint *con, + ID **idpoin, + bool is_reference, + void *user_data); + /* State which never changes, same for the whole builder time. */ Main *bmain_; Depsgraph *graph_; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index b9850209d7d..2eee1671795 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -51,6 +51,7 @@ extern "C" { #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_constraint.h" } /* extern "C" */ #include "DEG_depsgraph.h" @@ -411,6 +412,11 @@ void DepsgraphRelationBuilder::build_rig(Object *object) /* constraints */ if (pchan->constraints.first != NULL) { + /* Build relations for indirectly linked objects. */ + BuilderWalkUserData data; + data.builder = this; + BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data); + /* constraints stack and constraint dependencies */ build_constraints(&object->id, DEG_NODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map); @@ -436,6 +442,11 @@ void DepsgraphRelationBuilder::build_rig(Object *object) /* assume that all bones must be done for the pose to be ready (for deformers) */ add_relation(bone_done_key, flush_key, "PoseEval Result-Bone Link"); + + /* Custom shape. */ + if (pchan->custom != NULL) { + build_object(pchan->custom); + } } } diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 66ddaa6b0d5..da7ac03146e 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -531,12 +531,14 @@ void DEG_debug_print_eval(const char *function_name, if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) { return; } - printf("%s on %s %s(%p)%s\n", - function_name, - object_name, - DEG::deg_color_for_pointer(object_address).c_str(), - object_address, - DEG::deg_color_end().c_str()); + fprintf(stdout, + "%s on %s %s(%p)%s\n", + function_name, + object_name, + DEG::deg_color_for_pointer(object_address).c_str(), + object_address, + DEG::deg_color_end().c_str()); + fflush(stdout); } void DEG_debug_print_eval_subdata(const char *function_name, @@ -549,17 +551,19 @@ void DEG_debug_print_eval_subdata(const char *function_name, if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) { return; } - printf("%s on %s %s(%p)%s %s %s %s(%p)%s\n", - function_name, - object_name, - DEG::deg_color_for_pointer(object_address).c_str(), - object_address, - DEG::deg_color_end().c_str(), - subdata_comment, - subdata_name, - DEG::deg_color_for_pointer(subdata_address).c_str(), - subdata_address, - DEG::deg_color_end().c_str()); + fprintf(stdout, + "%s on %s %s(%p)%s %s %s %s(%p)%s\n", + function_name, + object_name, + DEG::deg_color_for_pointer(object_address).c_str(), + object_address, + DEG::deg_color_end().c_str(), + subdata_comment, + subdata_name, + DEG::deg_color_for_pointer(subdata_address).c_str(), + subdata_address, + DEG::deg_color_end().c_str()); + fflush(stdout); } void DEG_debug_print_eval_subdata_index(const char *function_name, @@ -573,18 +577,20 @@ void DEG_debug_print_eval_subdata_index(const char *function_name, if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) { return; } - printf("%s on %s %s(%p)^%s %s %s[%d] %s(%p)%s\n", - function_name, - object_name, - DEG::deg_color_for_pointer(object_address).c_str(), - object_address, - DEG::deg_color_end().c_str(), - subdata_comment, - subdata_name, - subdata_index, - DEG::deg_color_for_pointer(subdata_address).c_str(), - subdata_address, - DEG::deg_color_end().c_str()); + fprintf(stdout, + "%s on %s %s(%p)^%s %s %s[%d] %s(%p)%s\n", + function_name, + object_name, + DEG::deg_color_for_pointer(object_address).c_str(), + object_address, + DEG::deg_color_end().c_str(), + subdata_comment, + subdata_name, + subdata_index, + DEG::deg_color_for_pointer(subdata_address).c_str(), + subdata_address, + DEG::deg_color_end().c_str()); + fflush(stdout); } void DEG_debug_print_eval_time(const char *function_name, @@ -595,11 +601,13 @@ void DEG_debug_print_eval_time(const char *function_name, if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) { return; } - printf("%s on %s %s(%p)%s at time %f\n", - function_name, - object_name, - DEG::deg_color_for_pointer(object_address).c_str(), - object_address, - DEG::deg_color_end().c_str(), - time); + fprintf(stdout, + "%s on %s %s(%p)%s at time %f\n", + function_name, + object_name, + DEG::deg_color_for_pointer(object_address).c_str(), + object_address, + DEG::deg_color_end().c_str(), + time); + fflush(stdout); } diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 92518ba73e4..fc71b5ccb7b 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -252,6 +252,9 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx, Depsgraph *graph, const unsigned int layers) { + /* Set time for the current graph evaluation context. */ + TimeSourceDepsNode *time_src = graph->find_time_source(); + eval_ctx->ctime = time_src->cfra; /* Nothing to update, early out. */ if (BLI_gset_len(graph->entry_tags) == 0) { return; @@ -262,9 +265,6 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx, graph->layers); const bool do_time_debug = ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0); const double start_time = do_time_debug ? PIL_check_seconds_timer() : 0; - /* Set time for the current graph evaluation context. */ - TimeSourceDepsNode *time_src = graph->find_time_source(); - eval_ctx->ctime = time_src->cfra; /* Set up evaluation context for depsgraph itself. */ DepsgraphEvalState state; state.eval_ctx = eval_ctx; diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt index be8829b0418..17a8eef1bdb 100644 --- a/source/blender/editors/CMakeLists.txt +++ b/source/blender/editors/CMakeLists.txt @@ -59,6 +59,7 @@ if(WITH_BLENDER) add_subdirectory(space_userpref) add_subdirectory(space_view3d) add_subdirectory(transform) + add_subdirectory(undo) add_subdirectory(util) add_subdirectory(uvedit) endif() diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index e9ab949dc95..8b922082fe8 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -2721,7 +2721,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, /* ensure we exit editmode on whatever object was active before to avoid getting stuck there - T48747 */ if (ob != sce->obedit) - ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); + ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); } diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c index 8d77460e197..8106be79521 100644 --- a/source/blender/editors/animation/fmodifier_ui.c +++ b/source/blender/editors/animation/fmodifier_ui.c @@ -62,7 +62,7 @@ #include "UI_resources.h" #include "ED_anim_api.h" -#include "ED_util.h" +#include "ED_undo.h" /* ********************************************** */ /* UI STUFF */ diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c index 2fb216c2ef8..3dd41f25e09 100644 --- a/source/blender/editors/armature/editarmature_retarget.c +++ b/source/blender/editors/armature/editarmature_retarget.c @@ -42,7 +42,7 @@ #include "BKE_context.h" #include "ED_armature.h" -#include "ED_util.h" +#include "ED_undo.h" #include "BIF_retarget.h" diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c index 36e6ec4ba7f..f27d68d0634 100644 --- a/source/blender/editors/armature/editarmature_undo.c +++ b/source/blender/editors/armature/editarmature_undo.c @@ -33,21 +33,31 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" +#include "BLI_array_utils.h" #include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_undo_system.h" #include "ED_armature.h" +#include "ED_object.h" #include "ED_util.h" +#include "WM_types.h" +#include "WM_api.h" + +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ + typedef struct UndoArmature { EditBone *act_edbone; ListBase lb; + size_t undo_size; } UndoArmature; -static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data)) +static void undoarm_to_editarm(UndoArmature *uarm, bArmature *arm) { - UndoArmature *uarm = uarmv; - bArmature *arm = armv; EditBone *ebone; ED_armature_ebone_listbase_free(arm->edbo); @@ -65,48 +75,117 @@ static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data)) ED_armature_ebone_listbase_temp_clear(arm->edbo); } -static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata)) +static void *undoarm_from_editarm(UndoArmature *uarm, bArmature *arm) { - bArmature *arm = armv; - UndoArmature *uarm; - EditBone *ebone; + BLI_assert(BLI_array_is_zeroed(uarm, 1)); - uarm = MEM_callocN(sizeof(UndoArmature), "listbase undo"); + /* TODO: include size of ID-properties. */ + uarm->undo_size = 0; ED_armature_ebone_listbase_copy(&uarm->lb, arm->edbo); /* active bone */ if (arm->act_edbone) { - ebone = arm->act_edbone; + EditBone *ebone = arm->act_edbone; uarm->act_edbone = ebone->temp.ebone; } ED_armature_ebone_listbase_temp_clear(&uarm->lb); + for (EditBone *ebone = uarm->lb.first; ebone; ebone = ebone->next) { + uarm->undo_size += sizeof(EditBone); + } + return uarm; } -static void free_undoBones(void *uarmv) +static void undoarm_free_data(UndoArmature *uarm) { - UndoArmature *uarm = uarmv; - ED_armature_ebone_listbase_free(&uarm->lb); - - MEM_freeN(uarm); } -static void *get_armature_edit(bContext *C) +static Object *editarm_object_from_context(bContext *C) { Object *obedit = CTX_data_edit_object(C); if (obedit && obedit->type == OB_ARMATURE) { - return obedit->data; + bArmature *arm = obedit->data; + if (arm->edbo != NULL) { + return obedit; + } } return NULL; } -/* and this is all the undo system needs to know */ -void undo_push_armature(bContext *C, const char *name) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct ArmatureUndoStep { + UndoStep step; + /* note: will split out into list for multi-object-editmode. */ + UndoRefID_Object obedit_ref; + UndoArmature data; +} ArmatureUndoStep; + +static bool armature_undosys_poll(bContext *C) { - // XXX solve getdata() - undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL); + return editarm_object_from_context(C) != NULL; } + +static bool armature_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; + us->obedit_ref.ptr = editarm_object_from_context(C); + bArmature *arm = us->obedit_ref.ptr->data; + undoarm_from_editarm(&us->data, arm); + us->step.data_size = us->data.undo_size; + return true; +} + +static void armature_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* TODO(campbell): undo_system: use low-level API to set mode. */ + ED_object_mode_set(C, OB_MODE_EDIT); + BLI_assert(armature_undosys_poll(C)); + + ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; + Object *obedit = us->obedit_ref.ptr; + bArmature *arm = obedit->data; + undoarm_to_editarm(&us->data, arm); + DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); +} + +static void armature_undosys_step_free(UndoStep *us_p) +{ + ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; + undoarm_free_data(&us->data); +} + +static void armature_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref)); +} + +/* Export for ED_undo_sys. */ +void ED_armature_undosys_type(UndoType *ut) +{ + ut->name = "Edit Armature"; + ut->poll = armature_undosys_poll; + ut->step_encode = armature_undosys_step_encode; + ut->step_decode = armature_undosys_step_decode; + ut->step_free = armature_undosys_step_free; + + ut->step_foreach_ID_ref = armature_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(ArmatureUndoStep); +} + +/** \} */ diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 2f536ebff6e..d0c467b2d2c 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -81,42 +81,55 @@ Object *ED_pose_object_from_context(bContext *C) } /* This function is used to process the necessary updates for */ -void ED_armature_enter_posemode(bContext *C, Base *base) +bool ED_object_posemode_enter_ex(Object *ob) { - ReportList *reports = CTX_wm_reports(C); - Object *ob = base->object; - - if (ID_IS_LINKED(ob)) { - BKE_report(reports, RPT_WARNING, "Cannot pose libdata"); - return; - } + BLI_assert(!ID_IS_LINKED(ob)); + bool ok = false; switch (ob->type) { case OB_ARMATURE: ob->restore_mode = ob->mode; ob->mode |= OB_MODE_POSE; - - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL); - + ok = true; + break; default: - return; + break; } - - /* XXX: disabled as this would otherwise cause a nasty loop... */ - //ED_object_mode_toggle(C, ob->mode); + + return ok; +} +bool ED_object_posemode_enter(bContext *C, Object *ob) +{ + ReportList *reports = CTX_wm_reports(C); + if (ID_IS_LINKED(ob)) { + BKE_report(reports, RPT_WARNING, "Cannot pose libdata"); + return false; + } + bool ok = ED_object_posemode_enter_ex(ob); + if (ok) { + WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL); + } + return ok; } -void ED_armature_exit_posemode(bContext *C, Base *base) +bool ED_object_posemode_exit_ex(Object *ob) { - if (base) { - Object *ob = base->object; - + bool ok = false; + if (ob) { ob->restore_mode = ob->mode; ob->mode &= ~OB_MODE_POSE; - + ok = true; + } + return ok; +} +bool ED_object_posemode_exit(bContext *C, Object *ob) +{ + bool ok = ED_object_posemode_exit_ex(ob); + if (ok) { WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); } + return ok; } /* if a selected or active bone is protected, throw error (oonly if warn == 1) and return 1 */ diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 4feb1681349..a44accd1cea 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -525,7 +525,7 @@ static int pose_paste_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } /* Make sure data from this file is usable for pose paste. */ - if (BLI_listbase_count_ex(&tmp_bmain->object, 2) != 1) { + if (BLI_listbase_count_at_most(&tmp_bmain->object, 2) != 1) { BKE_report(op->reports, RPT_ERROR, "Copy buffer is not from pose mode"); BKE_main_free(tmp_bmain); return OPERATOR_CANCELLED; diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 0dbe526117c..ebf2b63bb49 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -1229,7 +1229,10 @@ void ED_curve_editnurb_make(Object *obedit) if (actkey) { // XXX strcpy(G.editModeTitleExtra, "(Key) "); + /* TODO(campbell): undo_system: investigate why this was needed. */ +#if 0 undo_editmode_clear(); +#endif } if (editnurb) { diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c index cc8e272d4f7..b23f0f967ec 100644 --- a/source/blender/editors/curve/editcurve_add.c +++ b/source/blender/editors/curve/editcurve_add.c @@ -52,7 +52,7 @@ #include "ED_object.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "ED_view3d.h" #include "ED_curve.h" diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c index f8f96eb3bc9..4ced6ce506c 100644 --- a/source/blender/editors/curve/editcurve_undo.c +++ b/source/blender/editors/curve/editcurve_undo.c @@ -30,18 +30,29 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" +#include "BLI_array_utils.h" #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_fcurve.h" #include "BKE_library.h" #include "BKE_animsys.h" +#include "BKE_depsgraph.h" +#include "BKE_undo_system.h" +#include "ED_object.h" #include "ED_util.h" #include "ED_curve.h" +#include "WM_types.h" +#include "WM_api.h" + #include "curve_intern.h" +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ + typedef struct { ListBase nubase; int actvert; @@ -49,13 +60,18 @@ typedef struct { ListBase fcurves, drivers; int actnu; int flag; + + /* Stored in the object, needed since users may change the active key while in edit-mode. */ + struct { + short shapenr; + } obedit; + + size_t undo_size; } UndoCurve; -static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *cu_v) +static void undocurve_to_editcurve(UndoCurve *ucu, Curve *cu, short *r_shapenr) { - Curve *cu = cu_v; - UndoCurve *undoCurve = ucu; - ListBase *undobase = &undoCurve->nubase; + ListBase *undobase = &ucu->nubase; ListBase *editbase = BKE_curve_editNurbs_get(cu); Nurb *nu, *newnu; EditNurb *editnurb = cu->editnurb; @@ -63,19 +79,19 @@ static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *cu_v) BKE_nurbList_free(editbase); - if (undoCurve->undoIndex) { + if (ucu->undoIndex) { BKE_curve_editNurb_keyIndex_free(&editnurb->keyindex); - editnurb->keyindex = ED_curve_keyindex_hash_duplicate(undoCurve->undoIndex); + editnurb->keyindex = ED_curve_keyindex_hash_duplicate(ucu->undoIndex); } if (ad) { if (ad->action) { free_fcurves(&ad->action->curves); - copy_fcurves(&ad->action->curves, &undoCurve->fcurves); + copy_fcurves(&ad->action->curves, &ucu->fcurves); } free_fcurves(&ad->drivers); - copy_fcurves(&ad->drivers, &undoCurve->drivers); + copy_fcurves(&ad->drivers, &ucu->drivers); } /* copy */ @@ -89,75 +105,152 @@ static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *cu_v) BLI_addtail(editbase, newnu); } - cu->actvert = undoCurve->actvert; - cu->actnu = undoCurve->actnu; - cu->flag = undoCurve->flag; + cu->actvert = ucu->actvert; + cu->actnu = ucu->actnu; + cu->flag = ucu->flag; + *r_shapenr = ucu->obedit.shapenr; ED_curve_updateAnimPaths(cu); } -static void *editCurve_to_undoCurve(void *UNUSED(edata), void *cu_v) +static void undocurve_from_editcurve(UndoCurve *ucu, Curve *cu, const short shapenr) { - Curve *cu = cu_v; + BLI_assert(BLI_array_is_zeroed(ucu, 1)); ListBase *nubase = BKE_curve_editNurbs_get(cu); - UndoCurve *undoCurve; EditNurb *editnurb = cu->editnurb, tmpEditnurb; Nurb *nu, *newnu; AnimData *ad = BKE_animdata_from_id(&cu->id); - undoCurve = MEM_callocN(sizeof(UndoCurve), "undoCurve"); + /* TODO: include size of fcurve & undoIndex */ + // ucu->undo_size = 0; if (editnurb->keyindex) { - undoCurve->undoIndex = ED_curve_keyindex_hash_duplicate(editnurb->keyindex); - tmpEditnurb.keyindex = undoCurve->undoIndex; + ucu->undoIndex = ED_curve_keyindex_hash_duplicate(editnurb->keyindex); + tmpEditnurb.keyindex = ucu->undoIndex; } if (ad) { if (ad->action) - copy_fcurves(&undoCurve->fcurves, &ad->action->curves); + copy_fcurves(&ucu->fcurves, &ad->action->curves); - copy_fcurves(&undoCurve->drivers, &ad->drivers); + copy_fcurves(&ucu->drivers, &ad->drivers); } /* copy */ for (nu = nubase->first; nu; nu = nu->next) { newnu = BKE_nurb_duplicate(nu); - if (undoCurve->undoIndex) { + if (ucu->undoIndex) { ED_curve_keyindex_update_nurb(&tmpEditnurb, nu, newnu); } - BLI_addtail(&undoCurve->nubase, newnu); + BLI_addtail(&ucu->nubase, newnu); + + ucu->undo_size += ( + (nu->bezt ? (sizeof(BezTriple) * nu->pntsu) : 0) + + (nu->bp ? (sizeof(BPoint) * (nu->pntsu * nu->pntsv)) : 0) + + (nu->knotsu ? (sizeof(float) * KNOTSU(nu)) : 0) + + (nu->knotsv ? (sizeof(float) * KNOTSV(nu)) : 0) + + sizeof(Nurb)); } - undoCurve->actvert = cu->actvert; - undoCurve->actnu = cu->actnu; - undoCurve->flag = cu->flag; + ucu->actvert = cu->actvert; + ucu->actnu = cu->actnu; + ucu->flag = cu->flag; - return undoCurve; + ucu->obedit.shapenr = shapenr; } -static void free_undoCurve(void *ucv) +static void undocurve_free_data(UndoCurve *uc) { - UndoCurve *undoCurve = ucv; + BKE_nurbList_free(&uc->nubase); - BKE_nurbList_free(&undoCurve->nubase); + BKE_curve_editNurb_keyIndex_free(&uc->undoIndex); - BKE_curve_editNurb_keyIndex_free(&undoCurve->undoIndex); + free_fcurves(&uc->fcurves); + free_fcurves(&uc->drivers); +} - free_fcurves(&undoCurve->fcurves); - free_fcurves(&undoCurve->drivers); +static Object *editcurve_object_from_context(bContext *C) +{ + Object *obedit = CTX_data_edit_object(C); + if (obedit && ELEM(obedit->type, OB_CURVE, OB_SURF)) { + Curve *cu = obedit->data; + if (BKE_curve_editNurbs_get(cu) != NULL) { + return obedit; + } + } + return NULL; +} + +/** \} */ - MEM_freeN(undoCurve); +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct CurveUndoStep { + UndoStep step; + /* note: will split out into list for multi-object-editmode. */ + UndoRefID_Object obedit_ref; + UndoCurve data; +} CurveUndoStep; + +static bool curve_undosys_poll(bContext *C) +{ + Object *obedit = editcurve_object_from_context(C); + return (obedit != NULL); } -static void *get_data(bContext *C) +static bool curve_undosys_step_encode(struct bContext *C, UndoStep *us_p) { - Object *obedit = CTX_data_edit_object(C); - return obedit; + CurveUndoStep *us = (CurveUndoStep *)us_p; + us->obedit_ref.ptr = editcurve_object_from_context(C); + undocurve_from_editcurve(&us->data, us->obedit_ref.ptr->data, us->obedit_ref.ptr->shapenr); + us->step.data_size = us->data.undo_size; + return true; +} + +static void curve_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* TODO(campbell): undo_system: use low-level API to set mode. */ + ED_object_mode_set(C, OB_MODE_EDIT); + BLI_assert(curve_undosys_poll(C)); + + CurveUndoStep *us = (CurveUndoStep *)us_p; + Object *obedit = us->obedit_ref.ptr; + undocurve_to_editcurve(&us->data, obedit->data, &obedit->shapenr); + DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); +} + +static void curve_undosys_step_free(UndoStep *us_p) +{ + CurveUndoStep *us = (CurveUndoStep *)us_p; + undocurve_free_data(&us->data); } -/* and this is all the undo system needs to know */ -void undo_push_curve(bContext *C, const char *name) +static void curve_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) { - undo_editmode_push(C, name, get_data, free_undoCurve, undoCurve_to_editCurve, editCurve_to_undoCurve, NULL); + CurveUndoStep *us = (CurveUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref)); } + +/* Export for ED_undo_sys. */ +void ED_curve_undosys_type(UndoType *ut) +{ + ut->name = "Edit Curve"; + ut->poll = curve_undosys_poll; + ut->step_encode = curve_undosys_step_encode; + ut->step_decode = curve_undosys_step_decode; + ut->step_free = curve_undosys_step_free; + + ut->step_foreach_ID_ref = curve_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(CurveUndoStep); +} + +/** \} */ diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c index a61f863b61e..3a76d0333f9 100644 --- a/source/blender/editors/curve/editfont_undo.c +++ b/source/blender/editors/curve/editfont_undo.c @@ -29,6 +29,8 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" +#include "BLI_array_utils.h" + #include "DNA_curve_types.h" #include "DNA_object_types.h" @@ -36,10 +38,16 @@ #include "BKE_context.h" #include "BKE_font.h" +#include "BKE_depsgraph.h" +#include "BKE_undo_system.h" +#include "ED_object.h" #include "ED_curve.h" #include "ED_util.h" +#include "WM_types.h" +#include "WM_api.h" + #define USE_ARRAY_STORE #ifdef USE_ARRAY_STORE @@ -50,6 +58,10 @@ # define ARRAY_CHUNK_SIZE 32 #endif +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ + typedef struct UndoFont { wchar_t *textbuf; struct CharInfo *textbufinfo; @@ -62,6 +74,8 @@ typedef struct UndoFont { BArrayState *textbufinfo; } store; #endif + + size_t undo_size; } UndoFont; @@ -202,23 +216,20 @@ static void uf_arraystore_free(UndoFont *uf) BLI_array_store_at_size_clear(&uf_arraystore.bs_stride); } - } /** \} */ #endif /* USE_ARRAY_STORE */ -static void undoFont_to_editFont(void *uf_v, void *ecu, void *UNUSED(obdata)) +static void undofont_to_editfont(UndoFont *uf, Curve *cu) { - Curve *cu = (Curve *)ecu; EditFont *ef = cu->editfont; - const UndoFont *uf = uf_v; size_t final_size; #ifdef USE_ARRAY_STORE - uf_arraystore_expand(uf_v); + uf_arraystore_expand(uf); #endif final_size = sizeof(wchar_t) * (uf->len + 1); @@ -233,16 +244,17 @@ static void undoFont_to_editFont(void *uf_v, void *ecu, void *UNUSED(obdata)) ef->selstart = ef->selend = 0; #ifdef USE_ARRAY_STORE - uf_arraystore_expand_clear(uf_v); + uf_arraystore_expand_clear(uf); #endif } -static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata)) +static void *undofont_from_editfont(UndoFont *uf, Curve *cu) { - Curve *cu = (Curve *)ecu; + BLI_assert(BLI_array_is_zeroed(uf, 1)); + EditFont *ef = cu->editfont; - UndoFont *uf = MEM_callocN(sizeof(*uf), __func__); + size_t mem_used_prev = MEM_get_memory_in_use(); size_t final_size; @@ -269,13 +281,15 @@ static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata)) } #endif + size_t mem_used_curr = MEM_get_memory_in_use(); + + uf->undo_size = mem_used_prev < mem_used_curr ? mem_used_curr - mem_used_prev : sizeof(UndoFont); + return uf; } -static void free_undoFont(void *uf_v) +static void undofont_free_data(UndoFont *uf) { - UndoFont *uf = uf_v; - #ifdef USE_ARRAY_STORE { LinkData *link = BLI_findptr(&uf_arraystore.local_links, uf, offsetof(LinkData, data)); @@ -291,21 +305,91 @@ static void free_undoFont(void *uf_v) if (uf->textbufinfo) { MEM_freeN(uf->textbufinfo); } - - MEM_freeN(uf); } -static void *get_undoFont(bContext *C) +static Object *editfont_object_from_context(bContext *C) { Object *obedit = CTX_data_edit_object(C); if (obedit && obedit->type == OB_FONT) { - return obedit->data; + Curve *cu = obedit->data; + EditFont *ef = cu->editfont; + if (ef != NULL) { + return obedit; + } } return NULL; } -/* and this is all the undo system needs to know */ -void undo_push_font(bContext *C, const char *name) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct FontUndoStep { + UndoStep step; + /* note: will split out into list for multi-object-editmode. */ + UndoRefID_Object obedit_ref; + UndoFont data; +} FontUndoStep; + +static bool font_undosys_poll(bContext *C) +{ + return editfont_object_from_context(C) != NULL; +} + +static bool font_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + FontUndoStep *us = (FontUndoStep *)us_p; + us->obedit_ref.ptr = editfont_object_from_context(C); + Curve *cu = us->obedit_ref.ptr->data; + undofont_from_editfont(&us->data, cu); + us->step.data_size = us->data.undo_size; + return true; +} + +static void font_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* TODO(campbell): undo_system: use low-level API to set mode. */ + ED_object_mode_set(C, OB_MODE_EDIT); + BLI_assert(font_undosys_poll(C)); + + FontUndoStep *us = (FontUndoStep *)us_p; + Object *obedit = us->obedit_ref.ptr; + Curve *cu = obedit->data; + undofont_to_editfont(&us->data, cu); + DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); +} + +static void font_undosys_step_free(UndoStep *us_p) +{ + FontUndoStep *us = (FontUndoStep *)us_p; + undofont_free_data(&us->data); +} + +static void font_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) { - undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL); + FontUndoStep *us = (FontUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref)); } + +/* Export for ED_undo_sys. */ +void ED_font_undosys_type(UndoType *ut) +{ + ut->name = "Edit Font"; + ut->poll = font_undosys_poll; + ut->step_encode = font_undosys_step_encode; + ut->step_decode = font_undosys_step_decode; + ut->step_free = font_undosys_step_free; + + ut->step_foreach_ID_ref = font_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(FontUndoStep); +} + +/** \} */ diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index bb3800941ab..5fe16226421 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -54,7 +54,6 @@ #include "DNA_object_types.h" #include "BKE_context.h" -#include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_library.h" #include "BKE_report.h" diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 5bd5c9c74b9..9d183222c2d 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -53,7 +53,6 @@ #include "DNA_gpencil_types.h" #include "BKE_context.h" -#include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_library.h" #include "BKE_object.h" @@ -1063,7 +1062,7 @@ static int gp_brush_remove_exec(bContext *C, wmOperator *op) if (ELEM(NULL, ts, brush)) return OPERATOR_CANCELLED; - if (BLI_listbase_count_ex(&ts->gp_brushes, 2) < 2) { + if (BLI_listbase_count_at_most(&ts->gp_brushes, 2) < 2) { BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a brush, unable to delete the last one"); return OPERATOR_CANCELLED; } @@ -1421,7 +1420,7 @@ static int gp_palette_remove_exec(bContext *C, wmOperator *op) if (ELEM(NULL, gpd, palette)) return OPERATOR_CANCELLED; - if (BLI_listbase_count_ex(&gpd->palettes, 2) < 2) { + if (BLI_listbase_count_at_most(&gpd->palettes, 2) < 2) { BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a palette, unable to delete the last one"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 726215255aa..bc54bd89958 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -55,7 +55,6 @@ #include "DNA_gpencil_types.h" #include "BKE_context.h" -#include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_library.h" #include "BKE_report.h" diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index f54356dfed3..84b3ddccf77 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -46,7 +46,6 @@ #include "PIL_time.h" -#include "BKE_main.h" #include "BKE_paint.h" #include "BKE_gpencil.h" #include "BKE_context.h" diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c index 7a9ad2b32c0..202d7630ae0 100644 --- a/source/blender/editors/gpencil/gpencil_undo.c +++ b/source/blender/editors/gpencil/gpencil_undo.c @@ -45,7 +45,6 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_gpencil.h" -#include "BKE_main.h" #include "ED_gpencil.h" diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 91c9a36c31f..ae54dd802ee 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -49,6 +49,7 @@ struct Scene; struct ViewContext; struct wmKeyConfig; struct wmOperator; +struct UndoType; typedef struct EditBone { struct EditBone *next, *prev; @@ -139,7 +140,7 @@ bool ED_armature_select_pick(struct bContext *C, const int mval[2], bool extend, int join_armature_exec(struct bContext *C, struct wmOperator *op); struct Bone *get_indexed_bone(struct Object *ob, int index); float ED_rollBoneToVector(EditBone *bone, const float new_up_axis[3], const bool axis_only); -EditBone *ED_armature_bone_find_name(const ListBase *edbo, const char *name); +EditBone *ED_armature_bone_find_name(const struct ListBase *edbo, const char *name); EditBone *ED_armature_bone_get_mirrored(const struct ListBase *edbo, EditBone *ebo); void ED_armature_sync_selection(struct ListBase *edbo); void ED_armature_validate_active(struct bArmature *arm); @@ -178,8 +179,6 @@ void unique_editbone_name(struct ListBase *ebones, char *name, EditBone *bone); void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep); void ED_armature_bones_flip_names(struct bArmature *arm, struct ListBase *bones_names, const bool do_strip_numbers); -void undo_push_armature(struct bContext *C, const char *name); - /* low level selection functions which handle */ int ED_armature_ebone_selectflag_get(const EditBone *ebone); void ED_armature_ebone_selectflag_set(EditBone *ebone, int flag); @@ -187,14 +186,19 @@ void ED_armature_ebone_select_set(EditBone *ebone, bool select); void ED_armature_ebone_selectflag_enable(EditBone *ebone, int flag); void ED_armature_ebone_selectflag_disable(EditBone *ebone, int flag); +/* editarmature_undo.c */ +void ED_armature_undosys_type(struct UndoType *ut); + /* armature_utils.c */ void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb); void ED_armature_ebone_listbase_free(struct ListBase *lb); void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst, struct ListBase *lb_src); /* poseobject.c */ -void ED_armature_exit_posemode(struct bContext *C, struct Base *base); -void ED_armature_enter_posemode(struct bContext *C, struct Base *base); +bool ED_object_posemode_exit_ex(struct Object *ob); +bool ED_object_posemode_exit(struct bContext *C, struct Object *ob); +bool ED_object_posemode_enter_ex(struct Object *ob); +bool ED_object_posemode_enter(struct bContext *C, struct Object *ob); void ED_pose_de_selectall(struct Object *ob, int select_mode, const bool ignore_visibility); void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select); void ED_pose_recalculate_paths(struct Scene *scene, struct Object *ob); diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h index d45e52d4c5a..da726cb8000 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -41,6 +41,7 @@ struct Curve; struct EditNurb; struct BezTriple; struct BPoint; +struct UndoType; /* curve_ops.c */ void ED_operatortypes_curve(void); @@ -48,7 +49,7 @@ void ED_operatormacros_curve(void); void ED_keymap_curve(struct wmKeyConfig *keyconf); /* editcurve.c */ -ListBase *object_editcurve_get(struct Object *ob); +struct ListBase *object_editcurve_get(struct Object *ob); void ED_curve_editnurb_load(struct Object *obedit); void ED_curve_editnurb_make(struct Object *obedit); @@ -72,7 +73,7 @@ void ED_curve_select_all(struct EditNurb *editnurb); void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles); /* editcurve_undo.c */ -void undo_push_curve(struct bContext *C, const char *name); +void ED_curve_undosys_type(struct UndoType *ut); /* editfont.c */ void ED_curve_editfont_load(struct Object *obedit); @@ -91,7 +92,8 @@ bool ED_curve_active_center(struct Curve *cu, float center[3]); bool ED_curve_editfont_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); /* editfont_undo.c */ -void undo_push_font(struct bContext *C, const char *name); +void ED_font_undosys_type(struct UndoType *ut); + #if 0 /* debug only */ diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h index b652fb4c00b..b30929f5307 100644 --- a/source/blender/editors/include/ED_lattice.h +++ b/source/blender/editors/include/ED_lattice.h @@ -31,6 +31,8 @@ #define __ED_LATTICE_H__ struct wmKeyConfig; +struct UndoType; +struct Object; /* lattice_ops.c */ void ED_operatortypes_lattice(void); @@ -41,6 +43,6 @@ void ED_lattice_flags_set(struct Object *obedit, int flag); bool ED_lattice_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); /* editlattice_undo.c */ -void undo_push_lattice(struct bContext *C, const char *name); +void ED_lattice_undosys_type(struct UndoType *ut); #endif /* __ED_LATTICE_H__ */ diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h index 232d7d1d234..9982c87a764 100644 --- a/source/blender/editors/include/ED_mball.h +++ b/source/blender/editors/include/ED_mball.h @@ -34,6 +34,7 @@ struct bContext; struct Object; struct wmKeyConfig; +struct UndoType; void ED_operatortypes_metaball(void); void ED_operatormacros_metaball(void); @@ -47,6 +48,7 @@ void ED_mball_editmball_free(struct Object *obedit); void ED_mball_editmball_make(struct Object *obedit); void ED_mball_editmball_load(struct Object *obedit); -void undo_push_mball(struct bContext *C, const char *name); +/* editmball_undo.c */ +void ED_mball_undosys_type(struct UndoType *ut); #endif /* __ED_MBALL_H__ */ diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 40d796aeed1..349a1944a23 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -62,6 +62,7 @@ struct UvMapVert; struct ToolSettings; struct Object; struct rcti; +struct UndoType; /* editmesh_utils.c */ void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em, const int axis, @@ -98,8 +99,6 @@ void EDBM_selectmode_flush(struct BMEditMesh *em); void EDBM_deselect_flush(struct BMEditMesh *em); void EDBM_select_flush(struct BMEditMesh *em); -void undo_push_mesh(struct bContext *C, const char *name); - bool EDBM_vert_color_check(struct BMEditMesh *em); void EDBM_mesh_hide(struct BMEditMesh *em, bool swap); @@ -130,6 +129,9 @@ void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag); bool BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e, struct ARegion *ar, struct View3D *v3d, struct Object *obedit); +/* editmesh_undo.c */ +void ED_mesh_undosys_type(struct UndoType *ut); + /* editmesh_select.c */ void EDBM_select_mirrored( struct BMEditMesh *em, const int axis, const bool extend, diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 5b2fdf29dd5..11dde2f5913 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -112,11 +112,12 @@ struct Base *ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, st void ED_object_parent(struct Object *ob, struct Object *parent, const int type, const char *substr); /* bitflags for enter/exit editmode */ -#define EM_FREEDATA 1 -#define EM_FREEUNDO 2 -#define EM_WAITCURSOR 4 -#define EM_DO_UNDO 8 -#define EM_IGNORE_LAYER 16 +enum { + EM_FREEDATA = (1 << 0), + EM_WAITCURSOR = (1 << 1), + EM_DO_UNDO = (1 << 2), + EM_IGNORE_LAYER = (1 << 3), +}; void ED_object_editmode_exit_ex(struct bContext *C, struct Scene *scene, struct Object *obedit, int flag); void ED_object_editmode_exit(struct bContext *C, int flag); void ED_object_editmode_enter(struct bContext *C, int flag); @@ -196,6 +197,7 @@ void ED_object_constraint_dependency_tag_update(struct Main *bmain, struct Objec bool ED_object_mode_compat_test(const struct Object *ob, eObjectMode mode); bool ED_object_mode_compat_set(struct bContext *C, struct Object *ob, eObjectMode mode, struct ReportList *reports); void ED_object_mode_toggle(struct bContext *C, eObjectMode mode); +void ED_object_mode_set(struct bContext *C, eObjectMode mode); /* object_modifier.c */ enum { diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h index 79aa0a3a5ed..246419d64aa 100644 --- a/source/blender/editors/include/ED_paint.h +++ b/source/blender/editors/include/ED_paint.h @@ -28,31 +28,16 @@ struct bContext; struct wmKeyConfig; struct wmOperator; +struct ImBuf; +struct Image; +struct UndoStep; +struct UndoType; /* paint_ops.c */ void ED_operatortypes_paint(void); void ED_operatormacros_paint(void); void ED_keymap_paint(struct wmKeyConfig *keyconf); -/* paint_undo.c */ -enum { - UNDO_PAINT_IMAGE = 0, - UNDO_PAINT_MESH = 1, -}; - -typedef void (*UndoRestoreCb)(struct bContext *C, struct ListBase *lb); -typedef void (*UndoFreeCb)(struct ListBase *lb); -typedef bool (*UndoCleanupCb)(struct bContext *C, struct ListBase *lb); - -int ED_undo_paint_step(struct bContext *C, int type, int step, const char *name); -void ED_undo_paint_step_num(struct bContext *C, int type, int num); -const char *ED_undo_paint_get_name(struct bContext *C, int type, int nr, bool *r_active); -void ED_undo_paint_free(void); -bool ED_undo_paint_is_valid(int type, const char *name); -bool ED_undo_paint_empty(int type); -void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup); -void ED_undo_paint_push_end(int type); - /* paint_image.c */ void ED_imapaint_clear_partial_redraw(void); void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h, bool find_old); @@ -61,6 +46,14 @@ void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperat /* paint_image_undo.c */ void ED_image_undo_push_begin(const char *name); void ED_image_undo_push_end(void); -void ED_image_undo_restore(void); +void ED_image_undo_restore(struct UndoStep *us); + +void ED_image_undosys_type(struct UndoType *ut); + +/* paint_curve_undo.c */ +void ED_paintcurve_undo_push_begin(const char *name); +void ED_paintcurve_undo_push_end(void); + +void ED_paintcurve_undosys_type(struct UndoType *ut); #endif /* __ED_PAINT_H__ */ diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h index 6cb8c0cfb19..4f6aa1cc702 100644 --- a/source/blender/editors/include/ED_particle.h +++ b/source/blender/editors/include/ED_particle.h @@ -38,6 +38,7 @@ struct ParticleEditSettings; struct rcti; struct PTCacheEdit; struct Scene; +struct UndoType; /* particle edit mode */ void PE_free_ptcache_edit(struct PTCacheEdit *edit); @@ -61,14 +62,8 @@ int PE_circle_select(struct bContext *C, int selecting, const int mval[2], float int PE_lasso_select(struct bContext *C, const int mcords[][2], const short moves, bool extend, bool select); void PE_deselect_all_visible(struct PTCacheEdit *edit); -/* undo */ -void PE_undo_push(struct Scene *scene, const char *str); -void PE_undo_step(struct Scene *scene, int step); -void PE_undo(struct Scene *scene); -void PE_redo(struct Scene *scene); -bool PE_undo_is_valid(struct Scene *scene); -void PE_undo_number(struct Scene *scene, int nr); -const char *PE_undo_get_name(struct Scene *scene, int nr, bool *r_active); +/* particle_edit_undo.c */ +void ED_particle_undosys_type(struct UndoType *ut); #endif /* __ED_PARTICLE_H__ */ diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index 6daaac5bb42..7c17e7b68c3 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -36,6 +36,9 @@ struct Object; struct RegionView3D; struct ViewContext; struct rcti; +struct UndoStep; +struct UndoType; +struct ListBase; /* sculpt.c */ void ED_operatortypes_sculpt(void); @@ -43,4 +46,7 @@ void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *ar, struct RegionView3D *rv3d, struct Object *ob); int ED_sculpt_mask_box_select(struct bContext *C, struct ViewContext *vc, const struct rcti *rect, bool select, bool extend); +/* sculpt_undo.c */ +void ED_sculpt_undosys_type(struct UndoType *ut); + #endif /* __ED_SCULPT_H__ */ diff --git a/source/blender/editors/include/ED_text.h b/source/blender/editors/include/ED_text.h index 5df7d9cfaef..763fbe3bac5 100644 --- a/source/blender/editors/include/ED_text.h +++ b/source/blender/editors/include/ED_text.h @@ -30,12 +30,16 @@ #ifndef __ED_TEXT_H__ #define __ED_TEXT_H__ -struct bContext; struct SpaceText; struct ARegion; +struct UndoType; +struct TextUndoBuf; -void ED_text_undo_step(struct bContext *C, int step); bool ED_text_region_location_from_cursor(struct SpaceText *st, struct ARegion *ar, const int cursor_co[2], int r_pixel_co[2]); -#endif /* __ED_TEXT_H__ */ +/* text_undo.c */ +void ED_text_undosys_type(struct UndoType *ut); + +struct TextUndoBuf *ED_text_undo_push_init(struct bContext *C); +#endif /* __ED_TEXT_H__ */ diff --git a/source/blender/editors/include/ED_undo.h b/source/blender/editors/include/ED_undo.h new file mode 100644 index 00000000000..b3814ab5899 --- /dev/null +++ b/source/blender/editors/include/ED_undo.h @@ -0,0 +1,64 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ED_undo.h + * \ingroup editors + */ + +#ifndef __ED_UNDO_H__ +#define __ED_UNDO_H__ + +struct bContext; +struct wmOperator; +struct wmOperatorType; +struct UndoStack; + +/* undo.c */ +void ED_undo_push(struct bContext *C, const char *str); +void ED_undo_push_op(struct bContext *C, struct wmOperator *op); +void ED_undo_grouped_push(struct bContext *C, const char *str); +void ED_undo_grouped_push_op(struct bContext *C, struct wmOperator *op); +void ED_undo_pop_op(struct bContext *C, struct wmOperator *op); +void ED_undo_pop(struct bContext *C); +void ED_undo_redo(struct bContext *C); +void ED_OT_undo(struct wmOperatorType *ot); +void ED_OT_undo_push(struct wmOperatorType *ot); +void ED_OT_redo(struct wmOperatorType *ot); +void ED_OT_undo_redo(struct wmOperatorType *ot); +void ED_OT_undo_history(struct wmOperatorType *ot); + +int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op); +/* convenience since UI callbacks use this mostly*/ +void ED_undo_operator_repeat_cb(struct bContext *C, void *arg_op, void *arg_unused); +void ED_undo_operator_repeat_cb_evt(struct bContext *C, void *arg_op, int arg_unused); + +bool ED_undo_is_valid(const struct bContext *C, const char *undoname); + +struct UndoStack *ED_undo_stack_get(void); + +/* undo_system_types.c */ +void ED_undosys_type_init(void); +void ED_undosys_type_free(void); + +/* memfile_undo.c */ +struct MemFile *ED_undosys_stack_memfile_get_active(struct UndoStack *ustack); + +#endif /* __ED_UNDO_H__ */ + diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index 60c4b3593aa..2653585dacc 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -32,9 +32,10 @@ #define __ED_UTIL_H__ struct bContext; -struct SpaceLink; -struct wmOperator; struct wmOperatorType; +struct ScrArea; +struct SpaceLink; +struct PackedFile; /* ed_util.c */ @@ -47,40 +48,6 @@ void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, struct I void ED_OT_flush_edits(struct wmOperatorType *ot); -/* ************** Undo ************************ */ - -/* undo.c */ -void ED_undo_push(struct bContext *C, const char *str); -void ED_undo_push_op(struct bContext *C, struct wmOperator *op); -void ED_undo_grouped_push(struct bContext *C, const char *str); -void ED_undo_grouped_push_op(struct bContext *C, struct wmOperator *op); -void ED_undo_pop_op(struct bContext *C, struct wmOperator *op); -void ED_undo_pop(struct bContext *C); -void ED_undo_redo(struct bContext *C); -void ED_OT_undo(struct wmOperatorType *ot); -void ED_OT_undo_push(struct wmOperatorType *ot); -void ED_OT_redo(struct wmOperatorType *ot); -void ED_OT_undo_redo(struct wmOperatorType *ot); -void ED_OT_undo_history(struct wmOperatorType *ot); - -int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op); -/* convenience since UI callbacks use this mostly*/ -void ED_undo_operator_repeat_cb(struct bContext *C, void *arg_op, void *arg_unused); -void ED_undo_operator_repeat_cb_evt(struct bContext *C, void *arg_op, int arg_unused); - -bool ED_undo_is_valid(const struct bContext *C, const char *undoname); - -/* undo_editmode.c */ -void undo_editmode_push(struct bContext *C, const char *name, - void * (*getdata)(struct bContext *C), - void (*freedata)(void *), - void (*to_editmode)(void *, void *, void *), - void *(*from_editmode)(void *, void *), - int (*validate_undo)(void *, void *)); - - -void undo_editmode_clear(void); - /* ************** XXX OLD CRUFT WARNING ************* */ void apply_keyb_grid(int shift, int ctrl, float *val, float fac1, float fac2, float fac3, int invert); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index bf39a8d353f..9f7cd62227c 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -74,7 +74,7 @@ #include "BKE_paint.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "ED_keyframing.h" #include "UI_interface.h" diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 7cf8a315895..046bb114a62 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -611,7 +611,8 @@ 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) { - BKE_text_write(txt, str); + TextUndoBuf *utxt = NULL; // FIXME + BKE_text_write(txt, utxt, str); MEM_freeN(str); return OPERATOR_FINISHED; diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c index 15053f0d8ca..4714efdb4a7 100644 --- a/source/blender/editors/interface/interface_region_popup.c +++ b/source/blender/editors/interface/interface_region_popup.c @@ -303,19 +303,36 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, static void ui_block_region_draw(const bContext *C, ARegion *ar) { + ScrArea *ctx_area = CTX_wm_area(C); + ARegion *ctx_region = CTX_wm_region(C); uiBlock *block; if (ar->do_draw & RGN_DRAW_REFRESH_UI) { + ScrArea *handle_ctx_area; + ARegion *handle_ctx_region; uiBlock *block_next; + ar->do_draw &= ~RGN_DRAW_REFRESH_UI; for (block = ar->uiblocks.first; block; block = block_next) { block_next = block->next; if (block->handle->can_refresh) { + handle_ctx_area = block->handle->ctx_area; + handle_ctx_region = block->handle->ctx_region; + + if (handle_ctx_area) { + CTX_wm_area_set((bContext *)C, handle_ctx_area); + } + if (handle_ctx_region) { + CTX_wm_region_set((bContext *)C, handle_ctx_region); + } ui_popup_block_refresh((bContext *)C, block->handle, NULL, NULL); } } } + CTX_wm_area_set((bContext *)C, ctx_area); + CTX_wm_region_set((bContext *)C, ctx_region); + for (block = ar->uiblocks.first; block; block = block->next) UI_block_draw(C, block); } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 82a502db0ad..b92216138fd 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -75,7 +75,7 @@ #include "ED_screen.h" #include "ED_object.h" #include "ED_render.h" -#include "ED_util.h" +#include "ED_undo.h" #include "RNA_access.h" diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index 975bbddd893..eb79d0bec13 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -33,7 +33,6 @@ #include "BKE_cachefile.h" #include "BKE_context.h" -#include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_report.h" diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index e6c9b924c7f..42c19c6bc65 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -145,7 +145,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) include_animations = RNA_boolean_get(op->ptr, "include_animations"); sample_animations = RNA_boolean_get(op->ptr, "sample_animations"); - sampling_rate = (sample_animations)? RNA_int_get(op->ptr, "sampling_rate") : 0; + sampling_rate = (sample_animations) ? RNA_int_get(op->ptr, "sampling_rate") : 0; deform_bones_only = RNA_boolean_get(op->ptr, "deform_bones_only"); @@ -496,8 +496,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op) import_settings.min_chain_length = min_chain_length; import_settings.keep_bind_info = keep_bind_info != 0; - if (collada_import(C, &import_settings) ) - { + if (collada_import(C, &import_settings)) { return OPERATOR_FINISHED; } else { diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c index aa817928f92..7a7372f5a6a 100644 --- a/source/blender/editors/lattice/editlattice_undo.c +++ b/source/blender/editors/lattice/editlattice_undo.c @@ -34,6 +34,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" +#include "BLI_array_utils.h" #include "DNA_curve_types.h" #include "DNA_lattice_types.h" @@ -41,31 +42,39 @@ #include "DNA_scene_types.h" #include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_undo_system.h" +#include "ED_object.h" #include "ED_lattice.h" #include "ED_util.h" +#include "WM_types.h" +#include "WM_api.h" + #include "lattice_intern.h" +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ + typedef struct UndoLattice { BPoint *def; int pntsu, pntsv, pntsw, actbp; + size_t undo_size; } UndoLattice; -static void undoLatt_to_editLatt(void *data, void *edata, void *UNUSED(obdata)) +static void undolatt_to_editlatt(UndoLattice *ult, EditLatt *editlatt) { - UndoLattice *ult = (UndoLattice *)data; - EditLatt *editlatt = (EditLatt *)edata; - int a = editlatt->latt->pntsu * editlatt->latt->pntsv * editlatt->latt->pntsw; + int len = editlatt->latt->pntsu * editlatt->latt->pntsv * editlatt->latt->pntsw; - memcpy(editlatt->latt->def, ult->def, a * sizeof(BPoint)); + memcpy(editlatt->latt->def, ult->def, sizeof(BPoint) * len); editlatt->latt->actbp = ult->actbp; } -static void *editLatt_to_undoLatt(void *edata, void *UNUSED(obdata)) +static void *undolatt_from_editlatt(UndoLattice *ult, EditLatt *editlatt) { - UndoLattice *ult = MEM_callocN(sizeof(UndoLattice), "UndoLattice"); - EditLatt *editlatt = (EditLatt *)edata; + BLI_assert(BLI_array_is_zeroed(ult, 1)); ult->def = MEM_dupallocN(editlatt->latt->def); ult->pntsu = editlatt->latt->pntsu; @@ -73,17 +82,19 @@ static void *editLatt_to_undoLatt(void *edata, void *UNUSED(obdata)) ult->pntsw = editlatt->latt->pntsw; ult->actbp = editlatt->latt->actbp; + ult->undo_size += sizeof(*ult->def) * ult->pntsu * ult->pntsv * ult->pntsw; + return ult; } -static void free_undoLatt(void *data) +static void undolatt_free_data(UndoLattice *ult) { - UndoLattice *ult = (UndoLattice *)data; - - if (ult->def) MEM_freeN(ult->def); - MEM_freeN(ult); + if (ult->def) { + MEM_freeN(ult->def); + } } +#if 0 static int validate_undoLatt(void *data, void *edata) { UndoLattice *ult = (UndoLattice *)data; @@ -93,21 +104,92 @@ static int validate_undoLatt(void *data, void *edata) ult->pntsv == editlatt->latt->pntsv && ult->pntsw == editlatt->latt->pntsw); } +#endif -static void *get_editlatt(bContext *C) +static Object *editlatt_object_from_context(bContext *C) { Object *obedit = CTX_data_edit_object(C); - if (obedit && obedit->type == OB_LATTICE) { Lattice *lt = obedit->data; - return lt->editlatt; + if (lt->editlatt != NULL) { + return obedit; + } } return NULL; } -/* and this is all the undo system needs to know */ -void undo_push_lattice(bContext *C, const char *name) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct LatticeUndoStep { + UndoStep step; + /* note: will split out into list for multi-object-editmode. */ + UndoRefID_Object obedit_ref; + UndoLattice data; +} LatticeUndoStep; + +static bool lattice_undosys_poll(bContext *C) +{ + return editlatt_object_from_context(C) != NULL; +} + +static bool lattice_undosys_step_encode(struct bContext *C, UndoStep *us_p) { - undo_editmode_push(C, name, get_editlatt, free_undoLatt, undoLatt_to_editLatt, editLatt_to_undoLatt, validate_undoLatt); + LatticeUndoStep *us = (LatticeUndoStep *)us_p; + us->obedit_ref.ptr = editlatt_object_from_context(C); + Lattice *lt = us->obedit_ref.ptr->data; + undolatt_from_editlatt(&us->data, lt->editlatt); + us->step.data_size = us->data.undo_size; + return true; } + +static void lattice_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* TODO(campbell): undo_system: use low-level API to set mode. */ + ED_object_mode_set(C, OB_MODE_EDIT); + BLI_assert(lattice_undosys_poll(C)); + + LatticeUndoStep *us = (LatticeUndoStep *)us_p; + Object *obedit = us->obedit_ref.ptr; + Lattice *lt = obedit->data; + EditLatt *editlatt = lt->editlatt; + undolatt_to_editlatt(&us->data, editlatt); + DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); +} + +static void lattice_undosys_step_free(UndoStep *us_p) +{ + LatticeUndoStep *us = (LatticeUndoStep *)us_p; + undolatt_free_data(&us->data); +} + +static void lattice_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + LatticeUndoStep *us = (LatticeUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref)); +} + +/* Export for ED_undo_sys. */ +void ED_lattice_undosys_type(UndoType *ut) +{ + ut->name = "Edit Lattice"; + ut->poll = lattice_undosys_poll; + ut->step_encode = lattice_undosys_step_encode; + ut->step_decode = lattice_undosys_step_decode; + ut->step_free = lattice_undosys_step_free; + + ut->step_foreach_ID_ref = lattice_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(LatticeUndoStep); +} + +/** \} */ diff --git a/source/blender/editors/lattice/lattice_intern.h b/source/blender/editors/lattice/lattice_intern.h index 94f528a0457..7902b992270 100644 --- a/source/blender/editors/lattice/lattice_intern.h +++ b/source/blender/editors/lattice/lattice_intern.h @@ -21,7 +21,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/editors/metaball/lattice_intern.h +/** \file blender/editors/lattice/lattice_intern.h * \ingroup edlattice */ diff --git a/source/blender/editors/lattice/lattice_ops.c b/source/blender/editors/lattice/lattice_ops.c index 37a10cbe12a..d3d57a0b510 100644 --- a/source/blender/editors/lattice/lattice_ops.c +++ b/source/blender/editors/lattice/lattice_ops.c @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/editors/metaball/lattice_ops.c +/** \file blender/editors/lattice/lattice_ops.c * \ingroup edlattice */ diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 2c98f05bd27..78bc361b222 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -36,8 +36,6 @@ #include "BLI_listbase.h" #include "BKE_context.h" -#include "BKE_global.h" -#include "BKE_main.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_editmesh.h" diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 3ce9257de0c..874225e96a7 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -857,7 +857,7 @@ static void knife_cut_face(KnifeTool_OpData *kcd, BMFace *f, ListBase *hits) { Ref *r; - if (BLI_listbase_count_ex(hits, 2) != 2) + if (BLI_listbase_count_at_most(hits, 2) != 2) return; for (r = hits->first; r->next; r = r->next) { diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 3a900cfdcae..ccb42e15aa6 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -1125,7 +1125,7 @@ static bool bm_vert_connect_select_history(BMesh *bm) * - Otherwise connect faces. * - If all edges have been created already, closed the loop. */ - if (BLI_listbase_count_ex(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) { + if (BLI_listbase_count_at_most(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) { BMEditSelection *ese; int tot = 0; bool changed = false; @@ -3751,7 +3751,7 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span * * note: we may have already checked 'edbm_fill_grid_vert_tag_angle()' on each * vert, but advantage of de-duplicating is minimal. */ - struct SortPointerByFloat *ele_sort = MEM_mallocN(sizeof(*ele_sort) * verts_len, __func__); + struct SortPtrByFloat *ele_sort = MEM_mallocN(sizeof(*ele_sort) * verts_len, __func__); LinkData *v_link; for (v_link = verts->first, i = 0; v_link; v_link = v_link->next, i++) { BMVert *v = v_link->data; diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index dab6ecc9359..509cdb0e049 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -29,16 +29,24 @@ #include "DNA_key_types.h" #include "BLI_listbase.h" +#include "BLI_array_utils.h" +#include "BLI_alloca.h" #include "BKE_DerivedMesh.h" #include "BKE_context.h" #include "BKE_key.h" #include "BKE_mesh.h" #include "BKE_editmesh.h" +#include "BKE_depsgraph.h" +#include "BKE_undo_system.h" +#include "ED_object.h" #include "ED_mesh.h" #include "ED_util.h" +#include "WM_types.h" +#include "WM_api.h" + #define USE_ARRAY_STORE #ifdef USE_ARRAY_STORE @@ -60,6 +68,9 @@ # include "BLI_task.h" #endif +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ #ifdef USE_ARRAY_STORE @@ -95,6 +106,8 @@ typedef struct UndoMesh { BArrayState *mselect; } store; #endif /* USE_ARRAY_STORE */ + + size_t undo_size; } UndoMesh; @@ -474,23 +487,17 @@ static void um_arraystore_free(UndoMesh *um) /* for callbacks */ /* undo simply makes copies of a bmesh */ -static void *editbtMesh_to_undoMesh(void *emv, void *obdata) +static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key) { - + BLI_assert(BLI_array_is_zeroed(um, 1)); #ifdef USE_ARRAY_STORE_THREAD /* changes this waits is low, but must have finished */ if (um_arraystore.task_pool) { BLI_task_pool_work_and_wait(um_arraystore.task_pool); } #endif - - BMEditMesh *em = emv; - Mesh *obme = obdata; - - UndoMesh *um = MEM_callocN(sizeof(UndoMesh), "undo Mesh"); - /* make sure shape keys work */ - um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL; + um->me.key = key ? BKE_key_copy_nolib(key) : NULL; /* BM_mesh_validate(em->bm); */ /* for troubleshooting */ @@ -536,13 +543,12 @@ static void *editbtMesh_to_undoMesh(void *emv, void *obdata) return um; } -static void undoMesh_to_editbtMesh(void *um_v, void *em_v, void *obdata) +static void undomesh_to_editmesh(UndoMesh *um, BMEditMesh *em, Mesh *obmesh) { - BMEditMesh *em = em_v, *em_tmp; + BMEditMesh *em_tmp; Object *ob = em->ob; - UndoMesh *um = um_v; BMesh *bm; - Key *key = ((Mesh *) obdata)->key; + Key *key = obmesh->key; #ifdef USE_ARRAY_STORE #ifdef USE_ARRAY_STORE_THREAD @@ -617,9 +623,8 @@ static void undoMesh_to_editbtMesh(void *um_v, void *em_v, void *obdata) #endif } -static void free_undo(void *um_v) +static void undomesh_free_data(UndoMesh *um) { - UndoMesh *um = um_v; Mesh *me = &um->me; #ifdef USE_ARRAY_STORE @@ -646,28 +651,165 @@ static void free_undo(void *um_v) } BKE_mesh_free(me); - MEM_freeN(me); } -static void *getEditMesh(bContext *C) +static Object *editmesh_object_from_context(bContext *C) { Object *obedit = CTX_data_edit_object(C); if (obedit && obedit->type == OB_MESH) { Mesh *me = obedit->data; - return me->edit_btmesh; + if (me->edit_btmesh != NULL) { + return obedit; + } } return NULL; } -/* and this is all the undo system needs to know */ -void undo_push_mesh(bContext *C, const char *name) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct MeshUndoStep { + UndoStep step; + /* Use for all ID lookups (can be NULL). */ + struct UndoIDPtrMap *id_map; + + /* note: will split out into list for multi-object-editmode. */ + UndoRefID_Object obedit_ref; + /* Needed for MTexPoly's image use. */ + UndoRefID_Object *image_array_ref; + UndoMesh data; +} MeshUndoStep; + +static void mesh_undosys_step_encode_store_ids(MeshUndoStep *us) { - /* em->ob gets out of date and crashes on mesh undo, - * this is an easy way to ensure its OK - * though we could investigate the matter further. */ - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - em->ob = obedit; + Mesh *me = us->obedit_ref.ptr->data; + BMesh *bm = me->edit_btmesh->bm; + const int mtex_len = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); + if (mtex_len != 0) { + ID **id_prev_array = BLI_array_alloca(id_prev_array, mtex_len); + memset(id_prev_array, 0x0, sizeof(*id_prev_array) * mtex_len); + + BMIter iter; + BMFace *efa; + + if (us->id_map == NULL) { + us->id_map = BKE_undosys_ID_map_create(); + } - undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL); + uint cd_poly_tex_offset_first = CustomData_get_n_offset(&bm->pdata, CD_MTEXPOLY, 0); + uint cd_poly_tex_offset_end = cd_poly_tex_offset_first + (sizeof(MTexPoly) * mtex_len); + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + for (uint cd_poly_tex_offset = cd_poly_tex_offset_first, i = 0; + cd_poly_tex_offset < cd_poly_tex_offset_end; + cd_poly_tex_offset += sizeof(MTexPoly), i++) + { + const MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); + if (tf->tpage != NULL) { + BKE_undosys_ID_map_add_with_prev(us->id_map, (ID *)tf->tpage, &id_prev_array[i]); + } + } + } + } +} + +static void mesh_undosys_step_decode_restore_ids(MeshUndoStep *us) +{ + Mesh *me = us->obedit_ref.ptr->data; + BMesh *bm = me->edit_btmesh->bm; + const int mtex_len = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); + if (mtex_len != 0 && us->id_map) { + BMIter iter; + BMFace *efa; + + ID *(*id_prev_array)[2] = BLI_array_alloca(id_prev_array, mtex_len); + memset(id_prev_array, 0x0, sizeof(*id_prev_array) * mtex_len); + + uint cd_poly_tex_offset_first = CustomData_get_n_offset(&bm->pdata, CD_MTEXPOLY, 0); + uint cd_poly_tex_offset_end = cd_poly_tex_offset_first + (sizeof(MTexPoly) * mtex_len); + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + for (uint cd_poly_tex_offset = cd_poly_tex_offset_first, i = 0; + cd_poly_tex_offset < cd_poly_tex_offset_end; + cd_poly_tex_offset += sizeof(MTexPoly), i++) + { + MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); + if (tf->tpage != NULL) { + tf->tpage = (Image *)BKE_undosys_ID_map_lookup_with_prev(us->id_map, (ID *)tf->tpage, id_prev_array[i]); + } + } + } + } } + +static bool mesh_undosys_poll(bContext *C) +{ + return editmesh_object_from_context(C) != NULL; +} + +static bool mesh_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + MeshUndoStep *us = (MeshUndoStep *)us_p; + us->obedit_ref.ptr = editmesh_object_from_context(C); + Mesh *me = us->obedit_ref.ptr->data; + undomesh_from_editmesh(&us->data, me->edit_btmesh, me->key); + mesh_undosys_step_encode_store_ids(us); + us->step.data_size = us->data.undo_size; + return true; +} + +static void mesh_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* TODO(campbell): undo_system: use low-level API to set mode. */ + ED_object_mode_set(C, OB_MODE_EDIT); + BLI_assert(mesh_undosys_poll(C)); + + MeshUndoStep *us = (MeshUndoStep *)us_p; + Object *obedit = us->obedit_ref.ptr; + Mesh *me = obedit->data; + BMEditMesh *em = me->edit_btmesh; + undomesh_to_editmesh(&us->data, em, obedit->data); + mesh_undosys_step_decode_restore_ids(us); + DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); +} + +static void mesh_undosys_step_free(UndoStep *us_p) +{ + MeshUndoStep *us = (MeshUndoStep *)us_p; + undomesh_free_data(&us->data); + + if (us->id_map != NULL) { + BKE_undosys_ID_map_destroy(us->id_map); + } +} + +static void mesh_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + MeshUndoStep *us = (MeshUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref)); + if (us->id_map != NULL) { + BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data); + } +} + +/* Export for ED_undo_sys. */ +void ED_mesh_undosys_type(UndoType *ut) +{ + ut->name = "Edit Mesh"; + ut->poll = mesh_undosys_poll; + ut->step_encode = mesh_undosys_step_encode; + ut->step_decode = mesh_undosys_step_decode; + ut->step_free = mesh_undosys_step_free; + + ut->step_foreach_ID_ref = mesh_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(MeshUndoStep); +} + +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 34b8d76db86..84374986b30 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -43,9 +43,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_context.h" -#include "BKE_global.h" #include "BKE_depsgraph.h" -#include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_report.h" diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c index 974bfb237d3..dc64f61a916 100644 --- a/source/blender/editors/metaball/editmball_undo.c +++ b/source/blender/editors/metaball/editmball_undo.c @@ -29,19 +29,31 @@ #include "BLI_utildefines.h" #include "BLI_listbase.h" +#include "BLI_array_utils.h" #include "DNA_defs.h" #include "DNA_meta_types.h" #include "DNA_object_types.h" #include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_undo_system.h" +#include "ED_object.h" #include "ED_mball.h" #include "ED_util.h" +#include "WM_types.h" +#include "WM_api.h" + +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ + typedef struct UndoMBall { ListBase editelems; int lastelem_index; + size_t undo_size; } UndoMBall; /* free all MetaElems from ListBase */ @@ -58,11 +70,8 @@ static void freeMetaElemlist(ListBase *lb) } } -static void undoMball_to_editMball(void *umb_v, void *mb_v, void *UNUSED(obdata)) +static void undomball_to_editmball(UndoMBall *umb, MetaBall *mb) { - MetaBall *mb = mb_v; - UndoMBall *umb = umb_v; - freeMetaElemlist(mb->editelems); mb->lastelem = NULL; @@ -75,18 +84,15 @@ static void undoMball_to_editMball(void *umb_v, void *mb_v, void *UNUSED(obdata) mb->lastelem = ml_edit; } } - } -static void *editMball_to_undoMball(void *mb_v, void *UNUSED(obdata)) +static void *editmball_from_undomball(UndoMBall *umb, MetaBall *mb) { - MetaBall *mb = mb_v; - UndoMBall *umb; + BLI_assert(BLI_array_is_zeroed(umb, 1)); /* allocate memory for undo ListBase */ - umb = MEM_callocN(sizeof(UndoMBall), __func__); umb->lastelem_index = -1; - + /* copy contents of current ListBase to the undo ListBase */ int index = 0; for (MetaElem *ml_edit = mb->editelems->first; ml_edit; ml_edit = ml_edit->next, index += 1) { @@ -95,37 +101,99 @@ static void *editMball_to_undoMball(void *mb_v, void *UNUSED(obdata)) if (ml_edit == mb->lastelem) { umb->lastelem_index = index; } + umb->undo_size += sizeof(MetaElem); } - + return umb; } /* free undo ListBase of MetaElems */ -static void free_undoMball(void *umb_v) +static void undomball_free_data(UndoMBall *umb) { - UndoMBall *umb = umb_v; - freeMetaElemlist(&umb->editelems); - MEM_freeN(umb); } -static MetaBall *metaball_get_obdata(Object *ob) +static Object *editmball_object_from_context(bContext *C) { - if (ob && ob->type == OB_MBALL) { - return ob->data; + Object *obedit = CTX_data_edit_object(C); + if (obedit && obedit->type == OB_MBALL) { + MetaBall *mb = obedit->data; + if (mb->editelems != NULL) { + return obedit; + } } return NULL; } +/** \} */ -static void *get_data(bContext *C) +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct MBallUndoStep { + UndoStep step; + /* note: will split out into list for multi-object-editmode. */ + UndoRefID_Object obedit_ref; + UndoMBall data; +} MBallUndoStep; + +static bool mball_undosys_poll(bContext *C) { - Object *obedit = CTX_data_edit_object(C); - return metaball_get_obdata(obedit); + return editmball_object_from_context(C) != NULL; } -/* this is undo system for MetaBalls */ -void undo_push_mball(bContext *C, const char *name) +static bool mball_undosys_step_encode(struct bContext *C, UndoStep *us_p) { - undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL); + MBallUndoStep *us = (MBallUndoStep *)us_p; + us->obedit_ref.ptr = editmball_object_from_context(C); + MetaBall *mb = us->obedit_ref.ptr->data; + editmball_from_undomball(&us->data, mb); + us->step.data_size = us->data.undo_size; + return true; } + +static void mball_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + ED_object_mode_set(C, OB_MODE_EDIT); + + MBallUndoStep *us = (MBallUndoStep *)us_p; + Object *obedit = us->obedit_ref.ptr; + MetaBall *mb = obedit->data; + undomball_to_editmball(&us->data, mb); + DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); +} + +static void mball_undosys_step_free(UndoStep *us_p) +{ + MBallUndoStep *us = (MBallUndoStep *)us_p; + undomball_free_data(&us->data); +} + +static void mball_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + MBallUndoStep *us = (MBallUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref)); +} + +/* Export for ED_undo_sys. */ +void ED_mball_undosys_type(UndoType *ut) +{ + ut->name = "Edit MBall"; + ut->poll = mball_undosys_poll; + ut->step_encode = mball_undosys_step_encode; + ut->step_decode = mball_undosys_step_decode; + ut->step_free = mball_undosys_step_free; + + ut->step_foreach_ID_ref = mball_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(MBallUndoStep); + +} + +/** \} */ diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 0b486f8e5a3..c6820c83f95 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -413,7 +413,7 @@ Object *ED_object_add_type( /* for as long scene has editmode... */ if (CTX_data_edit_object(C)) - ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */ + ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */ /* deselects all, sets scene->basact */ ob = BKE_object_add(bmain, scene, type, name); @@ -1573,7 +1573,7 @@ static void curvetomesh(Main *bmain, Scene *scene, Object *ob) BKE_mesh_from_nurbs(ob); /* also does users */ if (ob->type == OB_MESH) { - BKE_object_free_modifiers(ob); + BKE_object_free_modifiers(ob, 0); /* Game engine defaults for mesh objects */ ob->body_type = OB_BODY_TYPE_STATIC; @@ -1702,7 +1702,7 @@ static int convert_exec(bContext *C, wmOperator *op) /* When 2 objects with linked data are selected, converting both * would keep modifiers on all but the converted object [#26003] */ if (ob->type == OB_MESH) { - BKE_object_free_modifiers(ob); /* after derivedmesh calls! */ + BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */ } } } @@ -1727,7 +1727,7 @@ static int convert_exec(bContext *C, wmOperator *op) BKE_mesh_to_curve(scene, newob); if (newob->type == OB_CURVE) { - BKE_object_free_modifiers(newob); /* after derivedmesh calls! */ + BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */ ED_rigidbody_object_remove(bmain, scene, newob); } } @@ -1760,7 +1760,7 @@ static int convert_exec(bContext *C, wmOperator *op) /* re-tessellation is called by DM_to_mesh */ - BKE_object_free_modifiers(newob); /* after derivedmesh calls! */ + BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */ } else if (ob->type == OB_FONT) { ob->flag |= OB_DONE; diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index f67ecbce1d0..844ed168157 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -85,6 +85,7 @@ #include "BKE_editlattice.h" #include "BKE_editmesh.h" #include "BKE_report.h" +#include "BKE_undo_system.h" #include "ED_armature.h" #include "ED_curve.h" @@ -93,7 +94,7 @@ #include "ED_lattice.h" #include "ED_object.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "ED_image.h" #include "RNA_access.h" @@ -657,7 +658,7 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op) if (!is_mode_set) ED_object_editmode_enter(C, EM_WAITCURSOR); else - ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR); /* had EM_DO_UNDO but op flag calls undo too [#24685] */ + ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR); /* had EM_DO_UNDO but op flag calls undo too [#24685] */ ED_space_image_uv_sculpt_update(CTX_wm_manager(C), scene); @@ -702,7 +703,7 @@ static int posemode_exec(bContext *C, wmOperator *op) Base *base = CTX_data_active_base(C); Object *ob = base->object; const int mode_flag = OB_MODE_POSE; - const bool is_mode_set = (ob->mode & mode_flag) != 0; + bool is_mode_set = (ob->mode & mode_flag) != 0; if (!is_mode_set) { if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { @@ -713,12 +714,15 @@ static int posemode_exec(bContext *C, wmOperator *op) if (ob->type == OB_ARMATURE) { if (ob == CTX_data_edit_object(C)) { ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO); - ED_armature_enter_posemode(C, base); + is_mode_set = false; + } + + if (is_mode_set) { + ED_object_posemode_exit(C, ob); + } + else { + ED_object_posemode_enter(C, ob); } - else if (is_mode_set) - ED_armature_exit_posemode(C, base); - else - ED_armature_enter_posemode(C, base); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c index fda342f8a4d..d70a69e30f8 100644 --- a/source/blender/editors/object/object_modes.c +++ b/source/blender/editors/object/object_modes.c @@ -136,3 +136,43 @@ void ED_object_mode_toggle(bContext *C, eObjectMode mode) } } } + +/* Wrapper for operator */ +void ED_object_mode_set(bContext *C, eObjectMode mode) +{ +#if 0 + wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_mode_set", false); + PointerRNA ptr; + + WM_operator_properties_create_ptr(&ptr, ot); + RNA_enum_set(&ptr, "mode", mode); + RNA_boolean_set(&ptr, "toggle", false); + WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &ptr); + WM_operator_properties_free(&ptr); +#else + Object *ob = CTX_data_active_object(C); + if (ob == NULL) { + return; + } + if (ob->mode == mode) { + /* pass */ + } + else if (mode != OB_MODE_OBJECT) { + if (ob && (ob->mode & mode) == 0) { + /* needed so we don't do undo pushes. */ + wmWindowManager *wm = CTX_wm_manager(C); + wm->op_undo_depth++; + ED_object_mode_toggle(C, mode); + wm->op_undo_depth--; + } + } + else { + /* needed so we don't do undo pushes. */ + wmWindowManager *wm = CTX_wm_manager(C); + wm->op_undo_depth++; + ED_object_mode_toggle(C, ob->mode); + wm->op_undo_depth--; + + } +#endif +} diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 93bfd156707..bdffaf31384 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -126,8 +126,6 @@ void PE_free_ptcache_edit(PTCacheEdit *edit) if (edit==0) return; - PTCacheUndo_clear(edit); - if (edit->points) { LOOP_POINTS { if (point->keys) @@ -4379,9 +4377,6 @@ void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, Partic if (psys && !cache) recalc_emitter_field(ob, psys); PE_update_object(scene, ob, 1); - - PTCacheUndo_clear(edit); - PE_undo_push(scene, "Original"); } } diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c index 288e59a8671..ef0a2711fdd 100644 --- a/source/blender/editors/physics/particle_edit_undo.c +++ b/source/blender/editors/physics/particle_edit_undo.c @@ -38,47 +38,37 @@ #include "DNA_scene_types.h" #include "DNA_meshdata_types.h" +#include "DNA_windowmanager_types.h" #include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_utildefines.h" #include "BKE_depsgraph.h" -#include "BKE_global.h" #include "BKE_particle.h" #include "BKE_pointcache.h" +#include "BKE_context.h" +#include "BKE_undo_system.h" +#include "ED_object.h" #include "ED_particle.h" +#include "ED_physics.h" #include "particle_edit_utildefines.h" #include "physics_intern.h" -static void free_PTCacheUndo(PTCacheUndo *undo) -{ - PTCacheEditPoint *point; - int i; - - for (i=0, point=undo->points; i<undo->totpoint; i++, point++) { - if (undo->particles && (undo->particles + i)->hair) - MEM_freeN((undo->particles + i)->hair); - if (point->keys) - MEM_freeN(point->keys); - } - if (undo->points) - MEM_freeN(undo->points); +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ - if (undo->particles) - MEM_freeN(undo->particles); - - BKE_ptcache_free_mem(&undo->mem_cache); -} - -static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) +static void undoptcache_from_editcache(PTCacheUndo *undo, PTCacheEdit *edit) { PTCacheEditPoint *point; int i; + size_t mem_used_prev = MEM_get_memory_in_use(); + undo->totpoint= edit->totpoint; if (edit->psys) { @@ -86,8 +76,9 @@ static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) pa= undo->particles= MEM_dupallocN(edit->psys->particles); - for (i=0; i<edit->totpoint; i++, pa++) + for (i=0; i<edit->totpoint; i++, pa++) { pa->hair= MEM_dupallocN(pa->hair); + } undo->psys_flag = edit->psys->flag; } @@ -98,8 +89,9 @@ static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) pm = undo->mem_cache.first; for (; pm; pm=pm->next) { - for (i=0; i<BPHYS_TOT_DATA; i++) + for (i=0; i<BPHYS_TOT_DATA; i++) { pm->data[i] = MEM_dupallocN(pm->data[i]); + } } } @@ -110,9 +102,13 @@ static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) point->keys= MEM_dupallocN(point->keys); /* no need to update edit key->co & key->time pointers here */ } + + size_t mem_used_curr = MEM_get_memory_in_use(); + + undo->undo_size = mem_used_prev < mem_used_curr ? mem_used_curr - mem_used_prev : sizeof(PTCacheUndo); } -static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) +static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit) { ParticleSystem *psys = edit->psys; ParticleData *pa; @@ -120,16 +116,20 @@ static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) POINT_P; KEY_K; LOOP_POINTS { - if (psys && psys->particles[p].hair) + if (psys && psys->particles[p].hair) { MEM_freeN(psys->particles[p].hair); + } - if (point->keys) + if (point->keys) { MEM_freeN(point->keys); + } } - if (psys && psys->particles) + if (psys && psys->particles) { MEM_freeN(psys->particles); - if (edit->points) + } + if (edit->points) { MEM_freeN(edit->points); + } if (edit->mirror_cache) { MEM_freeN(edit->mirror_cache); edit->mirror_cache= NULL; @@ -171,9 +171,9 @@ static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) pm = edit->pid.cache->mem_cache.first; for (; pm; pm=pm->next) { - for (i=0; i<BPHYS_TOT_DATA; i++) + for (i = 0; i < BPHYS_TOT_DATA; i++) { pm->data[i] = MEM_dupallocN(pm->data[i]); - + } BKE_ptcache_mem_pointers_init(pm); LOOP_POINTS { @@ -191,150 +191,107 @@ static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) } } -void PE_undo_push(Scene *scene, const char *str) +static void undoptcache_free_data(PTCacheUndo *undo) { - PTCacheEdit *edit= PE_get_current(scene, OBACT); - PTCacheUndo *undo; - int nr; - - if (!edit) return; - - /* remove all undos after (also when curundo==NULL) */ - while (edit->undo.last != edit->curundo) { - undo= edit->undo.last; - BLI_remlink(&edit->undo, undo); - free_PTCacheUndo(undo); - MEM_freeN(undo); - } + PTCacheEditPoint *point; + int i; - /* make new */ - edit->curundo= undo= MEM_callocN(sizeof(PTCacheUndo), "particle undo file"); - BLI_strncpy(undo->name, str, sizeof(undo->name)); - BLI_addtail(&edit->undo, undo); - - /* and limit amount to the maximum */ - nr= 0; - undo= edit->undo.last; - while (undo) { - nr++; - if (nr==U.undosteps) break; - undo= undo->prev; - } - if (undo) { - while (edit->undo.first != undo) { - PTCacheUndo *first= edit->undo.first; - BLI_remlink(&edit->undo, first); - free_PTCacheUndo(first); - MEM_freeN(first); + for (i = 0, point=undo->points; i < undo->totpoint; i++, point++) { + if (undo->particles && (undo->particles + i)->hair) { + MEM_freeN((undo->particles + i)->hair); + } + if (point->keys) { + MEM_freeN(point->keys); } } - - /* copy */ - make_PTCacheUndo(edit, edit->curundo); + if (undo->points) { + MEM_freeN(undo->points); + } + if (undo->particles) { + MEM_freeN(undo->particles); + } + BKE_ptcache_free_mem(&undo->mem_cache); } -void PE_undo_step(Scene *scene, int step) -{ - PTCacheEdit *edit= PE_get_current(scene, OBACT); +/** \} */ - if (!edit) return; +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ - if (step==0) { - get_PTCacheUndo(edit, edit->curundo); - } - else if (step==1) { - - if (edit->curundo==NULL || edit->curundo->prev==NULL) { - /* pass */ - } - else { - if (G.debug & G_DEBUG) printf("undo %s\n", edit->curundo->name); - edit->curundo= edit->curundo->prev; - get_PTCacheUndo(edit, edit->curundo); - } - } - else { - /* curundo has to remain current situation! */ - - if (edit->curundo==NULL || edit->curundo->next==NULL) { - /* pass */ - } - else { - get_PTCacheUndo(edit, edit->curundo->next); - edit->curundo= edit->curundo->next; - if (G.debug & G_DEBUG) printf("redo %s\n", edit->curundo->name); - } - } +typedef struct ParticleUndoStep { + UndoStep step; + UndoRefID_Scene scene_ref; + UndoRefID_Object object_ref; + PTCacheUndo data; +} ParticleUndoStep; - DAG_id_tag_update(&OBACT->id, OB_RECALC_DATA); +static bool particle_undosys_poll(struct bContext *C) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = OBACT; + PTCacheEdit *edit = PE_get_current(scene, ob); + return (edit != NULL); } -bool PE_undo_is_valid(Scene *scene) +static bool particle_undosys_step_encode(struct bContext *C, UndoStep *us_p) { - PTCacheEdit *edit= PE_get_current(scene, OBACT); - - if (edit) { - return (edit->undo.last != edit->undo.first); - } - return 0; + ParticleUndoStep *us = (ParticleUndoStep *)us_p; + us->scene_ref.ptr = CTX_data_scene(C); + us->object_ref.ptr = us->scene_ref.ptr->basact->object; + PTCacheEdit *edit = PE_get_current(us->scene_ref.ptr, us->object_ref.ptr); + undoptcache_from_editcache(&us->data, edit); + return true; } -void PTCacheUndo_clear(PTCacheEdit *edit) +static void particle_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) { - PTCacheUndo *undo; - - if (edit==NULL) return; - - undo= edit->undo.first; - while (undo) { - free_PTCacheUndo(undo); - undo= undo->next; + /* TODO(campbell): undo_system: use low-level API to set mode. */ + ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT); + BLI_assert(particle_undosys_poll(C)); + + ParticleUndoStep *us = (ParticleUndoStep *)us_p; + Scene *scene = us->scene_ref.ptr; + Object *ob = us->object_ref.ptr; + PTCacheEdit *edit = PE_get_current(scene, ob); + if (edit) { + undoptcache_to_editcache(&us->data, edit); + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + } + else { + BLI_assert(0); } - BLI_freelistN(&edit->undo); - edit->curundo= NULL; } -void PE_undo(Scene *scene) +static void particle_undosys_step_free(UndoStep *us_p) { - PE_undo_step(scene, 1); + ParticleUndoStep *us = (ParticleUndoStep *)us_p; + undoptcache_free_data(&us->data); } -void PE_redo(Scene *scene) +static void particle_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) { - PE_undo_step(scene, -1); + ParticleUndoStep *us = (ParticleUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->scene_ref)); + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->object_ref)); } -void PE_undo_number(Scene *scene, int nr) +/* Export for ED_undo_sys. */ +void ED_particle_undosys_type(UndoType *ut) { - PTCacheEdit *edit= PE_get_current(scene, OBACT); - PTCacheUndo *undo; - int a=0; - - for (undo= edit->undo.first; undo; undo= undo->next, a++) { - if (a==nr) break; - } - edit->curundo= undo; - PE_undo_step(scene, 0); -} + ut->name = "Edit Particle"; + ut->poll = particle_undosys_poll; + ut->step_encode = particle_undosys_step_encode; + ut->step_decode = particle_undosys_step_decode; + ut->step_free = particle_undosys_step_free; + ut->step_foreach_ID_ref = particle_undosys_foreach_ID_ref; -/* get name of undo item, return null if no item with this index */ -/* if active pointer, set it to 1 if true */ -const char *PE_undo_get_name(Scene *scene, int nr, bool *r_active) -{ - PTCacheEdit *edit= PE_get_current(scene, OBACT); - PTCacheUndo *undo; - - if (r_active) *r_active = false; - - if (edit) { - undo= BLI_findlink(&edit->undo, nr); - if (undo) { - if (r_active && (undo == edit->curundo)) { - *r_active = true; - } - return undo->name; - } - } - return NULL; + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(ParticleUndoStep); } + +/** \} */ diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index d85720f956c..53a70abca05 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -911,10 +911,7 @@ static void copy_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys, P edit->emitter_field = NULL; edit->emitter_cosnos = NULL; - - BLI_listbase_clear(&edit->undo); - edit->curundo = NULL; - + edit->points = MEM_dupallocN(edit_from->points); pa = psys->particles; LOOP_POINTS { @@ -943,9 +940,6 @@ static void copy_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys, P recalc_lengths(edit); recalc_emitter_field(ob, psys); PE_update_object(scene, ob, true); - - PTCacheUndo_clear(edit); - PE_undo_push(scene, "Original"); } static void remove_particle_systems_from_object(Object *ob_to) diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index 2f95f360fe2..ce1e9d5cf6a 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -48,8 +48,6 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_fluidsim.h" -#include "BKE_global.h" -#include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_report.h" @@ -67,6 +65,8 @@ /* enable/disable overall compilation */ #ifdef WITH_MOD_FLUID +#include "BKE_global.h" + #include "WM_api.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h index cb281936634..f3f3697caaa 100644 --- a/source/blender/editors/physics/physics_intern.h +++ b/source/blender/editors/physics/physics_intern.h @@ -68,7 +68,6 @@ void PARTICLE_OT_edited_clear(struct wmOperatorType *ot); void PARTICLE_OT_unify_length(struct wmOperatorType *ot); -void PTCacheUndo_clear(struct PTCacheEdit *edit); void PE_create_particle_edit(struct Scene *scene, struct Object *ob, struct PointCache *cache, struct ParticleSystem *psys); void recalc_lengths(struct PTCacheEdit *edit); void recalc_emitter_field(struct Object *ob, struct ParticleSystem *psys); diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c index 1bfc162a331..412f9acf718 100644 --- a/source/blender/editors/physics/rigidbody_constraint.c +++ b/source/blender/editors/physics/rigidbody_constraint.c @@ -39,7 +39,6 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" -#include "BKE_global.h" #include "BKE_group.h" #include "BKE_main.h" #include "BKE_report.h" diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c index fa80fb5fbc1..b7083c29721 100644 --- a/source/blender/editors/physics/rigidbody_object.c +++ b/source/blender/editors/physics/rigidbody_object.c @@ -44,7 +44,6 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" -#include "BKE_global.h" #include "BKE_group.h" #include "BKE_main.h" #include "BKE_report.h" diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index c27570aabc5..509fdcf080a 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -65,6 +65,7 @@ #include "BKE_sequencer.h" #include "BKE_screen.h" #include "BKE_scene.h" +#include "BKE_undo_system.h" #include "WM_api.h" #include "WM_types.h" @@ -73,6 +74,7 @@ #include "ED_render.h" #include "ED_screen.h" #include "ED_util.h" +#include "ED_undo.h" #include "ED_view3d.h" #include "RE_pipeline.h" @@ -88,6 +90,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "BLO_undofile.h" #include "render_intern.h" @@ -624,7 +627,7 @@ static void render_image_restore_layer(RenderJob *rj) /* For single layer renders keep the active layer * visible, or show the compositing result. */ RenderResult *rr = RE_AcquireResultRead(rj->re); - if(RE_HasCombinedLayer(rr)) { + if (RE_HasCombinedLayer(rr)) { sima->iuser.layer = 0; } RE_ReleaseResult(rj->re); @@ -866,7 +869,8 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even /* get main */ if (G.debug_value == 101) { /* thread-safety experiment, copy main from the undo buffer */ - mainp = BKE_undo_get_main(&scene); + struct MemFile *memfile = ED_undosys_stack_memfile_get_active(CTX_wm_manager(C)->undo_stack); + mainp = BLO_memfile_main_get(memfile, CTX_data_main(C), &scene); } else mainp = CTX_data_main(C); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index fc0922c7b7c..a53a16906d3 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -63,6 +63,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "IMB_metadata.h" #include "UI_interface.h" #include "UI_interface_icons.h" @@ -1938,15 +1939,29 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c /* before setting the view */ if (vertical) { /* we always keep the scroll offset - so the total view gets increased with the scrolled away part */ - if (v2d->cur.ymax < - 0.001f) - y = min_ii(y, v2d->cur.ymin); - + if (v2d->cur.ymax < -FLT_EPSILON) { + /* Clamp to lower view boundary */ + if (v2d->tot.ymin < -v2d->winy) { + y = min_ii(y, 0); + } + else { + y = min_ii(y, v2d->cur.ymin); + } + } + y = -y; } else { /* don't jump back when panels close or hide */ - if (!is_context_new) - x = max_ii(x, v2d->cur.xmax); + if (!is_context_new) { + if (v2d->tot.xmax > v2d->winx) { + x = max_ii(x, 0); + } + else { + x = max_ii(x, v2d->cur.xmax); + } + } + y = -y; } @@ -2138,7 +2153,7 @@ static const char *meta_data_list[] = BLI_INLINE bool metadata_is_valid(ImBuf *ibuf, char *r_str, short index, int offset) { - return (IMB_metadata_get_field(ibuf, meta_data_list[index], r_str + offset, MAX_METADATA_STR - offset) && r_str[0]); + return (IMB_metadata_get_field(ibuf->metadata, meta_data_list[index], r_str + offset, MAX_METADATA_STR - offset) && r_str[0]); } static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const bool is_top) diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index c365f8c5fcc..437d82bdc77 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -75,6 +75,7 @@ #include "ED_screen_types.h" #include "ED_sequencer.h" #include "ED_util.h" +#include "ED_undo.h" #include "ED_view3d.h" #include "RNA_access.h" diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index adead9a8b9e..9527dc4fe83 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -51,7 +51,6 @@ set(SRC paint_mask.c paint_ops.c paint_stroke.c - paint_undo.c paint_utils.c paint_vertex.c paint_vertex_color_ops.c diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c index 8d9812f41d9..120514762f4 100644 --- a/source/blender/editors/sculpt_paint/paint_curve.c +++ b/source/blender/editors/sculpt_paint/paint_curve.c @@ -40,6 +40,7 @@ #include "BKE_paint.h" #include "ED_view3d.h" +#include "ED_paint.h" #include "WM_api.h" #include "WM_types.h" @@ -203,7 +204,7 @@ static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2]) br->paint_curve = pc = BKE_paint_curve_add(bmain, "PaintCurve"); } - ED_paintcurve_undo_push(C, op, pc); + ED_paintcurve_undo_push_begin(op->type->name); pcp = MEM_mallocN((pc->tot_points + 1) * sizeof(PaintCurvePoint), "PaintCurvePoint"); add_index = pc->add_index; @@ -241,6 +242,8 @@ static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2]) pcp[add_index].bez.h1 = HD_ALIGN; } + ED_paintcurve_undo_push_end(); + WM_paint_cursor_tag_redraw(window, ar); } @@ -302,7 +305,7 @@ static int paintcurve_delete_point_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - ED_paintcurve_undo_push(C, op, pc); + ED_paintcurve_undo_push_begin(op->type->name); #define DELETE_TAG 2 @@ -342,6 +345,8 @@ static int paintcurve_delete_point_exec(bContext *C, wmOperator *op) #undef DELETE_TAG + ED_paintcurve_undo_push_end(); + WM_paint_cursor_tag_redraw(window, ar); return OPERATOR_FINISHED; @@ -379,7 +384,7 @@ static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2 if (!pc) return false; - ED_paintcurve_undo_push(C, op, pc); + ED_paintcurve_undo_push_begin(op->type->name); if (toggle) { PaintCurvePoint *pcp; @@ -444,10 +449,14 @@ static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2 } } - if (!pcp) + if (!pcp) { + ED_paintcurve_undo_push_end(); return false; + } } + ED_paintcurve_undo_push_end(); + WM_paint_cursor_tag_redraw(window, ar); return true; @@ -562,9 +571,6 @@ static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *e psd->align = align; op->customdata = psd; - if (do_select) - ED_paintcurve_undo_push(C, op, pc); - /* first, clear all selection from points */ for (i = 0; i < pc->tot_points; i++) pc->points[i].bez.f1 = pc->points[i].bez.f3 = pc->points[i].bez.f2 = 0; @@ -587,6 +593,8 @@ static int paintcurve_slide_modal(bContext *C, wmOperator *op, const wmEvent *ev if (event->type == psd->event && event->val == KM_RELEASE) { MEM_freeN(psd); + ED_paintcurve_undo_push_begin(op->type->name); + ED_paintcurve_undo_push_end(); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c index 70f92999864..77f06180df6 100644 --- a/source/blender/editors/sculpt_paint/paint_curve_undo.c +++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c @@ -30,100 +30,139 @@ #include "DNA_space_types.h" #include "BLI_string.h" +#include "BLI_array_utils.h" #include "BKE_context.h" #include "BKE_paint.h" +#include "BKE_undo_system.h" #include "ED_paint.h" +#include "ED_undo.h" #include "WM_api.h" #include "WM_types.h" #include "paint_intern.h" -typedef struct UndoCurve { - struct UndoImageTile *next, *prev; +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ +typedef struct UndoCurve { PaintCurvePoint *points; /* points of curve */ int tot_points; - int active_point; - - char idname[MAX_ID_NAME]; /* name instead of pointer*/ + int add_index; } UndoCurve; -static void paintcurve_undo_restore(bContext *C, ListBase *lb) +static void undocurve_from_paintcurve(UndoCurve *uc, const PaintCurve *pc) { - Paint *p = BKE_paint_get_active_from_context(C); - UndoCurve *uc; - PaintCurve *pc = NULL; + BLI_assert(BLI_array_is_zeroed(uc, 1)); + uc->points = MEM_dupallocN(pc->points); + uc->tot_points = pc->tot_points; + uc->add_index = pc->add_index; +} - if (p->brush) { - pc = p->brush->paint_curve; - } +static void undocurve_to_paintcurve(const UndoCurve *uc, PaintCurve *pc) +{ + MEM_SAFE_FREE(pc->points); + pc->points = MEM_dupallocN(uc->points); + pc->tot_points = uc->tot_points; + pc->add_index = uc->add_index; +} - if (!pc) { - return; - } +static void undocurve_free_data(UndoCurve *uc) +{ + MEM_SAFE_FREE(uc->points); +} - uc = (UndoCurve *)lb->first; +/** \} */ - if (STREQLEN(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname)))) { - SWAP(PaintCurvePoint *, pc->points, uc->points); - SWAP(int, pc->tot_points, uc->tot_points); - SWAP(int, pc->add_index, uc->active_point); - } -} +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ -static void paintcurve_undo_delete(ListBase *lb) +typedef struct PaintCurveUndoStep { + UndoStep step; + PaintCurve *pc; + UndoCurve data; +} PaintCurveUndoStep; + +static bool paintcurve_undosys_poll(bContext *C) { - UndoCurve *uc; - uc = (UndoCurve *)lb->first; + Paint *p = BKE_paint_get_active_from_context(C); + return (p->brush && p->brush->paint_curve); +} - if (uc->points) - MEM_freeN(uc->points); - uc->points = NULL; +static void paintcurve_undosys_step_encode_init(struct bContext *C, UndoStep *us_p) +{ + /* XXX, use to set the undo type only. */ + UNUSED_VARS(C, us_p); } -/** - * \note This is called before executing steps (not after). - */ -void ED_paintcurve_undo_push(bContext *C, wmOperator *op, PaintCurve *pc) +static bool paintcurve_undosys_step_encode(struct bContext *C, UndoStep *us_p) { - ePaintMode mode = BKE_paintmode_get_active_from_context(C); - ListBase *lb = NULL; - int undo_stack_id; - UndoCurve *uc; - - switch (mode) { - case ePaintTexture2D: - case ePaintTextureProjective: - undo_stack_id = UNDO_PAINT_IMAGE; - break; - - case ePaintSculpt: - undo_stack_id = UNDO_PAINT_MESH; - break; - - default: - /* do nothing, undo is handled by global */ - return; + Paint *p = BKE_paint_get_active_from_context(C); + PaintCurve *pc = p ? (p->brush ? p->brush->paint_curve : NULL) : NULL; + if (pc == NULL) { + return false; } + PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p; + BLI_assert(us->step.data_size == 0); - ED_undo_paint_push_begin(undo_stack_id, op->type->name, - paintcurve_undo_restore, paintcurve_undo_delete, NULL); - lb = undo_paint_push_get_list(undo_stack_id); + us->pc = pc; + undocurve_from_paintcurve(&us->data, pc); - uc = MEM_callocN(sizeof(*uc), "Undo_curve"); + return true; +} - lb->first = uc; +static void paintcurve_undosys_step_decode(struct bContext *UNUSED(C), UndoStep *us_p, int UNUSED(dir)) +{ + PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p; + undocurve_to_paintcurve(&us->data, us->pc); +} - BLI_strncpy(uc->idname, pc->id.name, sizeof(uc->idname)); - uc->tot_points = pc->tot_points; - uc->active_point = pc->add_index; - uc->points = MEM_dupallocN(pc->points); +static void paintcurve_undosys_step_free(UndoStep *us_p) +{ + PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p; + undocurve_free_data(&us->data); +} + +/* Export for ED_undo_sys. */ +void ED_paintcurve_undosys_type(UndoType *ut) +{ + ut->name = "Paint Curve"; + /* don't poll for now */ + ut->poll = paintcurve_undosys_poll; + ut->step_encode_init = paintcurve_undosys_step_encode_init; + ut->step_encode = paintcurve_undosys_step_encode; + ut->step_decode = paintcurve_undosys_step_decode; + ut->step_free = paintcurve_undosys_step_free; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = false; + + ut->step_size = sizeof(PaintCurveUndoStep); +} + +/** \} */ - undo_paint_push_count_alloc(undo_stack_id, sizeof(*uc) + sizeof(*pc->points) * pc->tot_points); - ED_undo_paint_push_end(undo_stack_id); +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +void ED_paintcurve_undo_push_begin(const char *name) +{ + UndoStack *ustack = ED_undo_stack_get(); + bContext *C = NULL; /* special case, we never read from this. */ + BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_PAINTCURVE); } + +void ED_paintcurve_undo_push_end(void) +{ + UndoStack *ustack = ED_undo_stack_get(); + BKE_undosys_step_push(ustack, NULL, NULL); +} + +/** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index c6472b258ca..cb6dba4772f 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -58,6 +58,8 @@ #include "BKE_material.h" #include "BKE_node.h" #include "BKE_paint.h" +#include "BKE_undo_system.h" + #include "UI_interface.h" #include "UI_view2d.h" @@ -145,9 +147,11 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh); + ListBase *undo_tiles = ED_image_undo_get_tiles(); + for (ty = tiley; ty <= tileh; ty++) for (tx = tilex; tx <= tilew; tx++) - image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old); + image_undo_push_tile(undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old); ibuf->userflags |= IB_BITMAPDIRTY; @@ -491,7 +495,8 @@ static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, Po BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * alphafac)); if ((brush->flag & BRUSH_DRAG_DOT) || (brush->flag & BRUSH_ANCHORED)) { - ED_image_undo_restore(); + UndoStack *ustack = CTX_wm_manager(C)->undo_stack; + ED_image_undo_restore(ustack->step_init); } if (pop->mode == PAINT_MODE_3D_PROJECT) { @@ -1174,14 +1179,17 @@ void PAINT_OT_brush_colors_flip(wmOperatorType *ot) void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op) { + wmWindowManager *wm = CTX_wm_manager(C); SpaceImage *sima = CTX_wm_space_image(C); Image *ima = sima->image; + BKE_undosys_step_push_init_with_type(wm->undo_stack, C, op->type->name, BKE_UNDOSYS_TYPE_IMAGE); + ED_image_undo_push_begin(op->type->name); paint_2d_bucket_fill(C, color, NULL, NULL, NULL); - ED_undo_paint_push_end(UNDO_PAINT_IMAGE); + BKE_undosys_step_push(wm->undo_stack, C, op->type->name); DAG_id_tag_update(&ima->id, 0); } diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 894277402a7..c1dd31ea055 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -1035,6 +1035,8 @@ static void paint_2d_do_making_brush(ImagePaintState *s, ImBuf tmpbuf; IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0); + ListBase *undo_tiles = ED_image_undo_get_tiles(); + for (int ty = tiley; ty <= tileh; ty++) { for (int tx = tilex; tx <= tilew; tx++) { /* retrieve original pixels + mask from undo buffer */ @@ -1043,9 +1045,9 @@ static void paint_2d_do_making_brush(ImagePaintState *s, int origy = region->desty - ty * IMAPAINT_TILE_SIZE; if (s->canvas->rect_float) - tmpbuf.rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false); + tmpbuf.rect_float = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false); else - tmpbuf.rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false); + tmpbuf.rect = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false); IMB_rectblend(s->canvas, &tmpbuf, frombuf, mask, curveb, texmaskb, mask_max, diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 60fe8555ba2..e5bddae971d 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -1499,15 +1499,16 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty) if (generate_tile) { + ListBase *undo_tiles = ED_image_undo_get_tiles(); volatile void *undorect; if (tinf->masked) { undorect = image_undo_push_tile( - pjIma->ima, pjIma->ibuf, tinf->tmpibuf, + undo_tiles, pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, &pjIma->maskRect[tile_index], &pjIma->valid[tile_index], true, false); } else { undorect = image_undo_push_tile( - pjIma->ima, pjIma->ibuf, tinf->tmpibuf, + undo_tiles, pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, NULL, &pjIma->valid[tile_index], true, false); } diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c index b5b64eb3e16..ef28dafa8c9 100644 --- a/source/blender/editors/sculpt_paint/paint_image_undo.c +++ b/source/blender/editors/sculpt_paint/paint_image_undo.c @@ -29,6 +29,10 @@ #include "BLI_threads.h" #include "DNA_image_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -37,17 +41,22 @@ #include "BKE_depsgraph.h" #include "BKE_image.h" #include "BKE_main.h" +#include "BKE_undo_system.h" #include "ED_paint.h" +#include "ED_undo.h" #include "GPU_draw.h" #include "paint_intern.h" +/* -------------------------------------------------------------------- */ +/** \name Undo Conversion + * \{ */ + typedef struct UndoImageTile { struct UndoImageTile *next, *prev; - char idname[MAX_ID_NAME]; /* name instead of pointer*/ char ibufname[IMB_FILENAME_SIZE]; union { @@ -64,6 +73,8 @@ typedef struct UndoImageTile { short source, use_float; char gen_type; bool valid; + + size_t undo_size; } UndoImageTile; /* this is a static resource for non-globality, @@ -129,16 +140,17 @@ static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, Cop } } -void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate) +void *image_undo_find_tile( + ListBase *undo_tiles, + Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate) { - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); UndoImageTile *tile; short use_float = ibuf->rect_float ? 1 : 0; - for (tile = lb->first; tile; tile = tile->next) { + for (tile = undo_tiles->first; tile; tile = tile->next) { if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) { if (tile->use_float == use_float) { - if (STREQ(tile->idname, ima->id.name) && STREQ(tile->ibufname, ibuf->name)) { + if (STREQ(tile->ibufname, ibuf->name)) { if (mask) { /* allocate mask if requested */ if (!tile->mask) { @@ -161,10 +173,10 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi } void *image_undo_push_tile( + ListBase *undo_tiles, Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **mask, bool **valid, bool proj, bool find_prev) { - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); UndoImageTile *tile; int allocsize; short use_float = ibuf->rect_float ? 1 : 0; @@ -174,7 +186,7 @@ void *image_undo_push_tile( /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */ if (find_prev) { - data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, mask, true); + data = image_undo_find_tile(undo_tiles, ima, ibuf, x_tile, y_tile, mask, true); if (data) { return data; } @@ -185,7 +197,6 @@ void *image_undo_push_tile( } tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile"); - BLI_strncpy(tile->idname, ima->id.name, sizeof(tile->idname)); tile->x = x_tile; tile->y = y_tile; @@ -214,8 +225,7 @@ void *image_undo_push_tile( if (proj) { BLI_spin_lock(&undolock); } - undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize); - BLI_addtail(lb, tile); + BLI_addtail(undo_tiles, tile); if (proj) { BLI_spin_unlock(&undolock); @@ -225,10 +235,10 @@ void *image_undo_push_tile( void image_undo_remove_masks(void) { - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); + ListBase *undo_tiles = ED_image_undo_get_tiles(); UndoImageTile *tile; - for (tile = lb->first; tile; tile = tile->next) { + for (tile = undo_tiles->first; tile; tile = tile->next) { if (tile->mask) { MEM_freeN(tile->mask); tile->mask = NULL; @@ -265,28 +275,19 @@ static void image_undo_restore_runtime(ListBase *lb) IMB_freeImBuf(tmpibuf); } -static void image_undo_restore_list(bContext *C, ListBase *lb) +static void image_undo_restore_list(ListBase *lb, struct UndoIDPtrMap *id_map) { - Main *bmain = CTX_data_main(C); - Image *ima = NULL; - ImBuf *ibuf, *tmpibuf; - UndoImageTile *tile; + ImBuf *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect); - tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, - IB_rectfloat | IB_rect); + /* Store last found image. */ + ID *image_prev[2] = {NULL}; - for (tile = lb->first; tile; tile = tile->next) { + for (UndoImageTile *tile = lb->first; tile; tile = tile->next) { short use_float; - /* find image based on name, pointer becomes invalid with global undo */ - if (ima && STREQ(tile->idname, ima->id.name)) { - /* ima is valid */ - } - else { - ima = BLI_findstring(&bmain->image, tile->idname, offsetof(ID, name)); - } + Image *ima = (Image *)BKE_undosys_ID_map_lookup_with_prev(id_map, &tile->ima->id, image_prev); - ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) { /* current ImBuf filename was changed, probably current frame @@ -346,50 +347,187 @@ static void image_undo_free_list(ListBase *lb) void ED_image_undo_push_begin(const char *name) { - ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, name, image_undo_restore_list, image_undo_free_list, NULL); + UndoStack *ustack = ED_undo_stack_get(); + bContext *C = NULL; /* special case, we never read from this. */ + BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE); } void ED_image_undo_push_end(void) { - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); + UndoStack *ustack = ED_undo_stack_get(); + BKE_undosys_step_push(ustack, NULL, NULL); +} + +static void image_undo_invalidate(void) +{ UndoImageTile *tile; - int deallocsize = 0; + ListBase *lb = ED_image_undo_get_tiles(); + + for (tile = lb->first; tile; tile = tile->next) { + tile->valid = false; + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct ImageUndoStep { + UndoStep step; + ListBase tiles; + + /* Use for all ID lookups (can be NULL). */ + struct UndoIDPtrMap *id_map; +} ImageUndoStep; + +static void image_undosys_step_encode_store_ids(ImageUndoStep *us) +{ + us->id_map = BKE_undosys_ID_map_create(); + + ID *image_prev = NULL; + for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) { + BKE_undosys_ID_map_add_with_prev(us->id_map, &tile->ima->id, &image_prev); + } +} + +/* Restore at runtime. */ +#if 0 +static void paint_undosys_step_decode_restore_ids(ImageUndoStep *us) +{ + ID *image_prev[2] = {NULL}; + for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) { + tile->ima = (Image *)BKE_undosys_ID_map_lookup_with_prev(us->id_map, &tile->ima->id, image_prev); + } +} +#endif + +static bool image_undosys_poll(bContext *C) +{ + Object *obact = CTX_data_active_object(C); + + ScrArea *sa = CTX_wm_area(C); + if (sa && (sa->spacetype == SPACE_IMAGE)) { + SpaceImage *sima = (SpaceImage *)sa->spacedata.first; + if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { + return true; + } + } + else if (sa && (sa->spacetype == SPACE_VIEW3D)) { + if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) { + return true; + } + } + return false; +} + +static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p) +{ + ImageUndoStep *us = (ImageUndoStep *)us_p; + /* dummy, memory is cleared anyway. */ + BLI_listbase_clear(&us->tiles); +} + +static bool image_undosys_step_encode(struct bContext *UNUSED(C), UndoStep *us_p) +{ + /* dummy, encoding is done along the way by adding tiles + * to the current 'ImageUndoStep' added by encode_init. */ + ImageUndoStep *us = (ImageUndoStep *)us_p; + + BLI_assert(us->step.data_size == 0); + int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; + /* first dispose of invalid tiles (may happen due to drag dot for instance) */ - for (tile = lb->first; tile;) { + for (UndoImageTile *tile = us->tiles.first; tile;) { if (!tile->valid) { UndoImageTile *tmp_tile = tile->next; - deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char)); MEM_freeN(tile->rect.pt); - BLI_freelinkN(lb, tile); + BLI_freelinkN(&us->tiles, tile); tile = tmp_tile; } else { + us->step.data_size += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char)); tile = tile->next; } } - /* don't forget to remove the size of deallocated tiles */ - undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, -deallocsize); + image_undosys_step_encode_store_ids(us); - ED_undo_paint_push_end(UNDO_PAINT_IMAGE); + return true; } -static void image_undo_invalidate(void) +static void image_undosys_step_decode(struct bContext *UNUSED(C), UndoStep *us_p, int UNUSED(dir)) { - UndoImageTile *tile; - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); + ImageUndoStep *us = (ImageUndoStep *)us_p; +#if 0 + paint_undosys_step_decode_restore_ids(us); +#endif + image_undo_restore_list(&us->tiles, us->id_map); +} - for (tile = lb->first; tile; tile = tile->next) { - tile->valid = false; +static void image_undosys_step_free(UndoStep *us_p) +{ + ImageUndoStep *us = (ImageUndoStep *)us_p; + image_undo_free_list(&us->tiles); + BKE_undosys_ID_map_destroy(us->id_map); +} + +static void image_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + ImageUndoStep *us = (ImageUndoStep *)us_p; + if (us->id_map != NULL) { + BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data); } } +/* Export for ED_undo_sys. */ +void ED_image_undosys_type(UndoType *ut) +{ + ut->name = "Image"; + ut->poll = image_undosys_poll; + ut->step_encode_init = image_undosys_step_encode_init; + ut->step_encode = image_undosys_step_encode; + ut->step_decode = image_undosys_step_decode; + ut->step_free = image_undosys_step_free; + + ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE; + ut->use_context = true; + + ut->step_size = sizeof(ImageUndoStep); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +ListBase *ED_image_undosys_step_get_tiles(UndoStep *us_p) +{ + ImageUndoStep *us = (ImageUndoStep *)us_p; + return &us->tiles; +} + +ListBase *ED_image_undo_get_tiles(void) +{ + UndoStack *ustack = ED_undo_stack_get(); + UndoStep *us = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE); + return ED_image_undosys_step_get_tiles(us); +} + /* restore painting image to previous state. Used for anchored and drag-dot style brushes*/ -void ED_image_undo_restore(void) +void ED_image_undo_restore(UndoStep *us) { - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); + ListBase *lb = ED_image_undosys_step_get_tiles(us); image_undo_restore_runtime(lb); image_undo_invalidate(); } + +/** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 52be4be4c0d..63a12b3c145 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -55,6 +55,7 @@ struct wmOperator; struct wmOperatorType; struct wmWindowManager; struct DMCoNo; +struct UndoStep; enum ePaintMode; /* paint_stroke.c */ @@ -221,15 +222,20 @@ void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot); /* paint_image_undo.c */ void *image_undo_find_tile( + ListBase *undo_tiles, struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate); void *image_undo_push_tile( + ListBase *undo_tiles, struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **, bool **valid, bool proj, bool find_prev); void image_undo_remove_masks(void); void image_undo_init_locks(void); void image_undo_end_locks(void); +struct ListBase *ED_image_undosys_step_get_tiles(struct UndoStep *us_p); +struct ListBase *ED_image_undo_get_tiles(void); + /* sculpt_uv.c */ int uv_sculpt_poll(struct bContext *C); int uv_sculpt_keymap_poll(struct bContext *C); @@ -304,10 +310,6 @@ typedef enum { void set_brush_rc_props(struct PointerRNA *ptr, const char *paint, const char *prop, const char *secondary_prop, RCFlags flags); -/* paint_undo.c */ -struct ListBase *undo_paint_push_get_list(int type); -void undo_paint_push_count_alloc(int type, int size); - /* paint_hide.c */ typedef enum { diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c deleted file mode 100644 index 27d3f6648a2..00000000000 --- a/source/blender/editors/sculpt_paint/paint_undo.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/sculpt_paint/paint_undo.c - * \ingroup edsculpt - * \brief Undo system for painting and sculpting. - */ - -#include <stdlib.h> -#include <string.h> - -#include "MEM_guardedalloc.h" - -#include "BLI_listbase.h" -#include "BLI_utildefines.h" -#include "BLI_string.h" - -#include "DNA_userdef_types.h" - -#include "BKE_blender_undo.h" -#include "BKE_context.h" -#include "BKE_global.h" - -#include "ED_paint.h" - -#include "paint_intern.h" - -typedef struct UndoElem { - struct UndoElem *next, *prev; - char name[BKE_UNDO_STR_MAX]; - uintptr_t undosize; - - ListBase elems; - - UndoRestoreCb restore; - UndoFreeCb free; - UndoCleanupCb cleanup; -} UndoElem; - -typedef struct UndoStack { - int type; - ListBase elems; - UndoElem *current; -} UndoStack; - -static UndoStack ImageUndoStack = {UNDO_PAINT_IMAGE, {NULL, NULL}, NULL}; -static UndoStack MeshUndoStack = {UNDO_PAINT_MESH, {NULL, NULL}, NULL}; - -/* Generic */ - -static void undo_restore(bContext *C, UndoStack *UNUSED(stack), UndoElem *uel) -{ - if (uel && uel->restore) - uel->restore(C, &uel->elems); -} - -static void undo_elem_free(UndoStack *UNUSED(stack), UndoElem *uel) -{ - if (uel && uel->free) { - uel->free(&uel->elems); - BLI_freelistN(&uel->elems); - } -} - -static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup) -{ - UndoElem *uel; - int nr; - - /* Undo push is split up in begin and end, the reason is that as painting - * happens more tiles/nodes are added to the list, and at the very end we - * know how much memory the undo used to remove old undo elements */ - - /* remove all undos after (also when stack->current==NULL) */ - while (stack->elems.last != stack->current) { - uel = stack->elems.last; - undo_elem_free(stack, uel); - BLI_freelinkN(&stack->elems, uel); - } - - /* make new */ - stack->current = uel = MEM_callocN(sizeof(UndoElem), "undo file"); - uel->restore = restore; - uel->free = free; - uel->cleanup = cleanup; - BLI_addtail(&stack->elems, uel); - - /* name can be a dynamic string */ - BLI_strncpy(uel->name, name, sizeof(uel->name)); - - /* limit amount to the maximum amount*/ - nr = 0; - uel = stack->elems.last; - while (uel) { - nr++; - if (nr == U.undosteps) break; - uel = uel->prev; - } - if (uel) { - while (stack->elems.first != uel) { - UndoElem *first = stack->elems.first; - undo_elem_free(stack, first); - BLI_freelinkN(&stack->elems, first); - } - } -} - -static void undo_stack_push_end(UndoStack *stack) -{ - UndoElem *uel; - uintptr_t totmem, maxmem; - int totundo = 0; - - /* first limit to undo steps */ - uel = stack->elems.last; - - while (uel) { - totundo++; - if (totundo > U.undosteps) break; - uel = uel->prev; - } - - if (uel) { - UndoElem *first; - - /* in case the undo steps are zero, the current pointer will be invalid */ - if (uel == stack->current) - stack->current = NULL; - - do { - first = stack->elems.first; - undo_elem_free(stack, first); - BLI_freelinkN(&stack->elems, first); - } while (first != uel); - } - - if (U.undomemory != 0) { - /* limit to maximum memory (afterwards, we can't know in advance) */ - totmem = 0; - maxmem = ((uintptr_t)U.undomemory) * 1024 * 1024; - - uel = stack->elems.last; - while (uel) { - totmem += uel->undosize; - if (totmem > maxmem) break; - uel = uel->prev; - } - - if (uel) { - while (stack->elems.first != uel) { - UndoElem *first = stack->elems.first; - undo_elem_free(stack, first); - BLI_freelinkN(&stack->elems, first); - } - } - } -} - -static void undo_stack_cleanup(UndoStack *stack, bContext *C) -{ - UndoElem *uel = stack->elems.first; - bool stack_reset = false; - - while (uel) { - if (uel->cleanup && uel->cleanup(C, &uel->elems)) { - UndoElem *uel_tmp = uel->next; - if (stack->current == uel) { - stack->current = NULL; - stack_reset = true; - } - undo_elem_free(stack, uel); - BLI_freelinkN(&stack->elems, uel); - uel = uel_tmp; - } - else - uel = uel->next; - } - if (stack_reset) { - stack->current = stack->elems.last; - } - -} - -static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *name) -{ - UndoElem *undo; - - /* first cleanup any old undo steps that may belong to invalid data */ - undo_stack_cleanup(stack, C); - - if (step == 1) { - if (stack->current == NULL) { - /* pass */ - } - else { - if (!name || STREQ(stack->current->name, name)) { - if (G.debug & G_DEBUG_WM) { - printf("%s: undo '%s'\n", __func__, stack->current->name); - } - undo_restore(C, stack, stack->current); - stack->current = stack->current->prev; - return 1; - } - } - } - else if (step == -1) { - if ((stack->current != NULL && stack->current->next == NULL) || BLI_listbase_is_empty(&stack->elems)) { - /* pass */ - } - else { - if (!name || STREQ(stack->current->name, name)) { - undo = (stack->current && stack->current->next) ? stack->current->next : stack->elems.first; - undo_restore(C, stack, undo); - stack->current = undo; - if (G.debug & G_DEBUG_WM) { - printf("%s: redo %s\n", __func__, undo->name); - } - return 1; - } - } - } - - return 0; -} - -static void undo_stack_free(UndoStack *stack) -{ - UndoElem *uel; - - for (uel = stack->elems.first; uel; uel = uel->next) - undo_elem_free(stack, uel); - - BLI_freelistN(&stack->elems); - stack->current = NULL; -} - -/* Exported Functions */ - -void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup) -{ - if (type == UNDO_PAINT_IMAGE) - undo_stack_push_begin(&ImageUndoStack, name, restore, free, cleanup); - else if (type == UNDO_PAINT_MESH) - undo_stack_push_begin(&MeshUndoStack, name, restore, free, cleanup); -} - -ListBase *undo_paint_push_get_list(int type) -{ - if (type == UNDO_PAINT_IMAGE) { - if (ImageUndoStack.current) { - return &ImageUndoStack.current->elems; - } - } - else if (type == UNDO_PAINT_MESH) { - if (MeshUndoStack.current) { - return &MeshUndoStack.current->elems; - } - } - - return NULL; -} - -void undo_paint_push_count_alloc(int type, int size) -{ - if (type == UNDO_PAINT_IMAGE) - ImageUndoStack.current->undosize += size; - else if (type == UNDO_PAINT_MESH) - MeshUndoStack.current->undosize += size; -} - -void ED_undo_paint_push_end(int type) -{ - if (type == UNDO_PAINT_IMAGE) - undo_stack_push_end(&ImageUndoStack); - else if (type == UNDO_PAINT_MESH) - undo_stack_push_end(&MeshUndoStack); -} - -int ED_undo_paint_step(bContext *C, int type, int step, const char *name) -{ - if (type == UNDO_PAINT_IMAGE) - return undo_stack_step(C, &ImageUndoStack, step, name); - else if (type == UNDO_PAINT_MESH) - return undo_stack_step(C, &MeshUndoStack, step, name); - - return 0; -} - -static void undo_step_num(bContext *C, UndoStack *stack, int step) -{ - UndoElem *uel; - int a = 0; - int curnum = BLI_findindex(&stack->elems, stack->current); - - for (uel = stack->elems.first; uel; uel = uel->next, a++) { - if (a == step) break; - } - - if (curnum > a) { - while (a++ != curnum) - undo_stack_step(C, stack, 1, NULL); - } - else if (curnum < a) { - while (a-- != curnum) - undo_stack_step(C, stack, -1, NULL); - } -} - -void ED_undo_paint_step_num(bContext *C, int type, int step) -{ - if (type == UNDO_PAINT_IMAGE) - undo_step_num(C, &ImageUndoStack, step); - else if (type == UNDO_PAINT_MESH) - undo_step_num(C, &MeshUndoStack, step); -} - -static char *undo_stack_get_name(UndoStack *stack, int nr, bool *r_active) -{ - UndoElem *uel; - - if (r_active) *r_active = false; - - uel = BLI_findlink(&stack->elems, nr); - if (uel) { - if (r_active && (uel == stack->current)) { - *r_active = true; - } - return uel->name; - } - - return NULL; -} - -const char *ED_undo_paint_get_name(bContext *C, int type, int nr, bool *r_active) -{ - - if (type == UNDO_PAINT_IMAGE) { - undo_stack_cleanup(&ImageUndoStack, C); - return undo_stack_get_name(&ImageUndoStack, nr, r_active); - } - else if (type == UNDO_PAINT_MESH) { - undo_stack_cleanup(&MeshUndoStack, C); - return undo_stack_get_name(&MeshUndoStack, nr, r_active); - } - return NULL; -} - -bool ED_undo_paint_empty(int type) -{ - UndoStack *stack; - - if (type == UNDO_PAINT_IMAGE) - stack = &ImageUndoStack; - else if (type == UNDO_PAINT_MESH) - stack = &MeshUndoStack; - else - return true; - - if (stack->current == NULL) { - return true; - } - - return false; -} - -bool ED_undo_paint_is_valid(int type, const char *name) -{ - UndoStack *stack; - - if (type == UNDO_PAINT_IMAGE) - stack = &ImageUndoStack; - else if (type == UNDO_PAINT_MESH) - stack = &MeshUndoStack; - else - return 0; - - if (stack->current == NULL) { - /* pass */ - } - else { - if (name && STREQ(stack->current->name, name)) - return 1; - else - return stack->elems.first != stack->elems.last; - } - return 0; -} - -void ED_undo_paint_free(void) -{ - undo_stack_free(&ImageUndoStack); - undo_stack_free(&MeshUndoStack); -} diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index ede1269e220..34e60187a73 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1563,7 +1563,7 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert) static void bmesh_neighbor_average(float avg[3], BMVert *v) { /* logic for 3 or more is identical */ - const int vfcount = BM_vert_face_count_ex(v, 3); + const int vfcount = BM_vert_face_count_at_most(v, 3); /* Don't modify corner vertices */ if (vfcount > 1) { @@ -1578,7 +1578,7 @@ static void bmesh_neighbor_average(float avg[3], BMVert *v) for (i = 0; i < ARRAY_SIZE(adj_v); i++) { const BMVert *v_other = adj_v[i]; - if (vfcount != 2 || BM_vert_face_count_ex(v_other, 2) <= 2) { + if (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) { add_v3_v3(avg, v_other->co); total++; } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index cf1937f14d4..e46760258e1 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -122,6 +122,8 @@ typedef struct SculptUndoNode { /* shape keys */ char shapeName[sizeof(((KeyBlock *)0))->name]; + + size_t undo_size; } SculptUndoNode; /* Factor of brush to have rake point following behind diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 794ac14483a..e90d2b58c0c 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -48,6 +48,8 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_mesh_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" #include "BKE_ccg.h" #include "BKE_context.h" @@ -57,6 +59,7 @@ #include "BKE_key.h" #include "BKE_mesh.h" #include "BKE_subsurf.h" +#include "BKE_undo_system.h" #include "WM_api.h" #include "WM_types.h" @@ -64,12 +67,22 @@ #include "GPU_buffers.h" #include "ED_paint.h" +#include "ED_object.h" +#include "ED_sculpt.h" +#include "ED_undo.h" #include "bmesh.h" #include "paint_intern.h" #include "sculpt_intern.h" -/************************** Undo *************************/ + +typedef struct UndoSculpt { + ListBase nodes; + + size_t undo_size; +} UndoSculpt; + +static UndoSculpt *sculpt_undo_get_nodes(void); static void update_cb(PBVHNode *node, void *rebuild) { @@ -454,7 +467,7 @@ static int sculpt_undo_bmesh_restore(bContext *C, return false; } -static void sculpt_undo_restore(bContext *C, ListBase *lb) +static void sculpt_undo_restore_list(bContext *C, ListBase *lb) { Scene *scene = CTX_data_scene(C); Sculpt *sd = CTX_data_tool_settings(C)->sculpt; @@ -574,7 +587,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) } } -static void sculpt_undo_free(ListBase *lb) +static void sculpt_undo_free_list(ListBase *lb) { SculptUndoNode *unode; int i; @@ -617,6 +630,8 @@ static void sculpt_undo_free(ListBase *lb) } } +/* Most likely we don't need this. */ +#if 0 static bool sculpt_undo_cleanup(bContext *C, ListBase *lb) { Object *ob = CTX_data_active_object(C); @@ -633,16 +648,17 @@ static bool sculpt_undo_cleanup(bContext *C, ListBase *lb) return false; } +#endif SculptUndoNode *sculpt_undo_get_node(PBVHNode *node) { - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH); + UndoSculpt *usculpt = sculpt_undo_get_nodes(); - if (!lb) { + if (usculpt == NULL) { return NULL; } - return BLI_findptr(lb, node, offsetof(SculptUndoNode, node)); + return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node)); } static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, @@ -668,10 +684,11 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, } } -static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, - SculptUndoType type) +static SculptUndoNode *sculpt_undo_alloc_node( + Object *ob, PBVHNode *node, + SculptUndoType type) { - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH); + UndoSculpt *usculpt = sculpt_undo_get_nodes(); SculptUndoNode *unode; SculptSession *ss = ob->sculpt; int totvert, allvert, totgrid, maxgrid, gridsize, *grids; @@ -696,23 +713,23 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, /* general TODO, fix count_alloc */ switch (type) { case SCULPT_UNDO_COORDS: - unode->co = MEM_mapallocN(sizeof(float) * 3 * allvert, "SculptUndoNode.co"); - unode->no = MEM_mapallocN(sizeof(short) * 3 * allvert, "SculptUndoNode.no"); - undo_paint_push_count_alloc(UNDO_PAINT_MESH, - (sizeof(float) * 3 + - sizeof(short) * 3 + - sizeof(int)) * allvert); + unode->co = MEM_mapallocN(sizeof(float[3]) * allvert, "SculptUndoNode.co"); + unode->no = MEM_mapallocN(sizeof(short[3]) * allvert, "SculptUndoNode.no"); + + usculpt->undo_size = (sizeof(float[3]) + sizeof(short[3]) + sizeof(int)) * allvert; break; case SCULPT_UNDO_HIDDEN: if (maxgrid) sculpt_undo_alloc_and_store_hidden(ss->pbvh, unode); else unode->vert_hidden = BLI_BITMAP_NEW(allvert, "SculptUndoNode.vert_hidden"); - + break; case SCULPT_UNDO_MASK: unode->mask = MEM_mapallocN(sizeof(float) * allvert, "SculptUndoNode.mask"); - undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float) * sizeof(int)) * allvert); + + usculpt->undo_size += (sizeof(float) * sizeof(int)) * allvert; + break; case SCULPT_UNDO_DYNTOPO_BEGIN: case SCULPT_UNDO_DYNTOPO_END: @@ -721,7 +738,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, break; } - BLI_addtail(lb, unode); + BLI_addtail(&usculpt->nodes, unode); if (maxgrid) { /* multires */ @@ -798,12 +815,13 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, SculptUndoType type) { - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH); - SculptUndoNode *unode = lb->first; + UndoSculpt *usculpt = sculpt_undo_get_nodes(); SculptSession *ss = ob->sculpt; PBVHVertexIter vd; - if (!lb->first) { + SculptUndoNode *unode = usculpt->nodes.first; + + if (unode == NULL) { unode = MEM_callocN(sizeof(*unode), __func__); BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname)); @@ -842,7 +860,7 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, unode->bm_entry = BM_log_entry_add(ss->bm_log); } - BLI_addtail(lb, unode); + BLI_addtail(&usculpt->nodes, unode); } if (node) { @@ -883,8 +901,9 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, return unode; } -SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, - SculptUndoType type) +SculptUndoNode *sculpt_undo_push_node( + Object *ob, PBVHNode *node, + SculptUndoType type) { SculptSession *ss = ob->sculpt; SculptUndoNode *unode; @@ -954,17 +973,18 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, void sculpt_undo_push_begin(const char *name) { - ED_undo_paint_push_begin(UNDO_PAINT_MESH, name, - sculpt_undo_restore, sculpt_undo_free, sculpt_undo_cleanup); + UndoStack *ustack = ED_undo_stack_get(); + bContext *C = NULL; /* special case, we never read from this. */ + BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_SCULPT); } void sculpt_undo_push_end(void) { - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH); + UndoSculpt *usculpt = sculpt_undo_get_nodes(); SculptUndoNode *unode; /* we don't need normals in the undo stack */ - for (unode = lb->first; unode; unode = unode->next) { + for (unode = usculpt->nodes.first; unode; unode = unode->next) { if (unode->no) { MEM_freeN(unode->no); unode->no = NULL; @@ -974,7 +994,97 @@ void sculpt_undo_push_end(void) BKE_pbvh_node_layer_disp_free(unode->node); } - ED_undo_paint_push_end(UNDO_PAINT_MESH); + UndoStack *ustack = ED_undo_stack_get(); + BKE_undosys_step_push(ustack, NULL, NULL); +} + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct SculptUndoStep { + UndoStep step; + /* note: will split out into list for multi-object-sculpt-mode. */ + UndoSculpt data; +} SculptUndoStep; + +static bool sculpt_undosys_poll(bContext *C) +{ + ScrArea *sa = CTX_wm_area(C); + if (sa && (sa->spacetype == SPACE_VIEW3D)) { + Object *obact = CTX_data_active_object(C); + if (obact && (obact->mode & OB_MODE_SCULPT)) { + return true; + } + } + return false; +} + +static void sculpt_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p) +{ + SculptUndoStep *us = (SculptUndoStep *)us_p; + /* dummy, memory is cleared anyway. */ + BLI_listbase_clear(&us->data.nodes); +} + +static bool sculpt_undosys_step_encode(struct bContext *UNUSED(C), UndoStep *us_p) +{ + /* dummy, encoding is done along the way by adding tiles + * to the current 'SculptUndoStep' added by encode_init. */ + SculptUndoStep *us = (SculptUndoStep *)us_p; + us->step.data_size = us->data.undo_size; + return true; +} + +static void sculpt_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* TODO(campbell): undo_system: use low-level API to set mode. */ + ED_object_mode_set(C, OB_MODE_SCULPT); + BLI_assert(sculpt_undosys_poll(C)); + + SculptUndoStep *us = (SculptUndoStep *)us_p; + sculpt_undo_restore_list(C, &us->data.nodes); +} - WM_file_tag_modified(); +static void sculpt_undosys_step_free(UndoStep *us_p) +{ + SculptUndoStep *us = (SculptUndoStep *)us_p; + sculpt_undo_free_list(&us->data.nodes); } + +/* Export for ED_undo_sys. */ +void ED_sculpt_undosys_type(UndoType *ut) +{ + ut->name = "Sculpt"; + ut->poll = sculpt_undosys_poll; + ut->step_encode_init = sculpt_undosys_step_encode_init; + ut->step_encode = sculpt_undosys_step_encode; + ut->step_decode = sculpt_undosys_step_decode; + ut->step_free = sculpt_undosys_step_free; + + ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE; + ut->use_context = true; + + ut->step_size = sizeof(SculptUndoStep); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +static UndoSculpt *sculpt_undosys_step_get_nodes(UndoStep *us_p) +{ + SculptUndoStep *us = (SculptUndoStep *)us_p; + return &us->data; +} + +static UndoSculpt *sculpt_undo_get_nodes(void) +{ + UndoStack *ustack = ED_undo_stack_get(); + UndoStep *us = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_SCULPT); + return sculpt_undosys_step_get_nodes(us); +} + +/** \} */ diff --git a/source/blender/editors/space_action/action_buttons.c b/source/blender/editors/space_action/action_buttons.c index bfc808f6d83..ba6cef38acd 100644 --- a/source/blender/editors/space_action/action_buttons.c +++ b/source/blender/editors/space_action/action_buttons.c @@ -50,8 +50,6 @@ #include "BKE_curve.h" #include "BKE_depsgraph.h" #include "BKE_fcurve.h" -#include "BKE_main.h" -#include "BKE_global.h" #include "BKE_screen.h" #include "BKE_unit.h" diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index fbef14c07c4..f1153b5bed0 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -54,10 +54,8 @@ #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_fcurve.h" -#include "BKE_global.h" #include "BKE_library.h" #include "BKE_key.h" -#include "BKE_main.h" #include "BKE_nla.h" #include "BKE_scene.h" #include "BKE_context.h" diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 72b1245ca8a..1c15a7c5950 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -59,7 +59,6 @@ #include "BKE_global.h" #include "BKE_library.h" #include "BKE_key.h" -#include "BKE_main.h" #include "BKE_nla.h" #include "BKE_context.h" #include "BKE_report.h" diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index fc1b6877f5e..2a703ebb46c 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -51,7 +51,7 @@ #include "WM_types.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "RNA_access.h" diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 3c48f3c1111..49bd0794a51 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -470,7 +470,7 @@ void buttons_texture_context_compute(const bContext *C, SpaceButs *sbuts) } else { /* set one user as active based on active index */ - if (ct->index >= BLI_listbase_count_ex(&ct->users, ct->index + 1)) + if (ct->index >= BLI_listbase_count_at_most(&ct->users, ct->index + 1)) ct->index = 0; ct->user = BLI_findlink(&ct->users, ct->index); diff --git a/source/blender/editors/space_clip/clip_toolbar.c b/source/blender/editors/space_clip/clip_toolbar.c index 1504ce1a7ba..d2a7244eded 100644 --- a/source/blender/editors/space_clip/clip_toolbar.c +++ b/source/blender/editors/space_clip/clip_toolbar.c @@ -49,7 +49,7 @@ #include "WM_api.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/editors/space_clip/tracking_ops_orient.c b/source/blender/editors/space_clip/tracking_ops_orient.c index 71a5a825b0e..8c5be7c9d04 100644 --- a/source/blender/editors/space_clip/tracking_ops_orient.c +++ b/source/blender/editors/space_clip/tracking_ops_orient.c @@ -42,7 +42,6 @@ #include "BKE_context.h" #include "BKE_constraint.h" #include "BKE_tracking.h" -#include "BKE_global.h" #include "BKE_depsgraph.h" #include "BKE_object.h" #include "BKE_report.h" diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 52d01063175..396f3cf32f4 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -597,7 +597,7 @@ void file_draw_list(const bContext *C, ARegion *ar) int colorid = (file_selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK; int shade = (params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ? 35 : 0; - BLI_assert(i > 0 || FILENAME_IS_CURRPAR(file->relpath)); + BLI_assert(i == 0 || !FILENAME_IS_CURRPAR(file->relpath)); draw_tile(sx, sy - 1, layout->tile_w + 4, sfile->layout->tile_h + layout->tile_border_y, colorid, shade); } diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index df6bd01144d..1ada5538fe3 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -64,7 +64,7 @@ #include "ED_anim_api.h" #include "ED_keyframing.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index df6de83336d..530506e7c1d 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -686,7 +686,7 @@ static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID if (sgraph->ads && (ID *)sgraph->ads->filter_grp == old_id) { sgraph->ads->filter_grp = (Group *)new_id; } - if ((ID *)sgraph->ads->source == old_id) { + if (sgraph->ads && (ID *)sgraph->ads->source == old_id) { sgraph->ads->source = new_id; } } diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 20f9658020d..c105f40f1d6 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -762,7 +762,7 @@ static void uiblock_layer_pass_buttons( } /* view */ - if (BLI_listbase_count_ex(&rr->views, 2) > 1 && + if (BLI_listbase_count_at_most(&rr->views, 2) > 1 && ((!show_stereo) || (!RE_RenderResult_is_stereo(rr)))) { rview = BLI_findlink(&rr->views, iuser->view); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 9740a62d4f0..e14e7820403 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1851,7 +1851,7 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI /* we need renderresult for exr and rendered multiview */ scene = CTX_data_scene(C); rr = BKE_image_acquire_renderresult(scene, ima); - bool is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : BLI_listbase_count_ex(&ima->views, 2) < 2; + bool is_mono = rr ? BLI_listbase_count_at_most(&rr->views, 2) < 2 : BLI_listbase_count_at_most(&ima->views, 2) < 2; bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && RE_HasFloatPixels(rr); /* error handling */ @@ -2658,8 +2658,9 @@ static int image_invert_exec(bContext *C, wmOperator *op) if (ibuf->mipmap[0]) ibuf->userflags |= IB_MIPMAP_INVALID; - if (support_undo) - ED_undo_paint_push_end(UNDO_PAINT_IMAGE); + if (support_undo) { + ED_image_undo_push_end(); + } /* force GPU reupload, all image is invalid */ GPU_free_image(ima); diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index e1a31be4afb..4dd3f369204 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -56,7 +56,7 @@ #include "BKE_main.h" #include "BKE_sca.h" -#include "ED_util.h" +#include "ED_undo.h" #include "BLT_translation.h" diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 87b7599ec66..c86e9872c0a 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -1501,7 +1501,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op) NlaStrip *mstrip = (NlaStrip *)nlt->strips.first; if ((mstrip->flag & NLASTRIP_FLAG_TEMP_META) && - (BLI_listbase_count_ex(&mstrip->strips, 3) == 2)) + (BLI_listbase_count_at_most(&mstrip->strips, 3) == 2)) { /* remove this temp meta, so that we can see the strips inside */ BKE_nlastrips_clear_metas(&nlt->strips, 0, 1); diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index 508a16926e6..173c919e38c 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -53,7 +53,7 @@ #include "ED_node.h" /* own include */ -#include "ED_util.h" +#include "ED_undo.h" /************************* Node Socket Manipulation **************************/ diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 0b001ca9578..71edd855cf0 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -52,7 +52,6 @@ #include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_depsgraph.h" -#include "BKE_global.h" #include "BKE_idcode.h" #include "BKE_library.h" #include "BKE_library_query.h" diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 12b9d273a47..27c96bd0232 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -54,7 +54,7 @@ #include "ED_object.h" #include "ED_screen.h" #include "ED_sequencer.h" -#include "ED_util.h" +#include "ED_undo.h" #include "WM_api.h" #include "WM_types.h" @@ -241,7 +241,7 @@ static eOLDrawState tree_element_set_active_object( } if (ob != scene->obedit) - ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); + ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); return OL_DRAWSEL_NORMAL; } @@ -714,13 +714,16 @@ static eOLDrawState tree_element_active_pose( } if (set != OL_SETSEL_NONE) { - if (scene->obedit) - ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); + if (scene->obedit) { + ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); + } - if (ob->mode & OB_MODE_POSE) - ED_armature_exit_posemode(C, base); - else - ED_armature_enter_posemode(C, base); + if (ob->mode & OB_MODE_POSE) { + ED_object_posemode_exit(C, ob); + } + else { + ED_object_posemode_enter(C, ob); + } } else { if (ob->mode & OB_MODE_POSE) { diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index cf9deeaedf8..e8275d597a6 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -68,7 +68,7 @@ #include "ED_object.h" #include "ED_screen.h" #include "ED_sequencer.h" -#include "ED_util.h" +#include "ED_undo.h" #include "WM_api.h" #include "WM_types.h" @@ -418,7 +418,7 @@ static void object_delete_cb( // check also library later if (scene->obedit == base->object) - ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); + ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); ED_base_object_free_and_unlink(CTX_data_main(C), scene, base); /* leave for ED_outliner_id_unref to handle */ @@ -873,7 +873,7 @@ static void object_delete_hierarchy_cb( /* Check also library later. */ for (; obedit && (obedit != base->object); obedit = obedit->parent); if (obedit == base->object) { - ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); + ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); } outline_delete_hierarchy(C, reports, scene, base); diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt index 39b48f5b52c..91420a5d63a 100644 --- a/source/blender/editors/space_text/CMakeLists.txt +++ b/source/blender/editors/space_text/CMakeLists.txt @@ -48,6 +48,7 @@ set(SRC text_format_py.c text_header.c text_ops.c + text_undo.c text_format.h text_intern.h diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c index da5fa9da046..9163831c333 100644 --- a/source/blender/editors/space_text/text_autocomplete.c +++ b/source/blender/editors/space_text/text_autocomplete.c @@ -241,7 +241,7 @@ static void get_suggest_prefix(Text *text, int offset) texttool_suggest_prefix(line + i, len); } -static void confirm_suggestion(Text *text) +static void confirm_suggestion(Text *text, TextUndoBuf *utxt) { SuggItem *sel; int i, over = 0; @@ -260,7 +260,7 @@ static void confirm_suggestion(Text *text) // for (i = 0; i < skipleft; i++) // txt_move_left(text, 0); BLI_assert(memcmp(sel->name, &line[i], over) == 0); - txt_insert_buf(text, sel->name + over); + txt_insert_buf(text, utxt, sel->name + over); // for (i = 0; i < skipleft; i++) // txt_move_right(text, 0); @@ -284,7 +284,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()) { - confirm_suggestion(st->text); + TextUndoBuf *utxt = NULL; // FIXME + confirm_suggestion(st->text, utxt); text_update_line_edited(st->text->curl); text_autocomplete_free(C, op); return OPERATOR_FINISHED; @@ -314,6 +315,8 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e (void)text; + TextUndoBuf *utxt = NULL; // FIXME + if (st->doplugins && texttool_text_is_active(st->text)) { if (texttool_suggest_first()) tools |= TOOL_SUGG_LIST; if (texttool_docs_get()) tools |= TOOL_DOCUMENT; @@ -340,7 +343,7 @@ 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)) { - confirm_suggestion(st->text); + confirm_suggestion(st->text, utxt); text_update_line_edited(st->text->curl); swallow = 1; } @@ -375,7 +378,7 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e case PADENTER: if (event->val == KM_PRESS) { if (tools & TOOL_SUGG_LIST) { - confirm_suggestion(st->text); + confirm_suggestion(st->text, utxt); text_update_line_edited(st->text->curl); swallow = 1; draw = 1; diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index f75cd129f67..223a3031f3b 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -731,7 +731,8 @@ static int text_paste_exec(bContext *C, wmOperator *op) text_drawcache_tag_update(CTX_wm_space_text(C), 0); - txt_insert_buf(text, buf); + TextUndoBuf *utxt = ED_text_undo_push_init(C); + txt_insert_buf(text, utxt, buf); text_update_edited(text); MEM_freeN(buf); @@ -756,7 +757,10 @@ void TEXT_OT_paste(wmOperatorType *ot) /* api callbacks */ ot->exec = text_paste_exec; ot->poll = text_edit_poll; - + + /* flags */ + ot->flag = OPTYPE_UNDO; + /* properties */ RNA_def_boolean(ot->srna, "selection", 0, "Selection", "Paste text selected elsewhere rather than copied (X11 only)"); } @@ -766,9 +770,11 @@ void TEXT_OT_paste(wmOperatorType *ot) static int text_duplicate_line_exec(bContext *C, wmOperator *UNUSED(op)) { Text *text = CTX_data_edit_text(C); - - txt_duplicate_line(text); - + + TextUndoBuf *utxt = ED_text_undo_push_init(C); + + txt_duplicate_line(text, utxt); + WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); /* run the script while editing, evil but useful */ @@ -785,10 +791,13 @@ void TEXT_OT_duplicate_line(wmOperatorType *ot) ot->name = "Duplicate Line"; ot->idname = "TEXT_OT_duplicate_line"; ot->description = "Duplicate the current line"; - + /* api callbacks */ ot->exec = text_duplicate_line_exec; ot->poll = text_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* copy operator *********************/ @@ -838,7 +847,9 @@ static int text_cut_exec(bContext *C, wmOperator *UNUSED(op)) text_drawcache_tag_update(CTX_wm_space_text(C), 0); txt_copy_clipboard(text); - txt_delete_selected(text); + + TextUndoBuf *utxt = ED_text_undo_push_init(C); + txt_delete_selected(text, utxt); text_update_cursor_moved(C); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); @@ -860,6 +871,9 @@ void TEXT_OT_cut(wmOperatorType *ot) /* api callbacks */ ot->exec = text_cut_exec; ot->poll = text_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* indent operator *********************/ @@ -870,12 +884,15 @@ 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); + if (txt_has_sel(text)) { txt_order_cursors(text, false); - txt_indent(text); + txt_indent(text, utxt); + } + else { + txt_add_char(text, utxt, '\t'); } - else - txt_add_char(text, '\t'); text_update_edited(text); @@ -895,6 +912,9 @@ void TEXT_OT_indent(wmOperatorType *ot) /* api callbacks */ ot->exec = text_indent_exec; ot->poll = text_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* unindent operator *********************/ @@ -905,8 +925,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); + txt_order_cursors(text, false); - txt_unindent(text); + txt_unindent(text, utxt); text_update_edited(text); @@ -926,6 +948,9 @@ void TEXT_OT_unindent(wmOperatorType *ot) /* api callbacks */ ot->exec = text_unindent_exec; ot->poll = text_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* line break operator *********************/ @@ -941,14 +966,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); - txt_split_curline(text); + TextUndoBuf *utxt = ED_text_undo_push_init(C); + txt_split_curline(text, utxt); for (a = 0; a < curts; a++) { if (text->flags & TXT_TABSTOSPACES) { - txt_add_char(text, ' '); + txt_add_char(text, utxt, ' '); } else { - txt_add_char(text, '\t'); + txt_add_char(text, utxt, '\t'); } } @@ -970,10 +996,13 @@ void TEXT_OT_line_break(wmOperatorType *ot) ot->name = "Line Break"; ot->idname = "TEXT_OT_line_break"; ot->description = "Insert line break at cursor position"; - + /* api callbacks */ ot->exec = text_line_break_exec; ot->poll = text_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* comment operator *********************/ @@ -985,8 +1014,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); + txt_order_cursors(text, false); - txt_comment(text); + txt_comment(text, utxt); text_update_edited(text); text_update_cursor_moved(C); @@ -1003,10 +1034,13 @@ void TEXT_OT_comment(wmOperatorType *ot) ot->name = "Comment"; ot->idname = "TEXT_OT_comment"; ot->description = "Convert selected text to comment"; - + /* api callbacks */ ot->exec = text_comment_exec; ot->poll = text_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* uncomment operator *********************/ @@ -1018,8 +1052,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); + txt_order_cursors(text, false); - txt_uncomment(text); + txt_uncomment(text, utxt); text_update_edited(text); text_update_cursor_moved(C); @@ -1041,6 +1077,9 @@ void TEXT_OT_uncomment(wmOperatorType *ot) /* api callbacks */ ot->exec = text_uncomment_exec; ot->poll = text_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* convert whitespace operator *********************/ @@ -1174,6 +1213,9 @@ void TEXT_OT_convert_whitespace(wmOperatorType *ot) ot->exec = text_convert_whitespace_exec; ot->poll = text_edit_poll; + /* flags */ + ot->flag = OPTYPE_UNDO; + /* properties */ RNA_def_enum(ot->srna, "type", whitespace_type_items, TO_SPACES, "Type", "Type of whitespace to convert to"); } @@ -1265,8 +1307,10 @@ 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"); - - txt_move_lines(text, direction); + + TextUndoBuf *utxt = ED_text_undo_push_init(C); + + txt_move_lines(text, utxt, direction); text_update_cursor_moved(C); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); @@ -1295,6 +1339,9 @@ void TEXT_OT_move_lines(wmOperatorType *ot) ot->exec = move_lines_exec; ot->poll = text_edit_poll; + /* flags */ + ot->flag = OPTYPE_UNDO; + /* properties */ RNA_def_enum(ot->srna, "direction", direction_items, 1, "Direction", ""); } @@ -1936,6 +1983,7 @@ static int text_delete_exec(bContext *C, wmOperator *op) Text *text = CTX_data_edit_text(C); int type = RNA_enum_get(op->ptr, "type"); + text_drawcache_tag_update(st, 0); /* behavior could be changed here, @@ -1945,11 +1993,13 @@ static int text_delete_exec(bContext *C, wmOperator *op) else if (type == DEL_NEXT_WORD) type = DEL_NEXT_CHAR; } + TextUndoBuf *utxt = ED_text_undo_push_init(C); + if (type == DEL_PREV_WORD) { if (txt_cursor_is_line_start(text)) { - txt_backspace_char(text); + txt_backspace_char(text, utxt); } - txt_backspace_word(text); + txt_backspace_word(text, utxt); } else if (type == DEL_PREV_CHAR) { @@ -1965,13 +2015,13 @@ static int text_delete_exec(bContext *C, wmOperator *op) } } - txt_backspace_char(text); + txt_backspace_char(text, utxt); } else if (type == DEL_NEXT_WORD) { if (txt_cursor_is_line_end(text)) { - txt_delete_char(text); + txt_delete_char(text, utxt); } - txt_delete_word(text); + txt_delete_word(text, utxt); } else if (type == DEL_NEXT_CHAR) { @@ -1987,7 +2037,7 @@ static int text_delete_exec(bContext *C, wmOperator *op) } } - txt_delete_char(text); + txt_delete_char(text, utxt); } text_update_line_edited(text->curl); @@ -2840,16 +2890,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); + if (st && st->overwrite) { while (str[i]) { code = BLI_str_utf8_as_unicode_step(str, &i); - done |= txt_replace_char(text, code); + done |= txt_replace_char(text, utxt, code); } } else { while (str[i]) { code = BLI_str_utf8_as_unicode_step(str, &i); - done |= txt_add_char(text, code); + done |= txt_add_char(text, utxt, code); } } @@ -2919,6 +2971,9 @@ void TEXT_OT_insert(wmOperatorType *ot) ot->invoke = text_insert_invoke; ot->poll = text_edit_poll; + /* flags */ + ot->flag = OPTYPE_UNDO; + /* properties */ prop = RNA_def_string(ot->srna, "text", NULL, 0, "Text", "Text to insert at the cursor position"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); @@ -2955,7 +3010,8 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode) if (found) { if (mode == TEXT_REPLACE) { - txt_insert_buf(text, st->replacestr); + TextUndoBuf *utxt = ED_text_undo_push_init(C); + txt_insert_buf(text, utxt, st->replacestr); if (text->curl && text->curl->format) { MEM_freeN(text->curl->format); text->curl->format = NULL; @@ -3024,6 +3080,9 @@ void TEXT_OT_replace(wmOperatorType *ot) /* api callbacks */ ot->exec = text_replace_exec; ot->poll = text_space_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /******************* find set selected *********************/ @@ -3081,6 +3140,9 @@ void TEXT_OT_replace_set_selected(wmOperatorType *ot) /* api callbacks */ ot->exec = text_replace_set_selected_exec; ot->poll = text_space_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; } /****************** resolve conflict operator ******************/ @@ -3201,26 +3263,3 @@ void TEXT_OT_to_3d_object(wmOperatorType *ot) /* properties */ RNA_def_boolean(ot->srna, "split_lines", 0, "Split Lines", "Create one object per line in the text"); } - - -/************************ undo ******************************/ - -void ED_text_undo_step(bContext *C, int step) -{ - Text *text = CTX_data_edit_text(C); - - if (!text) - return; - - if (step == 1) - txt_do_undo(text); - else if (step == -1) - txt_do_redo(text); - - text_update_edited(text); - - text_update_cursor_moved(C); - text_drawcache_tag_update(CTX_wm_space_text(C), 1); - WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); -} - diff --git a/source/blender/editors/space_text/text_undo.c b/source/blender/editors/space_text/text_undo.c new file mode 100644 index 00000000000..729522cc8f4 --- /dev/null +++ b/source/blender/editors/space_text/text_undo.c @@ -0,0 +1,185 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_text/text_undo.c + * \ingroup sptext + */ + +#include <string.h> +#include <errno.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_text_types.h" + +#include "BLI_listbase.h" +#include "BLI_array_utils.h" + +#include "BLT_translation.h" + +#include "PIL_time.h" + +#include "BKE_context.h" +#include "BKE_library.h" +#include "BKE_report.h" +#include "BKE_text.h" +#include "BKE_undo_system.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_text.h" +#include "ED_curve.h" +#include "ED_screen.h" +#include "ED_undo.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "text_intern.h" +#include "text_format.h" + +/* TODO(campbell): undo_system: move text undo out of text block. */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct TextUndoStep { + UndoStep step; + UndoRefID_Text text_ref; + TextUndoBuf data; +} TextUndoStep; + +static bool text_undosys_poll(bContext *C) +{ + Text *text = CTX_data_edit_text(C); + if (text == NULL) { + return false; + } + if (ID_IS_LINKED(text)) { + return false; + } + return true; +} + +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); + /* 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, UndoStep *us_p) +{ + TextUndoStep *us = (TextUndoStep *)us_p; + + 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; + } + + us->text_ref.ptr = text; + + us->step.data_size = us->data.len; + + return true; +} + +static void text_undosys_step_decode(struct bContext *C, UndoStep *us_p, int dir) +{ + TextUndoStep *us = (TextUndoStep *)us_p; + Text *text = us->text_ref.ptr; + + if (dir < 0) { + TextUndoBuf data = us->data; + txt_do_undo(text, &data); + } + else { + TextUndoBuf data = us->data; + data.pos = -1; + txt_do_redo(text, &data); + } + + text_update_edited(text); + text_update_cursor_moved(C); + text_drawcache_tag_update(CTX_wm_space_text(C), 1); + WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); +} + +static void text_undosys_step_free(UndoStep *us_p) +{ + TextUndoStep *us = (TextUndoStep *)us_p; + MEM_SAFE_FREE(us->data.buf); +} + +static void text_undosys_foreach_ID_ref( + UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + TextUndoStep *us = (TextUndoStep *)us_p; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->text_ref)); +} + +/* Export for ED_undo_sys. */ + +void ED_text_undosys_type(UndoType *ut) +{ + ut->name = "Text"; + ut->poll = text_undosys_poll; + ut->step_encode_init = text_undosys_step_encode_init; + ut->step_encode = text_undosys_step_encode; + ut->step_decode = text_undosys_step_decode; + ut->step_free = text_undosys_step_free; + + ut->step_foreach_ID_ref = text_undosys_foreach_ID_ref; + + ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE; + ut->use_context = false; + + ut->step_size = sizeof(TextUndoStep); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +/* Use operator system to finish the undo step. */ +TextUndoBuf *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; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 11dc4d10f2a..d80ef486663 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -54,7 +54,7 @@ #include "WM_types.h" #include "ED_mesh.h" -#include "ED_util.h" +#include "ED_undo.h" #include "ED_screen.h" #include "UI_interface.h" diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c index 5e3c783c1b6..dfa64bd2015 100644 --- a/source/blender/editors/space_view3d/view3d_toolbar.c +++ b/source/blender/editors/space_view3d/view3d_toolbar.c @@ -55,7 +55,7 @@ #include "RNA_access.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 7708d1abe2e..d9d1f01de60 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1715,23 +1715,13 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) TransInfo *t = (TransInfo *)customdata; if (t->helpline != HLP_NONE && !(t->flag & T_USES_MANIPULATOR)) { - float vecrot[3], cent[2]; + float cent[2]; int mval[2]; mval[0] = x; mval[1] = y; - copy_v3_v3(vecrot, t->center); - if (t->flag & T_EDIT) { - Object *ob = t->obedit; - if (ob) mul_m4_v3(ob->obmat, vecrot); - } - else if (t->flag & T_POSE) { - Object *ob = t->poseobj; - if (ob) mul_m4_v3(ob->obmat, vecrot); - } - - projectFloatViewEx(t, vecrot, cent, V3D_PROJ_TEST_CLIP_ZERO); + projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO); glPushMatrix(); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 5621eede543..08bd36fe95c 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -979,7 +979,7 @@ static void setNearestAxis3d(TransInfo *t) * of two 2D points 30 pixels apart (that's the last factor in the formula) after * projecting them with ED_view3d_win_to_delta and then get the length of that vector. */ - zfac = mul_project_m4_v3_zfac(t->persmat, t->center); + zfac = mul_project_m4_v3_zfac(t->persmat, t->center_global); zfac = len_v3(t->persinv[0]) * 2.0f / t->ar->winx * zfac * 30.0f; for (i = 0; i < 3; i++) { diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 4e098cd7585..5a6bcdd0d4f 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1887,14 +1887,6 @@ void calculateCenter(TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { /* ED_view3d_calc_zfac() defines a factor for perspective depth correction, used in ED_view3d_win_to_delta() */ - float vec[3]; - if (t->flag & (T_EDIT | T_POSE)) { - Object *ob = t->obedit ? t->obedit : t->poseobj; - mul_v3_m4v3(vec, ob->obmat, t->center); - } - else { - copy_v3_v3(vec, t->center); - } /* zfac is only used convertViewVec only in cases operator was invoked in RGN_TYPE_WINDOW * and never used in other cases. @@ -1903,7 +1895,7 @@ void calculateCenter(TransInfo *t) * for a region different from RGN_TYPE_WINDOW. */ if (t->ar->regiontype == RGN_TYPE_WINDOW) { - t->zfac = ED_view3d_calc_zfac(t->ar->regiondata, vec, NULL); + t->zfac = ED_view3d_calc_zfac(t->ar->regiondata, t->center_global, NULL); } else { t->zfac = 0.0f; diff --git a/source/blender/editors/undo/CMakeLists.txt b/source/blender/editors/undo/CMakeLists.txt new file mode 100644 index 00000000000..89832604ed8 --- /dev/null +++ b/source/blender/editors/undo/CMakeLists.txt @@ -0,0 +1,45 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + ../include + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/guardedalloc + ../../../../intern/clog +) + +set(SRC + ed_undo.c + memfile_undo.c + undo_system_types.c + + undo_intern.h +) + +if(WITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) +endif() + +blender_add_lib(bf_editor_undo "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/undo/ed_undo.c index d791818331e..d8b194e3336 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -25,17 +25,16 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/editors/util/undo.c - * \ingroup edutil +/** \file blender/editors/undo/ed_undo.c + * \ingroup edundo */ -#include <stdlib.h> #include <string.h> -#include <math.h> #include "MEM_guardedalloc.h" -#include "DNA_object_types.h" +#include "CLG_log.h" + #include "DNA_scene_types.h" #include "BLI_utildefines.h" @@ -47,20 +46,12 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BKE_screen.h" +#include "BKE_undo_system.h" -#include "ED_armature.h" -#include "ED_particle.h" -#include "ED_curve.h" #include "ED_gpencil.h" -#include "ED_lattice.h" -#include "ED_mball.h" -#include "ED_mesh.h" -#include "ED_object.h" #include "ED_render.h" #include "ED_screen.h" -#include "ED_paint.h" -#include "ED_util.h" -#include "ED_text.h" +#include "ED_undo.h" #include "WM_api.h" #include "WM_types.h" @@ -71,44 +62,37 @@ #include "UI_interface.h" #include "UI_resources.h" -#include "util_intern.h" +/** We only need this locally. */ +static CLG_LogRef LOG = {"ed.undo"}; -/* ***************** generic undo system ********************* */ +/* -------------------------------------------------------------------- */ +/** \name Generic Undo System Access + * + * Non-operator undo editor functions. + * \{ */ void ED_undo_push(bContext *C, const char *str) { - Object *obedit = CTX_data_edit_object(C); - Object *obact = CTX_data_active_object(C); - - if (G.debug & G_DEBUG) - printf("%s: %s\n", __func__, str); - - if (obedit) { - if (U.undosteps == 0) return; - - if (obedit->type == OB_MESH) - undo_push_mesh(C, str); - else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) - undo_push_curve(C, str); - else if (obedit->type == OB_FONT) - undo_push_font(C, str); - else if (obedit->type == OB_MBALL) - undo_push_mball(C, str); - else if (obedit->type == OB_LATTICE) - undo_push_lattice(C, str); - else if (obedit->type == OB_ARMATURE) - undo_push_armature(C, str); - } - else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) { - if (U.undosteps == 0) return; + CLOG_INFO(&LOG, 1, "name='%s'", str); + + const int steps = U.undosteps; - PE_undo_push(CTX_data_scene(C), str); + if (steps <= 0) { + return; } - else if (obact && obact->mode & OB_MODE_SCULPT) { - /* do nothing for now */ + + wmWindowManager *wm = CTX_wm_manager(C); + + /* Only apply limit if this is the last undo step. */ + if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) { + BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, steps - 1, 0); } - else { - BKE_undo_write(C, str); + + BKE_undosys_step_push(wm->undo_stack, C, str); + + if (U.undomemory != 0) { + const size_t memory_limit = (size_t)U.undomemory * 1024 * 1024; + BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, 0, memory_limit); } WM_file_tag_modified(); @@ -117,13 +101,11 @@ void ED_undo_push(bContext *C, const char *str) /* note: also check undo_history_exec() in bottom if you change notifiers */ static int ed_undo_step(bContext *C, int step, const char *undoname) { + CLOG_INFO(&LOG, 1, "name='%s', step=%d", undoname, step); wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); - Main *bmain = CTX_data_main(C); + // Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - Object *obact = CTX_data_active_object(C); - ScrArea *sa = CTX_wm_area(C); /* undo during jobs are running can easily lead to freeing data using by jobs, * or they can just lead to freezing job in some other cases */ @@ -131,100 +113,45 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) return OPERATOR_CANCELLED; } + /* TODO(campbell): undo_system: use undo system */ /* grease pencil can be can be used in plenty of spaces, so check it first */ if (ED_gpencil_session_active()) { return ED_undo_gpencil_step(C, step, undoname); } - if (sa && (sa->spacetype == SPACE_IMAGE)) { - SpaceImage *sima = (SpaceImage *)sa->spacedata.first; - - if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { - if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname) { - if (U.uiflag & USER_GLOBALUNDO) { - ED_viewport_render_kill_jobs(wm, bmain, true); - BKE_undo_name(C, undoname); - } - } - - WM_event_add_notifier(C, NC_WINDOW, NULL); - return OPERATOR_FINISHED; - } - } - - if (sa && (sa->spacetype == SPACE_TEXT)) { - ED_text_undo_step(C, step); - } - else if (obedit) { - if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) { - if (undoname) - undo_editmode_name(C, undoname); - else - undo_editmode_step(C, step); - - WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); - } - } - else { - /* Note: we used to do a fall-through here where if the - * mode-specific undo system had no more steps to undo (or - * redo), the global undo would run. - * - * That was inconsistent with editmode, and also makes for - * unecessarily tricky interaction with the other undo - * systems. */ - if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) { - ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname); + /* Undo System */ + { + if (undoname) { + UndoStep *step_data = BKE_undosys_step_find_by_name(wm->undo_stack, undoname); + BKE_undosys_step_undo_with_data(wm->undo_stack, C, step_data); } - else if (obact && obact->mode & OB_MODE_SCULPT) { - ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname); - } - else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) { - if (step == 1) - PE_undo(scene); - else - PE_redo(scene); - } - else if (U.uiflag & USER_GLOBALUNDO) { - // note python defines not valid here anymore. - //#ifdef WITH_PYTHON - // XXX BPY_scripts_clear_pyobjects(); - //#endif - - /* for global undo/redo we should just clear the editmode stack */ - /* for example, texface stores image pointers */ - undo_editmode_clear(); - - ED_viewport_render_kill_jobs(wm, bmain, true); - - if (undoname) - BKE_undo_name(C, undoname); - else - BKE_undo_step(C, step); - - scene = CTX_data_scene(C); - - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); + else { + BKE_undosys_step_undo_compat_only(wm->undo_stack, C, step); } } - + WM_event_add_notifier(C, NC_WINDOW, NULL); WM_event_add_notifier(C, NC_WM | ND_UNDO, NULL); if (win) { win->addmousemove = true; } - + return OPERATOR_FINISHED; } void ED_undo_grouped_push(bContext *C, const char *str) { /* do nothing if previous undo task is the same as this one (or from the same undo group) */ - const char *last_undo = BKE_undo_get_name_last(); + { + wmWindowManager *wm = CTX_wm_manager(C); + if (wm->undo_stack->steps.last) { + const UndoStep *us = wm->undo_stack->steps.last; + if (STREQ(str, us->name)) { + return; + } + } - if (last_undo && STREQ(str, last_undo)) { - return; } /* push as usual */ @@ -265,49 +192,29 @@ void ED_undo_pop_op(bContext *C, wmOperator *op) /* name optionally, function used to check for operator redo panel */ bool ED_undo_is_valid(const bContext *C, const char *undoname) { - Object *obedit = CTX_data_edit_object(C); - Object *obact = CTX_data_active_object(C); - ScrArea *sa = CTX_wm_area(C); - - if (sa && sa->spacetype == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)sa->spacedata.first; - - if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { - return 1; - } - } - - if (sa && (sa->spacetype == SPACE_TEXT)) { - return 1; - } - else if (obedit) { - if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) { - return undo_editmode_is_valid(undoname); - } - } - else { - - /* if below tests fail, global undo gets executed */ - - if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) { - if (ED_undo_paint_is_valid(UNDO_PAINT_IMAGE, undoname)) - return 1; - } - else if (obact && obact->mode & OB_MODE_SCULPT) { - if (ED_undo_paint_is_valid(UNDO_PAINT_MESH, undoname)) - return 1; - } - else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) { - return PE_undo_is_valid(CTX_data_scene(C)); - } - - if (U.uiflag & USER_GLOBALUNDO) { - return BKE_undo_is_valid(undoname); - } - } - return 0; + wmWindowManager *wm = CTX_wm_manager(C); + return BKE_undosys_stack_has_undo(wm->undo_stack, undoname); +} + +/** + * Ideally we wont access the stack directly, + * this is needed for modes which handle undo themselves (bypassing #ED_undo_push). + * + * Using global isn't great, this just avoids doing inline, + * causing 'BKE_global.h' & 'BKE_main.h' includes. + */ +UndoStack *ED_undo_stack_get(void) +{ + wmWindowManager *wm = G.main->wm.first; + return wm->undo_stack; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Undo, Undo Push & Redo Operators + * \{ */ + static int ed_undo_exec(bContext *C, wmOperator *UNUSED(op)) { /* "last operator" should disappear, later we can tie this with undo stack nicer */ @@ -338,19 +245,17 @@ static int ed_undo_redo_exec(bContext *C, wmOperator *UNUSED(op)) static int ed_undo_redo_poll(bContext *C) { wmOperator *last_op = WM_operator_last_redo(C); - return last_op && ED_operator_screenactive(C) && + return last_op && ED_operator_screenactive(C) && WM_operator_check_ui_enabled(C, last_op->type->name); } -/* ********************** */ - void ED_OT_undo(wmOperatorType *ot) { /* identifiers */ ot->name = "Undo"; ot->description = "Undo previous action"; ot->idname = "ED_OT_undo"; - + /* api callbacks */ ot->exec = ed_undo_exec; ot->poll = ED_operator_screenactive; @@ -362,7 +267,7 @@ void ED_OT_undo_push(wmOperatorType *ot) ot->name = "Undo Push"; ot->description = "Add an undo state (internal use only)"; ot->idname = "ED_OT_undo_push"; - + /* api callbacks */ ot->exec = ed_undo_push_exec; @@ -377,7 +282,7 @@ void ED_OT_redo(wmOperatorType *ot) ot->name = "Redo"; ot->description = "Redo previous action"; ot->idname = "ED_OT_redo"; - + /* api callbacks */ ot->exec = ed_redo_exec; ot->poll = ED_operator_screenactive; @@ -389,18 +294,25 @@ void ED_OT_undo_redo(wmOperatorType *ot) ot->name = "Undo and Redo"; ot->description = "Undo and redo previous action"; ot->idname = "ED_OT_undo_redo"; - + /* api callbacks */ ot->exec = ed_undo_redo_exec; ot->poll = ed_undo_redo_poll; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operator Repeat + * \{ */ + /* ui callbacks should call this rather than calling WM_operator_repeat() themselves */ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op) { int ret = 0; if (op) { + CLOG_INFO(&LOG, 1, "idname='%s'", op->type->idname); wmWindowManager *wm = CTX_wm_manager(C); struct Scene *scene = CTX_data_scene(C); @@ -461,9 +373,7 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op) CTX_wm_region_set(C, ar); } else { - if (G.debug & G_DEBUG) { - printf("redo_cb: ED_undo_operator_repeat called with NULL 'op'\n"); - } + CLOG_WARN(&LOG, "called with NULL 'op'"); } return ret; @@ -480,114 +390,50 @@ void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_ev ED_undo_operator_repeat(C, (wmOperator *)arg_op); } +/** \} */ -/* ************************** */ - -enum { - UNDOSYSTEM_GLOBAL = 1, - UNDOSYSTEM_EDITMODE = 2, - UNDOSYSTEM_PARTICLE = 3, - UNDOSYSTEM_IMAPAINT = 4, - UNDOSYSTEM_SCULPT = 5, -}; - -static int get_undo_system(bContext *C) -{ - Object *obact = CTX_data_active_object(C); - Object *obedit = CTX_data_edit_object(C); - ScrArea *sa = CTX_wm_area(C); - - /* first check for editor undo */ - if (sa && (sa->spacetype == SPACE_IMAGE)) { - SpaceImage *sima = (SpaceImage *)sa->spacedata.first; - - if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { - if (!ED_undo_paint_empty(UNDO_PAINT_IMAGE)) - return UNDOSYSTEM_IMAPAINT; - } - } - /* find out which undo system */ - if (obedit) { - if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) { - return UNDOSYSTEM_EDITMODE; - } - } - else { - if (obact) { - if (obact->mode & OB_MODE_PARTICLE_EDIT) - return UNDOSYSTEM_PARTICLE; - else if (obact->mode & OB_MODE_TEXTURE_PAINT) { - if (!ED_undo_paint_empty(UNDO_PAINT_IMAGE)) - return UNDOSYSTEM_IMAPAINT; - } - else if (obact->mode & OB_MODE_SCULPT) { - if (!ED_undo_paint_empty(UNDO_PAINT_MESH)) - return UNDOSYSTEM_SCULPT; - } - } - if (U.uiflag & USER_GLOBALUNDO) - return UNDOSYSTEM_GLOBAL; - } - - return 0; -} +/* -------------------------------------------------------------------- */ +/** \name Undo History Operator + * \{ */ /* create enum based on undo items */ -static const EnumPropertyItem *rna_undo_itemf(bContext *C, int undosys, int *totitem) +static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem) { EnumPropertyItem item_tmp = {0}, *item = NULL; int i = 0; - bool active; - - while (true) { - const char *name = NULL; - - if (undosys == UNDOSYSTEM_PARTICLE) { - name = PE_undo_get_name(CTX_data_scene(C), i, &active); - } - else if (undosys == UNDOSYSTEM_EDITMODE) { - name = undo_editmode_get_name(C, i, &active); - } - else if (undosys == UNDOSYSTEM_IMAPAINT) { - name = ED_undo_paint_get_name(C, UNDO_PAINT_IMAGE, i, &active); - } - else if (undosys == UNDOSYSTEM_SCULPT) { - name = ED_undo_paint_get_name(C, UNDO_PAINT_MESH, i, &active); - } - else { - name = BKE_undo_get_name(i, &active); - } - - if (name) { - item_tmp.identifier = name; - /* XXX This won't work with non-default contexts (e.g. operators) :/ */ - item_tmp.name = IFACE_(name); - if (active) + + wmWindowManager *wm = CTX_wm_manager(C); + if (wm->undo_stack == NULL) { + return NULL; + } + + for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) { + if (us->skip == false) { + item_tmp.identifier = us->name; + item_tmp.name = IFACE_(us->name); + if (us == wm->undo_stack->step_active) { item_tmp.icon = ICON_RESTRICT_VIEW_OFF; - else + } + else { item_tmp.icon = ICON_NONE; - item_tmp.value = i++; + } + item_tmp.value = i; RNA_enum_item_add(&item, totitem, &item_tmp); } - else - break; } - RNA_enum_item_end(&item, totitem); - + return item; } static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - int undosys, totitem = 0; - - undosys = get_undo_system(C); - - if (undosys) { - const EnumPropertyItem *item = rna_undo_itemf(C, undosys, &totitem); - + int totitem = 0; + + { + const EnumPropertyItem *item = rna_undo_itemf(C, &totitem); + if (totitem > 0) { uiPopupMenu *pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE); uiLayout *layout = UI_popup_menu_layout(pup); @@ -596,7 +442,7 @@ static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE const int col_size = 20 + totitem / 12; int i, c; bool add_col = true; - + for (c = 0, i = totitem; i--;) { if (add_col && !(c % col_size)) { column = uiLayoutColumn(split, false); @@ -608,12 +454,12 @@ static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE add_col = true; } } - + MEM_freeN((void *)item); - + UI_popup_menu_end(C, pup); } - + } return OPERATOR_CANCELLED; } @@ -621,30 +467,12 @@ static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE /* note: also check ed_undo_step() in top if you change notifiers */ static int undo_history_exec(bContext *C, wmOperator *op) { - if (RNA_struct_property_is_set(op->ptr, "item")) { - int undosys = get_undo_system(C); - int item = RNA_int_get(op->ptr, "item"); - - if (undosys == UNDOSYSTEM_PARTICLE) { - PE_undo_number(CTX_data_scene(C), item); - } - else if (undosys == UNDOSYSTEM_EDITMODE) { - undo_editmode_number(C, item + 1); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); - } - else if (undosys == UNDOSYSTEM_IMAPAINT) { - ED_undo_paint_step_num(C, UNDO_PAINT_IMAGE, item); - } - else if (undosys == UNDOSYSTEM_SCULPT) { - ED_undo_paint_step_num(C, UNDO_PAINT_MESH, item); - } - else { - ED_viewport_render_kill_jobs(CTX_wm_manager(C), CTX_data_main(C), true); - BKE_undo_number(C, item); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C)); - } + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item"); + if (RNA_property_is_set(op->ptr, prop)) { + int item = RNA_property_int_get(op->ptr, prop); + wmWindowManager *wm = CTX_wm_manager(C); + BKE_undosys_step_undo_from_index(wm->undo_stack, C, item); WM_event_add_notifier(C, NC_WINDOW, NULL); - return OPERATOR_FINISHED; } return OPERATOR_CANCELLED; @@ -656,14 +484,14 @@ void ED_OT_undo_history(wmOperatorType *ot) ot->name = "Undo History"; ot->description = "Redo specific action in history"; ot->idname = "ED_OT_undo_history"; - + /* api callbacks */ ot->invoke = undo_history_invoke; ot->exec = undo_history_exec; ot->poll = ED_operator_screenactive; - + RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX); } - +/** \} */ diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c new file mode 100644 index 00000000000..a0f7ebac477 --- /dev/null +++ b/source/blender/editors/undo/memfile_undo.c @@ -0,0 +1,149 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/undo/memfile_undo.c + * \ingroup edundo + * + * Wrapper between 'ED_undo.h' and 'BKE_undo_system.h' API's. + */ + +#include "BLI_utildefines.h" +#include "BLI_sys_types.h" + +#include "DNA_object_enums.h" + +#include "BKE_blender_undo.h" +#include "BKE_context.h" +#include "BKE_undo_system.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_object.h" +#include "ED_undo.h" +#include "ED_render.h" + + +#include "../blenloader/BLO_undofile.h" + +#include "undo_intern.h" + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct MemFileUndoStep { + UndoStep step; + MemFileUndoData *data; +} MemFileUndoStep; + +static bool memfile_undosys_poll(bContext *UNUSED(C)) +{ + /* other poll functions must run first, this is a catch-all. */ + + if ((U.uiflag & USER_GLOBALUNDO) == 0) { + return false; + } + return true; +} + +static bool memfile_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + MemFileUndoStep *us = (MemFileUndoStep *)us_p; + + /* Important we only use 'main' from the context (see: BKE_undosys_stack_init_from_main). */ + struct Main *bmain = CTX_data_main(C); + + /* can be NULL, use when set. */ + MemFileUndoStep *us_prev = (MemFileUndoStep *)BKE_undosys_step_same_type_prev(us_p); + us->data = BKE_memfile_undo_encode(bmain, us_prev ? us_prev->data : NULL); + us->step.data_size = us->data->undo_size; + return true; +} + +static void memfile_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* Loading the content will correctly switch into compatible non-object modes. */ + ED_object_mode_set(C, OB_MODE_OBJECT); + + /* This is needed so undoing/redoing doesn't crash with threaded previews going */ + ED_viewport_render_kill_jobs(CTX_wm_manager(C), CTX_data_main(C), true); + MemFileUndoStep *us = (MemFileUndoStep *)us_p; + BKE_memfile_undo_decode(us->data, C); + + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C)); +} + +static void memfile_undosys_step_free(UndoStep *us_p) +{ + /* To avoid unnecessary slow down, free backwards (so we don't need to merge when clearing all). */ + MemFileUndoStep *us = (MemFileUndoStep *)us_p; + if (us_p->next != NULL) { + UndoStep *us_next_p = BKE_undosys_step_same_type_next(us_p); + if (us_next_p != NULL) { + MemFileUndoStep *us_next = (MemFileUndoStep *)us_next_p; + BLO_memfile_merge(&us->data->memfile, &us_next->data->memfile); + } + } + + BKE_memfile_undo_free(us->data); +} + +/* Export for ED_undo_sys. */ +void ED_memfile_undosys_type(UndoType *ut) +{ + ut->name = "Global Undo"; + ut->poll = memfile_undosys_poll; + ut->step_encode = memfile_undosys_step_encode; + ut->step_decode = memfile_undosys_step_decode; + ut->step_free = memfile_undosys_step_free; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(MemFileUndoStep); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +/** + * Ideally we wouldn't need to export global undo internals, there are some cases where it's needed though. + */ +static struct MemFile *ed_undosys_step_get_memfile(UndoStep *us_p) +{ + MemFileUndoStep *us = (MemFileUndoStep *)us_p; + return &us->data->memfile; +} + +struct MemFile *ED_undosys_stack_memfile_get_active(UndoStack *ustack) +{ + UndoStep *us = BKE_undosys_stack_active_with_type(ustack, BKE_UNDOSYS_TYPE_MEMFILE); + if (us) { + return ed_undosys_step_get_memfile(us); + } + return NULL; +} + + +/** \} */ diff --git a/source/blender/editors/util/util_intern.h b/source/blender/editors/undo/undo_intern.h index 0f650330951..671f9637d65 100644 --- a/source/blender/editors/util/util_intern.h +++ b/source/blender/editors/undo/undo_intern.h @@ -15,32 +15,21 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2008 Blender Foundation. - * All rights reserved. - * - * - * Contributor(s): Blender Foundation - * * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/editors/util/util_intern.h - * \ingroup edutil +/** \file blender/editors/undo/undo_intern.h + * \ingroup edundo */ - -#ifndef __UTIL_INTERN_H__ -#define __UTIL_INTERN_H__ +#ifndef __UNDO_INTERN_H__ +#define __UNDO_INTERN_H__ /* internal exports only */ -/* editmode_undo.c */ -void undo_editmode_name(struct bContext *C, const char *undoname); -bool undo_editmode_is_valid(const char *undoname); -const char *undo_editmode_get_name(struct bContext *C, int nr, bool *r_active); -void *undo_editmode_get_prev(struct Object *ob); -void undo_editmode_step(struct bContext *C, int step); -void undo_editmode_number(struct bContext *C, int nr); +struct UndoType; -#endif /* __UTIL_INTERN_H__ */ +/* memfile_undo.c */ +void ED_memfile_undosys_type(struct UndoType *ut); +#endif /* __UNDO_INTERN_H__ */ diff --git a/source/blender/editors/undo/undo_system_types.c b/source/blender/editors/undo/undo_system_types.c new file mode 100644 index 00000000000..75c3d2cc1b7 --- /dev/null +++ b/source/blender/editors/undo/undo_system_types.c @@ -0,0 +1,74 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/undo/undo_system_types.c + * \ingroup edundo + */ + +#include <string.h> + +#include "BLI_utildefines.h" + + +#include "ED_armature.h" +#include "ED_curve.h" +#include "ED_lattice.h" +#include "ED_mball.h" +#include "ED_mesh.h" +#include "ED_paint.h" +#include "ED_particle.h" +#include "ED_sculpt.h" +#include "ED_text.h" +#include "ED_undo.h" +#include "undo_intern.h" + +/* Keep last */ +#include "BKE_undo_system.h" + +void ED_undosys_type_init(void) +{ + /* Edit Modes */ + BKE_undosys_type_append(ED_armature_undosys_type); + BKE_undosys_type_append(ED_curve_undosys_type); + BKE_undosys_type_append(ED_font_undosys_type); + BKE_undosys_type_append(ED_lattice_undosys_type); + BKE_undosys_type_append(ED_mball_undosys_type); + BKE_undosys_type_append(ED_mesh_undosys_type); + + /* Paint Modes */ + BKE_UNDOSYS_TYPE_IMAGE = BKE_undosys_type_append(ED_image_undosys_type); + + BKE_UNDOSYS_TYPE_SCULPT = BKE_undosys_type_append(ED_sculpt_undosys_type); + + BKE_UNDOSYS_TYPE_PARTICLE = BKE_undosys_type_append(ED_particle_undosys_type); + + BKE_UNDOSYS_TYPE_PAINTCURVE = BKE_undosys_type_append(ED_paintcurve_undosys_type); + + /* Text editor */ + BKE_UNDOSYS_TYPE_TEXT = BKE_undosys_type_append(ED_text_undosys_type); + + /* Keep global undo last (as a fallback). */ + BKE_UNDOSYS_TYPE_MEMFILE = BKE_undosys_type_append(ED_memfile_undosys_type); +} + +void ED_undosys_type_free(void) +{ + BKE_undosys_type_free_all(); +} diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index a8225bb64d1..8657c876d47 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -41,11 +41,8 @@ set(INC_SYS set(SRC ed_transverts.c ed_util.c - editmode_undo.c numinput.c - undo.c - util_intern.h # general includes ../include/BIF_gl.h ../include/BIF_glutil.h diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 57ff8b6db01..03d0b4a8d48 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -58,6 +58,7 @@ #include "BKE_packedFile.h" #include "BKE_paint.h" #include "BKE_screen.h" +#include "BKE_undo_system.h" #include "ED_armature.h" #include "ED_buttons.h" @@ -89,6 +90,10 @@ void ED_editors_init(bContext *C) Object *ob, *obact = (sce && sce->basact) ? sce->basact->object : NULL; ID *data; + if (wm->undo_stack == NULL) { + wm->undo_stack = BKE_undosys_stack_create(); + } + /* This is called during initialization, so we don't want to store any reports */ ReportList *reports = CTX_wm_reports(C); int reports_flag_prev = reports->flag & ~RPT_STORE; @@ -128,9 +133,15 @@ void ED_editors_exit(bContext *C) return; /* frees all editmode undos */ - undo_editmode_clear(); - ED_undo_paint_free(); - + if (G.main->wm.first) { + wmWindowManager *wm = G.main->wm.first; + /* normally we don't check for NULL undo stack, do here since it may run in different context. */ + if (wm->undo_stack) { + BKE_undosys_stack_destroy(wm->undo_stack); + wm->undo_stack = NULL; + } + } + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->obedit) { Object *ob = sce->obedit; diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c deleted file mode 100644 index fa697a0f006..00000000000 --- a/source/blender/editors/util/editmode_undo.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2004 Blender Foundation - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/util/editmode_undo.c - * \ingroup edutil - */ - -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_object_types.h" - -#include "BLI_blenlib.h" -#include "BLI_utildefines.h" - -#include "BKE_blender_undo.h" -#include "BKE_context.h" -#include "BKE_depsgraph.h" -#include "BKE_global.h" - -#include "ED_util.h" -#include "ED_mesh.h" - -#include "util_intern.h" - -/* ****** XXX ***** */ -static void error(const char *UNUSED(arg)) {} -/* ****** XXX ***** */ - -typedef struct UndoElem { - struct UndoElem *next, *prev; - /** copy of edit-mode object ID */ - ID id; - /** pointer to edited object */ - Object *ob; - /** type of edited object */ - int type; - void *undodata; - uintptr_t undosize; - char name[BKE_UNDO_STR_MAX]; - - /** Use context to retrieve current edit-data. */ - void * (*getdata)(bContext * C); - /** Pointer to function freeing data. */ - void (*freedata)(void *); - /** Data to edit-mode conversion. */ - void (*to_editmode)(void *, void *, void *); - /** Edit-mode to data conversion. */ - void * (*from_editmode)(void *, void *); - /** Check if undo data is still valid. */ - int (*validate_undo)(void *, void *); -} UndoElem; - -static ListBase g_undobase = {NULL, NULL}; -static UndoElem *g_curundo = NULL; - -static void undo_restore(UndoElem *undo, void *editdata, void *obdata) -{ - if (undo) { - undo->to_editmode(undo->undodata, editdata, obdata); - } -} - -/** - * name can be a dynamic string - * See #UndoElem for callbacks docs. - * */ -void undo_editmode_push( - bContext *C, const char *name, - void * (*getdata)(bContext * C), - void (*freedata)(void *), - void (*to_editmode)(void *, void *, void *), - void *(*from_editmode)(void *, void *), - int (*validate_undo)(void *, void *)) -{ - UndoElem *uel; - Object *obedit = CTX_data_edit_object(C); - void *editdata; - int nr; - uintptr_t mem_used, mem_total, mem_max; - - /* at first here was code to prevent an "original" key to be inserted twice - * this was giving conflicts for example when mesh changed due to keys or apply */ - - /* remove all undos after (also when g_curundo == NULL) */ - while (g_undobase.last != g_curundo) { - uel = g_undobase.last; - uel->freedata(uel->undodata); - BLI_freelinkN(&g_undobase, uel); - } - - /* make new */ - g_curundo = uel = MEM_callocN(sizeof(UndoElem), "undo editmode"); - BLI_strncpy(uel->name, name, sizeof(uel->name)); - BLI_addtail(&g_undobase, uel); - - uel->getdata = getdata; - uel->freedata = freedata; - uel->to_editmode = to_editmode; - uel->from_editmode = from_editmode; - uel->validate_undo = validate_undo; - - /* limit amount to the maximum amount*/ - nr = 0; - uel = g_undobase.last; - while (uel) { - nr++; - if (nr == U.undosteps) { - break; - } - uel = uel->prev; - } - if (uel) { - while (g_undobase.first != uel) { - UndoElem *first = g_undobase.first; - first->freedata(first->undodata); - BLI_freelinkN(&g_undobase, first); - } - } - - /* copy */ - mem_used = MEM_get_memory_in_use(); - editdata = getdata(C); - g_curundo->undodata = g_curundo->from_editmode(editdata, obedit->data); - g_curundo->undosize = MEM_get_memory_in_use() - mem_used; - g_curundo->ob = obedit; - g_curundo->id = obedit->id; - g_curundo->type = obedit->type; - - if (U.undomemory != 0) { - /* limit to maximum memory (afterwards, we can't know in advance) */ - mem_total = 0; - mem_max = ((uintptr_t)U.undomemory) * 1024 * 1024; - - uel = g_undobase.last; - while (uel && uel->prev) { - mem_total += uel->undosize; - if (mem_total > mem_max) { - break; - } - uel = uel->prev; - } - - if (uel) { - if (uel->prev && uel->prev->prev) { - uel = uel->prev; - } - while (g_undobase.first != uel) { - UndoElem *first = g_undobase.first; - first->freedata(first->undodata); - BLI_freelinkN(&g_undobase, first); - } - } - } -} - -/* helper to remove clean other objects from undo stack */ -static void undo_clean_stack(bContext *C) -{ - UndoElem *uel; - Object *obedit = CTX_data_edit_object(C); - - /* global undo changes pointers, so we also allow identical names */ - /* side effect: when deleting/renaming object and start editing new one with same name */ - - uel = g_undobase.first; - while (uel) { - void *editdata = uel->getdata(C); - bool is_valid = false; - UndoElem *uel_next = uel->next; - - /* for when objects are converted, renamed, or global undo changes pointers... */ - if (uel->type == obedit->type) { - if (STREQ(uel->id.name, obedit->id.name)) { - if (uel->validate_undo == NULL) { - is_valid = true; - } - else if (uel->validate_undo(uel->undodata, editdata)) { - is_valid = true; - } - } - } - if (is_valid) { - uel->ob = obedit; - } - else { - if (uel == g_curundo) { - g_curundo = NULL; - } - - uel->freedata(uel->undodata); - BLI_freelinkN(&g_undobase, uel); - } - - uel = uel_next; - } - - if (g_curundo == NULL) { - g_curundo = g_undobase.last; - } -} - -/** - * 1 = an undo, -1 is a redo. - * we have to make sure 'g_curundo' remains at current situation - */ -void undo_editmode_step(bContext *C, int step) -{ - Object *obedit = CTX_data_edit_object(C); - - /* prevent undo to happen on wrong object, stack can be a mix */ - undo_clean_stack(C); - - if (step == 0) { - undo_restore(g_curundo, g_curundo->getdata(C), obedit->data); - } - else if (step == 1) { - if (g_curundo == NULL || g_curundo->prev == NULL) { - error("No more steps to undo"); - } - else { - if (G.debug & G_DEBUG) printf("undo %s\n", g_curundo->name); - g_curundo = g_curundo->prev; - undo_restore(g_curundo, g_curundo->getdata(C), obedit->data); - } - } - else { - /* g_curundo has to remain current situation! */ - if (g_curundo == NULL || g_curundo->next == NULL) { - error("No more steps to redo"); - } - else { - undo_restore(g_curundo->next, g_curundo->getdata(C), obedit->data); - g_curundo = g_curundo->next; - if (G.debug & G_DEBUG) printf("redo %s\n", g_curundo->name); - } - } - - /* special case for editmesh, mode must be copied back to the scene */ - if (obedit->type == OB_MESH) { - EDBM_selectmode_to_scene(C); - } - - DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); - - /* XXX notifiers */ -} - -void undo_editmode_clear(void) -{ - UndoElem *uel; - - uel = g_undobase.first; - while (uel) { - uel->freedata(uel->undodata); - uel = uel->next; - } - BLI_freelistN(&g_undobase); - g_curundo = NULL; -} - -/* based on index nr it does a restore */ -void undo_editmode_number(bContext *C, int nr) -{ - UndoElem *uel; - int a = 1; - - for (uel = g_undobase.first; uel; uel = uel->next, a++) { - if (a == nr) { - break; - } - } - g_curundo = uel; - undo_editmode_step(C, 0); -} - -void undo_editmode_name(bContext *C, const char *undoname) -{ - UndoElem *uel; - - for (uel = g_undobase.last; uel; uel = uel->prev) { - if (STREQ(undoname, uel->name)) { - break; - } - } - if (uel && uel->prev) { - g_curundo = uel->prev; - undo_editmode_step(C, 0); - } -} - -/** - * \a undoname is optional, when NULL it just checks for existing undo steps - */ -bool undo_editmode_is_valid(const char *undoname) -{ - if (undoname) { - UndoElem *uel; - - for (uel = g_undobase.last; uel; uel = uel->prev) { - if (STREQ(undoname, uel->name)) { - break; - } - } - return uel != NULL; - } - return g_undobase.last != g_undobase.first; -} - - -/** - * Get name of undo item, return null if no item with this index. - * - * if active pointer, set it to 1 if true - */ -const char *undo_editmode_get_name(bContext *C, int nr, bool *r_active) -{ - UndoElem *uel; - - /* prevent wrong numbers to be returned */ - undo_clean_stack(C); - - if (r_active) { - *r_active = false; - } - - uel = BLI_findlink(&g_undobase, nr); - if (uel) { - if (r_active && (uel == g_curundo)) { - *r_active = true; - } - return uel->name; - } - return NULL; -} - - -void *undo_editmode_get_prev(Object *ob) -{ - UndoElem *ue = g_undobase.last; - if (ue && ue->prev && ue->prev->ob == ob) { - return ue->prev->undodata; - } - return NULL; -} diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt index c3950d8eb83..e73f227dec8 100644 --- a/source/blender/imbuf/CMakeLists.txt +++ b/source/blender/imbuf/CMakeLists.txt @@ -73,6 +73,7 @@ set(SRC IMB_colormanagement.h IMB_imbuf.h IMB_imbuf_types.h + IMB_metadata.h IMB_moviecache.h IMB_thumbs.h intern/IMB_allocimbuf.h @@ -81,7 +82,6 @@ set(SRC intern/IMB_filetype.h intern/IMB_filter.h intern/IMB_indexer.h - intern/IMB_metadata.h intern/imbuf.h # orphan include diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index a7f793b5b11..e5cd21a3248 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -380,13 +380,13 @@ struct ImBuf *IMB_onehalf(struct ImBuf *ibuf1); * * \attention Defined in scaling.c */ -struct ImBuf *IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy); +bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy); /** * * \attention Defined in scaling.c */ -struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy); +bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy); /** * @@ -399,7 +399,7 @@ void IMB_scaleImBuf_threaded(struct ImBuf *ibuf, unsigned int newx, unsigned int * \attention Defined in writeimage.c */ short IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags); -struct ImBuf *IMB_prepare_write_ImBuf(const bool isfloat, struct ImBuf *ibuf); +bool IMB_prepare_write_ImBuf(const bool isfloat, struct ImBuf *ibuf); /** * @@ -566,22 +566,6 @@ void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height, const float col[4], struct ColorManagedDisplay *display, int x1, int y1, int x2, int y2); -/** - * - * \attention Defined in metadata.c - */ -/** read the field from the image info into the field - * \param img - the ImBuf that contains the image data - * \param key - the key of the field - * \param value - the data in the field, first one found with key is returned, - * memory has to be allocated by user. - * \param len - length of value buffer allocated by user. - * \return - 1 (true) if ImageInfo present and value for the key found, 0 (false) otherwise - */ -bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *value, const size_t len); -bool IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *field); -void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb); - /* exported for image tools in blender, to quickly allocate 32 bits rect */ void *imb_alloc_pixels(unsigned int x, unsigned int y, diff --git a/source/blender/imbuf/intern/IMB_metadata.h b/source/blender/imbuf/IMB_metadata.h index bc0b2c70ecb..6a29fa01594 100644 --- a/source/blender/imbuf/intern/IMB_metadata.h +++ b/source/blender/imbuf/IMB_metadata.h @@ -4,7 +4,7 @@ * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/imbuf/intern/IMB_metadata.h +/** \file blender/imbuf/IMB_metadata.h * \ingroup imbuf */ @@ -33,7 +33,9 @@ #ifndef __IMB_METADATA_H__ #define __IMB_METADATA_H__ +struct anim; struct ImBuf; +struct IDProperty; /** The metadata is a list of key/value pairs (both char *) that can me * saved in the header of several image formats. @@ -41,26 +43,36 @@ struct ImBuf; * 'Software' and 'Description' (png standard) we'll use keys within the * Blender namespace, so should be called 'Blender::StampInfo' or 'Blender::FrameNum' * etc... + * + * The keys & values are stored in ID properties, in the group "metadata". */ +/** Ensure that the metadata property is a valid IDProperty object. + * This is a no-op when *metadata != NULL. + */ +void IMB_metadata_ensure(struct IDProperty **metadata); +void IMB_metadata_free(struct IDProperty *metadata); -/* free blender ImMetaData struct */ -void IMB_metadata_free(struct ImBuf *img); +/** Read the field from the image info into the field. + * \param metadata - the IDProperty that contains the metadata + * \param key - the key of the field + * \param value - the data in the field, first one found with key is returned, + * memory has to be allocated by user. + * \param len - length of value buffer allocated by user. + * \return - 1 (true) if metadata is present and value for the key found, 0 (false) otherwise + */ +bool IMB_metadata_get_field(struct IDProperty *metadata, const char *key, char *value, const size_t len); -/** set user data in the ImMetaData struct, which has to be allocated with IMB_metadata_create - * before calling this function. - * \param img - the ImBuf that contains the image data +/** Set user data in the metadata. + * If the field already exists its value is overwritten, otherwise the field + * will be added with the given value. + * \param metadata - the IDProperty that contains the metadata * \param key - the key of the field * \param value - the data to be written to the field. zero terminated string - * \return - 1 (true) if ImageInfo present, 0 (false) otherwise */ -bool IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value); +void IMB_metadata_set_field(struct IDProperty *metadata, const char *key, const char *value); -/** delete the key/field par in the ImMetaData struct. - * \param img - the ImBuf that contains the image data - * \param key - the key of the field - * \return - 1 (true) if delete the key/field, 0 (false) otherwise - */ -bool IMB_metadata_del_field(struct ImBuf *img, const char *key); +void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb); +struct IDProperty *IMB_anim_load_metadata(struct anim *anim); #endif /* __IMB_METADATA_H__ */ diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index c4c4f4405a5..6fa31e122cc 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -93,6 +93,7 @@ struct _AviMovie; struct anim_index; +struct IDProperty; struct anim { int ib_flags; @@ -158,6 +159,8 @@ struct anim { char colorspace[64]; char suffix[64]; /* MAX_NAME - multiview */ + + struct IDProperty *metadata; }; #endif diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index 7fc4a65d8d7..faa0b5f7b6e 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -219,7 +219,7 @@ void IMB_freeImBuf(ImBuf *ibuf) IMB_freezbufImBuf(ibuf); IMB_freezbuffloatImBuf(ibuf); freeencodedbufferImBuf(ibuf); - IMB_metadata_free(ibuf); + IMB_metadata_free(ibuf->metadata); colormanage_cache_free(ibuf); if (ibuf->dds_data.data != NULL) { diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index a770b34ecc6..f842b69418e 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -68,8 +68,6 @@ #include "MEM_guardedalloc.h" -#include "BKE_global.h" - #ifdef WITH_AVI # include "AVI_avi.h" #endif @@ -82,8 +80,11 @@ #include "IMB_anim.h" #include "IMB_indexer.h" +#include "IMB_metadata.h" #ifdef WITH_FFMPEG +# include "BKE_global.h" /* ENDIAN_ORDER */ + # include <libavformat/avformat.h> # include <libavcodec/avcodec.h> # include <libavutil/rational.h> @@ -220,6 +221,7 @@ void IMB_free_anim(struct anim *anim) free_anim_ffmpeg(anim); #endif IMB_free_indices(anim); + IMB_metadata_free(anim->metadata); MEM_freeN(anim); } @@ -239,6 +241,26 @@ void IMB_close_anim_proxies(struct anim *anim) IMB_free_indices(anim); } +struct IDProperty *IMB_anim_load_metadata(struct anim *anim) +{ +#ifdef WITH_FFMPEG + AVDictionaryEntry *entry = NULL; + + BLI_assert(anim->pFormatCtx != NULL); + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "METADATA FETCH\n"); + + while (true) { + entry = av_dict_get(anim->pFormatCtx->metadata, "", entry, AV_DICT_IGNORE_SUFFIX); + if (entry == NULL) break; + + /* Delay creation of the property group until there is actual metadata to put in there. */ + IMB_metadata_ensure(&anim->metadata); + IMB_metadata_set_field(anim->metadata, entry->key, entry->value); + } +#endif + return anim->metadata; +} + struct anim *IMB_open_anim(const char *name, int ib_flags, int streamindex, char colorspace[IM_MAX_SPACE]) { struct anim *anim; diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index e28c8122006..b2197ecb3b5 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -49,6 +49,7 @@ #include "IMB_filetype.h" #include "IMB_filter.h" #include "IMB_moviecache.h" +#include "IMB_metadata.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c index 35c7b6363a1..ef9217fbc8c 100644 --- a/source/blender/imbuf/intern/jpeg.c +++ b/source/blender/imbuf/intern/jpeg.c @@ -382,7 +382,8 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla * the information when we write * it back to disk. */ - IMB_metadata_add_field(ibuf, "None", str); + IMB_metadata_ensure(&ibuf->metadata); + IMB_metadata_set_field(ibuf->metadata, "None", str); ibuf->flags |= IB_metadata; MEM_freeN(str); goto next_stamp_marker; @@ -408,7 +409,8 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla *value = '\0'; /* need finish the key string */ value++; - IMB_metadata_add_field(ibuf, key, value); + IMB_metadata_ensure(&ibuf->metadata); + IMB_metadata_set_field(ibuf->metadata, key, value); ibuf->flags |= IB_metadata; MEM_freeN(str); next_stamp_marker: diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c index da39967a4fe..ef103f7afcf 100644 --- a/source/blender/imbuf/intern/metadata.c +++ b/source/blender/imbuf/intern/metadata.c @@ -45,97 +45,69 @@ #include "IMB_metadata.h" +#define METADATA_MAX_VALUE_LENGTH 1024 -void IMB_metadata_free(struct ImBuf *img) +void IMB_metadata_ensure(struct IDProperty **metadata) { - if (!img) + if (*metadata != NULL) { return; - if (!img->metadata) { + } + + IDPropertyTemplate val; + *metadata = IDP_New(IDP_GROUP, &val, "metadata"); +} + +void IMB_metadata_free(struct IDProperty *metadata) +{ + if (metadata == NULL) { return; } - IDP_FreeProperty(img->metadata); - MEM_freeN(img->metadata); + IDP_FreeProperty(metadata); + MEM_freeN(metadata); } -bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *field, const size_t len) +bool IMB_metadata_get_field(struct IDProperty *metadata, const char *key, char *field, const size_t len) { IDProperty *prop; - bool retval = false; - - if (!img) - return false; - if (!img->metadata) + if (metadata == NULL) { return false; + } - prop = IDP_GetPropertyFromGroup(img->metadata, key); + prop = IDP_GetPropertyFromGroup(metadata, key); if (prop && prop->type == IDP_STRING) { BLI_strncpy(field, IDP_String(prop), len); - retval = true; + return true; } - return retval; + return false; } void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb) { BLI_assert(dimb != simb); if (simb->metadata) { - IMB_metadata_free(dimb); + IMB_metadata_free(dimb->metadata); dimb->metadata = IDP_CopyProperty(simb->metadata); } } -bool IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value) +void IMB_metadata_set_field(struct IDProperty *metadata, const char *key, const char *value) { - IDProperty *prop; - - if (!img) - return false; + BLI_assert(metadata); + IDProperty *prop = IDP_GetPropertyFromGroup(metadata, key); - if (!img->metadata) { - IDPropertyTemplate val; - img->metadata = IDP_New(IDP_GROUP, &val, "metadata"); + if (prop != NULL && prop->type != IDP_STRING) { + IDP_FreeFromGroup(metadata, prop); + prop = NULL; } - prop = IDP_NewString(value, key, 512); - return IDP_AddToGroup(img->metadata, prop); -} - -bool IMB_metadata_del_field(struct ImBuf *img, const char *key) -{ - IDProperty *prop; - - if ((!img) || (!img->metadata)) - return false; - - prop = IDP_GetPropertyFromGroup(img->metadata, key); - - if (prop) { - IDP_FreeFromGroup(img->metadata, prop); + if (prop == NULL) { + prop = IDP_NewString(value, key, METADATA_MAX_VALUE_LENGTH); + IDP_AddToGroup(metadata, prop); } - return false; -} - -bool IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *field) -{ - IDProperty *prop; - if (!img) - return false; - - prop = (img->metadata) ? IDP_GetPropertyFromGroup(img->metadata, key) : NULL; - - if (!prop) { - return (IMB_metadata_add_field(img, key, field)); - } - else if (prop->type == IDP_STRING) { - IDP_AssignString(prop, field, 1024); - return true; - } - else { - return false; - } + IDP_AssignString(prop, value, METADATA_MAX_VALUE_LENGTH); } diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 4e85d70d382..ad04f1fb78d 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -1790,12 +1790,13 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem, size_t size, int flags, const Header & header = file->header(0); Header::ConstIterator iter; + IMB_metadata_ensure(&ibuf->metadata); for (iter = header.begin(); iter != header.end(); iter++) { const StringAttribute *attrib = file->header(0).findTypedAttribute <StringAttribute> (iter.name()); /* not all attributes are string attributes so we might get some NULLs here */ if (attrib) { - IMB_metadata_add_field(ibuf, iter.name(), attrib->value().c_str()); + IMB_metadata_set_field(ibuf->metadata, iter.name(), attrib->value().c_str()); ibuf->flags |= IB_metadata; } } diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c index 857f72e10eb..29fbe79d8db 100644 --- a/source/blender/imbuf/intern/png.c +++ b/source/blender/imbuf/intern/png.c @@ -759,8 +759,9 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors if (flags & IB_metadata) { png_text *text_chunks; int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL); + IMB_metadata_ensure(&ibuf->metadata); for (int i = 0; i < count; i++) { - IMB_metadata_add_field(ibuf, text_chunks[i].key, text_chunks[i].text); + IMB_metadata_set_field(ibuf->metadata, text_chunks[i].key, text_chunks[i].text); ibuf->flags |= IB_metadata; } } diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c index 504b59b2b1d..ff92ce15811 100644 --- a/source/blender/imbuf/intern/scaling.c +++ b/source/blender/imbuf/intern/scaling.c @@ -1550,12 +1550,17 @@ static void scalefast_Z_ImBuf(ImBuf *ibuf, int newx, int newy) } } -struct ImBuf *IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy) +/** + * Return true if \a ibuf is modified. + */ +bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy) { - if (ibuf == NULL) return (NULL); - if (ibuf->rect == NULL && ibuf->rect_float == NULL) return (ibuf); + if (ibuf == NULL) return false; + if (ibuf->rect == NULL && ibuf->rect_float == NULL) return false; - if (newx == ibuf->x && newy == ibuf->y) { return ibuf; } + if (newx == ibuf->x && newy == ibuf->y) { + return false; + } /* scaleup / scaledown functions below change ibuf->x and ibuf->y * so we first scale the Z-buffer (if any) */ @@ -1564,7 +1569,7 @@ struct ImBuf *IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int /* try to scale common cases in a fast way */ /* disabled, quality loss is unacceptable, see report #18609 (ton) */ if (0 && q_scale_linear_interpolation(ibuf, newx, newy)) { - return ibuf; + return true; } if (newx && (newx < ibuf->x)) scaledownx(ibuf, newx); @@ -1572,14 +1577,17 @@ struct ImBuf *IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int if (newx && (newx > ibuf->x)) scaleupx(ibuf, newx); if (newy && (newy > ibuf->y)) scaleupy(ibuf, newy); - return(ibuf); + return true; } struct imbufRGBA { float r, g, b, a; }; -struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy) +/** + * Return true if \a ibuf is modified. + */ +bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy) { unsigned int *rect, *_newrect, *newrect; struct imbufRGBA *rectf, *_newrectf, *newrectf; @@ -1590,16 +1598,16 @@ struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned rect = NULL; _newrect = NULL; newrect = NULL; rectf = NULL; _newrectf = NULL; newrectf = NULL; - if (ibuf == NULL) return(NULL); + if (ibuf == NULL) return false; if (ibuf->rect) do_rect = true; if (ibuf->rect_float) do_float = true; - if (do_rect == false && do_float == false) return(ibuf); + if (do_rect == false && do_float == false) return false; - if (newx == ibuf->x && newy == ibuf->y) return(ibuf); + if (newx == ibuf->x && newy == ibuf->y) return false; if (do_rect) { _newrect = MEM_mallocN(newx * newy * sizeof(int), "scalefastimbuf"); - if (_newrect == NULL) return(ibuf); + if (_newrect == NULL) return false; newrect = _newrect; } @@ -1607,7 +1615,7 @@ struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned _newrectf = MEM_mallocN(newx * newy * sizeof(float) * 4, "scalefastimbuf f"); if (_newrectf == NULL) { if (_newrect) MEM_freeN(_newrect); - return(ibuf); + return false; } newrectf = _newrectf; } @@ -1643,18 +1651,18 @@ struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned ibuf->mall |= IB_rect; ibuf->rect = _newrect; } - + if (do_float) { imb_freerectfloatImBuf(ibuf); ibuf->mall |= IB_rectfloat; ibuf->rect_float = (float *)_newrectf; } - + scalefast_Z_ImBuf(ibuf, newx, newy); - + ibuf->x = newx; ibuf->y = newy; - return(ibuf); + return true; } /* ******** threaded scaling ******** */ diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c index 3c587684641..2fa5b5a0170 100644 --- a/source/blender/imbuf/intern/thumbs.c +++ b/source/blender/imbuf/intern/thumbs.c @@ -430,16 +430,17 @@ static ImBuf *thumb_create_ex( IMB_scaleImBuf(img, ex, ey); } BLI_snprintf(desc, sizeof(desc), "Thumbnail for %s", uri); - IMB_metadata_change_field(img, "Description", desc); - IMB_metadata_change_field(img, "Software", "Blender"); - IMB_metadata_change_field(img, "Thumb::URI", uri); - IMB_metadata_change_field(img, "Thumb::MTime", mtime); + IMB_metadata_ensure(&img->metadata); + IMB_metadata_set_field(img->metadata, "Software", "Blender"); + IMB_metadata_set_field(img->metadata, "Thumb::URI", uri); + IMB_metadata_set_field(img->metadata, "Description", desc); + IMB_metadata_set_field(img->metadata, "Thumb::MTime", mtime); if (use_hash) { - IMB_metadata_change_field(img, "X-Blender::Hash", hash); + IMB_metadata_set_field(img->metadata, "X-Blender::Hash", hash); } if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) { - IMB_metadata_change_field(img, "Thumb::Image::Width", cwidth); - IMB_metadata_change_field(img, "Thumb::Image::Height", cheight); + IMB_metadata_set_field(img->metadata, "Thumb::Image::Width", cwidth); + IMB_metadata_set_field(img->metadata, "Thumb::Image::Height", cheight); } img->ftype = IMB_FTYPE_PNG; img->planes = 32; @@ -589,7 +590,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source const bool use_hash = thumbhash_from_path(file_path, source, thumb_hash); - if (IMB_metadata_get_field(img, "Thumb::MTime", mtime, sizeof(mtime))) { + if (IMB_metadata_get_field(img->metadata, "Thumb::MTime", mtime, sizeof(mtime))) { regenerate = (st.st_mtime != atol(mtime)); } else { @@ -598,7 +599,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source } if (use_hash && !regenerate) { - if (IMB_metadata_get_field(img, "X-Blender::Hash", thumb_hash_curr, sizeof(thumb_hash_curr))) { + if (IMB_metadata_get_field(img->metadata, "X-Blender::Hash", thumb_hash_curr, sizeof(thumb_hash_curr))) { regenerate = !STREQ(thumb_hash, thumb_hash_curr); } else { diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c index b5c6deb6b01..d04f5fc87e6 100644 --- a/source/blender/imbuf/intern/thumbs_blend.c +++ b/source/blender/imbuf/intern/thumbs_blend.c @@ -36,7 +36,6 @@ #include "BLO_blend_defs.h" #include "BLO_readfile.h" -#include "BKE_global.h" #include "BKE_idcode.h" #include "BKE_icons.h" #include "BKE_library.h" diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index 76a44aa81f7..9dfe926ddff 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -43,8 +43,6 @@ #include "BLI_fileops.h" #include "BLI_string.h" -#include "BKE_global.h" - #include "imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -53,6 +51,7 @@ #include "IMB_anim.h" #ifdef WITH_FFMPEG +#include "BKE_global.h" /* G.debug */ #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavdevice/avdevice.h> diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c index 84ec2534e7f..e340d082895 100644 --- a/source/blender/imbuf/intern/writeimage.c +++ b/source/blender/imbuf/intern/writeimage.c @@ -46,7 +46,7 @@ #include "IMB_colormanagement.h" #include "IMB_colormanagement_intern.h" -static ImBuf *prepare_write_imbuf(const ImFileType *type, ImBuf *ibuf) +static bool prepare_write_imbuf(const ImFileType *type, ImBuf *ibuf) { return IMB_prepare_write_ImBuf((type->flag & IM_FTYPE_FLOAT), ibuf); } @@ -64,15 +64,11 @@ short IMB_saveiff(struct ImBuf *ibuf, const char *name, int flags) for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) { if (type->save && type->ftype(type, ibuf)) { - ImBuf *write_ibuf; short result = false; - write_ibuf = prepare_write_imbuf(type, ibuf); + prepare_write_imbuf(type, ibuf); - result = type->save(write_ibuf, name, flags); - - if (write_ibuf != ibuf) - IMB_freeImBuf(write_ibuf); + result = type->save(ibuf, name, flags); return result; } @@ -83,9 +79,9 @@ short IMB_saveiff(struct ImBuf *ibuf, const char *name, int flags) return false; } -ImBuf *IMB_prepare_write_ImBuf(const bool isfloat, ImBuf *ibuf) +bool IMB_prepare_write_ImBuf(const bool isfloat, ImBuf *ibuf) { - ImBuf *write_ibuf = ibuf; + bool changed = false; if (isfloat) { /* pass */ @@ -94,8 +90,11 @@ ImBuf *IMB_prepare_write_ImBuf(const bool isfloat, ImBuf *ibuf) if (ibuf->rect == NULL && ibuf->rect_float) { ibuf->rect_colorspace = colormanage_colorspace_get_roled(COLOR_ROLE_DEFAULT_BYTE); IMB_rect_from_float(ibuf); + if (ibuf->rect != NULL) { + changed = true; + } } } - return write_ibuf; + return changed; } diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index a7f3d27e9d2..1691038e13c 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -377,7 +377,12 @@ typedef enum eRotationModes { typedef struct bPose { ListBase chanbase; /* list of pose channels, PoseBones in RNA */ struct GHash *chanhash; /* ghash for quicker string lookups */ - + + /* Flat array of pose channels. It references pointers from + * chanbase. Used for quick pose channel lookup from an index. + */ + bPoseChannel **chan_array; + short flag, pad; unsigned int proxy_layer; /* proxy layer: copy from armature, gets synced */ int pad1; diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index f7fd54a77cf..32b0702e208 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -101,17 +101,28 @@ typedef struct AviCodecData { typedef enum eFFMpegPreset { FFM_PRESET_NONE, - FFM_PRESET_ULTRAFAST, - FFM_PRESET_SUPERFAST, - FFM_PRESET_VERYFAST, - FFM_PRESET_FASTER, - FFM_PRESET_FAST, - FFM_PRESET_MEDIUM, - FFM_PRESET_SLOW, - FFM_PRESET_SLOWER, - FFM_PRESET_VERYSLOW, -} eFFMpegPreset; +#ifdef DNA_DEPRECATED + /* Previously used by h.264 to control encoding speed vs. file size. */ + FFM_PRESET_ULTRAFAST, /* DEPRECATED */ + FFM_PRESET_SUPERFAST, /* DEPRECATED */ + FFM_PRESET_VERYFAST, /* DEPRECATED */ + FFM_PRESET_FASTER, /* DEPRECATED */ + FFM_PRESET_FAST, /* DEPRECATED */ + FFM_PRESET_MEDIUM, /* DEPRECATED */ + FFM_PRESET_SLOW, /* DEPRECATED */ + FFM_PRESET_SLOWER, /* DEPRECATED */ + FFM_PRESET_VERYSLOW, /* DEPRECATED */ +#endif + + /* Used by WEBM/VP9 and h.264 to control encoding speed vs. file size. + * WEBM/VP9 use these values directly, whereas h.264 map those to + * respectively the MEDIUM, SLOWER, and SUPERFAST presets. + */ + FFM_PRESET_GOOD = 10, /* the default and recommended for most applications */ + FFM_PRESET_BEST, /* recommended if you have lots of time and want the best compression efficiency */ + FFM_PRESET_REALTIME, /* recommended for live / fast encoding */ +} eFFMpegPreset; /* Mapping from easily-understandable descriptions to CRF values. * Assumes we output 8-bit video. Needs to be remapped if 10-bit @@ -1836,10 +1847,11 @@ enum { #define R_STAMP_STRIPMETA 0x1000 #define R_STAMP_MEMORY 0x2000 #define R_STAMP_HIDE_LABELS 0x4000 +#define R_STAMP_FRAME_RANGE 0x8000 #define R_STAMP_ALL (R_STAMP_TIME|R_STAMP_FRAME|R_STAMP_DATE|R_STAMP_CAMERA|R_STAMP_SCENE| \ R_STAMP_NOTE|R_STAMP_MARKER|R_STAMP_FILENAME|R_STAMP_SEQSTRIP| \ R_STAMP_RENDERTIME|R_STAMP_CAMERALENS|R_STAMP_MEMORY| \ - R_STAMP_HIDE_LABELS) + R_STAMP_HIDE_LABELS|R_STAMP_FRAME_RANGE) /* RenderData.alphamode */ #define R_ADDSKY 0 diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h index 17ef098a3bb..163dda678d9 100644 --- a/source/blender/makesdna/DNA_text_types.h +++ b/source/blender/makesdna/DNA_text_types.h @@ -59,10 +59,6 @@ typedef struct Text { TextLine *curl, *sell; int curc, selc; - char *undo_buf; - void *pad; - int undo_pos, undo_len; - double mtime; } Text; diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 687a883f792..20470ba862e 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -58,6 +58,7 @@ struct ReportList; struct Report; struct uiLayout; struct Stereo3dFormat; +struct UndoStep; #define OP_MAX_TYPENAME 64 #define KMAP_MAX_NAME 64 @@ -154,6 +155,8 @@ typedef struct wmWindowManager { ListBase timers; /* active timers */ struct wmTimer *autosavetimer; /* timer for auto save */ + struct UndoStack *undo_stack; /* all undo history (runtime only). */ + char is_interface_locked; /* indicates whether interface is locked for user interaction */ char par[7]; } wmWindowManager; diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index a9e34247cbd..bc2c26c2b2b 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -754,6 +754,14 @@ static PointerRNA rna_IDPreview_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_ImagePreview, prv_img); } +static IDProperty *rna_IDPropertyWrapPtr_idprops(PointerRNA *ptr, bool UNUSED(create)) +{ + if (ptr == NULL) { + return NULL; + } + return ptr->data; +} + #else static void rna_def_ID_properties(BlenderRNA *brna) @@ -1105,6 +1113,20 @@ static void rna_def_library(BlenderRNA *brna) RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT); RNA_def_function_ui_description(func, "Reload this library and all its linked data-blocks"); } + +/** + * \attention This is separate from the above. It allows for RNA functions to + * return an IDProperty *. See MovieClip.metadata for a usage example. + **/ +static void rna_def_idproperty_wrap_ptr(BlenderRNA *brna) +{ + StructRNA *srna; + + srna = RNA_def_struct(brna, "IDPropertyWrapPtr", NULL); + RNA_def_struct_idprops_func(srna, "rna_IDPropertyWrapPtr_idprops"); + RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES); +} + void RNA_def_ID(BlenderRNA *brna) { StructRNA *srna; @@ -1122,6 +1144,7 @@ void RNA_def_ID(BlenderRNA *brna) rna_def_ID_properties(brna); rna_def_ID_materials(brna); rna_def_library(brna); + rna_def_idproperty_wrap_ptr(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 18e42488829..bec6830f8c3 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -1842,14 +1842,14 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char * else { flag = prop->flag; if ((flag & PROP_EDITABLE) == 0 || (flag & PROP_REGISTER)) { - *r_info = "This property is for internal use only and can't be edited."; + *r_info = N_("This property is for internal use only and can't be edited"); } } /* property from linked data-block */ if (id && ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) { if (!(*r_info)[0]) { - *r_info = "Can't edit this property from a linked data-block."; + *r_info = N_("Can't edit this property from a linked data-block"); } return false; } diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c index fb743f5236d..d63f3fe76f8 100644 --- a/source/blender/makesrna/intern/rna_movieclip.c +++ b/source/blender/makesrna/intern/rna_movieclip.c @@ -33,6 +33,7 @@ #include "DNA_movieclip_types.h" #include "DNA_scene_types.h" +#include "RNA_access.h" #include "RNA_define.h" #include "rna_internal.h" @@ -44,6 +45,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" +#include "IMB_metadata.h" #ifdef RNA_RUNTIME @@ -103,6 +105,22 @@ static void rna_MovieClipUser_proxy_render_settings_update(Main *UNUSED(bmain), } } +static PointerRNA rna_MovieClip_metadata_get(MovieClip *clip) +{ + if (clip == NULL || clip->anim == NULL) { + return PointerRNA_NULL; + } + + IDProperty *metadata = IMB_anim_load_metadata(clip->anim); + if (metadata == NULL) { + return PointerRNA_NULL; + } + + PointerRNA ptr; + RNA_pointer_create(NULL, &RNA_IDPropertyWrapPtr, metadata, &ptr); + return ptr; +} + #else static void rna_def_movieclip_proxy(BlenderRNA *brna) @@ -257,6 +275,8 @@ static void rna_def_movieclip(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; static const EnumPropertyItem clip_source_items[] = { {MCLIP_SRC_SEQUENCE, "SEQUENCE", 0, "Image Sequence", "Multiple image files, as a sequence"}, @@ -348,6 +368,14 @@ static void rna_def_movieclip(BlenderRNA *brna) RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings"); RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings"); + /* metadata */ + func = RNA_def_function(srna, "metadata", "rna_MovieClip_metadata_get"); + RNA_def_function_ui_description(func, "Retrieve metadata of the movie file"); + /* return type */ + parm = RNA_def_pointer(func, "metadata", "IDPropertyWrapPtr", "", "Dict-like object containing the metadata"); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); + RNA_def_function_return(func, parm); + rna_def_animdata_common(srna); } diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index ccd16e16760..773ca307a8c 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -2701,7 +2701,7 @@ static int rna_Node_image_has_views_get(PointerRNA *ptr) if (!ima || !(ima->rr)) return 0; - return BLI_listbase_count_ex(&ima->rr->views, 2) > 1; + return BLI_listbase_count_at_most(&ima->rr->views, 2) > 1; } static const EnumPropertyItem *renderresult_views_add_enum(RenderView *rv) diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index 188200eaff9..4c3301d5f9e 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -1293,49 +1293,49 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Z Angle Stiffness", "Stiffness on the Z rotational axis"); RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); - prop = RNA_def_property(srna, "spring_damping_x", PROP_FLOAT, PROP_FACTOR); + prop = RNA_def_property(srna, "spring_damping_x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "spring_damping_x"); - RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_x_set", NULL); RNA_def_property_ui_text(prop, "Damping X", "Damping on the X axis"); RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); - prop = RNA_def_property(srna, "spring_damping_y", PROP_FLOAT, PROP_FACTOR); + prop = RNA_def_property(srna, "spring_damping_y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "spring_damping_y"); - RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_y_set", NULL); RNA_def_property_ui_text(prop, "Damping Y", "Damping on the Y axis"); RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); - prop = RNA_def_property(srna, "spring_damping_z", PROP_FLOAT, PROP_FACTOR); + prop = RNA_def_property(srna, "spring_damping_z", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "spring_damping_z"); - RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_z_set", NULL); RNA_def_property_ui_text(prop, "Damping Z", "Damping on the Z axis"); RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); - prop = RNA_def_property(srna, "spring_damping_ang_x", PROP_FLOAT, PROP_FACTOR); + prop = RNA_def_property(srna, "spring_damping_ang_x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_x"); - RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_x_set", NULL); RNA_def_property_ui_text(prop, "Damping X Angle", "Damping on the X rotational axis"); RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); - prop = RNA_def_property(srna, "spring_damping_ang_y", PROP_FLOAT, PROP_FACTOR); + prop = RNA_def_property(srna, "spring_damping_ang_y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_y"); - RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_y_set", NULL); RNA_def_property_ui_text(prop, "Damping Y Angle", "Damping on the Y rotational axis"); RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); - prop = RNA_def_property(srna, "spring_damping_ang_z", PROP_FLOAT, PROP_FACTOR); + prop = RNA_def_property(srna, "spring_damping_ang_z", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_z"); - RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_z_set", NULL); RNA_def_property_ui_text(prop, "Damping Z Angle", "Damping on the Z rotational axis"); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 6cd748c0026..b1b7965286f 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -629,7 +629,7 @@ static const EnumPropertyItem *rna_Property_tags_itemf( int totitem = 0; for (const EnumPropertyItem *struct_tags = RNA_struct_property_tag_defines(srna); - struct_tags->identifier; + struct_tags != NULL && struct_tags->identifier != NULL; struct_tags++) { memcpy(&tmp, struct_tags, sizeof(tmp)); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 70fe38cb60d..48c42c44a3d 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -5451,8 +5451,6 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) {FFMPEG_AVI, "AVI", 0, "AVI", ""}, {FFMPEG_MOV, "QUICKTIME", 0, "Quicktime", ""}, {FFMPEG_DV, "DV", 0, "DV", ""}, -// {FFMPEG_H264, "H264", 0, "H.264", ""}, not a container -// {FFMPEG_XVID, "XVID", 0, "Xvid", ""}, not a container {FFMPEG_OGG, "OGG", 0, "Ogg", ""}, {FFMPEG_MKV, "MKV", 0, "Matroska", ""}, {FFMPEG_FLV, "FLASH", 0, "Flash", ""}, @@ -5460,38 +5458,37 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) }; static const EnumPropertyItem ffmpeg_codec_items[] = { - {AV_CODEC_ID_NONE, "NONE", 0, "None", ""}, - {AV_CODEC_ID_MPEG1VIDEO, "MPEG1", 0, "MPEG-1", ""}, - {AV_CODEC_ID_MPEG2VIDEO, "MPEG2", 0, "MPEG-2", ""}, - {AV_CODEC_ID_MPEG4, "MPEG4", 0, "MPEG-4(divx)", ""}, - {AV_CODEC_ID_HUFFYUV, "HUFFYUV", 0, "HuffYUV", ""}, + {AV_CODEC_ID_NONE, "NONE", 0, "No Video", "Disables video output, for audio-only renders"}, + {AV_CODEC_ID_DNXHD, "DNXHD", 0, "DNxHD", ""}, {AV_CODEC_ID_DVVIDEO, "DV", 0, "DV", ""}, - {AV_CODEC_ID_H264, "H264", 0, "H.264", ""}, - {AV_CODEC_ID_THEORA, "THEORA", 0, "Theora", ""}, - {AV_CODEC_ID_FLV1, "FLASH", 0, "Flash Video", ""}, {AV_CODEC_ID_FFV1, "FFV1", 0, "FFmpeg video codec #1", ""}, - {AV_CODEC_ID_QTRLE, "QTRLE", 0, "QT rle / QT Animation", ""}, - {AV_CODEC_ID_DNXHD, "DNXHD", 0, "DNxHD", ""}, + {AV_CODEC_ID_FLV1, "FLASH", 0, "Flash Video", ""}, + {AV_CODEC_ID_H264, "H264", 0, "H.264", ""}, + {AV_CODEC_ID_HUFFYUV, "HUFFYUV", 0, "HuffYUV", ""}, + {AV_CODEC_ID_MPEG1VIDEO, "MPEG1", 0, "MPEG-1", ""}, + {AV_CODEC_ID_MPEG2VIDEO, "MPEG2", 0, "MPEG-2", ""}, + {AV_CODEC_ID_MPEG4, "MPEG4", 0, "MPEG-4 (divx)", ""}, {AV_CODEC_ID_PNG, "PNG", 0, "PNG", ""}, + {AV_CODEC_ID_QTRLE, "QTRLE", 0, "QT rle / QT Animation", ""}, + {AV_CODEC_ID_THEORA, "THEORA", 0, "Theora", ""}, + {AV_CODEC_ID_VP9, "WEBM", 0, "WEBM / VP9", ""}, {0, NULL, 0, NULL, NULL} }; + /* Recommendations come from the FFmpeg wiki, https://trac.ffmpeg.org/wiki/Encode/VP9. + * The label for BEST has been changed to "Slowest" so that it fits the "Encoding Speed" + * property label in the UI. */ static const EnumPropertyItem ffmpeg_preset_items[] = { - {FFM_PRESET_ULTRAFAST, "ULTRAFAST", 0, "Ultra fast; biggest file", ""}, - {FFM_PRESET_SUPERFAST, "SUPERFAST", 0, "Super fast", ""}, - {FFM_PRESET_VERYFAST, "VERYFAST", 0, "Very fast", ""}, - {FFM_PRESET_FASTER, "FASTER", 0, "Faster", ""}, - {FFM_PRESET_FAST, "FAST", 0, "Fast", ""}, - {FFM_PRESET_MEDIUM, "MEDIUM", 0, "Medium speed", ""}, - {FFM_PRESET_SLOW, "SLOW", 0, "Slow", ""}, - {FFM_PRESET_SLOWER, "SLOWER", 0, "Slower", ""}, - {FFM_PRESET_VERYSLOW, "VERYSLOW", 0, "Very slow; smallest file", ""}, + {FFM_PRESET_BEST, "BEST", 0, "Slowest", + "Recommended if you have lots of time and want the best compression efficiency"}, + {FFM_PRESET_GOOD, "GOOD", 0, "Good", "The default and recommended for most applications"}, + {FFM_PRESET_REALTIME, "REALTIME", 0, "Realtime", "Recommended for fast encoding"}, {0, NULL, 0, NULL, NULL} }; static const EnumPropertyItem ffmpeg_crf_items[] = { - {FFM_CRF_NONE, "NONE", 0, "None; use custom bitrate", - "Use constant bit rate, rather than constant output quality"}, + {FFM_CRF_NONE, "NONE", 0, "Constant Bitrate", + "Configure constant bit rate, rather than constant output quality"}, {FFM_CRF_LOSSLESS, "LOSSLESS", 0, "Lossless", ""}, {FFM_CRF_PERC_LOSSLESS, "PERC_LOSSLESS", 0, "Perceptually lossless", ""}, {FFM_CRF_HIGH, "HIGH", 0, "High quality", ""}, @@ -5503,14 +5500,14 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) }; static const EnumPropertyItem ffmpeg_audio_codec_items[] = { - {AV_CODEC_ID_NONE, "NONE", 0, "None", ""}, - {AV_CODEC_ID_MP2, "MP2", 0, "MP2", ""}, - {AV_CODEC_ID_MP3, "MP3", 0, "MP3", ""}, - {AV_CODEC_ID_AC3, "AC3", 0, "AC3", ""}, + {AV_CODEC_ID_NONE, "NONE", 0, "No Audio", "Disables audio output, for video-only renders"}, {AV_CODEC_ID_AAC, "AAC", 0, "AAC", ""}, - {AV_CODEC_ID_VORBIS, "VORBIS", 0, "Vorbis", ""}, + {AV_CODEC_ID_AC3, "AC3", 0, "AC3", ""}, {AV_CODEC_ID_FLAC, "FLAC", 0, "FLAC", ""}, + {AV_CODEC_ID_MP2, "MP2", 0, "MP2", ""}, + {AV_CODEC_ID_MP3, "MP3", 0, "MP3", ""}, {AV_CODEC_ID_PCM_S16LE, "PCM", 0, "PCM", ""}, + {AV_CODEC_ID_VORBIS, "VORBIS", 0, "Vorbis", ""}, {0, NULL, 0, NULL, NULL} }; #endif @@ -5542,7 +5539,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_enum_items(prop, ffmpeg_codec_items); RNA_def_property_enum_default(prop, AV_CODEC_ID_H264); - RNA_def_property_ui_text(prop, "Codec", "FFmpeg codec to use"); + RNA_def_property_ui_text(prop, "Video Codec", "FFmpeg codec to use for video output"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_FFmpegSettings_codec_settings_update"); prop = RNA_def_property(srna, "video_bitrate", PROP_INT, PROP_NONE); @@ -5621,7 +5618,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) RNA_def_property_enum_bitflag_sdna(prop, NULL, "ffmpeg_preset"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_enum_items(prop, ffmpeg_preset_items); - RNA_def_property_enum_default(prop, FFM_PRESET_MEDIUM); + RNA_def_property_enum_default(prop, FFM_PRESET_GOOD); RNA_def_property_ui_text(prop, "Encoding speed", "Tradeoff between encoding speed and compression ratio"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); @@ -6370,7 +6367,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "use_stamp_date", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_DATE); - RNA_def_property_ui_text(prop, "Stamp Date", "Include the current date in image metadata"); + RNA_def_property_ui_text(prop, "Stamp Date", "Include the current date in image/video metadata"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_stamp_frame", PROP_BOOLEAN, PROP_NONE); @@ -6378,6 +6375,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Stamp Frame", "Include the frame number in image metadata"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "use_stamp_frame_range", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_FRAME_RANGE); + RNA_def_property_ui_text(prop, "Stamp Frame", "Include the rendered frame range in image/video metadata"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "use_stamp_camera", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_CAMERA); RNA_def_property_ui_text(prop, "Stamp Camera", "Include the name of the active camera in image metadata"); @@ -6390,12 +6392,12 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "use_stamp_scene", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_SCENE); - RNA_def_property_ui_text(prop, "Stamp Scene", "Include the name of the active scene in image metadata"); + RNA_def_property_ui_text(prop, "Stamp Scene", "Include the name of the active scene in image/video metadata"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_stamp_note", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_NOTE); - RNA_def_property_ui_text(prop, "Stamp Note", "Include a custom note in image metadata"); + RNA_def_property_ui_text(prop, "Stamp Note", "Include a custom note in image/video metadata"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_stamp_marker", PROP_BOOLEAN, PROP_NONE); @@ -6405,7 +6407,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "use_stamp_filename", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_FILENAME); - RNA_def_property_ui_text(prop, "Stamp Filename", "Include the .blend filename in image metadata"); + RNA_def_property_ui_text(prop, "Stamp Filename", "Include the .blend filename in image/video metadata"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_stamp_sequencer_strip", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index cfd6d0c6db3..33621af69af 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -38,10 +38,11 @@ #include "BLT_translation.h" #include "BKE_animsys.h" -#include "BKE_global.h" #include "BKE_sequencer.h" #include "BKE_sound.h" +#include "IMB_metadata.h" + #include "MEM_guardedalloc.h" #include "RNA_access.h" @@ -588,6 +589,27 @@ static IDProperty *rna_Sequence_idprops(PointerRNA *ptr, bool create) return seq->prop; } +static PointerRNA rna_MovieSequence_metadata_get(Sequence *seq) +{ + if (seq == NULL || seq->anims.first == NULL) { + return PointerRNA_NULL; + } + + StripAnim *sanim = seq->anims.first; + if (sanim->anim == NULL) { + return PointerRNA_NULL; + } + + IDProperty *metadata = IMB_anim_load_metadata(sanim->anim); + if (metadata == NULL) { + return PointerRNA_NULL; + } + + PointerRNA ptr; + RNA_pointer_create(NULL, &RNA_IDPropertyWrapPtr, metadata, &ptr); + return ptr; +} + static PointerRNA rna_SequenceEditor_meta_stack_get(CollectionPropertyIterator *iter) { ListBaseIterator *internal = &iter->internal.listbase; @@ -1964,7 +1986,9 @@ static void rna_def_movie(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - + FunctionRNA *func; + PropertyRNA *parm; + srna = RNA_def_struct(brna, "MovieSequence", "Sequence"); RNA_def_struct_ui_text(srna, "Movie Sequence", "Sequence strip to load a video"); RNA_def_struct_sdna(srna, "Sequence"); @@ -1996,6 +2020,14 @@ static void rna_def_movie(BlenderRNA *brna) "rna_Sequence_filepath_set"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_filepath_update"); + /* metadata */ + func = RNA_def_function(srna, "metadata", "rna_MovieSequence_metadata_get"); + RNA_def_function_ui_description(func, "Retrieve metadata of the movie file"); + /* return type */ + parm = RNA_def_pointer(func, "metadata", "IDPropertyWrapPtr", "", "Dict-like object containing the metadata"); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); + RNA_def_function_return(func, parm); + /* multiview */ prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_VIEWS); diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index 3bfe1fbcb83..38c297def32 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -905,7 +905,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3); RNA_def_property_ui_text(prop, "Clipping", - "Value under which voxels are considered empty space to optimize caching or rendering"); + "Value under which voxels are considered empty space to optimize caching or rendering"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); } diff --git a/source/blender/makesrna/intern/rna_text_api.c b/source/blender/makesrna/intern/rna_text_api.c index 0287f74587b..d7a862fecbc 100644 --- a/source/blender/makesrna/intern/rna_text_api.c +++ b/source/blender/makesrna/intern/rna_text_api.c @@ -40,13 +40,13 @@ static void rna_Text_clear(Text *text) { - BKE_text_clear(text); + BKE_text_clear(text, NULL); WM_main_add_notifier(NC_TEXT | NA_EDITED, text); } static void rna_Text_write(Text *text, const char *str) { - BKE_text_write(text, str); + BKE_text_write(text, NULL, str); WM_main_add_notifier(NC_TEXT | NA_EDITED, text); } diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index d2d82ca23d2..72122fae6b4 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -81,14 +81,6 @@ static void copyData(ModifierData *md, ModifierData *target) modifier_copyData_generic(md, target); } -static void freeData(ModifierData *md) -{ - DisplaceModifierData *dmd = (DisplaceModifierData *) md; - if (dmd->texture) { - id_us_min(&dmd->texture->id); - } -} - static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) { DisplaceModifierData *dmd = (DisplaceModifierData *)md; @@ -444,7 +436,7 @@ ModifierTypeInfo modifierType_Displace = { /* applyModifierEM */ NULL, /* initData */ initData, /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, + /* freeData */ NULL, /* isDisabled */ isDisabled, /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c index 65f45c9af64..72c44121e0b 100644 --- a/source/blender/modifiers/intern/MOD_fluidsim_util.c +++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c @@ -48,7 +48,9 @@ #include "BKE_fluidsim.h" /* ensure definitions here match */ #include "BKE_cdderivedmesh.h" -#include "BKE_global.h" /* G.main->name only */ +#ifdef WITH_MOD_FLUID +# include "BKE_global.h" +#endif #include "MOD_fluidsim_util.h" #include "MOD_modifiertypes.h" diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index 793edf7c370..04de6fae336 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -33,7 +33,6 @@ #include "BKE_cachefile.h" #include "BKE_DerivedMesh.h" #include "BKE_cdderivedmesh.h" -#include "BKE_global.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_scene.h" @@ -45,6 +44,7 @@ #ifdef WITH_ALEMBIC # include "ABC_alembic.h" +# include "BKE_global.h" #endif static void initData(ModifierData *md) @@ -75,10 +75,6 @@ static void freeData(ModifierData *md) { MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; - if (mcmd->cache_file) { - id_us_min(&mcmd->cache_file->id); - } - if (mcmd->reader) { #ifdef WITH_ALEMBIC CacheReader_free(mcmd->reader); diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index d1c457526c2..82c6b82d492 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -44,7 +44,6 @@ #include "BKE_cdderivedmesh.h" #include "BKE_effect.h" -#include "BKE_global.h" #include "BKE_lattice.h" #include "BKE_library_query.h" #include "BKE_modifier.h" diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index 0c3781acb19..8fe29c78486 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -78,14 +78,6 @@ static void initData(ModifierData *md) wmd->defgrp_name[0] = 0; } -static void freeData(ModifierData *md) -{ - WaveModifierData *wmd = (WaveModifierData *) md; - if (wmd->texture) { - id_us_min(&wmd->texture->id); - } -} - static void copyData(ModifierData *md, ModifierData *target) { #if 0 @@ -383,7 +375,7 @@ ModifierTypeInfo modifierType_Wave = { /* applyModifierEM */ NULL, /* initData */ initData, /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, + /* freeData */ NULL, /* isDisabled */ NULL, /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index aeb3df42622..8d77747b45d 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -79,10 +79,6 @@ static void freeData(ModifierData *md) { WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md; curvemapping_free(wmd->cmap_curve); - - if (wmd->mask_texture) { - id_us_min(&wmd->mask_texture->id); - } } static void copyData(ModifierData *md, ModifierData *target) diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index 032e154e096..bd1f58e7d5e 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -126,14 +126,6 @@ static void initData(ModifierData *md) wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL; } -static void freeData(ModifierData *md) -{ - WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md; - if (wmd->mask_texture) { - id_us_min(&wmd->mask_texture->id); - } -} - static void copyData(ModifierData *md, ModifierData *target) { #if 0 @@ -427,7 +419,7 @@ ModifierTypeInfo modifierType_WeightVGMix = { /* applyModifierEM */ NULL, /* initData */ initData, /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, + /* freeData */ NULL, /* isDisabled */ isDisabled, /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index cbc62cdace5..09991887f69 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -286,14 +286,6 @@ static void initData(ModifierData *md) wmd->max_dist = 1.0f; /* vert arbitrary distance, but don't use 0 */ } -static void freeData(ModifierData *md) -{ - WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; - if (wmd->mask_texture) { - id_us_min(&wmd->mask_texture->id); - } -} - static void copyData(ModifierData *md, ModifierData *target) { #if 0 @@ -616,7 +608,7 @@ ModifierTypeInfo modifierType_WeightVGProximity = { /* applyModifierEM */ NULL, /* initData */ initData, /* requiredDataMask */ requiredDataMask, - /* freeData */ freeData, + /* freeData */ NULL, /* isDisabled */ isDisabled, /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, diff --git a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c index 3c165cfcb8a..74e23aed7de 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c +++ b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c @@ -202,7 +202,7 @@ void register_node_type_sh_vect_transform(void) { static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_VECT_TRANSFORM, "Vector Transform", NODE_CLASS_CONVERTOR, 0); + sh_node_type_base(&ntype, SH_NODE_VECT_TRANSFORM, "Vector Transform", NODE_CLASS_OP_VECTOR, 0); node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING); node_type_init(&ntype, node_shader_init_vect_transform); node_type_socket_templates(&ntype, sh_node_vect_transform_in, sh_node_vect_transform_out); diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c index f9a481e6c7e..e85fec1ec9d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c @@ -41,7 +41,7 @@ static bNodeSocketTemplate sh_node_volume_principled_in[] = { { SOCK_FLOAT, 1, N_("Blackbody Intensity"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, { SOCK_RGBA, 1, N_("Blackbody Tint"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f}, { SOCK_FLOAT, 1, N_("Temperature"), 1000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 6500.0f}, - { SOCK_STRING, 1, N_("Temperature Attribute"),0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_STRING, 1, N_("Temperature Attribute"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { -1, 0, "" } }; diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c index d676b1a1521..0fdc1d86d5c 100644 --- a/source/blender/physics/intern/implicit_blender.c +++ b/source/blender/physics/intern/implicit_blender.c @@ -48,7 +48,6 @@ #include "BKE_cloth.h" #include "BKE_collision.h" #include "BKE_effect.h" -#include "BKE_global.h" #include "BPH_mass_spring.h" diff --git a/source/blender/python/BPY_extern_clog.h b/source/blender/python/BPY_extern_clog.h new file mode 100644 index 00000000000..fbe7139ba1b --- /dev/null +++ b/source/blender/python/BPY_extern_clog.h @@ -0,0 +1,35 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BPY_extern_clog.h + * \ingroup python + * + * Logging defines. + */ + +#ifndef __BPY_EXTERN_CLOG_H__ +#define __BPY_EXTERN_CLOG_H__ + + +/* bpy_interface.c */ +extern struct CLG_LogRef *BPY_LOG_RNA; +extern struct CLG_LogRef *BPY_LOG_CONTEXT; + +#endif /* __BPY_EXTERN_CLOG_H__ */ diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index 36609c6f29b..6f265b2ae87 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -38,6 +38,8 @@ #include "python_utildefines.h" +#include "BLI_string.h" + #ifndef MATH_STANDALONE /* only for BLI_strncpy_wchar_from_utf8, should replace with py funcs but too late in release now */ #include "BLI_string_utf8.h" @@ -144,6 +146,15 @@ PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len) return tuple; } +PyObject *PyC_Tuple_PackArray_F64(const double *array, uint len) +{ + PyObject *tuple = PyTuple_New(len); + for (uint i = 0; i < len; i++) { + PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array[i])); + } + return tuple; +} + PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len) { PyObject *tuple = PyTuple_New(len); @@ -225,22 +236,49 @@ int PyC_ParseBool(PyObject *o, void *p) /* for debugging */ void PyC_ObSpit(const char *name, PyObject *var) { + const char *null_str = "<null>"; fprintf(stderr, "<%s> : ", name); if (var == NULL) { - fprintf(stderr, "<NIL>"); + fprintf(stderr, "%s\n", null_str); } else { PyObject_Print(var, stderr, 0); - fprintf(stderr, " ref:%d ", (int)var->ob_refcnt); - fprintf(stderr, " ptr:%p", (void *)var); - - fprintf(stderr, " type:"); - if (Py_TYPE(var)) - fprintf(stderr, "%s", Py_TYPE(var)->tp_name); - else - fprintf(stderr, "<NIL>"); + const PyTypeObject *type = Py_TYPE(var); + fprintf(stderr, + " ref:%d, ptr:%p, type: %s\n", + (int)var->ob_refcnt, (void *)var, type ? type->tp_name : null_str); + } +} + +/** + * A version of #PyC_ObSpit that writes into a string (and doesn't take a name argument). + * Use for logging. + */ +void PyC_ObSpitStr(char *result, size_t result_len, PyObject *var) +{ + /* No name, creator of string can manage that. */ + const char *null_str = "<null>"; + if (var == NULL) { + BLI_snprintf(result, result_len, "%s", null_str); + } + else { + const PyTypeObject *type = Py_TYPE(var); + PyObject *var_str = PyObject_Repr(var); + if (var_str == NULL) { + /* We could print error here, but this may be used for generating errors - so don't for now. */ + PyErr_Clear(); + } + BLI_snprintf( + result, result_len, + " ref=%d, ptr=%p, type=%s, value=%.200s", + (int)var->ob_refcnt, + (void *)var, + type ? type->tp_name : null_str, + var_str ? _PyUnicode_AsString(var_str) : "<error>"); + if (var_str != NULL) { + Py_DECREF(var_str); + } } - fprintf(stderr, "\n"); } void PyC_LineSpit(void) diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h index 25c88799027..fe7a046d99c 100644 --- a/source/blender/python/generic/py_capi_utils.h +++ b/source/blender/python/generic/py_capi_utils.h @@ -31,6 +31,7 @@ #include "BLI_utildefines_variadic.h" void PyC_ObSpit(const char *name, PyObject *var); +void PyC_ObSpitStr(char *result, size_t result_len, PyObject *var); void PyC_LineSpit(void); void PyC_StackSpit(void); PyObject * PyC_ExceptionBuffer(void); @@ -50,12 +51,15 @@ int PyC_AsArray( const PyTypeObject *type, const bool is_double, const char *error_prefix); PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len); +PyObject *PyC_Tuple_PackArray_F64(const double *array, uint len); PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len); PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len); PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len); #define PyC_Tuple_Pack_F32(...) \ PyC_Tuple_PackArray_F32(((const float []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) +#define PyC_Tuple_Pack_F64(...) \ + PyC_Tuple_PackArray_F64(((const double []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) #define PyC_Tuple_Pack_I32(...) \ PyC_Tuple_PackArray_I32(((const int []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) #define PyC_Tuple_Pack_I32FromBool(...) \ diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index 2b6dc54dad4..ae16bd4a145 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -23,7 +23,7 @@ # # ***** END GPL LICENSE BLOCK ***** -set(INC +set(INC .. ../../blenkernel ../../blenlib @@ -35,9 +35,10 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/cycles/blender - ../../../../intern/opencolorio + ../../../../intern/clog ../../../../intern/guardedalloc + ../../../../intern/opencolorio + ../../../../intern/cycles/blender ) set(INC_SYS @@ -111,6 +112,7 @@ set(SRC bpy_utils_units.h gpu.h ../BPY_extern.h + ../BPY_extern_clog.h ) # only to check if buildinfo is available diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index ae8e35ae3fc..99f87c61c5a 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -33,6 +33,8 @@ #include "MEM_guardedalloc.h" +#include "CLG_log.h" + #include "BLI_utildefines.h" #include "BLI_path_util.h" #include "BLI_fileops.h" @@ -75,6 +77,9 @@ #include "../bmesh/bmesh_py_api.h" #include "../mathutils/mathutils.h" +/* Logging types to use anywhere in the Python modules. */ +CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_CONTEXT, "bpy.context"); +CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_RNA, "bpy.rna"); /* for internal use, when starting and ending python scripts */ @@ -800,8 +805,9 @@ int BPY_context_member_get(bContext *C, const char *member, bContextDataResult * CTX_data_list_add(result, ptr->id.data, ptr->type, ptr->data); } else { - printf("PyContext: '%s' list item not a valid type in sequece type '%s'\n", - member, Py_TYPE(item)->tp_name); + CLOG_INFO(BPY_LOG_CONTEXT, 1, + "'%s' list item not a valid type in sequence type '%s'", + member, Py_TYPE(item)->tp_name); } } @@ -813,16 +819,14 @@ int BPY_context_member_get(bContext *C, const char *member, bContextDataResult * if (done == false) { if (item) { - printf("PyContext '%s' not a valid type\n", member); + CLOG_INFO(BPY_LOG_CONTEXT, 1, "'%s' not a valid type", member); } else { - printf("PyContext '%s' not found\n", member); + CLOG_INFO(BPY_LOG_CONTEXT, 1, "'%s' not found\n", member); } } else { - if (G.debug & G_DEBUG_PYTHON) { - printf("PyContext '%s' found\n", member); - } + CLOG_INFO(BPY_LOG_CONTEXT, 2, "'%s' found", member); } if (use_gil) diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 87260d6e786..baaae066b4b 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -45,6 +45,7 @@ #include "BLI_utildefines.h" #include "BPY_extern.h" +#include "BPY_extern_clog.h" #include "bpy_rna.h" #include "bpy_rna_anim.h" @@ -61,6 +62,8 @@ #include "RNA_define.h" /* RNA_def_property_free_identifier */ #include "RNA_access.h" +#include "CLG_log.h" + #include "MEM_guardedalloc.h" #include "BKE_main.h" @@ -1418,10 +1421,11 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val) const char *ptr_name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL); /* prefer not fail silently in case of api errors, maybe disable it later */ - printf("RNA Warning: Current value \"%d\" " - "matches no enum in '%s', '%s', '%s'\n", - val, RNA_struct_identifier(ptr->type), - ptr_name, RNA_property_identifier(prop)); + CLOG_WARN(BPY_LOG_RNA, + "current value '%d' " + "matches no enum in '%s', '%s', '%s'", + val, RNA_struct_identifier(ptr->type), + ptr_name, RNA_property_identifier(prop)); #if 0 /* gives python decoding errors while generating docs :( */ char error_str[256]; @@ -6596,7 +6600,7 @@ static PyObject *pyrna_srna_ExternalType(StructRNA *srna) if (bpy_types == NULL) { PyErr_Print(); PyErr_Clear(); - fprintf(stderr, "%s: failed to find 'bpy_types' module\n", __func__); + CLOG_ERROR(BPY_LOG_RNA, "failed to find 'bpy_types' module"); return NULL; } bpy_types_dict = PyModule_GetDict(bpy_types); /* borrow */ @@ -6614,20 +6618,22 @@ static PyObject *pyrna_srna_ExternalType(StructRNA *srna) PyObject *tp_slots = PyDict_GetItem(((PyTypeObject *)newclass)->tp_dict, bpy_intern_str___slots__); if (tp_slots == NULL) { - fprintf(stderr, "%s: expected class '%s' to have __slots__ defined\n\nSee bpy_types.py\n", __func__, idname); + CLOG_ERROR(BPY_LOG_RNA, "expected class '%s' to have __slots__ defined, see bpy_types.py", idname); newclass = NULL; } else if (PyTuple_GET_SIZE(tp_bases)) { PyObject *base = PyTuple_GET_ITEM(tp_bases, 0); if (base_compare != base) { - fprintf(stderr, "%s: incorrect subclassing of SRNA '%s'\nSee bpy_types.py\n", __func__, idname); - PyC_ObSpit("Expected! ", base_compare); + char pyob_info[256]; + PyC_ObSpitStr(pyob_info, sizeof(pyob_info), base_compare); + CLOG_ERROR(BPY_LOG_RNA, + "incorrect subclassing of SRNA '%s', expected '%s', see bpy_types.py", + idname, pyob_info); newclass = NULL; } else { - if (G.debug & G_DEBUG_PYTHON) - fprintf(stderr, "SRNA Subclassed: '%s'\n", idname); + CLOG_INFO(BPY_LOG_RNA, 2, "SRNA sub-classed: '%s'", idname); } } } @@ -6725,7 +6731,7 @@ static PyObject *pyrna_srna_Subtype(StructRNA *srna) } else { /* this should not happen */ - printf("%s: error registering '%s'\n", __func__, idname); + CLOG_ERROR(BPY_LOG_RNA, "failed to register '%s'", idname); PyErr_Print(); PyErr_Clear(); } @@ -6791,7 +6797,7 @@ PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr) Py_DECREF(tp); /* srna owns, cant hold a ref */ } else { - fprintf(stderr, "%s: could not make type\n", __func__); + CLOG_WARN(BPY_LOG_RNA, "could not make type '%s'", RNA_struct_identifier(ptr->type)); pyrna = (BPy_StructRNA *) PyObject_GC_New(BPy_StructRNA, &pyrna_struct_Type); #ifdef USE_WEAKREFS pyrna->in_weakreflist = NULL; @@ -7597,8 +7603,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param py_class = RNA_struct_py_type_get(ptr->type); /* rare case. can happen when registering subclasses */ if (py_class == NULL) { - fprintf(stderr, "%s: unable to get python class for rna struct '%.200s'\n", - __func__, RNA_struct_identifier(ptr->type)); + CLOG_WARN(BPY_LOG_RNA, "unable to get Python class for rna struct '%.200s'", RNA_struct_identifier(ptr->type)); return -1; } diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c index e0ca3634261..ed9d1e9c0e5 100644 --- a/source/blender/python/intern/bpy_rna_array.c +++ b/source/blender/python/intern/bpy_rna_array.c @@ -28,6 +28,8 @@ #include <Python.h> +#include "CLG_log.h" + #include "BLI_utildefines.h" #include "RNA_types.h" @@ -39,6 +41,8 @@ #include "RNA_access.h" +#include "BPY_extern_clog.h" + #include "../generic/py_capi_utils.h" #define USE_MATHUTILS @@ -785,8 +789,7 @@ PyObject *pyrna_py_from_array_index(BPy_PropertyArrayRNA *self, PointerRNA *ptr, len = RNA_property_multi_array_length(ptr, prop, arraydim); if (index >= len || index < 0) { /* this shouldn't happen because higher level funcs must check for invalid index */ - if (G.debug & G_DEBUG_PYTHON) - printf("%s: invalid index %d for array with length=%d\n", __func__, index, len); + CLOG_WARN(BPY_LOG_RNA, "invalid index %d for array with length=%d", index, len); PyErr_SetString(PyExc_IndexError, "out of range"); return NULL; diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c index 9492b6d67f3..026384743bd 100644 --- a/source/blender/python/mathutils/mathutils_Euler.c +++ b/source/blender/python/mathutils/mathutils_Euler.c @@ -689,6 +689,8 @@ PyDoc_STRVAR(euler_doc, "\n" " This object gives access to Eulers in Blender.\n" "\n" +" .. seealso:: `Euler angles <https://en.wikipedia.org/wiki/Euler_angles>`__ on Wikipedia.\n" +"\n" " :param angles: Three angles, in radians.\n" " :type angles: 3d vector\n" " :param order: Optional order of the angles, a permutation of ``XYZ``.\n" diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index e17a503cd4e..67c87d5d9b8 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -84,6 +84,7 @@ #include "IMB_colormanagement.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "IMB_metadata.h" #include "RE_engine.h" #include "RE_pipeline.h" @@ -3349,7 +3350,7 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen if (!rr) return false; - bool is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2; + bool is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2; bool is_exr_rr = ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && RE_HasFloatPixels(rr); @@ -3466,7 +3467,7 @@ bool RE_WriteRenderViewsMovie( if (!rr) return false; - is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2; + is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2; if (is_mono || (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) { int view_id; @@ -4067,7 +4068,7 @@ bool RE_WriteEnvmapResult(struct ReportList *reports, Scene *scene, EnvMap *env, /* Used in the interface to decide whether to show layers or passes. */ bool RE_layers_have_name(struct RenderResult *rr) { - switch (BLI_listbase_count_ex(&rr->layers, 2)) { + switch (BLI_listbase_count_at_most(&rr->layers, 2)) { case 0: return false; case 1: diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index 542c737348b..25377fb4f7e 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -753,7 +753,7 @@ void render_result_views_new(RenderResult *rr, RenderData *rd) } /* we always need at least one view */ - if (BLI_listbase_count_ex(&rr->views, 1) == 0) { + if (BLI_listbase_count_at_most(&rr->views, 1) == 0) { render_result_view_new(rr, ""); } } diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 9e877a83b3e..8be7555b34a 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -61,6 +61,7 @@ #include "wm.h" #include "ED_screen.h" +#include "BKE_undo_system.h" #ifdef WITH_PYTHON #include "BPY_extern.h" @@ -485,7 +486,12 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm) WM_drag_free_list(&wm->drags); wm_reports_free(wm); - + + if (wm->undo_stack) { + BKE_undosys_stack_destroy(wm->undo_stack); + wm->undo_stack = NULL; + } + if (C && CTX_wm_manager(C) == wm) CTX_wm_manager_set(C, NULL); } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index b2df53321c0..4f441c293c4 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -67,6 +67,7 @@ #include "ED_screen.h" #include "ED_view3d.h" #include "ED_util.h" +#include "ED_undo.h" #include "RNA_access.h" diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index e0b57effbe9..da5ebd7abcd 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -87,9 +87,11 @@ #include "BKE_sound.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "BKE_undo_system.h" #include "BLO_readfile.h" #include "BLO_writefile.h" +#include "BLO_undofile.h" /* to save from an undo memfile */ #include "RNA_access.h" #include "RNA_define.h" @@ -103,6 +105,7 @@ #include "ED_screen.h" #include "ED_view3d.h" #include "ED_util.h" +#include "ED_undo.h" #include "GHOST_C-api.h" #include "GHOST_Path-api.h" @@ -522,9 +525,13 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo } if (!G.background) { -// undo_editmode_clear(); - BKE_undo_reset(); - BKE_undo_write(C, "original"); /* save current state */ + if (wm->undo_stack == NULL) { + wm->undo_stack = BKE_undosys_stack_create(); + } + else { + BKE_undosys_stack_clear(wm->undo_stack); + } + BKE_undosys_stack_init_from_main(wm->undo_stack, CTX_data_main(C)); } } @@ -596,10 +603,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) success = true; } -#if 0 - else if (retval == BKE_READ_EXOTIC_OK_OTHER) - BKE_undo_write(C, "Import file"); -#endif else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) { BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath, errno ? strerror(errno) : TIP_("unable to open the file")); @@ -1271,7 +1274,10 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w if (U.uiflag & USER_GLOBALUNDO) { /* fast save of last undobuffer, now with UI */ - BKE_undo_save_file(filepath); + struct MemFile *memfile = ED_undosys_stack_memfile_get_active(wm->undo_stack); + if (memfile) { + BLO_memfile_write_file(memfile, filepath); + } } else { /* save as regular blend file */ diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 2743216ee07..52682523212 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -55,6 +55,7 @@ #include "BLI_utildefines.h" #include "BLO_writefile.h" +#include "BLO_undofile.h" #include "BKE_blender.h" #include "BKE_blender_undo.h" @@ -112,6 +113,7 @@ #include "ED_space_api.h" #include "ED_screen.h" #include "ED_util.h" +#include "ED_undo.h" #include "UI_interface.h" #include "BLF_api.h" @@ -149,11 +151,6 @@ static void wm_free_reports(bContext *C) BKE_reports_clear(reports); } -static void wm_undo_kill_callback(bContext *C) -{ - WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C)); -} - bool wm_start_with_console = false; /* used in creator.c */ /* only called once, for startup */ @@ -172,7 +169,7 @@ void WM_init(bContext *C, int argc, const char **argv) WM_menutype_init(); WM_uilisttype_init(); - BKE_undo_callback_wm_kill_jobs_set(wm_undo_kill_callback); + ED_undosys_type_init(); BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */ BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */ @@ -478,7 +475,8 @@ void WM_exit_ext(bContext *C, const bool do_python) wmWindow *win; if (!G.background) { - if ((U.uiflag2 & USER_KEEP_SESSION) || BKE_undo_is_valid(NULL)) { + struct MemFile *undo_memfile = wm->undo_stack ? ED_undosys_stack_memfile_get_active(wm->undo_stack) : NULL; + if ((U.uiflag2 & USER_KEEP_SESSION) || (undo_memfile != NULL)) { /* save the undo state as quit.blend */ char filename[FILE_MAX]; bool has_edited; @@ -489,7 +487,7 @@ void WM_exit_ext(bContext *C, const bool do_python) has_edited = ED_editors_flush_edits(C, false); if ((has_edited && BLO_write_file(CTX_data_main(C), filename, fileflags, NULL, NULL)) || - BKE_undo_save_file(filename)) + (undo_memfile && BLO_memfile_write_file(undo_memfile, filename))) { printf("Saved session recovery to '%s'\n", filename); } @@ -512,11 +510,13 @@ void WM_exit_ext(bContext *C, const bool do_python) wm_dropbox_free(); WM_menutype_free(); WM_uilisttype_free(); - + /* all non-screen and non-space stuff editors did, like editmode */ if (C) ED_editors_exit(C); + ED_undosys_type_free(); + // XXX // BIF_GlobalReebFree(); // BIF_freeRetarget(); @@ -594,8 +594,6 @@ void WM_exit_ext(bContext *C, const bool do_python) GPU_exit(); } - BKE_undo_reset(); - ED_file_exit(); /* for fsmenu */ UI_exit(); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index b05b2596719..f46358f83cf 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -96,7 +96,7 @@ #include "ED_numinput.h" #include "ED_screen.h" -#include "ED_util.h" +#include "ED_undo.h" #include "ED_view3d.h" #include "GPU_basic_shader.h" diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 0bfe62c7a8e..06bd60e8692 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -342,7 +342,7 @@ static uiBlock *block_create_confirm_quit(struct bContext *C, struct ARegion *ar uiStyle *style = UI_style_get(); uiBlock *block = UI_block_begin(C, ar, "confirm_quit_popup", UI_EMBOSS); - UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP ); + UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT); UI_block_emboss_set(block, UI_EMBOSS); uiLayout *layout = UI_block_layout( diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index d4af3cd6b09..1baae1864bf 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -715,16 +715,19 @@ static int arg_handle_background_mode_set(int UNUSED(argc), const char **UNUSED( static const char arg_handle_log_level_set_doc[] = "<level>\n" "\n" -"\tSet the logging verbosity level (higher for more details) defaults to 1." +"\tSet the logging verbosity level (higher for more details) defaults to 1, use -1 to log all levels." ; static int arg_handle_log_level_set(int argc, const char **argv, void *UNUSED(data)) { const char *arg_id = "--log-level"; if (argc > 1) { const char *err_msg = NULL; - if (!parse_int_clamp(argv[1], NULL, 0, INT_MAX, &G.log.level, &err_msg)) { + if (!parse_int_clamp(argv[1], NULL, -1, INT_MAX, &G.log.level, &err_msg)) { printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]); } + if (G.log.level == -1) { + G.log.level = INT_MAX; + } return 1; } else { diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c index 81e6178c502..feb108da289 100644 --- a/source/creator/creator_signals.c +++ b/source/creator/creator_signals.c @@ -64,6 +64,7 @@ #include "BKE_main.h" #include "BKE_report.h" + /* for passing information between creator and gameengine */ #ifdef WITH_GAMEENGINE # include "BL_System.h" @@ -75,6 +76,12 @@ #include "creator_intern.h" /* own include */ +// #define USE_WRITE_CRASH_BLEND +#ifdef USE_WRITE_CRASH_BLEND +# include "BKE_undo_system.h" +# include "BLO_undofile.h" +#endif + /* set breakpoints here when running in debug mode, useful to catch floating point errors */ #if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE) static void sig_handle_fpe(int UNUSED(sig)) @@ -110,29 +117,32 @@ static void sig_handle_crash_backtrace(FILE *fp) static void sig_handle_crash(int signum) { + wmWindowManager *wm = G.main->wm.first; -#if 0 - { - char fname[FILE_MAX]; +#ifdef USE_WRITE_CRASH_BLEND + if (wm->undo_stack) { + struct MemFile *memfile = BKE_undosys_stack_memfile_get_active(wm->undo_stack); + if (memfile) { + char fname[FILE_MAX]; - if (!G.main->name[0]) { - BLI_make_file_string("/", fname, BKE_tempdir_base(), "crash.blend"); - } - else { - BLI_strncpy(fname, G.main->name, sizeof(fname)); - BLI_replace_extension(fname, sizeof(fname), ".crash.blend"); - } + if (!G.main->name[0]) { + BLI_make_file_string("/", fname, BKE_tempdir_base(), "crash.blend"); + } + else { + BLI_strncpy(fname, G.main->name, sizeof(fname)); + BLI_replace_extension(fname, sizeof(fname), ".crash.blend"); + } - printf("Writing: %s\n", fname); - fflush(stdout); + printf("Writing: %s\n", fname); + fflush(stdout); - BKE_undo_save_file(fname); + BLO_memfile_write_file(memfile, fname); + } } #endif FILE *fp; char header[512]; - wmWindowManager *wm = G.main->wm.first; char fname[FILE_MAX]; @@ -338,4 +348,4 @@ void main_signal_setup_fpe(void) #endif } -#endif /* WITH_PYTHON_MODULE */
\ No newline at end of file +#endif /* WITH_PYTHON_MODULE */ diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 8ba39e288ca..a12437befaa 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -1540,7 +1540,7 @@ static KX_GameObject *gameobject_from_blenderobject( gameobj->AddMesh(meshobj); // gather levels of detail - if (BLI_listbase_count_ex(&ob->lodlevels, 2) > 1) { + if (BLI_listbase_count_at_most(&ob->lodlevels, 2) > 1) { LodLevel *lod = ((LodLevel*)ob->lodlevels.first)->next; Mesh* lodmesh = mesh; Object* lodmatob = ob; |