Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  mipmap.c   Sprache: C

 

/*
 * DDS GIMP plugin
 *
 * Copyright (C) 2004-2012 Shawn Kirst <skirst@gmail.com>,
 * with parts (C) 2003 Arne Reuter <homepage@arnereuter.de> where specified.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 51 Franklin Street, Fifth Floor
 * Boston, MA 02110-1301, USA.
 */


#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <float.h>

#include <gtk/gtk.h>

#include <libgimp/gimp.h>

#ifdef _OPENMP
#include <omp.h>
#endif

#include "dds.h"
#include "mipmap.h"
#include "imath.h"


typedef gfloat (*filterfunc_t)    (gfloat);
typedef gint   (*wrapfunc_t)      (gint, gint);
typedef void   (*mipmapfunc_t)    (guchar*, gint, gint, guchar*, gint, gint, gint,
                                   filterfunc_t, gfloat, wrapfunc_t, gint, gfloat);
typedef void   (*volmipmapfunc_t) (guchar*, gint, gint, gint, guchar*, gint, gint, gint,
                                   gint, filterfunc_t, gfloat, wrapfunc_t, gint, gfloat);


/**
 * Size Functions
 */


gint
get_num_mipmaps (gint  width,
                 gint  height)
{
  gint w = width  << 1;
  gint h = height << 1;
  gint n = 0;

  while (w != 1 || h != 1)
    {
      if (w > 1) w >>= 1;
      if (h > 1) h >>= 1;
      ++n;
    }

  return n;
}

guint
get_mipmapped_size (gint  width,
                    gint  height,
                    gint  bpp,
                    gint  level,
                    gint  num,
                    gint  format)
{
  gint  w, h, n = 0;
  guint size    = 0;

  w = width  >> level;
  h = height >> level;
  w = MAX (1, w);
  h = MAX (1, h);
  w <<= 1;
  h <<= 1;

  while (n < num && (w != 1 || h != 1))
    {
      if (w > 1) w >>= 1;
      if (h > 1) h >>= 1;
      if (format == DDS_COMPRESS_NONE)
        size += (w * h);
      else
        size += ((w + 3) >> 2) * ((h + 3) >> 2);
      ++n;
    }

  if (format == DDS_COMPRESS_NONE)
    {
      size *= bpp;
    }
  else
    {
      if (format == DDS_COMPRESS_BC1 || format == DDS_COMPRESS_BC4)
        size *= 8;
      else
        size *= 16;
    }

  return size;
}

guint
get_volume_mipmapped_size (gint  width,
                           gint  height,
                           gint  depth,
                           gint  bpp,
                           gint  level,
                           gint  num,
                           gint  format)
{
  gint  w, h, d, n = 0;
  guint size       = 0;

  w = width >> level;
  h = height >> level;
  d = depth >> level;
  w = MAX (1, w);
  h = MAX (1, h);
  d = MAX (1, d);
  w <<= 1;
  h <<= 1;
  d <<= 1;

  while (n < num && (w != 1 || h != 1))
    {
      if (w > 1) w >>= 1;
      if (h > 1) h >>= 1;
      if (d > 1) d >>= 1;
      if (format == DDS_COMPRESS_NONE)
        size += (w * h * d);
      else
        size += (((w + 3) >> 2) * ((h + 3) >> 2) * d);
      ++n;
    }

  if (format == DDS_COMPRESS_NONE)
    {
      size *= bpp;
    }
  else
    {
      if (format == DDS_COMPRESS_BC1 || format == DDS_COMPRESS_BC4)
        size *= 8;
      else
        size *= 16;
    }

  return size;
}

gint
get_next_mipmap_dimensions (gint *next_w,
                            gint *next_h,
                            gint  curr_w,
                            gint  curr_h)
{
  if (curr_w == 1 || curr_h == 1)
    return 0;

  if (next_w) *next_w = curr_w >> 1;
  if (next_h) *next_h = curr_h >> 1;

  return 1;
}


