/* This file is part of GEGL * * GEGL is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * GEGL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with GEGL; if not, see . * * Copyright 2009 Øyvind Kolås. */ #include "config.h" #include #include "gegl.h" #include "gegl-lookup.h" GeglLookup * gegl_lookup_new_full (GeglLookupFunction function, gpointer data, gfloat start, gfloat end, gfloat precision) { GeglLookup *lookup; union { float f; guint32 i; } u; gint positive_min, positive_max, negative_min, negative_max; gint shift; /* normalize input parameters */ if (start > end) { /* swap */ u.f = start; start = end; end = u.f; } if (precision <= 0.000005) shift = 0; /* checked for later */ else if (precision <= 0.000010) shift = 8; else if (precision <= 0.000020) shift = 9; else if (precision <= 0.000040) shift = 10; else if (precision <= 0.000081) shift = 11; else if (precision <= 0.000161) shift = 12; else if (precision <= 0.000324) shift = 14; else if (precision <= 0.000649) shift = 15; else shift = 16; /* a bit better than 8bit sRGB quality */ /* Adjust slightly away from 0.0, saving many entries close to 0, this * causes lookups very close to zero to be passed directly to the * function instead. */ if (start == 0.0) start = precision; if (end == 0.0) end = -precision; /* Compute start and */ if (start < 0.0 || end < 0.0) { if (end < 0.0) { u.f = start; positive_max = u.i >> shift; u.f = end; positive_min = u.i >> shift; negative_min = positive_max; negative_max = positive_max; } else { u.f = 0 - precision; positive_min = u.i >> shift; u.f = start; positive_max = u.i >> shift; u.f = 0 + precision; negative_min = u.i >> shift; u.f = end; negative_max = u.i >> shift; } } else { u.f = start; positive_min = u.i >> shift; u.f = end; positive_max = u.i >> shift; negative_min = positive_max; negative_max = positive_max; } if (shift == 0) /* short circuit, do not use ranges */ { positive_min = positive_max = negative_min = negative_max = 0; } if ((positive_max-positive_min) + (negative_max-negative_min) > GEGL_LOOKUP_MAX_ENTRIES) { /* Reduce the size of the cache tables to fit within the bittable * budget (the maximum allocation is around 2.18mb of memory */ gint diff = (positive_max-positive_min) + (negative_max-negative_min) - GEGL_LOOKUP_MAX_ENTRIES; if (negative_max - negative_min > 0) { if (negative_max - negative_min >= diff) { negative_max -= diff; diff = 0; } else { diff -= negative_max - negative_min; negative_max = negative_min; } } if (diff) positive_max-=diff; } lookup = g_malloc0 (sizeof (GeglLookup) + sizeof (gfloat) * ((positive_max-positive_min)+ (negative_max-negative_min))); lookup->positive_min = positive_min; lookup->positive_max = positive_max; lookup->negative_min = negative_min; lookup->negative_max = negative_max; lookup->shift = shift; lookup->function = function; lookup->data = data; return lookup; } GeglLookup * gegl_lookup_new (GeglLookupFunction function, gpointer data) { return gegl_lookup_new_full (function, data, 0, 1.0, 0.000010); } void gegl_lookup_free (GeglLookup *lookup) { g_free (lookup); }