[Bf-blender-cvs] [235941fe91d] greasepencil-object: Merge branch 'patch/gpencil-update-on-write' into patch/gpencil-undo-system

Falk David noreply at git.blender.org
Mon Feb 7 18:35:14 CET 2022


Commit: 235941fe91daf5efc322d75a5e1f175071a23d06
Author: Falk David
Date:   Thu Feb 3 12:30:07 2022 +0100
Branches: greasepencil-object
https://developer.blender.org/rB235941fe91daf5efc322d75a5e1f175071a23d06

Merge branch 'patch/gpencil-update-on-write' into patch/gpencil-undo-system

===================================================================



===================================================================

diff --cc source/blender/editors/gpencil/gpencil_undo.c
index bf9d9d4ee80,ec70febc80c..86b1e5e9f7c
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@@ -192,418 -190,3 +192,418 @@@ void gpencil_undo_finish(void
  
    cur_node = NULL;
  }
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Implements ED Undo System
 + * \{ */
 +
 +typedef struct GPencilUndoData {
 +  GPencilUpdateCache *gpd_cache_data;
 +  /* Scene frame for this step. */
 +  int cfra;
 +  /* Store the grease pencil mode we are in. */
 +  eObjectMode mode;
 +} GPencilUndoData;
 +
 +typedef struct GPencilUndoStep {
 +  UndoStep step;
 +  GPencilUndoData *undo_data;
 +} GPencilUndoStep;
 +
 +static bool change_gpencil_mode(bContext *C, Object *ob, eObjectMode mode)
 +{
 +  if (ob->mode == mode) {
 +    return false;
 +  }
 +  bGPdata *gpd = (bGPdata *)ob->data;
 +  ob->mode = mode;
 +  ED_gpencil_setup_modes(C, gpd, mode);
 +
 +  return true;
 +}
 +
 +static void gpencil_data_to_undo_data(bGPdata *gpd, GPencilUndoData *gpd_undo_data)
 +{
 +  GPencilUpdateCache *update_cache = gpd->runtime.update_cache;
 +
 +  if (update_cache == NULL) {
 +    /* Need a full-copy of the grease pencil undo_data. */
 +    bGPdata *gpd_copy = NULL;
 +    BKE_gpencil_data_duplicate(NULL, gpd, &gpd_copy);
 +    gpd_copy->id.session_uuid = gpd->id.session_uuid;
 +
 +    gpd_undo_data->gpd_cache_data = BKE_gpencil_create_update_cache(gpd_copy, true);
 +  }
 +  else {
 +    gpd_undo_data->gpd_cache_data = BKE_gpencil_duplicate_update_cache_and_data(update_cache);
 +  }
 +}
 +
 +typedef struct tGPencilUpdateCacheUndoTraverseData {
 +  bGPdata *gpd;
 +  bGPDlayer *gpl;
 +  bGPDframe *gpf;
 +  bGPDstroke *gps;
 +  int gpl_index;
 +  int gpf_index;
 +  int gps_index;
 +  bool tag_update_cache;
 +} tGPencilUpdateCacheUndoTraverseData;
 +
 +static bool gpencil_decode_undo_data_layer_cb(GPencilUpdateCache *gpl_cache, void *user_data)
 +{
 +  tGPencilUpdateCacheUndoTraverseData *td = (tGPencilUpdateCacheUndoTraverseData *)user_data;
 +  td->gpl = BLI_findlinkfrom((Link *)td->gpl, gpl_cache->index - td->gpl_index);
 +  td->gpl_index = gpl_cache->index;
 +  bGPDlayer *gpl_new = (bGPDlayer *)gpl_cache->data;
 +
 +  if (gpl_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
 +    /* Do a full copy of the layer. */
 +    bGPDlayer *gpl_next = td->gpl->next;
 +    BKE_gpencil_layer_delete(td->gpd, td->gpl);
 +
 +    td->gpl = BKE_gpencil_layer_duplicate(gpl_new, true, true);
 +    BLI_insertlinkbefore(&td->gpd->layers, gpl_next, td->gpl);
 +
 +    if (td->tag_update_cache) {
 +      /* Tag the layer here. */
 +      BKE_gpencil_tag_full_update(td->gpd, td->gpl, NULL, NULL);
 +    }
 +    return true;
 +  }
 +  else if (gpl_cache->flag == GP_UPDATE_NODE_LIGHT_COPY) {
 +    BKE_gpencil_layer_copy_settings(gpl_new, td->gpl);
 +    if (td->tag_update_cache) {
 +      BKE_gpencil_tag_light_update(td->gpd, td->gpl, NULL, NULL);
 +    }
 +  }
 +
 +  td->gpf = td->gpl->frames.first;
 +  td->gpf_index = 0;
 +  return false;
 +}
 +
 +static bool gpencil_decode_undo_data_frame_cb(GPencilUpdateCache *gpf_cache, void *user_data)
 +{
 +  tGPencilUpdateCacheUndoTraverseData *td = (tGPencilUpdateCacheUndoTraverseData *)user_data;
 +  td->gpf = BLI_findlinkfrom((Link *)td->gpf, gpf_cache->index - td->gpf_index);
 +  td->gpf_index = gpf_cache->index;
 +  bGPDframe *gpf_new = (bGPDframe *)gpf_cache->data;
 +
 +  if (gpf_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
 +    /* Do a full copy of the frame. */
 +    bGPDframe *gpf_next = td->gpf->next;
 +
 +    bool update_actframe = (td->gpl->actframe == td->gpf) ? true : false;
 +    BKE_gpencil_free_strokes(td->gpf);
 +    BLI_freelinkN(&td->gpl->frames, td->gpf);
 +
 +    td->gpf = BKE_gpencil_frame_duplicate(gpf_new, true);
 +    BLI_insertlinkbefore(&td->gpl->frames, gpf_next, td->gpf);
 +
 +    if (update_actframe) {
 +      td->gpl->actframe = td->gpf;
 +    }
 +    if (td->tag_update_cache) {
 +      /* Tag the frame here. */
 +      BKE_gpencil_tag_full_update(td->gpd, td->gpl, td->gpf, NULL);
 +    }
 +    return true;
 +  }
 +  else if (gpf_cache->flag == GP_UPDATE_NODE_LIGHT_COPY) {
 +    BKE_gpencil_frame_copy_settings(gpf_new, td->gpf);
 +    if (td->tag_update_cache) {
 +      BKE_gpencil_tag_light_update(td->gpd, td->gpl, td->gpf, NULL);
 +    }
 +  }
 +
 +  td->gps = td->gpf->strokes.first;
 +  td->gps_index = 0;
 +  return false;
 +}
 +
 +static bool gpencil_decode_undo_data_stroke_cb(GPencilUpdateCache *gps_cache, void *user_data)
 +{
 +  tGPencilUpdateCacheUndoTraverseData *td = (tGPencilUpdateCacheUndoTraverseData *)user_data;
 +  td->gps = BLI_findlinkfrom((Link *)td->gps, gps_cache->index - td->gps_index);
 +  td->gps_index = gps_cache->index;
 +  bGPDstroke *gps_new = (bGPDstroke *)gps_cache->data;
 +
 +  if (gps_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
 +    /* Do a full copy of the stroke. */
 +    bGPDstroke *gps_next = td->gps->next;
 +
 +    BLI_remlink(&td->gpf->strokes, td->gps);
 +    BKE_gpencil_free_stroke(td->gps);
 +
 +    td->gps = BKE_gpencil_stroke_duplicate(gps_new, true, true);
 +    BLI_insertlinkbefore(&td->gpf->strokes, gps_next, td->gps);
 +
 +    if (td->tag_update_cache) {
 +      /* Tag the stroke here. */
 +      BKE_gpencil_tag_full_update(td->gpd, td->gpl, td->gpf, td->gps);
 +    }
 +  }
 +  else if (gps_cache->flag == GP_UPDATE_NODE_LIGHT_COPY) {
 +    BKE_gpencil_stroke_copy_settings(gps_new, td->gps);
 +    if (td->tag_update_cache) {
 +      BKE_gpencil_tag_light_update(td->gpd, td->gpl, td->gpf, td->gps);
 +    }
 +  }
 +  return false;
 +}
 +
 +static bool gpencil_undo_data_to_gpencil_data(GPencilUndoData *gpd_undo_data,
 +                                              bGPdata *gpd,
 +                                              bool tag_gpd_update_cache)
 +{
 +  GPencilUpdateCache *update_cache = gpd_undo_data->gpd_cache_data;
 +
 +  BLI_assert(update_cache != NULL);
 +
 +  if (update_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
 +    /* Full-copy. */
 +    BKE_gpencil_free_data(gpd, true);
 +    BKE_gpencil_data_duplicate(NULL, update_cache->data, &gpd);
 +    if (tag_gpd_update_cache) {
 +      BKE_gpencil_tag_full_update(gpd, NULL, NULL, NULL);
 +    }
 +    return true;
 +  }
 +  else if (update_cache->flag == GP_UPDATE_NODE_LIGHT_COPY) {
 +    BKE_gpencil_data_copy_settings(update_cache->data, gpd);
 +    if (tag_gpd_update_cache) {
 +      BKE_gpencil_tag_light_update(gpd, NULL, NULL, NULL);
 +    }
 +  }
 +
 +  GPencilUpdateCacheTraverseSettings ts = {{
 +      gpencil_decode_undo_data_layer_cb,
 +      gpencil_decode_undo_data_frame_cb,
 +      gpencil_decode_undo_data_stroke_cb,
 +  }};
 +
 +  tGPencilUpdateCacheUndoTraverseData data = {
 +      .gpd = gpd,
 +      .gpl = gpd->layers.first,
 +      .gpf = NULL,
 +      .gps = NULL,
 +      .gpl_index = 0,
 +      .gpf_index = 0,
 +      .gps_index = 0,
 +      .tag_update_cache = tag_gpd_update_cache,
 +  };
 +
 +  BKE_gpencil_traverse_update_cache(update_cache, &ts, &data);
 +
 +  return true;
 +}
 +
 +static bool gpencil_undosys_poll(bContext *C)
 +{
 +  if (!U.experimental.use_gpencil_undo_system) {
 +    return false;
 +  }
 +  bGPdata *gpd = ED_gpencil_data_get_active(C);
 +  return GPENCIL_ANY_MODE(gpd);
 +}
 +
 +static bool gpencil_undosys_step_encode(struct bContext *C,
 +                                        struct Main *UNUSED(bmain),
 +                                        UndoStep *us_p)
 +{
 +  GPencilUndoStep *us = (GPencilUndoStep *)us_p;
 +
 +  UndoStack *undo_stack = ED_undo_stack_get();
 +  Scene *scene = CTX_data_scene(C);
 +  Object *ob = CTX_data_active_object(C);
 +  bGPdata *gpd = (bGPdata *)ob->data;
 +
 +  bool only_frame_changed = false;
 +
 +  /* In case the step we are about to encode would be the first in the gpencil undo system, ensure
 +   * that we do a full-copy. */
 +  if (undo_stack->step_active == NULL ||
 +      undo_stack->step_active->type != BKE_UNDOSYS_TYPE_GPENCIL) {
 +    BKE_gpencil_tag_full_update(gpd, NULL, NULL, NULL);
 +  }
 +  /* If the ID of the grease pencil object was not tagged or the update cache is empty, we assume
 +   * the data hasn't changed. */
 +  else if ((gpd->id.recalc & ID_RECALC_ALL) == 0 && gpd->runtime.update_cache == NULL) {
 +    /* If the previous step is of our undo system, check if the frame changed. */
 +    if (undo_stack->step_active && undo_stack->step_active->type == BKE_UNDOSYS_TYPE_GPENCIL) {
 +      GPencilUndoStep *us_prev = (GPencilUndoStep *)undo_stack->step_active;
 +      /* We want to be able to undo frame changes, so check this here. */
 +      only_frame_changed = us_prev->undo_data->cfra != scene->r.cfra;
 +      if (!only_frame_changed) {
 +        /* If the frame did not change, we don't need to encode anything, return. */
 +        return false;
 +      }
 +    }
 +    else {
 +      /* No change (that we want to undo) happend, return. */
 +      return false;
 +    }
 +  }
 +
 +  /* TODO: Handle this case properly once the update cache is more widly used. We avoid full-copies
 +   * for now at the expense of to being able to undo them. */
 +#if 1
 +  if (!only_frame_changed && gpd->runtime.update_cache == NULL) {
 +    return false;
 +  }
 +#endif
 +
 +  us->undo_data = MEM_callocN(sizeof(GPencilUndoData), __func__);
 +  us->undo_data->cfra = scene->r.cfra;
 +  us->undo_data->mode = ob->mode;
 +
 +  /* If that step only encodes a frame change (data itself has not changed), return early. */
 +  if (only_frame_changed) {
 +    return true;
 +  }
 +
 +  gpencil_data_to_undo_data(gpd, us->undo_data);
 +  gpd->flag |= GP_DATA_UPDATE_CACHE_UNDO_ENCODED;
 +  return true;
 +}
 +
 +static void gpencil_undosys_step_decode(struct bContext *C,
 +                                        struct Main *UNUSED(bmain),
 +                                        UndoStep *us_p,
 +                                        const eUndoStepDir dir,
 +                                        bool UNUSED(is_final))
 +{
 +  GPencilUndoStep *us = (GPencilUndoStep *)us_p;
 +  GPencilUndoData *undo_data = us->undo_data;
 +
 +  Object *ob = CTX_data_active_object(C);
 +  bGPdata *gpd = (bGPdata *)ob->data;
 +
 +  if (gpd == NULL) 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list