/**
 * Wrap Modes
 */


static gint
wrap_mirror (gint  x,
             gint  max)
{
  if (max == 1)
    x = 0;

  x = abs (x);
  while (x >= max)
    x = abs (max + max - x - 2);

  return x;
}

static gint
wrap_repeat (gint  x,
             gint  max)
{
  gfloat t;
  t = (gfloat) x / (gfloat) max;
  return (gint) ((t - floorf (t)) * (gfloat) max);
}

static gint
wrap_clamp (gint  x,
            gint  max)
{
  return MAX (0, MIN (max - 1, x));
}


/**
 * Gamma-correction
 */


static gfloat
linear_to_sRGB (gfloat c)
{
  gfloat v = (gfloat) c;

  if (v < 0.0f)
    v = 0.0f;
  else if (v > 1.0f)
    v = 1.0f;
  else if (v <= 0.0031308f)
    v = 12.92f * v;
  else
    v = 1.055f * powf (v, 0.41666f) - 0.055f;

  return v;
}

static gfloat
linear_to_gamma (gint    gc,
                 gfloat  v,
                 gfloat  gamma)
{
  if (gc == 1)
    {
      v = powf (v, 1.0f / gamma);
      if (v > 1.0f)
        v = 1.0f;
    }
  else if (gc == 2)
    {
      v = linear_to_sRGB (v);
    }

  return v;
}


static gfloat
sRGB_to_linear (gfloat c)
{
  gfloat v = (gfloat) c;

  if (v < 0.0f)
    v = 0.0f;
  else if (v > 1.0f)
    v = 1.0f;
  else if (v <= 0.04045f)
    v /= 12.92f;
  else
    v = powf ((v + 0.055f) / 1.055f, 2.4f);

  return v;
}

static gfloat
gamma_to_linear (gint    gc,
                 gfloat  v,
                 gfloat  gamma)
{
  if (gc == 1)
    {
      v = powf (v, gamma);
      if (v > 1.0f)
        v = 1.0f;
    }
  else if (gc == 2)
    {
      v = sRGB_to_linear (v);
    }

  return v;
}


/**
 * Filters
 */


static gfloat
box_filter (gfloat  t)
{
  if ((t >= -0.5f) && (t < 0.5f))
    return 1.0f;

  return 0.0f;
}

static gfloat
triangle_filter (gfloat  t)
{
  if (t < 0.0f) t = -t;
  if (t < 1.0f) return 1.0f - t;

  return 0.0f;
}

static gfloat
quadratic_filter (gfloat  t)
{
  if (t < 0.0f) t = -t;
  if (t < 0.5f) return 0.75f - t * t;
  if (t < 1.5f)
    {
      t -= 1.5f;
      return 0.5f * t * t;
    }

  return 0.0f;
}

static gfloat
mitchell (gfloat        t,
          const gfloat  B)
{
  gfloat C, tt;

  C  = 0.5f * (1.0f - B);
  tt = t * t;
  if (t < 0.0f)
    t = -t;

  if (t < 1.0f)
    {
      t = (((12.0f - 9.0f * B - 6.0f * C) * (t * tt)) +
           ((-18.0f + 12.0f * B + 6.0f * C) * tt) +
           (6.0f - 2.0f * B));

      return t / 6.0f;
    }
  else if (t < 2.0f)
    {
      t = (((-1.0f * B - 6.0f * C) * (t * tt)) +
           ((6.0f * B + 30.0f * C) * tt) +
           ((-12.0f * B - 48.0f * C) * t) +
           (8.0f * B + 24.0f * C));

      return t / 6.0f;
    }

  return 0.0f;
}

static gfloat
bspline_filter (gfloat  t)
{
  return mitchell (t, 1.0f);
}

static gfloat
mitchell_filter (gfloat  t)
{
  return mitchell (t, 1.0f / 3.0f);
}

