This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/blenkernel/intern/curvemapping_cache.c

312 lines
6.9 KiB
C

#include "MEM_guardedalloc.h"
#include "BLI_alloca.h"
#include "BLI_array.h"
#include "BLI_bitmap.h"
#include "BLI_compiler_attrs.h"
#include "BLI_compiler_compat.h"
#include "BLI_ghash.h"
#include "BLI_hash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_mempool.h"
#include "BLI_rand.h"
#include "BLI_rect.h"
#include "BLI_smallhash.h"
#include "BLI_string.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "DNA_brush_enums.h"
#include "DNA_brush_types.h"
#include "DNA_color_types.h"
#include "DNA_curveprofile_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_sculpt_brush_types.h"
#include "BKE_brush.h"
#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_brush_engine.h"
#include "BKE_curvemapping_cache.h"
#include "BKE_curveprofile.h"
#include "BLO_read_write.h"
/*
The brush system needs to make lots of copies of BrushChannels
as it resolves relationships between commands, brushes and the tool settings.
Unfortunately each brush command has five parameter curves, and copying
them over and over again has proven to be slow.
Solution: a kind of small string optimization approach but for curves
*/
static int curvmapping_curve_count(const CurveMapping *cumap)
{
int count = 0;
for (int i = 0; i < CM_TOT; i++) {
if (cumap->cm[i].curve) {
count++;
}
}
return count;
}
bool BKE_curvemapping_equals(const CurveMapping *a, const CurveMapping *b)
{
int count = curvmapping_curve_count(a);
if (curvmapping_curve_count(b) != count) {
return false;
}
bool ok = true;
ok = ok && a->tone == b->tone;
for (int i = 0; i < 3; i++) {
ok = ok && a->black[i] == b->black[i];
ok = ok && a->white[i] == b->white[i];
ok = ok && a->bwmul[i] == b->bwmul[i];
}
if (!ok) {
return false;
}
for (int i = 0; i < count; i++) {
const CurveMap *c1 = a->cm + i;
const CurveMap *c2 = b->cm + i;
if (!c1 || !c2) {
return false;
}
if (c1->totpoint != c2->totpoint) {
return false;
}
for (int j = 0; j < c1->totpoint; j++) {
ok = ok && fabsf(c1->curve[j].x - c2->curve[j].x) <= FLT_EPSILON * 8;
ok = ok && fabsf(c1->curve[j].y - c2->curve[j].y) <= FLT_EPSILON * 8;
}
if (!ok) {
return false;
}
}
return true;
}
/*truncate float to avoid rounding errors
messing up the hash*/
#define FRACT_TRUNCATE_STEPS 8192.0f
BLI_INLINE unsigned int get_float_hash(float f)
{
float f_floor = floor(f);
float fract = f - f_floor;
fract = floorf(fract * FRACT_TRUNCATE_STEPS) / FRACT_TRUNCATE_STEPS;
uint *ret = (uint *)&f;
return *ret;
}
#define HASHFLOAT(f) h = get_float_hash(f), hash ^= BLI_hash_int(h + hi++)
#define HASHINT(f) h = get_float_hash(f), hash ^= BLI_hash_int(f + hi++)
uint BKE_curvemapping_calc_hash(const CurveMapping *cumap)
{
uint hash = 0;
uint h = 0;
uint hi = 0;
int totcurve = curvmapping_curve_count(cumap);
HASHINT(totcurve);
HASHINT(cumap->tone);
for (int i = 0; i < 3; i++) {
HASHFLOAT(cumap->white[i]);
HASHFLOAT(cumap->black[i]);
HASHFLOAT(cumap->bwmul[i]);
}
for (int i = 0; i < totcurve; i++) {
if (!cumap->cm[i].curve) {
break;
}
const CurveMap *cu = cumap->cm + i;
for (int j = 0; j < cu->totpoint; j++) {
HASHFLOAT(cu->curve[j].x);
HASHFLOAT(cu->curve[j].y);
}
}
return hash & ((1 << 29) - 1);
}
static bool curves_equals(const void *a, const void *b)
{
// ghash requires we invert here
return !BKE_curvemapping_equals(a, b);
}
static unsigned int curve_hash(const void *c)
{
return BKE_curvemapping_calc_hash(c);
}
CurveMappingCache *BKE_curvemapping_cache_create()
{
CurveMappingCache *ret = MEM_callocN(sizeof(*ret), "CurveMappingCache");
ret->gh = BLI_ghash_new(curve_hash, curves_equals, "CurveMappingCache ghash");
return ret;
}
void BKE_curvemapping_cache_aquire(CurveMappingCache *cache, CurveMapping *curve)
{
curve->cache_users++;
// printf("%s: %d flag: %d\n", __func__, curve->cache_users, curve->flag);
}
void BKE_curvemapping_cache_release(CurveMappingCache *cache, CurveMapping *curve)
{
curve->cache_users--;
// printf("%s: %d flag: %d\n", __func__, curve->cache_users, curve->flag);
if ((curve->flag & CUMA_PART_OF_CACHE) && curve->cache_users <= 0) {
if (!BLI_ghash_remove(cache->gh, curve, NULL, NULL)) {
printf("error, curve was not in cache! %p\n", curve);
}
BKE_curvemapping_free(curve);
}
}
bool BKE_curvemapping_in_cache(CurveMapping *curve)
{
return curve->flag & CUMA_PART_OF_CACHE;
}
CurveMapping *BKE_curvemapping_cache_get(CurveMappingCache *cache,
CurveMapping *curve,
bool free_input)
{
void **key, **val;
CurveMapping *lookup;
if (BLI_ghash_ensure_p_ex(cache->gh, curve, &key, &val)) {
lookup = *key;
if (free_input && lookup != curve && !(curve->flag & CUMA_PART_OF_CACHE)) {
BKE_curvemapping_free(curve);
}
lookup->cache_users++;
return lookup;
}
CurveMapping *curve2 = BKE_curvemapping_copy(curve);
*key = curve2;
*val = curve2;
curve2->flag |= CUMA_PART_OF_CACHE;
#if 0
printf("adding curve key %d\n", BKE_curvemapping_calc_hash(curve));
printf("%d %d",
(int)BKE_curvemapping_calc_hash(curve2),
(int)BKE_curvemapping_equals(curve, curve2));
CurveMap *cu = curve2->cm;
printf("{\n");
for (int i = 0; i < cu->totpoint; i++) {
printf(" %f, %f\n", cu->curve[i].x, cu->curve[i].y);
}
printf("}\n");
#endif
if (free_input && !(curve->flag & CUMA_PART_OF_CACHE)) {
BKE_curvemapping_free(curve);
}
curve2->cache_users = 1;
return curve2;
}
void BKE_curvemapping_cache_free(CurveMappingCache *cache)
{
GHashIterator gi;
GHASH_ITER (gi, cache->gh) {
CurveMapping *curve = BLI_ghashIterator_getKey(&gi);
BKE_curvemapping_free(curve);
}
BLI_ghash_free(cache->gh, NULL, NULL);
MEM_freeN(cache);
}
void BKE_curvemapping_cache_exit()
{
}
// releases a curve if it's in the cache, otherwise frees it
void BKE_curvemapping_cache_release_or_free(CurveMappingCache *cache, CurveMapping *curve)
{
if (!curve) {
return;
}
if (curve->flag & CUMA_PART_OF_CACHE) {
BKE_curvemapping_cache_release(cache, curve);
}
else {
BKE_curvemapping_free(curve);
}
#if 0
CurveMap *cu1 = curve->cm;
CurveMap *cu2 = curve->cm;
if (cu1->totpoint != cu2->totpoint) {
printf("%s: curvemapping cache error; totpoint differed: %d %d\n",
__func__,
cu1->totpoint,
cu2->totpoint);
return;
}
printf("curve tables: {\n");
for (int i = 0; i < cu1->totpoint; i++) {
CurveMapPoint *p1 = cu1->curve + i;
CurveMapPoint *p2 = cu1->curve + i;
printf(" %f, %f, | %f, %f\n", p1->x, p1->y, p2->x, p2->y);
}
printf("}\n");
#endif
}