/* The GIMP -- an image manipulation program
 * Copyright (C) 1995-2003 Spencer Kimball and Peter Mattis
 *
 * 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; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/* NOTE: This file is autogenerated by pdbgen.pl. */

#include "config.h"


#include <glib-object.h>

#include "libgimpmath/gimpmath.h"

#include "pdb-types.h"
#include "procedural_db.h"

#include "config/gimpcoreconfig.h"
#include "core/gimp-transform-utils.h"
#include "core/gimp.h"
#include "core/gimpdrawable-transform.h"
#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
#include "core/gimpprogress.h"
#include "gimp-intl.h"

static ProcRecord drawable_transform_flip_simple_proc;
static ProcRecord drawable_transform_flip_proc;
static ProcRecord drawable_transform_flip_default_proc;
static ProcRecord drawable_transform_perspective_proc;
static ProcRecord drawable_transform_perspective_default_proc;
static ProcRecord drawable_transform_rotate_simple_proc;
static ProcRecord drawable_transform_rotate_proc;
static ProcRecord drawable_transform_rotate_default_proc;
static ProcRecord drawable_transform_scale_proc;
static ProcRecord drawable_transform_scale_default_proc;
static ProcRecord drawable_transform_shear_proc;
static ProcRecord drawable_transform_shear_default_proc;
static ProcRecord drawable_transform_2d_proc;
static ProcRecord drawable_transform_2d_default_proc;
static ProcRecord drawable_transform_matrix_proc;
static ProcRecord drawable_transform_matrix_default_proc;

void
register_drawable_transform_procs (Gimp *gimp)
{
  procedural_db_register (gimp, &drawable_transform_flip_simple_proc);
  procedural_db_register (gimp, &drawable_transform_flip_proc);
  procedural_db_register (gimp, &drawable_transform_flip_default_proc);
  procedural_db_register (gimp, &drawable_transform_perspective_proc);
  procedural_db_register (gimp, &drawable_transform_perspective_default_proc);
  procedural_db_register (gimp, &drawable_transform_rotate_simple_proc);
  procedural_db_register (gimp, &drawable_transform_rotate_proc);
  procedural_db_register (gimp, &drawable_transform_rotate_default_proc);
  procedural_db_register (gimp, &drawable_transform_scale_proc);
  procedural_db_register (gimp, &drawable_transform_scale_default_proc);
  procedural_db_register (gimp, &drawable_transform_shear_proc);
  procedural_db_register (gimp, &drawable_transform_shear_default_proc);
  procedural_db_register (gimp, &drawable_transform_2d_proc);
  procedural_db_register (gimp, &drawable_transform_2d_default_proc);
  procedural_db_register (gimp, &drawable_transform_matrix_proc);
  procedural_db_register (gimp, &drawable_transform_matrix_default_proc);
}

static Argument *
drawable_transform_flip_simple_invoker (Gimp         *gimp,
                                        GimpContext  *context,
                                        GimpProgress *progress,
                                        Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gint32 flip_type;
  gboolean auto_center;
  gdouble axis;
  gboolean clip_result;

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  flip_type = args[1].value.pdb_int;
  if (flip_type < GIMP_ORIENTATION_HORIZONTAL || flip_type > GIMP_ORIENTATION_VERTICAL)
    success = FALSE;

  auto_center = args[2].value.pdb_int ? TRUE : FALSE;

  axis = args[3].value.pdb_float;

  clip_result = args[4].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = gimp_item_is_attached (GIMP_ITEM (drawable));

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          success = gimp_drawable_transform_flip (drawable, context,
                                                  flip_type,
                                                  auto_center, axis,
                                                  clip_result);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_flip_simple_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_flip_simple_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_INT32,
    "flip_type",
    "Type of flip: GIMP_ORIENTATION_HORIZONTAL (0) or GIMP_ORIENTATION_VERTICAL (1)"
  },
  {
    GIMP_PDB_INT32,
    "auto_center",
    "Whether to automatically position the axis in the selection center"
  },
  {
    GIMP_PDB_FLOAT,
    "axis",
    "coord. of flip axis"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_flip_simple_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The flipped drawable"
  }
};

static ProcRecord drawable_transform_flip_simple_proc =
{
  "gimp_drawable_transform_flip_simple",
  "Flip the specified drawable either vertically or horizontally.",
  "This procedure flips the specified drawable if no selection exists. If a selection exists, the portion of the drawable which lies under the selection is cut from the drawable and made into a floating selection which is then flipped. If auto_center is set to true, the flip is around the selection's center. Otherwise, the coordinate of the axis needs to be specified. The return value is the ID of the flipped drawable. If there was no selection, this will be equal to the drawable ID supplied as input. Otherwise, this will be the newly created and flipped drawable.",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  5,
  drawable_transform_flip_simple_inargs,
  1,
  drawable_transform_flip_simple_outargs,
  { { drawable_transform_flip_simple_invoker } }
};

static Argument *
drawable_transform_flip_invoker (Gimp         *gimp,
                                 GimpContext  *context,
                                 GimpProgress *progress,
                                 Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gdouble x0;
  gdouble y0;
  gdouble x1;
  gdouble y1;
  gint32 transform_direction;
  gint32 interpolation;
  gboolean supersample;
  gint32 recursion_level;
  gboolean clip_result;

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  x0 = args[1].value.pdb_float;

  y0 = args[2].value.pdb_float;

  x1 = args[3].value.pdb_float;

  y1 = args[4].value.pdb_float;

  transform_direction = args[5].value.pdb_int;
  if (transform_direction < GIMP_TRANSFORM_FORWARD || transform_direction > GIMP_TRANSFORM_BACKWARD)
    success = FALSE;

  interpolation = args[6].value.pdb_int;
  if (interpolation < GIMP_INTERPOLATION_NONE || interpolation > GIMP_INTERPOLATION_CUBIC)
    success = FALSE;

  supersample = args[7].value.pdb_int ? TRUE : FALSE;

  recursion_level = args[8].value.pdb_int;
  if (recursion_level <= 0)
    success = FALSE;

  clip_result = args[9].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = gimp_item_is_attached (GIMP_ITEM (drawable));

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          GimpMatrix3 matrix;

          /* Assemble the transformation matrix */
          gimp_transform_matrix_flip_free (x, y, width, height,
                                           x0, y0, x1, y1,
                                           &matrix);

          if (progress)
            gimp_progress_start (progress, _("Flip..."), FALSE);

          /* Transform the selection */
          success = gimp_drawable_transform_affine (drawable, context,
                                                    &matrix, transform_direction,
                                                    interpolation, supersample,
                                                    recursion_level,
                                                    clip_result, progress);

          if (progress)
            gimp_progress_end (progress);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_flip_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_flip_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_FLOAT,
    "x0",
    "horz. coord. of one end of axis"
  },
  {
    GIMP_PDB_FLOAT,
    "y0",
    "vert. coord. of one end of axis"
  },
  {
    GIMP_PDB_FLOAT,
    "x1",
    "horz. coord. of other end of axis"
  },
  {
    GIMP_PDB_FLOAT,
    "y1",
    "vert. coord. of other end of axis"
  },
  {
    GIMP_PDB_INT32,
    "transform_direction",
    "Direction of Transformation: { GIMP_TRANSFORM_FORWARD (0), GIMP_TRANSFORM_BACKWARD (1) }"
  },
  {
    GIMP_PDB_INT32,
    "interpolation",
    "Type of interpolation: { GIMP_INTERPOLATION_NONE (0), GIMP_INTERPOLATION_LINEAR (1), GIMP_INTERPOLATION_CUBIC (2) }"
  },
  {
    GIMP_PDB_INT32,
    "supersample",
    "Whether to perform supersample"
  },
  {
    GIMP_PDB_INT32,
    "recursion_level",
    "Level of recursion (3 is a nice default)"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_flip_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The flipped drawable"
  }
};