static gfloat
catrom_filter (gfloat  t)
{
  return mitchell (t, 0.0f);
}

static gfloat
sinc (gfloat  x)
{
  x = (x * M_PI);
  if (fabsf (x) < 1e-04f)
    return 1.0f + x * x * (-1.0f / 6.0f + x * x * 1.0f / 120.0f);

  return sinf (x) / x;
}

static gfloat
lanczos_filter (gfloat  t)
{
  if (t < 0.0f) t = -t;
  if (t < 3.0f) return sinc (t) * sinc (t / 3.0f);

  return 0.0f;
}

static gfloat
bessel0 (gfloat  x)
{
  const gfloat EPSILON = 1e-6f;
  gfloat xh, sum, pow, ds;
  gint   k;

  xh  = 0.5f * x;
  sum = 1.0f;
  pow = 1.0f;
  k   = 0;
  ds  = 1.0f;

  while (ds > sum * EPSILON)
    {
      ++k;
      pow = pow * (xh / k);
      ds = pow * pow;
      sum += ds;
    }

  return sum;
}

static gfloat
kaiser_filter (gfloat  t)
{
  if (t < 0.0f) t = -t;

  if (t < 3.0f)
    {
      const gfloat alpha = 4.0f;
      const gfloat rb04  = 0.0884805322f; // 1.0f / bessel0(4.0f);
      const gfloat ratio = t / 3.0f;
      if ((1.0f - ratio * ratio) >= 0)
        return sinc (t) * bessel0 (alpha * sqrtf (1.0f - ratio * ratio)) * rb04;
    }

  return 0.0f;
}


/**
 * 2D Scaling
 */


static void
scale_image_nearest (guchar       *dst,
                     gint          dw,
                     gint          dh,
                     guchar       *src,
                     gint          sw,
                     gint          sh,
                     gint          bpp,
                     filterfunc_t  filter,
                     gfloat        support,
                     wrapfunc_t    wrap,
                     gint          gc,
                     gfloat        gamma)
{
  gint n, x, y;
  gint ix, iy;
  gint srowbytes = sw * bpp;
  gint drowbytes = dw * bpp;

  for (y = 0; y < dh; ++y)
    {
      iy = (y * sh + sh / 2) / dh;
      for (x = 0; x < dw; ++x)
        {
          ix = (x * sw + sw / 2) / dw;
          for (n = 0; n < bpp; ++n)
            {
              dst[y * drowbytes + (x * bpp) + n] =
                src[iy * srowbytes + (ix * bpp) + n];
            }
        }
    }
}

