312 lines
6.9 KiB
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
|
|
}
|