Blender V4.3
fcurve_cache.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <cstdlib>
12#include <cstring>
13
14#include "MEM_guardedalloc.h"
15
16#include "DNA_anim_types.h"
17
18#include "BLI_ghash.h"
19#include "BLI_listbase.h"
20
21#include "BKE_fcurve.hh"
22
23/* -------------------------------------------------------------------- */
35
45
49static int fcurve_cmp_for_cache(const void *fcu_a_p, const void *fcu_b_p)
50{
51 const FCurve *fcu_a = *((const FCurve **)fcu_a_p);
52 const FCurve *fcu_b = *((const FCurve **)fcu_b_p);
53 const int cmp = strcmp(fcu_a->rna_path, fcu_b->rna_path);
54 if (cmp != 0) {
55 return cmp;
56 }
57 if (fcu_a->array_index < fcu_b->array_index) {
58 return -1;
59 }
60 if (fcu_a->array_index > fcu_b->array_index) {
61 return 1;
62 }
63 return 0;
64}
65
67{
68 const uint fcurve_array_len = BLI_listbase_count(list);
69 FCurve **fcurve_array = static_cast<FCurve **>(
70 MEM_mallocN(sizeof(*fcurve_array) * fcurve_array_len, __func__));
71 uint i;
72 LISTBASE_FOREACH_INDEX (FCurve *, fcu, list, i) {
73 fcurve_array[i] = fcu;
74 }
75 qsort(fcurve_array, fcurve_array_len, sizeof(FCurve *), fcurve_cmp_for_cache);
76
77 /* Allow for the case no F-Curves share an RNA-path, otherwise this is over-allocated.
78 * Although in practice it's likely to only be 3-4x as large as is needed
79 * (with transform channels for e.g.). */
80 FCurvePathCache_Span *span_table = static_cast<FCurvePathCache_Span *>(
81 MEM_mallocN(sizeof(*span_table) * fcurve_array_len, __func__));
82
83 /* May over reserve, harmless. */
84 GHash *span_from_rna_path = BLI_ghash_str_new_ex(__func__, fcurve_array_len);
85 uint span_index = 0;
86 i = 0;
87 while (i < fcurve_array_len) {
88 uint i_end;
89 for (i_end = i + 1; i_end < fcurve_array_len; i_end++) {
90 /* As the indices are sorted, we know a decrease means a new RNA path is found. */
91 if (fcurve_array[i]->array_index > fcurve_array[i_end]->array_index) {
92 BLI_assert(!STREQ(fcurve_array[i]->rna_path, fcurve_array[i_end]->rna_path));
93 break;
94 }
95 if (!STREQ(fcurve_array[i]->rna_path, fcurve_array[i_end]->rna_path)) {
96 break;
97 }
98 }
99
100 FCurvePathCache_Span *span = &span_table[span_index++];
101 span->index = i;
102 span->len = i_end - i;
103 BLI_ghash_insert(span_from_rna_path, fcurve_array[i]->rna_path, span);
104 i = i_end;
105 }
106
107 FCurvePathCache *fcache = static_cast<FCurvePathCache *>(
108 MEM_callocN(sizeof(FCurvePathCache), __func__));
109 fcache->fcurve_array = fcurve_array;
110 fcache->fcurve_array_len = fcurve_array_len;
111 fcache->span_table = span_table;
112 fcache->span_from_rna_path = span_from_rna_path;
113
114 return fcache;
115}
116
118{
119 MEM_freeN(fcache->fcurve_array);
120 MEM_freeN(fcache->span_table);
121 BLI_ghash_free(fcache->span_from_rna_path, nullptr, nullptr);
122 MEM_freeN(fcache);
123}
124
126 const char *rna_path,
127 const int array_index)
128{
129 const FCurvePathCache_Span *span = static_cast<const FCurvePathCache_Span *>(
130 BLI_ghash_lookup(fcache->span_from_rna_path, rna_path));
131 if (span == nullptr) {
132 return nullptr;
133 }
134
135 FCurve **fcurve = fcache->fcurve_array + span->index;
136 const uint len = span->len;
137 for (int i = 0; i < len; i++) {
138 if (fcurve[i]->array_index == array_index) {
139 return fcurve[i];
140 }
141 /* As these are sorted, early exit. */
142 if (fcurve[i]->array_index > array_index) {
143 break;
144 }
145 }
146 return nullptr;
147}
148
150 const char *rna_path,
151 FCurve **fcurve_result,
152 int fcurve_result_len)
153{
154 memset(fcurve_result, 0x0, sizeof(*fcurve_result) * fcurve_result_len);
155
156 const FCurvePathCache_Span *span = static_cast<const FCurvePathCache_Span *>(
157 BLI_ghash_lookup(fcache->span_from_rna_path, rna_path));
158 if (span == nullptr) {
159 return 0;
160 }
161
162 int found = 0;
163 FCurve **fcurve = fcache->fcurve_array + span->index;
164 const uint len = span->len;
165 for (int i = 0; i < len; i++) {
166 /* As these are sorted, early exit. */
167 if (uint(fcurve[i]->array_index) > uint(fcurve_result_len)) {
168 break;
169 }
170 fcurve_result[fcurve[i]->array_index] = fcurve[i];
171 found += 1;
172 }
173 return found;
174}
175
#define BLI_assert(a)
Definition BLI_assert.h:50
GHash * BLI_ghash_str_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
unsigned int uint
#define STREQ(a, b)
Read Guarded memory(de)allocation.
int len
void BKE_fcurve_pathcache_destroy(FCurvePathCache *fcache)
FCurve * BKE_fcurve_pathcache_find(FCurvePathCache *fcache, const char *rna_path, const int array_index)
static int fcurve_cmp_for_cache(const void *fcu_a_p, const void *fcu_b_p)
int BKE_fcurve_pathcache_find_array(FCurvePathCache *fcache, const char *rna_path, FCurve **fcurve_result, int fcurve_result_len)
FCurvePathCache * BKE_fcurve_pathcache_create(ListBase *list)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
GHash * span_from_rna_path
FCurve ** fcurve_array
FCurvePathCache_Span * span_table
char * rna_path
int array_index