static ProcRecord drawable_transform_flip_proc =
{
  "gimp_drawable_transform_flip",
  "Flip the specified drawable around a given line.",
  "This procedure flips the specified drawable if no selection exists. If a selection exists, the portion of the drawable which lies under the selection is cut from the drawable and made into a floating selection which is then flipped. The axis to flip around is specified by specifying two points from that line. The return value is the ID of the flipped drawable. If there was no selection, this will be equal to the drawable ID supplied as input. Otherwise, this will be the newly created and flipped drawable. The clip results parameter specifies wheter current selection will affect the transform.",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  10,
  drawable_transform_flip_inargs,
  1,
  drawable_transform_flip_outargs,
  { { drawable_transform_flip_invoker } }
};

static Argument *
drawable_transform_flip_default_invoker (Gimp         *gimp,
                                         GimpContext  *context,
                                         GimpProgress *progress,
                                         Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gdouble x0;
  gdouble y0;
  gdouble x1;
  gdouble y1;
  gboolean interpolate;
  gboolean clip_result;

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  x0 = args[1].value.pdb_float;

  y0 = args[2].value.pdb_float;

  x1 = args[3].value.pdb_float;

  y1 = args[4].value.pdb_float;

  interpolate = args[5].value.pdb_int ? TRUE : FALSE;

  clip_result = args[6].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = gimp_item_is_attached (GIMP_ITEM (drawable));

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          GimpMatrix3           matrix;
          GimpInterpolationType interpolation_type = GIMP_INTERPOLATION_NONE;

          /* Assemble the transformation matrix */
          gimp_transform_matrix_flip_free (x, y, width, height,
                                           x0, y0, x1, y1,
                                           &matrix);

          if (interpolate)
            interpolation_type = gimp->config->interpolation_type;

          if (progress)
            gimp_progress_start (progress, _("Flip..."), FALSE);

          /* Transform the selection */
          success = gimp_drawable_transform_affine (drawable, context,
                                                    &matrix, GIMP_TRANSFORM_FORWARD,
                                                    interpolation_type,
                                                    interpolate, 3,
                                                    clip_result, progress);

          if (progress)
            gimp_progress_end (progress);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_flip_default_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_flip_default_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_FLOAT,
    "x0",
    "horz. coord. of one end of axis"
  },
  {
    GIMP_PDB_FLOAT,
    "y0",
    "vert. coord. of one end of axis"
  },
  {
    GIMP_PDB_FLOAT,
    "x1",
    "horz. coord. of other end of axis"
  },
  {
    GIMP_PDB_FLOAT,
    "y1",
    "vert. coord. of other end of axis"
  },
  {
    GIMP_PDB_INT32,
    "interpolate",
    "Whether to use interpolation and supersampling"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_flip_default_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The flipped drawable"
  }
};

static ProcRecord drawable_transform_flip_default_proc =
{
  "gimp_drawable_transform_flip_default",
  "Flip the specified drawable around a given line.",
  "This procedure is a variant of gimp_drawable_transform_flip() which uses no interpolation/supersampling at all, or default values (depending on the 'interpolate' parameter).",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  7,
  drawable_transform_flip_default_inargs,
  1,
  drawable_transform_flip_default_outargs,
  { { drawable_transform_flip_default_invoker } }
};

static Argument *
drawable_transform_perspective_invoker (Gimp         *gimp,
                                        GimpContext  *context,
                                        GimpProgress *progress,
                                        Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gint32 transform_direction;
  gint32 interpolation;
  gboolean supersample;
  gint32 recursion_level;
  gboolean clip_result;
  gdouble trans_info[8];

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  trans_info[X0] = args[1].value.pdb_float;

  trans_info[Y0] = args[2].value.pdb_float;

  trans_info[X1] = args[3].value.pdb_float;

  trans_info[Y1] = args[4].value.pdb_float;

  trans_info[X2] = args[5].value.pdb_float;

  trans_info[Y2] = args[6].value.pdb_float;

  trans_info[X3] = args[7].value.pdb_float;

  trans_info[Y3] = args[8].value.pdb_float;

  transform_direction = args[9].value.pdb_int;
  if (transform_direction < GIMP_TRANSFORM_FORWARD || transform_direction > GIMP_TRANSFORM_BACKWARD)
    success = FALSE;

  interpolation = args[10].value.pdb_int;
  if (interpolation < GIMP_INTERPOLATION_NONE || interpolation > GIMP_INTERPOLATION_CUBIC)
    success = FALSE;

  supersample = args[11].value.pdb_int ? TRUE : FALSE;

  recursion_level = args[12].value.pdb_int;
  if (recursion_level <= 0)
    success = FALSE;

  clip_result = args[13].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = gimp_item_is_attached (GIMP_ITEM (drawable));

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          GimpMatrix3 matrix;

          /* Assemble the transformation matrix */
          gimp_transform_matrix_perspective (x, y, width, height,
                                             trans_info[X0], trans_info[Y0],
                                             trans_info[X1], trans_info[Y1],
                                             trans_info[X2], trans_info[Y2],
                                             trans_info[X3], trans_info[Y3],
                                             &matrix);

          if (progress)
            gimp_progress_start (progress, _("Perspective..."), FALSE);

          /* Transform the selection */
          success = gimp_drawable_transform_affine (drawable, context,
                                                    &matrix, transform_direction,
                                                    interpolation, supersample,
                                                    recursion_level,
                                                    clip_result, progress);

          if (progress)
            gimp_progress_end (progress);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_perspective_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_perspective_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_FLOAT,
    "x0",
    "The new x coordinate of upper-left corner of original bounding box"
  },
  {
    GIMP_PDB_FLOAT,
    "y0",
    "The new y coordinate of upper-left corner of original bounding box"
  },
  {
    GIMP_PDB_FLOAT,
    "x1",
    "The new x coordinate of upper-right corner of original bounding box"
  },
  {
    GIMP_PDB_FLOAT,
    "y1",
    "The new y coordinate of upper-right corner of original bounding box"
  },
  {
    GIMP_PDB_FLOAT,
    "x2",
    "The new x coordinate of lower-left corner of original bounding box"
  },
  {
    GIMP_PDB_FLOAT,
    "y2",
    "The new y coordinate of lower-left corner of original bounding box"
  },
  {
    GIMP_PDB_FLOAT,
    "x3",
    "The new x coordinate of lower-right corner of original bounding box"
  },
  {
    GIMP_PDB_FLOAT,
    "y3",
    "The new y coordinate of lower-right corner of original bounding box"
  },
  {
    GIMP_PDB_INT32,
    "transform_direction",
    "Direction of Transformation: { GIMP_TRANSFORM_FORWARD (0), GIMP_TRANSFORM_BACKWARD (1) }"
  },
  {
    GIMP_PDB_INT32,
    "interpolation",
    "Type of interpolation: { GIMP_INTERPOLATION_NONE (0), GIMP_INTERPOLATION_LINEAR (1), GIMP_INTERPOLATION_CUBIC (2) }"
  },
  {
    GIMP_PDB_INT32,
    "supersample",
    "Whether to perform supersample"
  },
  {
    GIMP_PDB_INT32,
    "recursion_level",
    "Level of recursion (3 is a nice default)"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_perspective_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The newly mapped drawable"
  }
};

