Files
test2/source/blender/blenkernel/intern/gpencil_update_cache_legacy.c
Sergey Sharybin c1bc70b711 Cleanup: Add a copyright notice to files and use SPDX format
A lot of files were missing copyright field in the header and
the Blender Foundation contributed to them in a sense of bug
fixing and general maintenance.

This change makes it explicit that those files are at least
partially copyrighted by the Blender Foundation.

Note that this does not make it so the Blender Foundation is
the only holder of the copyright in those files, and developers
who do not have a signed contract with the foundation still
hold the copyright as well.

Another aspect of this change is using SPDX format for the
header. We already used it for the license specification,
and now we state it for the copyright as well, following the
FAQ:

    https://reuse.software/faq/
2023-05-31 16:19:06 +02:00

260 lines
7.9 KiB
C

/* SPDX-FileCopyrightText: 2022 Blender Foundation.
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
*/
#include <stdio.h>
#include "BKE_gpencil_update_cache_legacy.h"
#include "BLI_dlrbTree.h"
#include "BLI_listbase.h"
#include "BKE_gpencil_legacy.h"
#include "DNA_gpencil_legacy_types.h"
#include "DNA_userdef_types.h"
#include "MEM_guardedalloc.h"
static GPencilUpdateCache *update_cache_alloc(int index, int flag, void *data)
{
GPencilUpdateCache *new_cache = MEM_callocN(sizeof(GPencilUpdateCache), __func__);
new_cache->children = BLI_dlrbTree_new();
new_cache->flag = flag;
new_cache->index = index;
new_cache->data = data;
return new_cache;
}
static short cache_node_compare(void *node, void *data)
{
int index_a = ((GPencilUpdateCacheNode *)node)->cache->index;
int index_b = ((GPencilUpdateCache *)data)->index;
if (index_a == index_b) {
return 0;
}
return index_a < index_b ? 1 : -1;
}
static DLRBT_Node *cache_node_alloc(void *data)
{
GPencilUpdateCacheNode *new_node = MEM_callocN(sizeof(GPencilUpdateCacheNode), __func__);
new_node->cache = ((GPencilUpdateCache *)data);
return (DLRBT_Node *)new_node;
}
static void cache_node_free(void *node);
static void update_cache_free(GPencilUpdateCache *cache)
{
BLI_dlrbTree_free(cache->children, cache_node_free);
MEM_SAFE_FREE(cache->children);
MEM_freeN(cache);
}
static void cache_node_free(void *node)
{
GPencilUpdateCache *cache = ((GPencilUpdateCacheNode *)node)->cache;
if (cache != NULL) {
update_cache_free(cache);
}
MEM_freeN(node);
}
static void cache_node_update(void *node, void *data)
{
GPencilUpdateCache *update_cache = ((GPencilUpdateCacheNode *)node)->cache;
GPencilUpdateCache *new_update_cache = (GPencilUpdateCache *)data;
/* If the new cache is already "covered" by the current cache, just free it and return. */
if (new_update_cache->flag <= update_cache->flag) {
update_cache_free(new_update_cache);
return;
}
update_cache->data = new_update_cache->data;
update_cache->flag = new_update_cache->flag;
/* In case the new cache does a full update, remove its children since they will be all
* updated by this cache. */
if (new_update_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
BLI_dlrbTree_free(update_cache->children, cache_node_free);
}
update_cache_free(new_update_cache);
}
static void update_cache_node_create_ex(GPencilUpdateCache *root_cache,
void *data,
int gpl_index,
int gpf_index,
int gps_index,
bool full_copy)
{
if (root_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
/* Entire data-block has to be recalculated, e.g. nothing else needs to be added to the cache.
*/
return;
}
const int node_flag = full_copy ? GP_UPDATE_NODE_FULL_COPY : GP_UPDATE_NODE_LIGHT_COPY;
if (gpl_index == -1) {
root_cache->data = (bGPdata *)data;
root_cache->flag = node_flag;
if (full_copy) {
/* Entire data-block has to be recalculated, remove all caches of "lower" elements. */
BLI_dlrbTree_free(root_cache->children, cache_node_free);
}
return;
}
const bool is_layer_update_node = (gpf_index == -1);
/* If the data pointer in #GPencilUpdateCache is NULL, this element is not actually cached
* and does not need to be updated, but we do need the index to find elements that are in
* levels below. E.g. if a stroke needs to be updated, the frame it is in would not hold a
* pointer to it's data. */
GPencilUpdateCache *gpl_cache = update_cache_alloc(
gpl_index,
is_layer_update_node ? node_flag : GP_UPDATE_NODE_NO_COPY,
is_layer_update_node ? (bGPDlayer *)data : NULL);
GPencilUpdateCacheNode *gpl_node = (GPencilUpdateCacheNode *)BLI_dlrbTree_add(
root_cache->children, cache_node_compare, cache_node_alloc, cache_node_update, gpl_cache);
BLI_dlrbTree_linkedlist_sync(root_cache->children);
if (gpl_node->cache->flag == GP_UPDATE_NODE_FULL_COPY || is_layer_update_node) {
return;
}
const bool is_frame_update_node = (gps_index == -1);
GPencilUpdateCache *gpf_cache = update_cache_alloc(
gpf_index,
is_frame_update_node ? node_flag : GP_UPDATE_NODE_NO_COPY,
is_frame_update_node ? (bGPDframe *)data : NULL);
GPencilUpdateCacheNode *gpf_node = (GPencilUpdateCacheNode *)BLI_dlrbTree_add(
gpl_node->cache->children,
cache_node_compare,
cache_node_alloc,
cache_node_update,
gpf_cache);
BLI_dlrbTree_linkedlist_sync(gpl_node->cache->children);
if (gpf_node->cache->flag == GP_UPDATE_NODE_FULL_COPY || is_frame_update_node) {
return;
}
GPencilUpdateCache *gps_cache = update_cache_alloc(gps_index, node_flag, (bGPDstroke *)data);
BLI_dlrbTree_add(gpf_node->cache->children,
cache_node_compare,
cache_node_alloc,
cache_node_update,
gps_cache);
BLI_dlrbTree_linkedlist_sync(gpf_node->cache->children);
}
static void update_cache_node_create(
bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, bool full_copy)
{
if (gpd == NULL) {
return;
}
GPencilUpdateCache *root_cache = gpd->runtime.update_cache;
if (root_cache == NULL) {
gpd->runtime.update_cache = update_cache_alloc(0, GP_UPDATE_NODE_NO_COPY, NULL);
root_cache = gpd->runtime.update_cache;
}
if (root_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
/* Entire data-block has to be recalculated, e.g. nothing else needs to be added to the cache.
*/
return;
}
const int gpl_index = (gpl != NULL) ? BLI_findindex(&gpd->layers, gpl) : -1;
const int gpf_index = (gpl != NULL && gpf != NULL) ? BLI_findindex(&gpl->frames, gpf) : -1;
const int gps_index = (gpf != NULL && gps != NULL) ? BLI_findindex(&gpf->strokes, gps) : -1;
void *data = gps;
if (!data) {
data = gpf;
}
if (!data) {
data = gpl;
}
if (!data) {
data = gpd;
}
update_cache_node_create_ex(root_cache, data, gpl_index, gpf_index, gps_index, full_copy);
}
static void gpencil_traverse_update_cache_ex(GPencilUpdateCache *parent_cache,
GPencilUpdateCacheTraverseSettings *ts,
int depth,
void *user_data)
{
if (BLI_listbase_is_empty((ListBase *)parent_cache->children)) {
return;
}
LISTBASE_FOREACH (GPencilUpdateCacheNode *, cache_node, parent_cache->children) {
GPencilUpdateCache *cache = cache_node->cache;
GPencilUpdateCacheIter_Cb cb = ts->update_cache_cb[depth];
if (cb != NULL) {
bool skip = cb(cache, user_data);
if (skip) {
continue;
}
}
gpencil_traverse_update_cache_ex(cache, ts, depth + 1, user_data);
}
}
/* -------------------------------------------------------------------- */
/** \name Update Cache API
*
* \{ */
GPencilUpdateCache *BKE_gpencil_create_update_cache(void *data, bool full_copy)
{
return update_cache_alloc(
0, full_copy ? GP_UPDATE_NODE_FULL_COPY : GP_UPDATE_NODE_LIGHT_COPY, data);
}
void BKE_gpencil_traverse_update_cache(GPencilUpdateCache *cache,
GPencilUpdateCacheTraverseSettings *ts,
void *user_data)
{
gpencil_traverse_update_cache_ex(cache, ts, 0, user_data);
}
void BKE_gpencil_tag_full_update(bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps)
{
update_cache_node_create(gpd, gpl, gpf, gps, true);
}
void BKE_gpencil_tag_light_update(bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps)
{
update_cache_node_create(gpd, gpl, gpf, gps, false);
}
void BKE_gpencil_free_update_cache(bGPdata *gpd)
{
GPencilUpdateCache *gpd_cache = gpd->runtime.update_cache;
if (gpd_cache) {
update_cache_free(gpd_cache);
gpd->runtime.update_cache = NULL;
}
}
/** \} */