static void
scale_image (guchar       *dst,
             gint          dw,
             gint          dh,
             guchar       *src,
             gint          sw,
             gint          sh,
             gint          bpp,
             filterfunc_t  filter,
             gfloat        support,
             wrapfunc_t    wrap,
             gint          gc,
             gfloat        gamma)
{
  const gfloat xfactor = (gfloat) dw / (gfloat) sw;
  const gfloat yfactor = (gfloat) dh / (gfloat) sh;

  gint   x, y, start, stop, nmax, n, i;
  gfloat center, contrib, density, s, r, t;
  gint   sstride  = sw * bpp;
  gfloat xscale   = MIN (xfactor, 1.0f);
  gfloat yscale   = MIN (yfactor, 1.0f);
  gfloat xsupport = support / xscale;
  gfloat ysupport = support / yscale;
  guchar *d, *row, *col;
  guchar *tmp;

  if (xsupport <= 0.5f)
    {
      xsupport = 0.5f + 1e-10f;
      xscale = 1.0f;
    }

  if (ysupport <= 0.5f)
    {
      ysupport = 0.5f + 1e-10f;
      yscale = 1.0f;
    }

#ifdef _OPENMP
  tmp = g_malloc (sw * bpp * omp_get_max_threads ());
#else
  tmp = g_malloc (sw * bpp);
#endif

#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic)                              \
  private(x, y, d, row, col, center, start, stop, nmax, s, i, n, density, r, t, contrib)
#endif
  for (y = 0; y < dh; ++y)
    {
      /* resample in Y direction to temp buffer */
      d = tmp;
#ifdef _OPENMP
      d += (sw * bpp * omp_get_thread_num ());
#endif

      center = ((gfloat) y + 0.5f) / yfactor;
      start = (gint) roundf ((center - ysupport) + 0.5f);
      stop  = (gint) roundf ((center + ysupport) + 0.5f);
      nmax = stop - start;
      s = (gfloat) start - center + 0.5f;

      for (x = 0; x < sw; ++x)
        {
          col = src + (x * bpp);

          for (i = 0; i < bpp; ++i)
            {
              density = 0.0f;
              r = 0.0f;

              for (n = 0; n < nmax; ++n)
                {
                  contrib = filter((s + n) * yscale);
                  density += contrib;
                  if (i == 3)
                    t = (gfloat) col[(wrap (start + n, sh) * sstride) + i] / 255.0f;
                  else
                    t = gamma_to_linear (gc, (gfloat) col[(wrap (start + n, sh) * sstride) + i] / 255.0f, gamma);
                  r += t * contrib;
                }

              if (density != 0.0f && density != 1.0f)
                r /= density;

              r = MIN (1.0f, MAX (0.0f, r));

              if (i != 3)
                r = linear_to_gamma (gc, r, gamma);

              d[(x * bpp) + i] = (guchar) floorf (r * 255.0f + 0.5f);
            }
        }

      /* resample in X direction using temp buffer */
      row = d;
      d = dst;

      for (x = 0; x < dw; ++x)
        {
          center = ((gfloat) x + 0.5f) / xfactor;
          start = (gint) roundf ((center - xsupport) + 0.5f);
          stop  = (gint) roundf ((center + xsupport) + 0.5f);
          nmax = stop - start;
          s = (gfloat) start - center + 0.5f;

          for (i = 0; i < bpp; ++i)
            {
              density = 0.0f;
              r = 0.0f;

              for (n = 0; n < nmax; ++n)
                {
                  contrib = filter((s + n) * xscale);
                  density += contrib;
                  if (i == 3)
                    t = (gfloat) row[(wrap (start + n, sw) * bpp) + i] / 255.0f;
                  else
                    t = gamma_to_linear (gc, (gfloat) row[(wrap (start + n, sw) * bpp) + i] / 255.0f, gamma);
                  r += t * contrib;
                }

              if (density != 0.0f && density != 1.0f)
                r /= density;

              r = MIN (1.0f, MAX (0.0f, r));

              if (i != 3)
                r = linear_to_gamma (gc, r, gamma);

              d[(y * (dw * bpp)) + (x * bpp) + i] = (guchar) floorf (r * 255.0f + 0.5f);
            }
        }
    }

  g_free (tmp);
}


/**
 * 3D Scaling
 */


static void
scale_volume_image_nearest (guchar       *dst,
                            gint          dw,
                            gint          dh,
                            gint          dd,
                            guchar       *src,
                            gint          sw,
                            gint          sh,
                            gint          sd,
                            gint          bpp,
                            filterfunc_t  filter,
                            gfloat        support,
                            wrapfunc_t    wrap,
                            gint          gc,
                            gfloat        gamma)
{
  gint n, x, y, z;
  gint ix, iy, iz;

  for (z = 0; z < dd; ++z)
    {
      iz = (z * sd + sd / 2) / dd;
      for (y = 0; y < dh; ++y)
        {
          iy = (y * sh + sh / 2) / dh;
          for (x = 0; x < dw; ++x)
            {
              ix = (x * sw + sw / 2) / dw;
              for (n = 0; n < bpp; ++n)
                {
                  dst[(z * (dw * dh)) + (y * dw) + (x * bpp) + n] =
                    src[(iz * (sw * sh)) + (iy * sw) + (ix * bpp) + n];
                }
            }
        }
    }
}