static ProcRecord drawable_transform_perspective_proc =
{
  "gimp_drawable_transform_perspective",
  "Perform a possibly non-affine transformation on the specified drawable, with extra parameters.",
  "This procedure performs a possibly non-affine transformation on the specified drawable by allowing the corners of the original bounding box to be arbitrarily remapped to any values. The specified drawable is remapped if no selection exists. However, if a selection exists, the portion of the drawable which lies under the selection is cut from the drawable and made into a floating selection which is then remapped as specified. The return value is the ID of the remapped drawable. If there was no selection, this will be equal to the drawable ID supplied as input. Otherwise, this will be the newly created and remapped drawable. The 4 coordinates specify the new locations of each corner of the original bounding box. By specifying these values, any affine transformation (rotation, scaling, translation) can be affected. Additionally, these values can be specified such that the resulting transformed drawable will appear to have been projected via a perspective transform.",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  14,
  drawable_transform_perspective_inargs,
  1,
  drawable_transform_perspective_outargs,
  { { drawable_transform_perspective_invoker } }
};

static Argument *
drawable_transform_perspective_default_invoker (Gimp         *gimp,
                                                GimpContext  *context,
                                                GimpProgress *progress,
                                                Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gboolean interpolate;
  gboolean clip_result;
  gdouble trans_info[8];

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  trans_info[X0] = args[1].value.pdb_float;

  trans_info[Y0] = args[2].value.pdb_float;

  trans_info[X1] = args[3].value.pdb_float;

  trans_info[Y1] = args[4].value.pdb_float;

  trans_info[X2] = args[5].value.pdb_float;

  trans_info[Y2] = args[6].value.pdb_float;

  trans_info[X3] = args[7].value.pdb_float;

  trans_info[Y3] = args[8].value.pdb_float;

  interpolate = args[9].value.pdb_int ? TRUE : FALSE;

  clip_result = args[10].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = gimp_item_is_attached (GIMP_ITEM (drawable));

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          GimpMatrix3           matrix;
          GimpInterpolationType interpolation_type = GIMP_INTERPOLATION_NONE;

          /* Assemble the transformation matrix */
          gimp_transform_matrix_perspective (x, y, width, height,
                                             trans_info[X0], trans_info[Y0],
                                             trans_info[X1], trans_info[Y1],
                                             trans_info[X2], trans_info[Y2],
                                             trans_info[X3], trans_info[Y3],
                                             &matrix);

          if (interpolate)
            interpolation_type = gimp->config->interpolation_type;

          if (progress)
            gimp_progress_start (progress, _("Perspective..."), FALSE);

          /* Transform the selection */
          success = gimp_drawable_transform_affine (drawable, context,
                                                    &matrix, GIMP_TRANSFORM_FORWARD,
                                                    interpolation_type,
                                                    interpolate, 3,
                                                    clip_result, progress);

          if (progress)
            gimp_progress_end (progress);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_perspective_default_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_perspective_default_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_FLOAT,
    "x0",
    "The new x coordinate of upper-left corner of original bounding box"
  },
  {
    GIMP_PDB_FLOAT,
    "y0",
    "The new y coordinate of upper-left corner of original bounding box"
  },
  {
    GIMP_PDB_FLOAT,
    "x1",
    "The new x coordinate of upper-right corner of original bounding box"
  },
  {
    GIMP_PDB_FLOAT,
    "y1",
    "The new y coordinate of upper-right corner of original bounding box"
  },
  {
    GIMP_PDB_FLOAT,
    "x2",
    "The new x coordinate of lower-left corner of original bounding box"
  },
  {
    GIMP_PDB_FLOAT,
    "y2",
    "The new y coordinate of lower-left corner of original bounding box"
  },
  {
    GIMP_PDB_FLOAT,
    "x3",
    "The new x coordinate of lower-right corner of original bounding box"
  },
  {
    GIMP_PDB_FLOAT,
    "y3",
    "The new y coordinate of lower-right corner of original bounding box"
  },
  {
    GIMP_PDB_INT32,
    "interpolate",
    "Whether to use interpolation and supersampling"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_perspective_default_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The newly mapped drawable"
  }
};

static ProcRecord drawable_transform_perspective_default_proc =
{
  "gimp_drawable_transform_perspective_default",
  "Perform a possibly non-affine transformation on the specified drawable, with extra parameters.",
  "This procedure is a variant of gimp_drawable_transform_perspective() which uses no interpolation/supersampling at all, or default values (depending on the 'interpolate' parameter).",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  11,
  drawable_transform_perspective_default_inargs,
  1,
  drawable_transform_perspective_default_outargs,
  { { drawable_transform_perspective_default_invoker } }
};

static Argument *
drawable_transform_rotate_simple_invoker (Gimp         *gimp,
                                          GimpContext  *context,
                                          GimpProgress *progress,
                                          Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gint32 rotate_type;
  gboolean auto_center;
  gint32 center_x;
  gint32 center_y;
  gboolean clip_result;

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  rotate_type = args[1].value.pdb_int;
  if (rotate_type < GIMP_ROTATE_90 || rotate_type > GIMP_ROTATE_270)
    success = FALSE;

  auto_center = args[2].value.pdb_int ? TRUE : FALSE;

  center_x = args[3].value.pdb_int;

  center_y = args[4].value.pdb_int;

  clip_result = args[5].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = gimp_item_is_attached (GIMP_ITEM (drawable));

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          success = gimp_drawable_transform_rotate (drawable, context,
                                                    rotate_type,
                                                    auto_center, center_x, center_y,
                                                    clip_result);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_rotate_simple_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_rotate_simple_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_INT32,
    "rotate_type",
    "Type of rotation: GIMP_ROTATE_90 (0), GIMP_ROTATE_180 (1), GIMP_ROTATE_270 (2)"
  },
  {
    GIMP_PDB_INT32,
    "auto_center",
    "Whether to automatically rotate around the selection center"
  },
  {
    GIMP_PDB_INT32,
    "center_x",
    "The hor. coordinate of the center of rotation"
  },
  {
    GIMP_PDB_INT32,
    "center_y",
    "The vert. coordinate of the center of rotation"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_rotate_simple_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The rotated drawable"
  }
};

static ProcRecord drawable_transform_rotate_simple_proc =
{
  "gimp_drawable_transform_rotate_simple",
  "Rotate the specified drawable about given coordinates through the specified angle.",
  "This function rotates the specified drawable if no selection exists. If a selection exists, the portion of the drawable which lies under the selection is cut from the drawable and made into a floating selection which is then rotated by the specified amount. The return value is the ID of the rotated drawable. If there was no selection, this will be equal to the drawable ID supplied as input. Otherwise, this will be the newly created and rotated drawable.",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  6,
  drawable_transform_rotate_simple_inargs,
  1,
  drawable_transform_rotate_simple_outargs,
  { { drawable_transform_rotate_simple_invoker } }
};

