Listing the "Blender Foundation" as copyright holder implied the Blender Foundation holds copyright to files which may include work from many developers. While keeping copyright on headers makes sense for isolated libraries, Blender's own code may be refactored or moved between files in a way that makes the per file copyright holders less meaningful. Copyright references to the "Blender Foundation" have been replaced with "Blender Authors", with the exception of `./extern/` since these this contains libraries which are more isolated, any changed to license headers there can be handled on a case-by-case basis. Some directories in `./intern/` have also been excluded: - `./intern/cycles/` it's own `AUTHORS` file is planned. - `./intern/opensubdiv/`. An "AUTHORS" file has been added, using the chromium projects authors file as a template. Design task: #110784 Ref !110783.
177 lines
5.2 KiB
C++
177 lines
5.2 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup bke
|
|
*
|
|
* Cache F-Curve look-ups.
|
|
*/
|
|
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DNA_anim_types.h"
|
|
|
|
#include "BLI_ghash.h"
|
|
#include "BLI_listbase.h"
|
|
|
|
#include "BKE_fcurve.h"
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name F-Curve Path Cache
|
|
*
|
|
* Cache for finding curves by RNA path & array index.
|
|
* \{ */
|
|
|
|
struct FCurvePathCache_Span {
|
|
/** Index in the #FCurvePathCache.fcurve_array indicating the start of the span. */
|
|
uint index;
|
|
/** Number of items in the span in #FCurvePathCache.fcurve_array that share an RNA path. */
|
|
uint len;
|
|
};
|
|
|
|
struct FCurvePathCache {
|
|
/** All curves sorted by (#FCurve.rna_path, #FCurve.array_index) */
|
|
FCurve **fcurve_array;
|
|
uint fcurve_array_len;
|
|
/** Storage for values of `span_from_rna_path`. */
|
|
FCurvePathCache_Span *span_table;
|
|
/** Map `FCurve.rna_path` to elements in #FCurvePathCache.span_table */
|
|
GHash *span_from_rna_path;
|
|
};
|
|
|
|
/**
|
|
* #qsort callback for an #FCurve array.
|
|
*/
|
|
static int fcurve_cmp_for_cache(const void *fcu_a_p, const void *fcu_b_p)
|
|
{
|
|
const FCurve *fcu_a = *((const FCurve **)fcu_a_p);
|
|
const FCurve *fcu_b = *((const FCurve **)fcu_b_p);
|
|
const int cmp = strcmp(fcu_a->rna_path, fcu_b->rna_path);
|
|
if (cmp != 0) {
|
|
return cmp;
|
|
}
|
|
if (fcu_a->array_index < fcu_b->array_index) {
|
|
return -1;
|
|
}
|
|
if (fcu_a->array_index > fcu_b->array_index) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
FCurvePathCache *BKE_fcurve_pathcache_create(ListBase *list)
|
|
{
|
|
const uint fcurve_array_len = BLI_listbase_count(list);
|
|
FCurve **fcurve_array = static_cast<FCurve **>(
|
|
MEM_mallocN(sizeof(*fcurve_array) * fcurve_array_len, __func__));
|
|
uint i;
|
|
LISTBASE_FOREACH_INDEX (FCurve *, fcu, list, i) {
|
|
fcurve_array[i] = fcu;
|
|
}
|
|
qsort(fcurve_array, fcurve_array_len, sizeof(FCurve *), fcurve_cmp_for_cache);
|
|
|
|
/* Allow for the case no F-Curves share an RNA-path, otherwise this is over-allocated.
|
|
* Although in practice it's likely to only be 3-4x as large as is needed
|
|
* (with transform channels for e.g.). */
|
|
FCurvePathCache_Span *span_table = static_cast<FCurvePathCache_Span *>(
|
|
MEM_mallocN(sizeof(*span_table) * fcurve_array_len, __func__));
|
|
|
|
/* May over reserve, harmless. */
|
|
GHash *span_from_rna_path = BLI_ghash_str_new_ex(__func__, fcurve_array_len);
|
|
uint span_index = 0;
|
|
i = 0;
|
|
while (i < fcurve_array_len) {
|
|
uint i_end;
|
|
for (i_end = i + 1; i_end < fcurve_array_len; i_end++) {
|
|
/* As the indices are sorted, we know a decrease means a new RNA path is found. */
|
|
if (fcurve_array[i]->array_index > fcurve_array[i_end]->array_index) {
|
|
BLI_assert(!STREQ(fcurve_array[i]->rna_path, fcurve_array[i_end]->rna_path));
|
|
break;
|
|
}
|
|
if (!STREQ(fcurve_array[i]->rna_path, fcurve_array[i_end]->rna_path)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
FCurvePathCache_Span *span = &span_table[span_index++];
|
|
span->index = i;
|
|
span->len = i_end - i;
|
|
BLI_ghash_insert(span_from_rna_path, fcurve_array[i]->rna_path, span);
|
|
i = i_end;
|
|
}
|
|
|
|
FCurvePathCache *fcache = static_cast<FCurvePathCache *>(
|
|
MEM_callocN(sizeof(FCurvePathCache), __func__));
|
|
fcache->fcurve_array = fcurve_array;
|
|
fcache->fcurve_array_len = fcurve_array_len;
|
|
fcache->span_table = span_table;
|
|
fcache->span_from_rna_path = span_from_rna_path;
|
|
|
|
return fcache;
|
|
}
|
|
|
|
void BKE_fcurve_pathcache_destroy(FCurvePathCache *fcache)
|
|
{
|
|
MEM_freeN(fcache->fcurve_array);
|
|
MEM_freeN(fcache->span_table);
|
|
BLI_ghash_free(fcache->span_from_rna_path, nullptr, nullptr);
|
|
MEM_freeN(fcache);
|
|
}
|
|
|
|
FCurve *BKE_fcurve_pathcache_find(FCurvePathCache *fcache,
|
|
const char *rna_path,
|
|
const int array_index)
|
|
{
|
|
const FCurvePathCache_Span *span = static_cast<const FCurvePathCache_Span *>(
|
|
BLI_ghash_lookup(fcache->span_from_rna_path, rna_path));
|
|
if (span == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
FCurve **fcurve = fcache->fcurve_array + span->index;
|
|
const uint len = span->len;
|
|
for (int i = 0; i < len; i++) {
|
|
if (fcurve[i]->array_index == array_index) {
|
|
return fcurve[i];
|
|
}
|
|
/* As these are sorted, early exit. */
|
|
if (fcurve[i]->array_index > array_index) {
|
|
break;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
int BKE_fcurve_pathcache_find_array(FCurvePathCache *fcache,
|
|
const char *rna_path,
|
|
FCurve **fcurve_result,
|
|
int fcurve_result_len)
|
|
{
|
|
memset(fcurve_result, 0x0, sizeof(*fcurve_result) * fcurve_result_len);
|
|
|
|
const FCurvePathCache_Span *span = static_cast<const FCurvePathCache_Span *>(
|
|
BLI_ghash_lookup(fcache->span_from_rna_path, rna_path));
|
|
if (span == nullptr) {
|
|
return 0;
|
|
}
|
|
|
|
int found = 0;
|
|
FCurve **fcurve = fcache->fcurve_array + span->index;
|
|
const uint len = span->len;
|
|
for (int i = 0; i < len; i++) {
|
|
/* As these are sorted, early exit. */
|
|
if (uint(fcurve[i]->array_index) > uint(fcurve_result_len)) {
|
|
break;
|
|
}
|
|
fcurve_result[fcurve[i]->array_index] = fcurve[i];
|
|
found += 1;
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/** \} */
|