static void
scale_volume_image (guchar       *dst,
                    gint          dw,
                    gint          dh,
                    gint          dd,
                    guchar       *src,
                    gint          sw,
                    gint          sh,
                    gint          sd,
                    gint          bpp,
                    filterfunc_t  filter,
                    gfloat        support,
                    wrapfunc_t    wrap,
                    gint          gc,
                    gfloat        gamma)
{
  const gfloat xfactor = (gfloat) dw / (gfloat) sw;
  const gfloat yfactor = (gfloat) dh / (gfloat) sh;
  const gfloat zfactor = (gfloat) dd / (gfloat) sd;

  gint   x, y, z, start, stop, nmax, n, i;
  gfloat center, contrib, density, s, r, t;
  gint   sstride  = sw * bpp;
  gint   zstride  = sh * sw * bpp;
  gfloat xscale   = MIN (xfactor, 1.0f);
  gfloat yscale   = MIN (yfactor, 1.0f);
  gfloat zscale   = MIN (zfactor, 1.0f);
  gfloat xsupport = support / xscale;
  gfloat ysupport = support / yscale;
  gfloat zsupport = support / zscale;
  guchar *d, *row, *col, *slice;
  guchar *tmp1, *tmp2;

  /* down to a 2D image, use the faster 2D image resampler */
  if (dd == 1 && sd == 1)
    {
      scale_image (dst, dw, dh, src, sw, sh, bpp, filter, support, wrap, gc, gamma);
      return;
    }

  if (xsupport <= 0.5f)
    {
      xsupport = 0.5f + 1e-10f;
      xscale = 1.0f;
    }

  if (ysupport <= 0.5f)
    {
      ysupport = 0.5f + 1e-10f;
      yscale = 1.0f;
    }

  if (zsupport <= 0.5f)
    {
      zsupport = 0.5f + 1e-10f;
      zscale = 1.0f;
    }

  tmp1 = g_malloc (sh * sw * bpp);
  tmp2 = g_malloc (dh * sw * bpp);

  for (z = 0; z < dd; ++z)
    {
      /* resample in Z direction */
      d = tmp1;

      center = ((gfloat) z + 0.5f) / zfactor;
      start = (gint) roundf ((center - zsupport) + 0.5f);
      stop =  (gint) roundf ((center + zsupport) + 0.5f);
      nmax = stop - start;
      s = (gfloat) start - center + 0.5f;

#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic)                      \
  private(x, y, slice, i, n, density, r, t, contrib)
#endif
      for (y = 0; y < sh; ++y)
        {
          for (x = 0; x < sw; ++x)
            {
              slice = src + (y * (sw * bpp)) + (x * bpp);

              for (i = 0; i < bpp; ++i)
                {
                  density = 0.0f;
                  r = 0.0f;

                  for (n = 0; n < nmax; ++n)
                    {
                      contrib = filter((s + n) * zscale);
                      density += contrib;
                      if (i == 3)
                        t = (gfloat) slice[(wrap (start + n, sd) * zstride) + i] / 255.0f;
                      else
                        t = gamma_to_linear (gc, (gfloat) slice[(wrap (start + n, sd) * zstride) + i] / 255.0f, gamma);
                      r += t * contrib;
                    }

                  if (density != 0.0f && density != 1.0f)
                    r /= density;

                  r = MIN (1.0f, MAX (0.0f, r));

                  if (i != 3)
                    r = linear_to_gamma (gc, r, gamma);

                  d[((y * sw) + x) * bpp + i] = (guchar) floorf (r * 255.0f + 0.5f);
                }
            }
        }

      /* resample in Y direction */
      d = tmp2;
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic)                              \
  private(x, y, col, center, start, stop, nmax, s, i, n, density, r, t, contrib)
#endif
      for (y = 0; y < dh; ++y)
        {
          center = ((gfloat) y + 0.5f) / yfactor;
          start = (gint) roundf ((center - ysupport) + 0.5f);
          stop =  (gint) roundf ((center + ysupport) + 0.5f);
          nmax = stop - start;
          s = (gfloat) start - center + 0.5f;

          for (x = 0; x < sw; ++x)
            {
              col = tmp1 + (x * bpp);

              for (i = 0; i < bpp; ++i)
                {
                  density = 0.0f;
                  r = 0.0f;

                  for (n = 0; n < nmax; ++n)
                    {
                      contrib = filter((s + n) * yscale);
                      density += contrib;
                      if (i == 3)
                        t = (gfloat) col[(wrap (start + n, sh) * sstride) + i] / 255.0f;
                      else
                        t = gamma_to_linear (gc, (gfloat) col[(wrap (start + n, sh) * sstride) + i] / 255.0f, gamma);
                      r += t * contrib;
                    }

                  if (density != 0.0f && density != 1.0f)
                    r /= density;

                  r = MIN (1.0f, MAX (0.0f, r));

                  if (i != 3)
                    r = linear_to_gamma (gc, r, gamma);

                  d[((y * sw) + x) * bpp + i] = (guchar) floorf (r * 255.0f + 0.5f);
                }
            }
        }

      /* resample in X direction */
      d = dst;
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic)                              \
  private(x, y, row, center, start, stop, nmax, s, i, n, density, r, t, contrib)