static Argument *
drawable_transform_rotate_invoker (Gimp         *gimp,
                                   GimpContext  *context,
                                   GimpProgress *progress,
                                   Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gdouble angle;
  gboolean auto_center;
  gint32 center_x;
  gint32 center_y;
  gint32 transform_direction;
  gint32 interpolation;
  gboolean supersample;
  gint32 recursion_level;
  gboolean clip_result;

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  angle = args[1].value.pdb_float;

  auto_center = args[2].value.pdb_int ? TRUE : FALSE;

  center_x = args[3].value.pdb_int;

  center_y = args[4].value.pdb_int;

  transform_direction = args[5].value.pdb_int;
  if (transform_direction < GIMP_TRANSFORM_FORWARD || transform_direction > GIMP_TRANSFORM_BACKWARD)
    success = FALSE;

  interpolation = args[6].value.pdb_int;
  if (interpolation < GIMP_INTERPOLATION_NONE || interpolation > GIMP_INTERPOLATION_CUBIC)
    success = FALSE;

  supersample = args[7].value.pdb_int ? TRUE : FALSE;

  recursion_level = args[8].value.pdb_int;
  if (recursion_level <= 0)
    success = FALSE;

  clip_result = args[9].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = gimp_item_is_attached (GIMP_ITEM (drawable));

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          GimpMatrix3 matrix;

          /* Assemble the transformation matrix */
          if (auto_center)
            gimp_transform_matrix_rotate (x, y, width, height, angle,
                                          &matrix);
          else
            gimp_transform_matrix_rotate_center (center_x, center_y, angle,
                                                 &matrix);

          if (progress)
            gimp_progress_start (progress, _("Rotating..."), FALSE);

          /* Transform the selection */
          success = gimp_drawable_transform_affine (drawable, context,
                                                    &matrix, transform_direction,
                                                    interpolation, supersample,
                                                    recursion_level,
                                                    clip_result, progress);

          if (progress)
            gimp_progress_end (progress);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_rotate_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_rotate_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_FLOAT,
    "angle",
    "The angle of rotation (radians)"
  },
  {
    GIMP_PDB_INT32,
    "auto_center",
    "Whether to automatically rotate around the selection center"
  },
  {
    GIMP_PDB_INT32,
    "center_x",
    "The hor. coordinate of the center of rotation"
  },
  {
    GIMP_PDB_INT32,
    "center_y",
    "The vert. coordinate of the center of rotation"
  },
  {
    GIMP_PDB_INT32,
    "transform_direction",
    "Direction of Transformation: { GIMP_TRANSFORM_FORWARD (0), GIMP_TRANSFORM_BACKWARD (1) }"
  },
  {
    GIMP_PDB_INT32,
    "interpolation",
    "Type of interpolation: { GIMP_INTERPOLATION_NONE (0), GIMP_INTERPOLATION_LINEAR (1), GIMP_INTERPOLATION_CUBIC (2) }"
  },
  {
    GIMP_PDB_INT32,
    "supersample",
    "Whether to perform supersample"
  },
  {
    GIMP_PDB_INT32,
    "recursion_level",
    "Level of recursion (3 is a nice default)"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_rotate_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The rotated drawable"
  }
};

static ProcRecord drawable_transform_rotate_proc =
{
  "gimp_drawable_transform_rotate",
  "Rotate the specified drawable about given coordinates through the specified angle.",
  "This function rotates the specified drawable if no selection exists. If a selection exists, the portion of the drawable which lies under the selection is cut from the drawable and made into a floating selection which is then rotated by the specified amount. The return value is the ID of the rotated drawable. If there was no selection, this will be equal to the drawable ID supplied as input. Otherwise, this will be the newly created and rotated drawable.",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  10,
  drawable_transform_rotate_inargs,
  1,
  drawable_transform_rotate_outargs,
  { { drawable_transform_rotate_invoker } }
};

static Argument *
drawable_transform_rotate_default_invoker (Gimp         *gimp,
                                           GimpContext  *context,
                                           GimpProgress *progress,
                                           Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gdouble angle;
  gboolean auto_center;
  gint32 center_x;
  gint32 center_y;
  gboolean interpolate;
  gboolean clip_result;

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  angle = args[1].value.pdb_float;

  auto_center = args[2].value.pdb_int ? TRUE : FALSE;

  center_x = args[3].value.pdb_int;

  center_y = args[4].value.pdb_int;

  interpolate = args[5].value.pdb_int ? TRUE : FALSE;

  clip_result = args[6].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = gimp_item_is_attached (GIMP_ITEM (drawable));

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          GimpMatrix3           matrix;
          GimpInterpolationType interpolation_type = GIMP_INTERPOLATION_NONE;

          /* Assemble the transformation matrix */
          if (auto_center)
            gimp_transform_matrix_rotate (x, y, width, height, angle,
                                          &matrix);
          else
            gimp_transform_matrix_rotate_center (center_x, center_y, angle,
                                                 &matrix);

          if (interpolate)
            interpolation_type = gimp->config->interpolation_type;

          if (progress)
            gimp_progress_start (progress, _("Rotating..."), FALSE);

          /* Transform the selection */
          success = gimp_drawable_transform_affine (drawable, context,
                                                    &matrix, GIMP_TRANSFORM_FORWARD,
                                                    interpolation_type,
                                                    interpolate, 3,
                                                    clip_result, progress);

          if (progress)
            gimp_progress_end (progress);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_rotate_default_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_rotate_default_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_FLOAT,
    "angle",
    "The angle of rotation (radians)"
  },
  {
    GIMP_PDB_INT32,
    "auto_center",
    "Whether to automatically rotate around the selection center"
  },
  {
    GIMP_PDB_INT32,
    "center_x",
    "The hor. coordinate of the center of rotation"
  },
  {
    GIMP_PDB_INT32,
    "center_y",
    "The vert. coordinate of the center of rotation"
  },
  {
    GIMP_PDB_INT32,
    "interpolate",
    "Whether to use interpolation and supersampling"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_rotate_default_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The rotated drawable"
  }
};

static ProcRecord drawable_transform_rotate_default_proc =
{
  "gimp_drawable_transform_rotate_default",
  "Rotate the specified drawable about given coordinates through the specified angle.",
  "This procedure is a variant of gimp_drawable_transform_rotate() which uses no interpolation/supersampling at all, or default values (depending on the 'interpolate' parameter).",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  7,
  drawable_transform_rotate_default_inargs,
  1,
  drawable_transform_rotate_default_outargs,
  { { drawable_transform_rotate_default_invoker } }
};

