/* SPDX-License-Identifier: GPL-2.0-or-later * Copyright 2022 Blender Foundation. */ #pragma once /** \file * \ingroup bke */ #ifdef __cplusplus extern "C" { #endif #include "BLI_sys_types.h" /* for bool */ struct DLRBT_Tree; struct GPencilUpdateCache; struct bGPDframe; struct bGPDlayer; struct bGPDstroke; struct bGPdata; /** #GPencilUpdateCache.flag */ typedef enum eGPUpdateCacheNodeFlag { /* Node is a placeholder (e.g. when only an index is needed). */ GP_UPDATE_NODE_NO_COPY = 0, /* Copy only element, not the content. */ GP_UPDATE_NODE_LIGHT_COPY = 1, /* Copy the element as well as all of its content. */ GP_UPDATE_NODE_FULL_COPY = 2, } eGPUpdateCacheNodeFlag; /** * Cache for what needs to be updated after bGPdata was modified. * * Every node holds information about one element that was changed: * - The index of where that element is in the linked-list. * - The pointer to the original element in bGPdata. * * Additionally, nodes also hold other nodes that are one "level" below them. * E.g. a node that represents a change on a bGPDframe could contain a set of * nodes that represent a change on bGPDstrokes. * These nodes are stored in a red-black tree so that they are sorted by their * index to make sure they can be processed in the correct order. */ typedef struct GPencilUpdateCache { /* Mapping from index to a GPencilUpdateCache struct. */ struct DLRBT_Tree *children; /* eGPUpdateCacheNodeFlag */ int flag; /* Index of the element in the linked-list. */ int index; /* Pointer to one of bGPdata, bGPDLayer, bGPDFrame, bGPDStroke. */ void *data; } GPencilUpdateCache; /* Node structure in the DLRBT_Tree for GPencilUpdateCache mapping. */ typedef struct GPencilUpdateCacheNode { /* DLRB tree capabilities. */ struct GPencilUpdateCacheNode *next, *prev; struct GPencilUpdateCacheNode *left, *right; struct GPencilUpdateCacheNode *parent; char tree_col; char _pad[7]; /* Content of DLRB tree node. */ GPencilUpdateCache *cache; } GPencilUpdateCacheNode; /** * Callback that is called in BKE_gpencil_traverse_update_cache at each level. If the callback * returns true, then the children will not be iterated over and instead continue. * \param cache: The cache at this level. * \param user_data: Pointer to the user_data passed to BKE_gpencil_traverse_update_cache. * \returns true, if iterating over the children of \a cache should be skipped, false if not. */ typedef bool (*GPencilUpdateCacheIter_Cb)(GPencilUpdateCache *cache, void *user_data); typedef struct GPencilUpdateCacheTraverseSettings { /* Callbacks for the update cache traversal. Callback with index 0 is for layers, 1 for frames * and 2 for strokes. */ GPencilUpdateCacheIter_Cb update_cache_cb[3]; } GPencilUpdateCacheTraverseSettings; /** * Allocates a new GPencilUpdateCache and populates it. * \param data: A data pointer to populate the initial cache with. * \param full_copy: If true, will mark this update cache as a full copy * (GP_UPDATE_NODE_FULL_COPY). If false, it will be marked as a struct copy * (GP_UPDATE_NODE_LIGHT_COPY). */ GPencilUpdateCache *BKE_gpencil_create_update_cache(void *data, bool full_copy); /** * Traverses an update cache and executes callbacks at each level. * \param cache: The update cache to traverse. * \param ts: The traversal settings. This stores the callbacks that are called at each level. * \param user_data: Custom data passed to each callback. */ void BKE_gpencil_traverse_update_cache(GPencilUpdateCache *cache, GPencilUpdateCacheTraverseSettings *ts, void *user_data); /** * Tags an element (bGPdata, bGPDlayer, bGPDframe, or bGPDstroke) and all of its containing data to * be updated in the next update-on-write operation. * * The function assumes that when a parameter is NULL all of the following parameters are NULL too. * E.g. in order to tag a layer (gpl), the parameters would *have* to be (gpd, gpl, NULL, NULL). */ void BKE_gpencil_tag_full_update(struct bGPdata *gpd, struct bGPDlayer *gpl, struct bGPDframe *gpf, struct bGPDstroke *gps); /** * Tags an element (bGPdata, bGPDlayer, bGPDframe, or bGPDstroke) to be updated in the next * update-on-write operation. This function will not update any of the containing data, only the * struct itself. * * The function assumes that when a parameter is NULL all of the following parameters are NULL too. * E.g. in order to tag a layer (gpl), the parameters would *have* to be (gpd, gpl, NULL, NULL). */ void BKE_gpencil_tag_light_update(struct bGPdata *gpd, struct bGPDlayer *gpl, struct bGPDframe *gpf, struct bGPDstroke *gps); /** * Frees the GPencilUpdateCache on the gpd->runtime. This will not free the data that the cache * node might point to. It assumes that the cache does not own the data. */ void BKE_gpencil_free_update_cache(struct bGPdata *gpd); #ifdef __cplusplus } #endif