#endif
      for (y = 0; y < dh; ++y)
        {
          row = tmp2 + (y * sstride);

          for (x = 0; x < dw; ++x)
            {
              center = ((gfloat) x + 0.5f) / xfactor;
              start = (gint) roundf ((center - xsupport) + 0.5f);
              stop =  (gint) roundf ((center + xsupport) + 0.5f);
              nmax = stop - start;
              s = (gfloat) start - center + 0.5f;

              for (i = 0; i < bpp; ++i)
                {
                  density = 0.0f;
                  r = 0.0f;

                  for (n = 0; n < nmax; ++n)
                    {
                      contrib = filter((s + n) * xscale);
                      density += contrib;
                      if (i == 3)
                        t = (gfloat) row[(wrap (start + n, sw) * bpp) + i] / 255.0f;
                      else
                        t = gamma_to_linear (gc, (gfloat) row[(wrap (start + n, sw) * bpp) + i] / 255.0f, gamma);
                      r += t * contrib;
                    }

                  if (density != 0.0f && density != 1.0f)
                    r /= density;

                  r = MIN (1.0f, MAX (0.0f, r));

                  if (i != 3)
                    r = linear_to_gamma (gc, r, gamma);

                  d[((z * dh * dw) + (y * dw) + x) * bpp + i] = (guchar) floorf (r * 255.0f + 0.5f);
                }
            }
        }
    }

  g_free (tmp1);
  g_free (tmp2);
}


/**
 * Filter Lookup-table
 */


static struct
{
  gint         filter;
  filterfunc_t func;
  gfloat       support;
} filters[] =
{
  { DDS_MIPMAP_FILTER_BOX,       box_filter,       0.5f },
  { DDS_MIPMAP_FILTER_TRIANGLE,  triangle_filter,  1.0f },
  { DDS_MIPMAP_FILTER_QUADRATIC, quadratic_filter, 1.5f },
  { DDS_MIPMAP_FILTER_BSPLINE,   bspline_filter,   2.0f },
  { DDS_MIPMAP_FILTER_MITCHELL,  mitchell_filter,  2.0f },
  { DDS_MIPMAP_FILTER_CATROM,    catrom_filter,    2.0f },
  { DDS_MIPMAP_FILTER_LANCZOS,   lanczos_filter,   3.0f },
  { DDS_MIPMAP_FILTER_KAISER,    kaiser_filter,    3.0f },
  { DDS_MIPMAP_FILTER_MAX,       NULL,             0.0f }
};


/**
 * Alpha-test Coverage - portion of visible texels after alpha test:
 * if (texel_alpha < alpha_test_threshold) discard;
 */