static Argument *
drawable_transform_scale_invoker (Gimp         *gimp,
                                  GimpContext  *context,
                                  GimpProgress *progress,
                                  Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gint32 transform_direction;
  gint32 interpolation;
  gboolean supersample;
  gint32 recursion_level;
  gboolean clip_result;
  gdouble trans_info[4];

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  trans_info[X0] = args[1].value.pdb_float;

  trans_info[Y0] = args[2].value.pdb_float;

  trans_info[X1] = args[3].value.pdb_float;

  trans_info[Y1] = args[4].value.pdb_float;

  transform_direction = args[5].value.pdb_int;
  if (transform_direction < GIMP_TRANSFORM_FORWARD || transform_direction > GIMP_TRANSFORM_BACKWARD)
    success = FALSE;

  interpolation = args[6].value.pdb_int;
  if (interpolation < GIMP_INTERPOLATION_NONE || interpolation > GIMP_INTERPOLATION_CUBIC)
    success = FALSE;

  supersample = args[7].value.pdb_int ? TRUE : FALSE;

  recursion_level = args[8].value.pdb_int;
  if (recursion_level <= 0)
    success = FALSE;

  clip_result = args[9].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = (gimp_item_is_attached (GIMP_ITEM (drawable)) &&
                 trans_info[X0] < trans_info[X1] &&
                 trans_info[Y0] < trans_info[Y1]);

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          GimpMatrix3 matrix;

          /* Assemble the transformation matrix */
          gimp_transform_matrix_scale (x, y, width, height,
                                       trans_info[X0],
                                       trans_info[Y0],
                                       trans_info[X1] - trans_info[X0],
                                       trans_info[Y1] - trans_info[Y0],
                                       &matrix);

          if (progress)
            gimp_progress_start (progress, _("Scaling..."), FALSE);

          /* Transform the selection */
          success = gimp_drawable_transform_affine (drawable, context,
                                                    &matrix, transform_direction,
                                                    interpolation, supersample,
                                                    recursion_level,
                                                    clip_result, progress);

          if (progress)
            gimp_progress_end (progress);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_scale_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_scale_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_FLOAT,
    "x0",
    "The new x coordinate of upper-left corner of newly scaled region"
  },
  {
    GIMP_PDB_FLOAT,
    "y0",
    "The new y coordinate of upper-left corner of newly scaled region"
  },
  {
    GIMP_PDB_FLOAT,
    "x1",
    "The new x coordinate of lower-right corner of newly scaled region"
  },
  {
    GIMP_PDB_FLOAT,
    "y1",
    "The new y coordinate of lower-right corner of newly scaled region"
  },
  {
    GIMP_PDB_INT32,
    "transform_direction",
    "Direction of Transformation: { GIMP_TRANSFORM_FORWARD (0), GIMP_TRANSFORM_BACKWARD (1) }"
  },
  {
    GIMP_PDB_INT32,
    "interpolation",
    "Type of interpolation: { GIMP_INTERPOLATION_NONE (0), GIMP_INTERPOLATION_LINEAR (1), GIMP_INTERPOLATION_CUBIC (2) }"
  },
  {
    GIMP_PDB_INT32,
    "supersample",
    "Whether to perform supersample"
  },
  {
    GIMP_PDB_INT32,
    "recursion_level",
    "Level of recursion (3 is a nice default)"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_scale_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The scaled drawable"
  }
};

static ProcRecord drawable_transform_scale_proc =
{
  "gimp_drawable_transform_scale",
  "Scale the specified drawable with extra parameters",
  "This procedure scales the specified drawable if no selection exists. If a selection exists, the portion of the drawable which lies under the selection is cut from the drawable and made into a floating selection which is then scaled by the specified amount. The return value is the ID of the scaled drawable. If there was no selection, this will be equal to the drawable ID supplied as input. Otherwise, this will be the newly created and scaled drawable.",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  10,
  drawable_transform_scale_inargs,
  1,
  drawable_transform_scale_outargs,
  { { drawable_transform_scale_invoker } }
};

static Argument *
drawable_transform_scale_default_invoker (Gimp         *gimp,
                                          GimpContext  *context,
                                          GimpProgress *progress,
                                          Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gboolean interpolate;
  gboolean clip_result;
  gdouble trans_info[4];

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  trans_info[X0] = args[1].value.pdb_float;

  trans_info[Y0] = args[2].value.pdb_float;

  trans_info[X1] = args[3].value.pdb_float;

  trans_info[Y1] = args[4].value.pdb_float;

  interpolate = args[5].value.pdb_int ? TRUE : FALSE;

  clip_result = args[6].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = (gimp_item_is_attached (GIMP_ITEM (drawable)) &&
                 trans_info[X0] < trans_info[X1] &&
                 trans_info[Y0] < trans_info[Y1]);

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          GimpMatrix3           matrix;
          GimpInterpolationType interpolation_type = GIMP_INTERPOLATION_NONE;

          /* Assemble the transformation matrix */
          gimp_transform_matrix_scale (x, y, width, height,
                                       trans_info[X0],
                                       trans_info[Y0],
                                       trans_info[X1] - trans_info[X0],
                                       trans_info[Y1] - trans_info[Y0],
                                       &matrix);

          if (interpolate)
            interpolation_type = gimp->config->interpolation_type;

          if (progress)
            gimp_progress_start (progress, _("Scaling..."), FALSE);

          /* Transform the selection */
          success = gimp_drawable_transform_affine (drawable, context,
                                                    &matrix, GIMP_TRANSFORM_FORWARD,
                                                    interpolation_type,
                                                    interpolate, 3,
                                                    clip_result, progress);

          if (progress)
            gimp_progress_end (progress);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_scale_default_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_scale_default_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_FLOAT,
    "x0",
    "The new x coordinate of upper-left corner of newly scaled region"
  },
  {
    GIMP_PDB_FLOAT,
    "y0",
    "The new y coordinate of upper-left corner of newly scaled region"
  },
  {
    GIMP_PDB_FLOAT,
    "x1",
    "The new x coordinate of lower-right corner of newly scaled region"
  },
  {
    GIMP_PDB_FLOAT,
    "y1",
    "The new y coordinate of lower-right corner of newly scaled region"
  },
  {
    GIMP_PDB_INT32,
    "interpolate",
    "Whether to use interpolation and supersampling"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_scale_default_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The scaled drawable"
  }
};

static ProcRecord drawable_transform_scale_default_proc =
{
  "gimp_drawable_transform_scale_default",
  "Scale the specified drawable with extra parameters",
  "This procedure is a variant of gimp_drawable_transform_scale() which uses no interpolation/supersampling at all, or default values (depending on the 'interpolate' parameter).",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  7,
  drawable_transform_scale_default_inargs,
  1,
  drawable_transform_scale_default_outargs,
  { { drawable_transform_scale_default_invoker } }
};

static Argument *
drawable_transform_shear_invoker (Gimp         *gimp,
                                  GimpContext  *context,
                                  GimpProgress *progress,
                                  Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gint32 shear_type;
  gdouble magnitude;
  gint32 transform_direction;
  gint32 interpolation;
  gboolean supersample;
  gint32 recursion_level;
  gboolean clip_result;

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  shear_type = args[1].value.pdb_int;
  if (shear_type < GIMP_ORIENTATION_HORIZONTAL || shear_type > GIMP_ORIENTATION_VERTICAL)
    success = FALSE;

  magnitude = args[2].value.pdb_float;

  transform_direction = args[3].value.pdb_int;
  if (transform_direction < GIMP_TRANSFORM_FORWARD || transform_direction > GIMP_TRANSFORM_BACKWARD)
    success = FALSE;

  interpolation = args[4].value.pdb_int;
  if (interpolation < GIMP_INTERPOLATION_NONE || interpolation > GIMP_INTERPOLATION_CUBIC)
    success = FALSE;

  supersample = args[5].value.pdb_int ? TRUE : FALSE;

  recursion_level = args[6].value.pdb_int;
  if (recursion_level <= 0)
    success = FALSE;

  clip_result = args[7].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = gimp_item_is_attached (GIMP_ITEM (drawable));

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          GimpMatrix3 matrix;

          /* Assemble the transformation matrix */
          gimp_transform_matrix_shear (x, y, width, height,
                                       shear_type, magnitude,
                                       &matrix);

          if (progress)
            gimp_progress_start (progress, _("Shearing..."), FALSE);

          /* Transform the selection */
          success = gimp_drawable_transform_affine (drawable, context,
                                                    &matrix, transform_direction,
                                                    interpolation, supersample,
                                                    recursion_level,
                                                    clip_result, progress);

          if (progress)
            gimp_progress_end (progress);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_shear_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_shear_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_INT32,
    "shear_type",
    "Type of shear: GIMP_ORIENTATION_HORIZONTAL (0) or GIMP_ORIENTATION_VERTICAL (1)"
  },
  {
    GIMP_PDB_FLOAT,
    "magnitude",
    "The magnitude of the shear"
  },
  {
    GIMP_PDB_INT32,
    "transform_direction",
    "Direction of Transformation: { GIMP_TRANSFORM_FORWARD (0), GIMP_TRANSFORM_BACKWARD (1) }"
  },
  {
    GIMP_PDB_INT32,
    "interpolation",
    "Type of interpolation: { GIMP_INTERPOLATION_NONE (0), GIMP_INTERPOLATION_LINEAR (1), GIMP_INTERPOLATION_CUBIC (2) }"
  },
  {
    GIMP_PDB_INT32,
    "supersample",
    "Whether to perform supersample"
  },
  {
    GIMP_PDB_INT32,
    "recursion_level",
    "Level of recursion (3 is a nice default)"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_shear_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The sheared drawable"
  }
};

