gegl-lookup.c 4.35 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/* 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 <http://www.gnu.org/licenses/>.
 *
 * Copyright 2009 Øyvind Kolås.
 */

#include "config.h"

#include <glib-object.h>

#include "gegl.h"
#include "gegl-lookup.h"

26 27 28 29 30 31
GeglLookup *
gegl_lookup_new_full (GeglLookupFunction function,
                      gpointer           data,
                      gfloat             start,
                      gfloat             end,
                      gfloat             precision)
32
{
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
  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;
    }

110
  if ((positive_max-positive_min) + (negative_max-negative_min) > GEGL_LOOKUP_MAX_ENTRIES)
111 112 113 114 115
    {
      /* Reduce the size of the cache tables to fit within the bittable
       * budget (the maximum allocation is around 2.18mb of memory
       */

116
      gint diff = (positive_max-positive_min) + (negative_max-negative_min) - GEGL_LOOKUP_MAX_ENTRIES;
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134

      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;
    }

135
  lookup = g_malloc0 (sizeof (GeglLookup) + sizeof (gfloat) *
136
                                                  ((positive_max-positive_min)+
137 138
                                                   (negative_max-negative_min)));

139 140 141 142 143
  lookup->positive_min = positive_min;
  lookup->positive_max = positive_max;
  lookup->negative_min = negative_min;
  lookup->negative_max = negative_max;
  lookup->shift = shift;
144 145
  lookup->function = function;
  lookup->data = data;
146

147 148 149
  return lookup;
}

150 151 152
GeglLookup *
gegl_lookup_new (GeglLookupFunction function,
                 gpointer           data)
153 154 155 156
{
  return gegl_lookup_new_full (function, data, 0, 1.0, 0.000010);
}

157 158 159
void
gegl_lookup_free (GeglLookup *lookup)
{
160
  g_free (lookup);
161
}