static gfloat
calc_alpha_test_coverage (guchar *src,
                          guint   width,
                          guint   height,
                          gint    bpp,
                          gfloat  alpha_test_threshold,
                          gfloat  alpha_scale)
{
  const gint alpha_channel_idx = 3;
  gint  rowbytes = width * bpp;
  gint  coverage = 0;
  guint x, y;

  if (bpp <= alpha_channel_idx)
    {
      /* No alpha channel */
      return 1.0f;
    }

  for (y = 0; y < height; ++y)
    {
      for (x = 0; x < width; ++x)
        {
          const gfloat alpha = src[y * rowbytes + (x * bpp) + alpha_channel_idx];
          if ((alpha * alpha_scale) >= (alpha_test_threshold * 255))
            {
              ++coverage;
            }
        }
    }

  return (gfloat) coverage / (width * height);
}

static void
scale_alpha_to_coverage (guchar *img,
                         guint   width,
                         guint   height,
                         gint    bpp,
                         gfloat  desired_coverage,
                         gfloat  alpha_test_threshold)
{
  const gint rowbytes          = width * bpp;
  const gint alpha_channel_idx = 3;
  gfloat     min_alpha_scale   = 0.0f;
  gfloat     max_alpha_scale   = 4.0f;
  gfloat     alpha_scale       = 1.0f;
  guint      x, y;
  gint       i;

  if (bpp <= alpha_channel_idx)
    {
      /* No alpha channel */
      return;
    }

  /* Binary search */
  for (i = 0; i < 10; i++)
    {
      gfloat cur_coverage = calc_alpha_test_coverage (img, width, height, bpp, alpha_test_threshold, alpha_scale);

      if (cur_coverage < desired_coverage)
        {
          min_alpha_scale = alpha_scale;
        }
      else if (cur_coverage > desired_coverage)
        {
          max_alpha_scale = alpha_scale;
        }
      else
        {
          break;
        }

      alpha_scale = (min_alpha_scale + max_alpha_scale) / 2;
    }

  /* Scale alpha channel */
  for (y = 0; y < height; ++y)
    {
      for (x = 0; x < width; ++x)
        {
          gfloat new_alpha = img[y * rowbytes + (x * bpp) + alpha_channel_idx] * alpha_scale;
          if (new_alpha > 255.0f)
            {
              new_alpha = 255.0f;
            }

          img[y * rowbytes + (x * bpp) + alpha_channel_idx] = (guchar) new_alpha;
        }
    }
}


/**
 * Mipmap Generation
 */