static ProcRecord drawable_transform_shear_proc =
{
  "gimp_drawable_transform_shear",
  "Shear the specified drawable about its center by the specified magnitude, with extra parameters.",
  "This procedure shears the specified drawable if no selection exists. If a selection exists, the portion of the drawable which lies under the selection is cut from the drawable and made into a floating selection which is then sheard by the specified amount. The return value is the ID of the sheard drawable. If there was no selection, this will be equal to the drawable ID supplied as input. Otherwise, this will be the newly created and sheard drawable. The shear type parameter indicates whether the shear will be applied horizontally or vertically. The magnitude can be either positive or negative and indicates the extent (in pixels) to shear by.",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  8,
  drawable_transform_shear_inargs,
  1,
  drawable_transform_shear_outargs,
  { { drawable_transform_shear_invoker } }
};

static Argument *
drawable_transform_shear_default_invoker (Gimp         *gimp,
                                          GimpContext  *context,
                                          GimpProgress *progress,
                                          Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gint32 shear_type;
  gdouble magnitude;
  gboolean interpolate;
  gboolean clip_result;

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  shear_type = args[1].value.pdb_int;
  if (shear_type < GIMP_ORIENTATION_HORIZONTAL || shear_type > GIMP_ORIENTATION_VERTICAL)
    success = FALSE;

  magnitude = args[2].value.pdb_float;

  interpolate = args[3].value.pdb_int ? TRUE : FALSE;

  clip_result = args[4].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = gimp_item_is_attached (GIMP_ITEM (drawable));

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          GimpMatrix3           matrix;
          GimpInterpolationType interpolation_type = GIMP_INTERPOLATION_NONE;

          /* Assemble the transformation matrix */
          gimp_transform_matrix_shear (x, y, width, height,
                                       shear_type, magnitude,
                                       &matrix);

          if (interpolate)
            interpolation_type = gimp->config->interpolation_type;

          if (progress)
            gimp_progress_start (progress, _("Shearing..."), FALSE);

          /* Transform the selection */
          success = gimp_drawable_transform_affine (drawable, context,
                                                    &matrix, GIMP_TRANSFORM_FORWARD,
                                                    interpolation_type,
                                                    interpolate, 3,
                                                    clip_result, progress);

          if (progress)
            gimp_progress_end (progress);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_shear_default_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_shear_default_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_INT32,
    "shear_type",
    "Type of shear: GIMP_ORIENTATION_HORIZONTAL (0) or GIMP_ORIENTATION_VERTICAL (1)"
  },
  {
    GIMP_PDB_FLOAT,
    "magnitude",
    "The magnitude of the shear"
  },
  {
    GIMP_PDB_INT32,
    "interpolate",
    "Whether to use interpolation and supersampling"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_shear_default_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The sheared drawable"
  }
};

static ProcRecord drawable_transform_shear_default_proc =
{
  "gimp_drawable_transform_shear_default",
  "Shear the specified drawable about its center by the specified magnitude, with extra parameters.",
  "This procedure is a variant of gimp_drawable_transform_shear() which uses no interpolation/supersampling at all, or default values (depending on the 'interpolate' parameter).",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  5,
  drawable_transform_shear_default_inargs,
  1,
  drawable_transform_shear_default_outargs,
  { { drawable_transform_shear_default_invoker } }
};

static Argument *
drawable_transform_2d_invoker (Gimp         *gimp,
                               GimpContext  *context,
                               GimpProgress *progress,
                               Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gdouble source_x;
  gdouble source_y;
  gdouble scale_x;
  gdouble scale_y;
  gdouble angle;
  gdouble dest_x;
  gdouble dest_y;
  gint32 transform_direction;
  gint32 interpolation;
  gboolean supersample;
  gint32 recursion_level;
  gboolean clip_result;

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  source_x = args[1].value.pdb_float;

  source_y = args[2].value.pdb_float;

  scale_x = args[3].value.pdb_float;

  scale_y = args[4].value.pdb_float;

  angle = args[5].value.pdb_float;

  dest_x = args[6].value.pdb_float;

  dest_y = args[7].value.pdb_float;

  transform_direction = args[8].value.pdb_int;
  if (transform_direction < GIMP_TRANSFORM_FORWARD || transform_direction > GIMP_TRANSFORM_BACKWARD)
    success = FALSE;

  interpolation = args[9].value.pdb_int;
  if (interpolation < GIMP_INTERPOLATION_NONE || interpolation > GIMP_INTERPOLATION_CUBIC)
    success = FALSE;

  supersample = args[10].value.pdb_int ? TRUE : FALSE;

  recursion_level = args[11].value.pdb_int;
  if (recursion_level <= 0)
    success = FALSE;

  clip_result = args[12].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = gimp_item_is_attached (GIMP_ITEM (drawable));

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          GimpMatrix3 matrix;

          /* Assemble the transformation matrix */
          gimp_matrix3_identity  (&matrix);
          gimp_matrix3_translate (&matrix, -source_x, -source_y);
          gimp_matrix3_scale     (&matrix, scale_x, scale_y);
          gimp_matrix3_rotate    (&matrix, angle);
          gimp_matrix3_translate (&matrix, dest_x, dest_y);

          if (progress)
            gimp_progress_start (progress, _("2D Transform..."), FALSE);

          /* Transform the selection */
          success = gimp_drawable_transform_affine (drawable, context,
                                                    &matrix, transform_direction,
                                                    interpolation, supersample,
                                                    recursion_level,
                                                    clip_result, progress);

          if (progress)
            gimp_progress_end (progress);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_2d_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_2d_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_FLOAT,
    "source_x",
    "X coordinate of the transformation center"
  },
  {
    GIMP_PDB_FLOAT,
    "source_y",
    "Y coordinate of the transformation center"
  },
  {
    GIMP_PDB_FLOAT,
    "scale_x",
    "Amount to scale in x direction"
  },
  {
    GIMP_PDB_FLOAT,
    "scale_y",
    "Amount to scale in y direction"
  },
  {
    GIMP_PDB_FLOAT,
    "angle",
    "The angle of rotation (radians)"
  },
  {
    GIMP_PDB_FLOAT,
    "dest_x",
    "X coordinate of where the center goes"
  },
  {
    GIMP_PDB_FLOAT,
    "dest_y",
    "Y coordinate of where the center goes"
  },
  {
    GIMP_PDB_INT32,
    "transform_direction",
    "Direction of Transformation: { GIMP_TRANSFORM_FORWARD (0), GIMP_TRANSFORM_BACKWARD (1) }"
  },
  {
    GIMP_PDB_INT32,
    "interpolation",
    "Type of interpolation: { GIMP_INTERPOLATION_NONE (0), GIMP_INTERPOLATION_LINEAR (1), GIMP_INTERPOLATION_CUBIC (2) }"
  },
  {
    GIMP_PDB_INT32,
    "supersample",
    "Whether to perform supersample"
  },
  {
    GIMP_PDB_INT32,
    "recursion_level",
    "Level of recursion (3 is a nice default)"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_2d_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The transformed drawable"
  }
};