gint
generate_mipmaps (guchar *dst,
                  guchar *src,
                  guint   width,
                  guint   height,
                  gint    bpp,
                  gint    indexed,
                  gint    mipmaps,
                  gint    filter,
                  gint    wrap,
                  gint    gc,
                  gfloat  gamma,
                  gint    preserve_alpha_coverage,
                  gfloat  alpha_test_threshold)
{
  const gint   has_alpha   = (bpp >= 3);
  mipmapfunc_t mipmap_func = NULL;
  filterfunc_t filter_func = NULL;
  wrapfunc_t   wrap_func   = NULL;
  gfloat       coverage    = 1.0f;
  gfloat       support     = 0.0f;
  guint        sw, sh, dw, dh;
  guchar      *s, *d;
  gint         i;

  if (indexed || filter == DDS_MIPMAP_FILTER_NEAREST)
    {
      mipmap_func = scale_image_nearest;
    }
  else
    {
      if ((filter < DDS_MIPMAP_FILTER_NEAREST) ||
          (filter >= DDS_MIPMAP_FILTER_MAX))
        filter = DDS_MIPMAP_FILTER_BOX;

      mipmap_func = scale_image;

      for (i = 0; filters[i].filter != DDS_MIPMAP_FILTER_MAX; ++i)
        {
          if (filter == filters[i].filter)
            {
              filter_func = filters[i].func;
              support = filters[i].support;
              break;
            }
        }
    }

  switch (wrap)
    {
    case DDS_MIPMAP_WRAP_MIRROR: wrap_func = wrap_mirror; break;
    case DDS_MIPMAP_WRAP_REPEAT: wrap_func = wrap_repeat; break;
    case DDS_MIPMAP_WRAP_CLAMP:  wrap_func = wrap_clamp;  break;
    default:                     wrap_func = wrap_clamp;  break;
    }

  if (has_alpha && preserve_alpha_coverage)
    {
      coverage = calc_alpha_test_coverage (src, width, height, bpp,
                                           alpha_test_threshold,
                                           1.0f);
    }

  memcpy (dst, src, width * height * bpp);

  s = dst;
  d = dst + (width * height * bpp);

  dw = sw = width;
  dh = sh = height;

  for (i = 1; i < mipmaps; ++i)
    {
      dw = MAX (1, dw >> 1);
      dh = MAX (1, dh >> 1);

      mipmap_func (d, dw, dh, s, sw, sh, bpp, filter_func, support, wrap_func, gc, gamma);

      if (has_alpha && preserve_alpha_coverage)
        {
          scale_alpha_to_coverage (d, dw, dh, bpp, coverage, alpha_test_threshold);
        }

      s = d;
      sw = dw;
      sh = dh;
      d += (dw * dh * bpp);
    }

  return 1;
}

gint
generate_volume_mipmaps (guchar *dst,
                         guchar *src,
                         guint   width,
                         guint   height,
                         guint   depth,
                         gint    bpp,
                         gint    indexed,
                         gint    mipmaps,
                         gint    filter,
                         gint    wrap,
                         gint    gc,
                         gfloat  gamma)
{
  volmipmapfunc_t mipmap_func = NULL;
  filterfunc_t    filter_func = NULL;
  wrapfunc_t      wrap_func   = NULL;
  gfloat          support     = 0.0f;
  guint           sw, sh, sd;
  guint           dw, dh, dd;
  guchar         *s, *d;
  gint            i;

  if (indexed || filter == DDS_MIPMAP_FILTER_NEAREST)
    {
      mipmap_func = scale_volume_image_nearest;
    }
  else
    {
      if ((filter < DDS_MIPMAP_FILTER_NEAREST) ||
          (filter >= DDS_MIPMAP_FILTER_MAX))
        filter = DDS_MIPMAP_FILTER_BOX;

      mipmap_func = scale_volume_image;

      for (i = 0; filters[i].filter != DDS_MIPMAP_FILTER_MAX; ++i)
        {
          if (filter == filters[i].filter)
            {
              filter_func = filters[i].func;
              support = filters[i].support;
              break;
            }
        }
    }

  switch (wrap)
    {
    case DDS_MIPMAP_WRAP_MIRROR: wrap_func = wrap_mirror; break;
    case DDS_MIPMAP_WRAP_REPEAT: wrap_func = wrap_repeat; break;
    case DDS_MIPMAP_WRAP_CLAMP:  wrap_func = wrap_clamp;  break;
    default:                     wrap_func = wrap_clamp;  break;
    }

  memcpy (dst, src, width * height * depth * bpp);

  s = dst;
  d = dst + (width * height * depth * bpp);

  sw = width;
  sh = height;
  sd = depth;

  for (i = 1; i < mipmaps; ++i)
    {
      dw = MAX (1, sw >> 1);
      dh = MAX (1, sh >> 1);
      dd = MAX (1, sd >> 1);

      mipmap_func (d, dw, dh, dd, s, sw, sh, sd, bpp, filter_func, support, wrap_func, gc, gamma);

      s = d;
      sw = dw;
      sh = dh;
      sd = dd;
      d += (dw * dh * dd * bpp);
    }

  return 1;
}

Messung
CHZG
85889589

¤ Dauer der Verarbeitung: 0.14 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104842
#Domains=499166