static ProcRecord drawable_transform_2d_proc =
{
  "gimp_drawable_transform_2d",
  "Transform the specified drawable in 2d, with extra parameters.",
  "This procedure transforms the specified drawable if no selection exists. If a selection exists, the portion of the drawable which lies under the selection is cut from the drawable and made into a floating selection which is then transformed. The transformation is done by scaling the image by the x and y scale factors about the point (source_x, source_y), then rotating around the same point, then translating that point to the new position (dest_x, dest_y). The return value is the ID of the rotated drawable. If there was no selection, this will be equal to the drawable ID supplied as input. Otherwise, this will be the newly created and transformed drawable.",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  13,
  drawable_transform_2d_inargs,
  1,
  drawable_transform_2d_outargs,
  { { drawable_transform_2d_invoker } }
};

static Argument *
drawable_transform_2d_default_invoker (Gimp         *gimp,
                                       GimpContext  *context,
                                       GimpProgress *progress,
                                       Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gdouble source_x;
  gdouble source_y;
  gdouble scale_x;
  gdouble scale_y;
  gdouble angle;
  gdouble dest_x;
  gdouble dest_y;
  gboolean interpolate;
  gboolean clip_result;

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  source_x = args[1].value.pdb_float;

  source_y = args[2].value.pdb_float;

  scale_x = args[3].value.pdb_float;

  scale_y = args[4].value.pdb_float;

  angle = args[5].value.pdb_float;

  dest_x = args[6].value.pdb_float;

  dest_y = args[7].value.pdb_float;

  interpolate = args[8].value.pdb_int ? TRUE : FALSE;

  clip_result = args[9].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = gimp_item_is_attached (GIMP_ITEM (drawable));

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          GimpMatrix3           matrix;
          GimpInterpolationType interpolation_type = GIMP_INTERPOLATION_NONE;

          /* Assemble the transformation matrix */
          gimp_matrix3_identity  (&matrix);
          gimp_matrix3_translate (&matrix, -source_x, -source_y);
          gimp_matrix3_scale     (&matrix, scale_x, scale_y);
          gimp_matrix3_rotate    (&matrix, angle);
          gimp_matrix3_translate (&matrix, dest_x, dest_y);

          if (interpolate)
            interpolation_type = gimp->config->interpolation_type;

          if (progress)
            gimp_progress_start (progress, _("2D Transform..."), FALSE);

          /* Transform the selection */
          success = gimp_drawable_transform_affine (drawable, context,
                                                    &matrix, GIMP_TRANSFORM_FORWARD,
                                                    interpolation_type,
                                                    interpolate, 3,
                                                    clip_result, progress);

          if (progress)
            gimp_progress_end (progress);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_2d_default_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_2d_default_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_FLOAT,
    "source_x",
    "X coordinate of the transformation center"
  },
  {
    GIMP_PDB_FLOAT,
    "source_y",
    "Y coordinate of the transformation center"
  },
  {
    GIMP_PDB_FLOAT,
    "scale_x",
    "Amount to scale in x direction"
  },
  {
    GIMP_PDB_FLOAT,
    "scale_y",
    "Amount to scale in y direction"
  },
  {
    GIMP_PDB_FLOAT,
    "angle",
    "The angle of rotation (radians)"
  },
  {
    GIMP_PDB_FLOAT,
    "dest_x",
    "X coordinate of where the center goes"
  },
  {
    GIMP_PDB_FLOAT,
    "dest_y",
    "Y coordinate of where the center goes"
  },
  {
    GIMP_PDB_INT32,
    "interpolate",
    "Whether to use interpolation and supersampling"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_2d_default_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The transformed drawable"
  }
};

static ProcRecord drawable_transform_2d_default_proc =
{
  "gimp_drawable_transform_2d_default",
  "Transform the specified drawable in 2d, with extra parameters.",
  "This procedure is a variant of gimp_drawable_transform_2d() which uses no interpolation/supersampling at all, or default values (depending on the 'interpolate' parameter).",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  10,
  drawable_transform_2d_default_inargs,
  1,
  drawable_transform_2d_default_outargs,
  { { drawable_transform_2d_default_invoker } }
};

static Argument *
drawable_transform_matrix_invoker (Gimp         *gimp,
                                   GimpContext  *context,
                                   GimpProgress *progress,
                                   Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gdouble coeff_0_0;
  gdouble coeff_0_1;
  gdouble coeff_0_2;
  gdouble coeff_1_0;
  gdouble coeff_1_1;
  gdouble coeff_1_2;
  gdouble coeff_2_0;
  gdouble coeff_2_1;
  gdouble coeff_2_2;
  gint32 transform_direction;
  gint32 interpolation;
  gboolean supersample;
  gint32 recursion_level;
  gboolean clip_result;

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  coeff_0_0 = args[1].value.pdb_float;

  coeff_0_1 = args[2].value.pdb_float;

  coeff_0_2 = args[3].value.pdb_float;

  coeff_1_0 = args[4].value.pdb_float;

  coeff_1_1 = args[5].value.pdb_float;

  coeff_1_2 = args[6].value.pdb_float;

  coeff_2_0 = args[7].value.pdb_float;

  coeff_2_1 = args[8].value.pdb_float;

  coeff_2_2 = args[9].value.pdb_float;

  transform_direction = args[10].value.pdb_int;
  if (transform_direction < GIMP_TRANSFORM_FORWARD || transform_direction > GIMP_TRANSFORM_BACKWARD)
    success = FALSE;

  interpolation = args[11].value.pdb_int;
  if (interpolation < GIMP_INTERPOLATION_NONE || interpolation > GIMP_INTERPOLATION_CUBIC)
    success = FALSE;

  supersample = args[12].value.pdb_int ? TRUE : FALSE;

  recursion_level = args[13].value.pdb_int;
  if (recursion_level <= 0)
    success = FALSE;

  clip_result = args[14].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = gimp_item_is_attached (GIMP_ITEM (drawable));

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          GimpMatrix3 matrix;

          /* Assemble the transformation matrix */
          matrix.coeff[0][0] = coeff_0_0;
          matrix.coeff[0][1] = coeff_0_1;
          matrix.coeff[0][2] = coeff_0_2;
          matrix.coeff[1][0] = coeff_1_0;
          matrix.coeff[1][1] = coeff_1_1;
          matrix.coeff[1][2] = coeff_1_2;
          matrix.coeff[2][0] = coeff_2_0;
          matrix.coeff[2][1] = coeff_2_1;
          matrix.coeff[2][2] = coeff_2_2;

          if (progress)
            gimp_progress_start (progress, _("2D Transform..."), FALSE);

          /* Transform the selection */
          success = gimp_drawable_transform_affine (drawable, context,
                                                    &matrix, transform_direction,
                                                    interpolation, supersample,
                                                    recursion_level,
                                                    clip_result, progress);

          if (progress)
            gimp_progress_end (progress);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_matrix_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_matrix_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_0_0",
    "coefficient (0,0) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_0_1",
    "coefficient (0,1) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_0_2",
    "coefficient (0,2) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_1_0",
    "coefficient (1,0) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_1_1",
    "coefficient (1,1) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_1_2",
    "coefficient (1,2) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_2_0",
    "coefficient (2,0) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_2_1",
    "coefficient (2,1) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_2_2",
    "coefficient (2,2) of the transformation matrix"
  },
  {
    GIMP_PDB_INT32,
    "transform_direction",
    "Direction of Transformation: { GIMP_TRANSFORM_FORWARD (0), GIMP_TRANSFORM_BACKWARD (1) }"
  },
  {
    GIMP_PDB_INT32,
    "interpolation",
    "Type of interpolation: { GIMP_INTERPOLATION_NONE (0), GIMP_INTERPOLATION_LINEAR (1), GIMP_INTERPOLATION_CUBIC (2) }"
  },
  {
    GIMP_PDB_INT32,
    "supersample",
    "Whether to perform supersample"
  },
  {
    GIMP_PDB_INT32,
    "recursion_level",
    "Level of recursion (3 is a nice default)"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_matrix_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The transformed drawable"
  }
};

static ProcRecord drawable_transform_matrix_proc =
{
  "gimp_drawable_transform_matrix",
  "Transform the specified drawable in 2d, with extra parameters.",
  "This procedure transforms the specified drawable if no selection exists. If a selection exists, the portion of the drawable which lies under the selection is cut from the drawable and made into a floating selection which is then transformed. The transformation is done by assembling a 3x3 matrix from the coefficients passed. The return value is the ID of the rotated drawable. If there was no selection, this will be equal to the drawable ID supplied as input. Otherwise, this will be the newly created and transformed drawable.",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  15,
  drawable_transform_matrix_inargs,
  1,
  drawable_transform_matrix_outargs,
  { { drawable_transform_matrix_invoker } }
};

static Argument *
drawable_transform_matrix_default_invoker (Gimp         *gimp,
                                           GimpContext  *context,
                                           GimpProgress *progress,
                                           Argument     *args)
{
  gboolean success = TRUE;
  Argument *return_args;
  GimpDrawable *drawable;
  gdouble coeff_0_0;
  gdouble coeff_0_1;
  gdouble coeff_0_2;
  gdouble coeff_1_0;
  gdouble coeff_1_1;
  gdouble coeff_1_2;
  gdouble coeff_2_0;
  gdouble coeff_2_1;
  gdouble coeff_2_2;
  gboolean interpolate;
  gboolean clip_result;

  drawable = (GimpDrawable *) gimp_item_get_by_ID (gimp, args[0].value.pdb_int);
  if (! (GIMP_IS_DRAWABLE (drawable) && ! gimp_item_is_removed (GIMP_ITEM (drawable))))
    success = FALSE;

  coeff_0_0 = args[1].value.pdb_float;

  coeff_0_1 = args[2].value.pdb_float;

  coeff_0_2 = args[3].value.pdb_float;

  coeff_1_0 = args[4].value.pdb_float;

  coeff_1_1 = args[5].value.pdb_float;

  coeff_1_2 = args[6].value.pdb_float;

  coeff_2_0 = args[7].value.pdb_float;

  coeff_2_1 = args[8].value.pdb_float;

  coeff_2_2 = args[9].value.pdb_float;

  interpolate = args[10].value.pdb_int ? TRUE : FALSE;

  clip_result = args[11].value.pdb_int ? TRUE : FALSE;

  if (success)
    {
      gint x, y, width, height;

      success = gimp_item_is_attached (GIMP_ITEM (drawable));

      if (success &&
          gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
        {
          GimpMatrix3           matrix;
          GimpInterpolationType interpolation_type = GIMP_INTERPOLATION_NONE;

          /* Assemble the transformation matrix */
          matrix.coeff[0][0] = coeff_0_0;
          matrix.coeff[0][1] = coeff_0_1;
          matrix.coeff[0][2] = coeff_0_2;
          matrix.coeff[1][0] = coeff_1_0;
          matrix.coeff[1][1] = coeff_1_1;
          matrix.coeff[1][2] = coeff_1_2;
          matrix.coeff[2][0] = coeff_2_0;
          matrix.coeff[2][1] = coeff_2_1;
          matrix.coeff[2][2] = coeff_2_2;

          if (interpolate)
            interpolation_type = gimp->config->interpolation_type;

          if (progress)
            gimp_progress_start (progress, _("2D Transform..."), FALSE);

          /* Transform the selection */
          success = gimp_drawable_transform_affine (drawable, context,
                                                    &matrix, GIMP_TRANSFORM_FORWARD,
                                                    interpolation_type,
                                                    interpolate, 3,
                                                    clip_result, progress);

          if (progress)
            gimp_progress_end (progress);
        }
    }

  return_args = procedural_db_return_args (&drawable_transform_matrix_default_proc, success);

  if (success)
    return_args[1].value.pdb_int = gimp_item_get_ID (GIMP_ITEM (drawable));

  return return_args;
}

static ProcArg drawable_transform_matrix_default_inargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The affected drawable"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_0_0",
    "coefficient (0,0) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_0_1",
    "coefficient (0,1) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_0_2",
    "coefficient (0,2) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_1_0",
    "coefficient (1,0) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_1_1",
    "coefficient (1,1) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_1_2",
    "coefficient (1,2) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_2_0",
    "coefficient (2,0) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_2_1",
    "coefficient (2,1) of the transformation matrix"
  },
  {
    GIMP_PDB_FLOAT,
    "coeff_2_2",
    "coefficient (2,2) of the transformation matrix"
  },
  {
    GIMP_PDB_INT32,
    "interpolate",
    "Whether to use interpolation and supersampling"
  },
  {
    GIMP_PDB_INT32,
    "clip_result",
    "Whether to clip results"
  }
};

static ProcArg drawable_transform_matrix_default_outargs[] =
{
  {
    GIMP_PDB_DRAWABLE,
    "drawable",
    "The transformed drawable"
  }
};

static ProcRecord drawable_transform_matrix_default_proc =
{
  "gimp_drawable_transform_matrix_default",
  "Transform the specified drawable in 2d, with extra parameters.",
  "This procedure is a variant of gimp_drawable_transform_matrix() which uses no interpolation/supersampling at all, or default values (depending on the 'interpolate' parameter).",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "Jo\xc3\xa3o S. O. Bueno Calligaris",
  "2004",
  NULL,
  GIMP_INTERNAL,
  12,
  drawable_transform_matrix_default_inargs,
  1,
  drawable_transform_matrix_default_outargs,
  { { drawable_transform_matrix_default_invoker } }
};
