#ifndef WDL_NO_DEFINE_MINMAX
#define WDL_NO_DEFINE_MINMAX
#endif
#include "lice.h"
#include "lice_combine.h"
#include "lice_extended.h"
#include <math.h>
#include <stdio.h>
//#include <assert.h>

#define IGNORE_SCALING(mode) ((mode)&LICE_BLIT_IGNORE_SCALING)

template <class T> inline void SWAP(T& a, T& b) { T tmp = a; a = b; b = tmp; }

enum { eOK = 0, eXLo = 1, eXHi = 2, eYLo = 4, eYHi = 8 };

static int OffscreenTest(int x, int y, int nX, int nY)
{
  int e = eOK;
  if (x < 0) e |= eXLo;
  else if (x >= nX) e |= eXHi;
  if (y < 0) e |= eYLo;
  else if (y >= nY) e |= eYHi;
  return e;
}

// Cohen-Sutherland.  Returns false if the line is entirely offscreen.
static bool ClipLine(int* pX1, int* pY1, int* pX2, int* pY2, int nX, int nY)
{
  int x1 = *pX1, y1 = *pY1, x2 = *pX2, y2 = *pY2;
  int e1 = OffscreenTest(x1, y1, nX, nY);
  int e2 = OffscreenTest(x2, y2, nX, nY);
  int timeout = 32;
  bool accept = false, done = false;
  do
  {
    if (!(e1 | e2)) {
      accept = done = true;
    }
    else
    if (e1 & e2) {
      done = true;  // Line is entirely offscreen.
    }
    else {
      int x, y;
      int eOut = e1 ? e1 : e2;
      if (eOut & eYHi) {
        x = x1 + (int) ((double) (x2 - x1) * (double) (nY - 1 - y1) / (double) (y2 - y1));
        y = nY - 1;
      }
      else
      if (eOut & eYLo) {
        x = x1 + (int) ((double) (x2 - x1) * (double) -y1 / (double) (y2 - y1));
        y = 0;
      }
      else
      if (eOut & eXHi) {
        y = y1 + (int) ((double) (y2 - y1) * (double) (nX - 1 - x1) / (double) (x2 - x1));
        x = nX - 1;
      }
      else {
        y = y1 + (int) ((double) (y2 - y1) * (double) -x1 / (double) (x2 - x1));
        x = 0;
      }

      if (eOut == e1) {
        x1 = x;
        y1 = y;
        e1 = OffscreenTest(x1, y1, nX, nY);
      }
      else {
        x2 = x;
        y2 = y;
        e2 = OffscreenTest(x2, y2, nX, nY);
      }
    }
  }
  while (!done && timeout--);

  *pX1 = x1;
  *pY1 = y1;
  *pX2 = x2;
  *pY2 = y2;
  return accept;
}

template<class T> static int OffscreenFTest(T x, T y, T w, T h)
{
  int e = eOK;
  if (x < 0.0f) e |= eXLo;
  else if (x >= w) e |= eXHi;
  if (y < 0.0f) e |= eYLo;
  else if (y >= h) e |= eYHi;
  return e;
}

template<class T> static bool ClipFLine(T * x1, T * y1, T * x2, T *y2, int w, int h)
{
  T tx1 = *x1, ty1 = *y1, tx2 = *x2, ty2 = *y2;
  T tw = (T)(w-1), th = (T)(h-1);
  if (!lice_isfinite(tx1) || !lice_isfinite(tx2) ||
      !lice_isfinite(ty1) || !lice_isfinite(ty2)) return false;

  int e1 = OffscreenFTest(tx1, ty1, tw, th);
  int e2 = OffscreenFTest(tx2, ty2, tw, th);

  int timeout = 32;
  bool accept = false, done = false;
  do
  {
    if (!(e1|e2))
    {
      accept = done = true;
    }
    else
    if (e1&e2)
    {
      done = true;  // Line is entirely offscreen.
    }
    else
    {
      T x, y;
      int eOut = (e1 ? e1 : e2);
      if (eOut&eYHi)
      {
        x = tx1+(tx2-tx1)*(th-ty1)/(ty2-ty1);
        y = th-1.0f;
      }
      else if (eOut&eYLo)
      {
        x = tx1+(tx2-tx1)*ty1/(ty1-ty2);
        y = 0.0f;
      }
      else if (eOut&eXHi)
      {
        y = ty1+(ty2-ty1)*(tw-tx1)/(tx2-tx1);
        x = tw-1.0f;
      }
      else
      {
        y = ty1+(ty2-ty1)*tx1/(tx1-tx2);
        x = 0.0f;
      }

      if (eOut == e1)
      {
        tx1 = x;
        ty1 = y;
        e1 = OffscreenFTest(tx1, ty1, tw, th);
      }
      else
      {
        tx2 = x;
        ty2 = y;
        e2 = OffscreenFTest(tx2, ty2, tw, th);
      }
    }
  }
  while (!done && timeout--);

  *x1 = tx1;
  *y1 = ty1;
  *x2 = tx2;
  *y2 = ty2;
  return accept;
}


inline static void LICE_DiagLineFAST(LICE_pixel *px, int span, int n, int xstep, int ystep, LICE_pixel color, bool aa)
{
  int step = xstep+ystep;
  if (aa)
  {
    LICE_pixel color75 = ((color>>1)&0x7f7f7f7f)+((color>>2)&0x3f3f3f3f);
    LICE_pixel color25 = (color>>2)&0x3f3f3f3f;
    while (n--)
    {
      _LICE_CombinePixelsThreeQuarterMix2FAST::doPixFAST(px, color75);
      _LICE_CombinePixelsQuarterMix2FAST::doPixFAST(px+xstep, color25);
      _LICE_CombinePixelsQuarterMix2FAST::doPixFAST(px+ystep, color25);
      px += step;
    }
    _LICE_CombinePixelsThreeQuarterMix2FAST::doPixFAST(px, color75);
  }
  else
  {
    ++n;
    while (n--)
    {
      *px = color;
      px += step;
    }
  }
}

inline static void LICE_DottedVertLineFAST(LICE_IBitmap* dest, int x, int y1, int y2, LICE_pixel color)
{
  int span = dest->getRowSpan();
  LICE_pixel* px = dest->getBits()+y1*span+x;

  int n = (y2-y1+1)/2;
  while (n--)
  {
    *px = color;
    px += 2*span;
  }
}

// this is the white-color table, doing this properly requires correcting the destination color specifically
#define DO_AA_GAMMA_CORRECT 0
#if DO_AA_GAMMA_CORRECT
static unsigned char AA_GAMMA_CORRECT[256] =
{
  // 1.8 gamma
  0,11,17,21,25,28,31,34,37,39,42,44,46,48,50,52,54,56,58,60,61,63,65,67,68,70,71,73,74,76,77,79,80,81,83,84,85,87,88,89,91,92,93,94,96,97,98,99,100,101,103,104,105,106,107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,132,133,134,135,136,137,138,139,140,141,142,142,143,144,145,146,147,148,149,149,150,151,152,153,154,154,155,156,157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169,170,170,171,172,173,173,174,175,176,176,177,178,179,179,180,181,182,182,183,184,184,185,186,187,187,188,189,189,190,191,191,192,193,194,194,195,196,196,197,198,198,199,200,200,201,202,202,203,204,204,205,206,206,207,208,208,209,210,210,211,212,212,213,214,214,215,215,216,217,217,218,219,219,220,220,221,222,222,223,224,224,225,225,226,227,227,228,228,229,230,230,231,231,232,233,233,234,234,235,236,236,237,237,238,239,239,240,240,241,241,242,243,243,244,244,245,245,246,247,247,248,248,249,249,250,251,251,252,252,253,253,254,255

  // 2.0 gamma
  //0,15,22,27,31,35,39,42,45,47,50,52,55,57,59,61,63,65,67,69,71,73,74,76,78,79,81,82,84,85,87,88,90,91,93,94,95,97,98,99,100,102,103,104,105,107,108,109,110,111,112,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,141,142,143,144,145,146,147,148,148,149,150,151,152,153,153,154,155,156,157,158,158,159,160,161,162,162,163,164,165,165,166,167,168,168,169,170,171,171,172,173,174,174,175,176,177,177,178,179,179,180,181,182,182,183,184,184,185,186,186,187,188,188,189,190,190,191,192,192,193,194,194,195,196,196,197,198,198,199,200,200,201,201,202,203,203,204,205,205,206,206,207,208,208,209,210,210,211,211,212,213,213,214,214,215,216,216,217,217,218,218,219,220,220,221,221,222,222,223,224,224,225,225,226,226,227,228,228,229,229,230,230,231,231,232,233,233,234,234,235,235,236,236,237,237,238,238,239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252,253,253,254,255

  // 2.2 gamma
  //0,20,28,33,38,42,46,49,52,55,58,61,63,65,68,70,72,74,76,78,80,81,83,85,87,88,90,91,93,94,96,97,99,100,102,103,104,106,107,108,109,111,112,113,114,115,117,118,119,120,121,122,123,124,125,126,128,129,130,131,132,133,134,135,136,136,137,138,139,140,141,142,143,144,145,146,147,147,148,149,150,151,152,153,153,154,155,156,157,158,158,159,160,161,162,162,163,164,165,165,166,167,168,168,169,170,171,171,172,173,174,174,175,176,176,177,178,178,179,180,181,181,182,183,183,184,185,185,186,187,187,188,189,189,190,190,191,192,192,193,194,194,195,196,196,197,197,198,199,199,200,200,201,202,202,203,203,204,205,205,206,206,207,208,208,209,209,210,210,211,212,212,213,213,214,214,215,216,216,217,217,218,218,219,219,220,220,221,222,222,223,223,224,224,225,225,226,226,227,227,228,228,229,229,230,230,231,231,232,232,233,233,234,234,235,235,236,236,237,237,238,238,239,239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247,247,248,248,249,249,249,250,250,251,251,252,252,253,253,254,254,255

  // 2.6 gamma
  //0,30,39,46,51,56,60,63,67,70,73,76,78,81,83,85,87,89,91,93,95,97,99,101,102,104,105,107,109,110,111,113,114,116,117,118,120,121,122,123,125,126,127,128,129,130,131,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,148,149,150,151,152,153,154,155,155,156,157,158,159,160,160,161,162,163,164,164,165,166,167,167,168,169,170,170,171,172,173,173,174,175,175,176,177,177,178,179,179,180,181,181,182,183,183,184,185,185,186,187,187,188,188,189,190,190,191,192,192,193,193,194,195,195,196,196,197,197,198,199,199,200,200,201,201,202,203,203,204,204,205,205,206,206,207,207,208,208,209,210,210,211,211,212,212,213,213,214,214,215,215,216,216,217,217,218,218,219,219,220,220,221,221,222,222,223,223,223,224,224,225,225,226,226,227,227,228,228,229,229,230,230,230,231,231,232,232,233,233,234,234,234,235,235,236,236,237,237,237,238,238,239,239,240,240,240,241,241,242,242,243,243,243,244,244,245,245,245,246,246,247,247,247,248,248,249,249,249,250,250,251,251,251,252,252,253,253,253,254,254,255
};
#endif

static void GetAAPxWeight(int err, int alpha, int* wt, int* iwt)
{
  int i = err>>8;
  int w = 255-i;

#if DO_AA_GAMMA_CORRECT
  w = AA_GAMMA_CORRECT[w];
  i = AA_GAMMA_CORRECT[i];
#endif

  w = (alpha*w) >> 8;
  i = (alpha*i) >> 8;
  *wt = w;
  *iwt = i;
}

static void GetAAPxWeightFAST(int err, int* wt, int* iwt)
{
  int i = err>>8;
  int w = 255-i;

#if DO_AA_GAMMA_CORRECT
  w = AA_GAMMA_CORRECT[w];
  i = AA_GAMMA_CORRECT[i];
#endif

  *wt = w;
  *iwt = i;
}
template <class COMBFUNC> class __LICE_LineClassSimple
{
public:
  static void LICE_VertLineFAST(LICE_pixel *px, int span, int len, LICE_pixel color)
  {
    while (len--)
    {
      COMBFUNC::doPixFAST(px, color);
      px+=span;
    }
  }

  static void LICE_HorizLineFAST(LICE_pixel *px, int n, LICE_pixel color)
  {
    while (n--)
    {
      COMBFUNC::doPixFAST(px, color);
      px++;
    }
  }
  static void LICE_VertLine(LICE_pixel *px, int span, int len, int color, int aw)
  {
    int r = LICE_GETR(color), g = LICE_GETG(color), b = LICE_GETB(color), a = LICE_GETA(color);
    while (len--)
    {
      COMBFUNC::doPix((LICE_pixel_chan*) px, r, g, b, a, aw);
      px+=span;
    }
  }

  static void LICE_HorizLine(LICE_pixel *px, int n, LICE_pixel color, int aw)
  {
    int r = LICE_GETR(color), g = LICE_GETG(color), b = LICE_GETB(color), a = LICE_GETA(color);

    while (n--)
    {
      COMBFUNC::doPix((LICE_pixel_chan*) px, r, g, b, a, aw);
      px++;
    }
  }
  static void LICE_DiagLine(LICE_pixel *px, int span, int n, int xstep, int ystep, LICE_pixel color, int aw)
  {
    int r = LICE_GETR(color), g = LICE_GETG(color), b = LICE_GETB(color), a = LICE_GETA(color);
    int step = xstep+ystep;

    for (int i = 0; i <= n; ++i, px += step)
    {
      COMBFUNC::doPix((LICE_pixel_chan*) px, r, g, b, a, aw);
    }
  }
  static void LICE_DiagLineAA(LICE_pixel *px, int span, int n, int xstep, int ystep, LICE_pixel color, int aw)
  {
    int r = LICE_GETR(color), g = LICE_GETG(color), b = LICE_GETB(color), a = LICE_GETA(color);
    int step = xstep+ystep;

#if DO_AA_GAMMA_CORRECT
    int iw = aw*AA_GAMMA_CORRECT[256*3/4]/256;
    int dw = aw*AA_GAMMA_CORRECT[256/4]/256;
#else
    int iw = aw*3/4;
    int dw = aw/4;
#endif
    for (int i = 0; i < n; ++i, px += step)
    {
      COMBFUNC::doPix((LICE_pixel_chan*) px, r, g, b, a, iw);
      COMBFUNC::doPix((LICE_pixel_chan*) (px+xstep), r, g, b, a, dw);
      COMBFUNC::doPix((LICE_pixel_chan*) (px+ystep), r, g, b, a, dw);
    }
    COMBFUNC::doPix((LICE_pixel_chan*) px, r, g, b, a, iw);
  }
};


#ifndef LICE_FAVOR_SIZE
template<class COMBFUNC>
#endif
class __LICE_LineClass
{
public:

#ifdef LICE_FAVOR_SIZE
  #define DOPIX(pout,r,g,b,a,ia) combFunc(pout,r,g,b,a,ia);
#else
    #define DOPIX(pout,r,g,b,a,ia) COMBFUNC::doPix(pout,r,g,b,a,ia);
#endif

  static void DashedLine(LICE_IBitmap* dest, int x1, int y1, int x2, int y2, int pxon, int pxoff, LICE_pixel color, int aw
#ifdef LICE_FAVOR_SIZE
                          , LICE_COMBINEFUNC combFunc
#endif
    )
  {
    int span = dest->getRowSpan();
    LICE_pixel* px = dest->getBits()+y1*span+x1;
    int r = LICE_GETR(color), g = LICE_GETG(color), b = LICE_GETB(color), a = LICE_GETA(color);

    if (x1 == x2)
    {
      int i, y;
      for (y = y1; y < y2-pxon; y += pxon+pxoff)
      {
        for (i = 0; i < pxon; ++i, px += span) DOPIX((LICE_pixel_chan*) px, r, g, b, a, aw)
        px += pxoff*span;
      }
      for (i = 0; i < lice_min(pxon, y2-y); ++i, px += span) DOPIX((LICE_pixel_chan*) px, r, g, b, a, aw)
    }
    else if (y1 == y2)
    {
      int i, x;
      for (x = x1; x < x2-pxon; x += pxon+pxoff)
      {
        for (i = 0; i < pxon; ++i, ++px) DOPIX((LICE_pixel_chan*) px, r, g, b, a, aw)
        px += pxoff;
      }
      for (i = 0; i < lice_min(pxon, x2-x); ++i, ++px) DOPIX((LICE_pixel_chan*) px, r, g, b, a, aw)
    }
  }




  static void LICE_LineImpl(LICE_pixel *px, LICE_pixel *px2, int derr, int astep, int da, int bstep, LICE_pixel color, int aw, bool aa
#ifdef LICE_FAVOR_SIZE
                          , LICE_COMBINEFUNC combFunc
#endif
    )
  {
    int r = LICE_GETR(color), g = LICE_GETG(color), b = LICE_GETB(color), a = LICE_GETA(color);

    int err = 0;
    int i;
    int n = (da+1)/2;

    if (aa)
    {
      DOPIX((LICE_pixel_chan*) px, r, g, b, a, aw)
      DOPIX((LICE_pixel_chan*) px2, r, g, b, a, aw)
      px += astep;
      px2 -= astep;
      err = derr;

      if (aw == 256)
      {
        for (i = 1; i < n; ++i)
        {
          int wt, iwt;
          GetAAPxWeightFAST(err, &wt, &iwt);
          DOPIX((LICE_pixel_chan*)px, r, g, b, a, wt)
          DOPIX((LICE_pixel_chan*)(px+bstep), r, g, b, a, iwt)
          DOPIX((LICE_pixel_chan*)px2, r, g, b, a, wt)
          DOPIX((LICE_pixel_chan*)(px2-bstep), r, g, b, a, iwt)

          err += derr;
          if (err >= 65536)
          {
            px += bstep;
            px2 -= bstep;
            err -= 65536;
          }
          px += astep;
          px2 -= astep;
        }
      }
      else  // alpha<256
      {
        for (i = 1; i < n; ++i)
        {
          int wt, iwt;
          GetAAPxWeight(err, aw, &wt, &iwt);
          DOPIX((LICE_pixel_chan*)px, r, g, b, a, wt)
          DOPIX((LICE_pixel_chan*)(px+bstep), r, g, b, a, iwt)
          DOPIX((LICE_pixel_chan*)px2, r, g, b, a, wt)
          DOPIX((LICE_pixel_chan*)(px2-bstep), r, g, b, a, iwt)

          err += derr;
          if (err >= 65536)
          {
            px += bstep;
            px2 -= bstep;
            err -= 65536;
          }
          px += astep;
          px2 -= astep;
        }
      }
      if (!(da%2))
      {
        int wt, iwt;
        if (aw == 256) GetAAPxWeightFAST(err, &wt, &iwt);
        else GetAAPxWeight(err, aw, &wt, &iwt);
        DOPIX((LICE_pixel_chan*)px, r, g, b, a, wt)
        DOPIX((LICE_pixel_chan*)(px+bstep), r, g, b, a, iwt)
      }
    }
    else  // not aa
    {
      for (i = 0; i < n; ++i)
      {
        DOPIX((LICE_pixel_chan*)px, r, g, b, a, aw)
        DOPIX((LICE_pixel_chan*)px2, r, g, b, a, aw)
        err += derr;
        if (err >= 65536/2)
        {
          px += bstep;
          px2 -= bstep;
          err -= 65536;
        }

        px += astep;
        px2 -= astep;
      }
      if (!(da%2))
      {
        DOPIX((LICE_pixel_chan*)px, r, g, b, a, aw)
      }
    }
  }

  static void LICE_FLineImpl(LICE_pixel *px, int n , int err, int derr, int astep, int bstep, LICE_pixel color, int aw
#ifdef LICE_FAVOR_SIZE
                          , LICE_COMBINEFUNC combFunc
#endif

    ) // only does AA
  {
    int r = LICE_GETR(color), g = LICE_GETG(color), b = LICE_GETB(color), a = LICE_GETA(color);


    int wt, iwt;
    int i;

    if (aw == 256)
    {
      for (i = 0; i <= n; ++i)
      {
        GetAAPxWeightFAST(err, &wt, &iwt);
        DOPIX((LICE_pixel_chan*)px, r, g, b, a, wt)
        DOPIX((LICE_pixel_chan*)(px+bstep), r, g, b, a, iwt)

        err += derr;
        if (err >= 65536)
        {
          px += bstep;
          err -= 65536;
        }
        px += astep;
      }
    }
    else // alpha != 256
    {
      for (i = 0; i <= n; ++i)
      {
        GetAAPxWeight(err, aw, &wt, &iwt);
        DOPIX((LICE_pixel_chan*)px, r, g, b, a, wt)
        DOPIX((LICE_pixel_chan*)(px+bstep), r, g, b, a, iwt)

        err += derr;
        if (err >= 65536)
        {
          px += bstep;
          err -= 65536;
        }
        px += astep;
      }
    }
  }

  static void LICE_FLineImplFill(LICE_pixel *px, int n , int err, int derr, int astep, int bstep, LICE_pixel color, int aw,
      int fill_sz, int b_pos, unsigned int b_max
#ifdef LICE_FAVOR_SIZE
                          , LICE_COMBINEFUNC combFunc
#endif
    )
  {
    // fill_sz always >= 2
    int r = LICE_GETR(color), g = LICE_GETG(color), b = LICE_GETB(color), a = LICE_GETA(color);

    int wt, iwt;
    int i;

    const int dbpos = bstep < 0 ? -1 : 1;

    const int b_adj = -(fill_sz/2);
    b_pos += b_adj*dbpos;
    px += b_adj*bstep;

    fill_sz--; // fill size of 2 has one extra pixel in the middle, 2 AA pixels

    if (aw == 256)
    {
      for (i = 0; i <= n; ++i)
      {
        GetAAPxWeightFAST(err, &wt, &iwt);
        LICE_pixel *wr = px;
        unsigned int bp = b_pos;
        if (bp<b_max) { DOPIX((LICE_pixel_chan*)wr, r, g, b, a, wt)  }
        for (int j=0;j<fill_sz;j++)
        {
          wr += bstep;
          if ((bp+=dbpos)<b_max) { DOPIX((LICE_pixel_chan*)wr, r, g, b, a, 256) }
        }
        if ((bp+dbpos)<b_max) { DOPIX((LICE_pixel_chan*)(wr+bstep), r, g, b, a, iwt) }

        err += derr;
        if (err >= 65536)
        {
          px += bstep;
          b_pos += dbpos;
          err -= 65536;
        }
        px += astep;
      }
    }
    else // alpha != 256
    {
      for (i = 0; i <= n; ++i)
      {
        GetAAPxWeight(err, aw, &wt, &iwt);
        LICE_pixel *wr = px;
        unsigned int bp = b_pos;
        if (bp<b_max) { DOPIX((LICE_pixel_chan*)wr, r, g, b, a, wt) }
        for (int j=0;j<fill_sz;j++)
        {
          wr += bstep;
          if ((bp+=dbpos)<b_max) { DOPIX((LICE_pixel_chan*)wr, r, g, b, a, aw) }
        }
        if ((bp+dbpos)<b_max) { DOPIX((LICE_pixel_chan*)(wr+bstep), r, g, b, a, iwt) }

        err += derr;
        if (err >= 65536)
        {
          px += bstep;
          b_pos += dbpos;
          err -= 65536;
        }
        px += astep;
      }
    }
  }

#undef DOPIX
};


void LICE_Line(LICE_IBitmap *dest, int x1, int y1, int x2, int y2, LICE_pixel color, float alpha, int mode, bool aa)
{
  if (!dest) return;

  int w = dest->getWidth();
  int h = dest->getHeight();
  const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
  if (__sc>0)
  {
    __LICE_SCU(w);
    __LICE_SCU(h);
    if (!IGNORE_SCALING(mode))
    {
      __LICE_SC(x1);
      __LICE_SC(y1);
      __LICE_SC(x2);
      __LICE_SC(y2);
    }
  }

#ifndef DISABLE_LICE_EXTENSIONS
  if (dest->Extended(LICE_EXT_SUPPORTS_ID, (void*) LICE_EXT_LINE_ACCEL))
  {
    LICE_Ext_Line_acceldata data(x1, y1, x2, y2, color, alpha, mode, aa);
    if (dest->Extended(LICE_EXT_LINE_ACCEL, &data)) return;
  }
#endif

  if (dest->isFlipped())
  {
    y1 = h-1-y1;
    y2 = h-1-y2;
  }

  if (ClipLine(&x1, &y1, &x2, &y2, w, h))
  {
    int xdiff = x2-x1;
    if (y1 == y2) // horizontal line optimizations
    {
      if (x1 > x2) SWAP(x1, x2);
      int span = dest->getRowSpan();
      LICE_pixel* px = dest->getBits()+y1*span+x1;
      int n=x2-x1+1;

      if ((mode&LICE_BLIT_MODE_MASK) == LICE_BLIT_MODE_COPY && alpha == 1.0f)
      {
        __LICE_LineClassSimple<_LICE_CombinePixelsClobberFAST>::LICE_HorizLineFAST(px, n, color);
      }
      else if ((mode&LICE_BLIT_MODE_MASK) == LICE_BLIT_MODE_COPY && alpha == 0.5f)
      {
        color = (color>>1)&0x7f7f7f7f;
        __LICE_LineClassSimple<_LICE_CombinePixelsHalfMix2FAST>::LICE_HorizLineFAST(px, n, color);
      }
      else if ((mode&LICE_BLIT_MODE_MASK) == LICE_BLIT_MODE_COPY && alpha == 0.25f)
      {
        color = (color>>2)&0x3f3f3f3f;
        __LICE_LineClassSimple<_LICE_CombinePixelsQuarterMix2FAST>::LICE_HorizLineFAST(px, n, color);
      }
      else if ((mode&LICE_BLIT_MODE_MASK) == LICE_BLIT_MODE_COPY && alpha == 0.75f)
      {
        color = ((color>>1)&0x7f7f7f7f)+((color>>2)&0x3f3f3f3f);
        __LICE_LineClassSimple<_LICE_CombinePixelsThreeQuarterMix2FAST>::LICE_HorizLineFAST(px, n, color);
      }
      else
      {
        int aw = (int)(256.0f*alpha);
#define __LICE__ACTION(COMBFUNC) __LICE_LineClassSimple<COMBFUNC>::LICE_HorizLine(px, n, color, aw)
        __LICE_ACTION_CONSTANTALPHA(mode, aw, false);
#undef __LICE__ACTION
      }
    }
    else if (!xdiff)  // vertical line optimizations
    {
      if (y1 > y2) SWAP(y1, y2);
      int len=y2+1-y1;
      int span = dest->getRowSpan();
      LICE_pixel* px = dest->getBits()+y1*span+x1;
      int aw = (int)(256.0f*alpha);
      if ((mode&LICE_BLIT_MODE_MASK) == LICE_BLIT_MODE_COPY && alpha == 1.0f)
      {
        __LICE_LineClassSimple<_LICE_CombinePixelsClobberFAST>::LICE_VertLineFAST(px, span, len, color);
      }
      else if ((mode&LICE_BLIT_MODE_MASK) == LICE_BLIT_MODE_COPY && alpha == 0.5f)
      {
        color = (color>>1)&0x7f7f7f7f;
        __LICE_LineClassSimple<_LICE_CombinePixelsHalfMix2FAST>::LICE_VertLineFAST(px, span, len, color);
      }
      else if ((mode&LICE_BLIT_MODE_MASK) == LICE_BLIT_MODE_COPY && alpha == 0.25f)
      {
        color = (color>>2)&0x3f3f3f3f;
        __LICE_LineClassSimple<_LICE_CombinePixelsQuarterMix2FAST>::LICE_VertLineFAST(px, span, len, color);
      }
      else if ((mode&LICE_BLIT_MODE_MASK) == LICE_BLIT_MODE_COPY && alpha == 0.75f)
      {
        color = ((color>>1)&0x7f7f7f7f)+((color>>2)&0x3f3f3f3f);
        __LICE_LineClassSimple<_LICE_CombinePixelsThreeQuarterMix2FAST>::LICE_VertLineFAST(px, span, len, color);
      }
      else
      {
#define __LICE__ACTION(COMBFUNC) __LICE_LineClassSimple<COMBFUNC>::LICE_VertLine(px, span, len, color,aw)
        __LICE_ACTION_CONSTANTALPHA(mode, aw, false);
#undef __LICE__ACTION
      }
    }
    else if ((xdiff=abs(xdiff)) == abs(y2-y1)) // diagonal line optimizations
    {
      int span = dest->getRowSpan();
      LICE_pixel* px = dest->getBits()+y1*span+x1;
      int aw = (int)(256.0f*alpha);
      int xstep = (x2 > x1 ? 1 : -1);
      int ystep = (y2 > y1 ? span : -span);
      if ((mode&LICE_BLIT_MODE_MASK) == LICE_BLIT_MODE_COPY && alpha == 1.0f)
      {
        LICE_DiagLineFAST(px,span, xdiff, xstep, ystep, color, aa);
      }
      else
      {
        if (aa)
        {
#define __LICE__ACTION(COMBFUNC) __LICE_LineClassSimple<COMBFUNC>::LICE_DiagLineAA(px,span, xdiff, xstep, ystep, color, aw)
          __LICE_ACTION_NOSRCALPHA(mode, aw, false);
#undef __LICE__ACTION
        }
        else
        {
#define __LICE__ACTION(COMBFUNC) __LICE_LineClassSimple<COMBFUNC>::LICE_DiagLine(px,span, xdiff, xstep, ystep, color, aw)
          __LICE_ACTION_CONSTANTALPHA(mode, aw, false);
#undef __LICE__ACTION
        }
      }
    }
    else
    {

      // common set-up for normal line draws

      int span = dest->getRowSpan();
      int aw = (int)(256.0f*alpha);
      LICE_pixel* px = dest->getBits()+y1*span+x1;
      LICE_pixel* px2 = dest->getBits()+y2*span+x2;

      int da, db;
      int astep, bstep;
      int dx = x2-x1;
      int dy = y2-y1;

      if (abs(dx) > abs(dy))
      {
        da = dx;
        db = dy;
        astep = 1;
        bstep = span;
      }
      else
      {
        da = dy;
        db = dx;
        astep = span;
        bstep = 1;
      }

      if (da < 0)
      {
        da = -da;
        db = -db;
        SWAP(px, px2);
      }
      if (db < 0)
      {
        db = -db;
        bstep = -bstep;
      }

      double dbda = (double)db/(double)da;

      int derr = (int)(dbda*65536.0);

#ifdef LICE_FAVOR_SIZE

      LICE_COMBINEFUNC blitfunc=NULL;
      #define __LICE__ACTION(comb) blitfunc=comb::doPix;

#else
      #define __LICE__ACTION(COMBFUNC) __LICE_LineClass<COMBFUNC>::LICE_LineImpl(px,px2, derr, astep, da, bstep, color, aw, aa)
#endif
            if (aa)
            {
              __LICE_ACTION_NOSRCALPHA(mode, aw, false);
            }
            else
            {
              __LICE_ACTION_CONSTANTALPHA(mode, aw, false);
            }

      #undef __LICE__ACTION

#ifdef LICE_FAVOR_SIZE
        if (blitfunc) __LICE_LineClass::LICE_LineImpl(px,px2, derr, astep, da, bstep, color, aw, aa, blitfunc);
#endif
    }
  }
}

void LICE_FLine(LICE_IBitmap* dest, float x1, float y1, float x2, float y2, LICE_pixel color, float alpha, int mode, bool aa)
{
  if (!dest) return;
  if (!aa)
  {
    LICE_Line(dest,(int)x1,(int)y1,(int)x2,(int)y2,color,alpha,mode,false);
    return;
  }

  int w = dest->getWidth();
  int h = dest->getHeight();
  if (dest->isFlipped())
  {
    y1 = (float)(h-1)-y1;
    y2 = (float)(h-1)-y2;
  }

  const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
  if (__sc>0)
  {
    __LICE_SCU(w);
    __LICE_SCU(h);
    if (!IGNORE_SCALING(mode))
    {
      __LICE_SC(x1);
      __LICE_SC(x2);
      __LICE_SC(y1);
      __LICE_SC(y2);
    }
  }

  if (ClipFLine(&x1, &y1, &x2, &y2, w, h))
  {
    if (x1 != x2 || y1 != y2)
    {
      int span = dest->getRowSpan();
      int aw = (int)(256.0f*alpha);

      float a1, a2, b1, b2, da, db;
      int astep, bstep;
      float dx = x2-x1;
      float dy = y2-y1;

      if (fabs(dx) > fabs(dy))
      {
        a1 = x1;
        a2 = x2;
        b1 = y1;
        b2 = y2;
        da = dx;
        db = dy;
        astep = 1;
        bstep = span;
      }
      else
      {
        a1 = y1;
        a2 = y2;
        b1 = x1;
        b2 = x2;
        da = dy;
        db = dx;
        astep = span;
        bstep = 1;
      }

      if (da < 0.0f)
      {
        da = -da;
        db = -db;
        SWAP(a1, a2);
        SWAP(b1, b2);
      }
      if (db < 0.0f)
      {
        bstep = -bstep;
      }

      int n = (int)(floor(a2)-ceil(a1));
      float dbda = db/da;

      float ta = ceil(a1);
      float tb = b1+(ta-a1)*dbda;
      float bf = tb-floor(tb);
      int err = (int)(bf*65536.0f);
      if (bstep < 0) err = 65535-err;
      int derr = (int)(fabs(dbda)*65536.0f);

      LICE_pixel* px = dest->getBits()+(int)ta*astep+(int)tb*abs(bstep);

      if (bstep < 0) px -= bstep;

#ifdef LICE_FAVOR_SIZE

      LICE_COMBINEFUNC blitfunc=NULL;
      #define __LICE__ACTION(comb) blitfunc=comb::doPix;

#else

      #define __LICE__ACTION(COMBFUNC) __LICE_LineClass<COMBFUNC>::LICE_FLineImpl(px,n,err,derr,astep,bstep, color, aw)
#endif

      __LICE_ACTION_NOSRCALPHA(mode, aw, false);

#ifdef LICE_FAVOR_SIZE
      if (blitfunc) __LICE_LineClass::LICE_FLineImpl(px,n,err,derr,astep,bstep, color, aw, blitfunc);
#endif

  #undef __LICE__ACTION
    }
  }
}

void LICE_DashedLine(LICE_IBitmap* dest, int x1, int y1, int x2, int y2, int pxon, int pxoff, LICE_pixel color, float alpha, int mode, bool aa)
{
  if (!dest) return;

  int w = dest->getWidth();
  int h = dest->getHeight();
  const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
  if (__sc>0)
  {
    __LICE_SCU(w);
    __LICE_SCU(h);
    if (!IGNORE_SCALING(mode))
    {
      __LICE_SC(x1);
      __LICE_SC(y1);
      __LICE_SC(x2);
      __LICE_SC(y2);
      __LICE_SCU(pxon);
      __LICE_SCU(pxoff);
    }
  }

#ifndef DISABLE_LICE_EXTENSIONS
  if (dest->Extended(LICE_EXT_SUPPORTS_ID, (void*) LICE_EXT_DASHEDLINE_ACCEL))
  {
    LICE_Ext_DashedLine_acceldata data(x1, y1, x2, y2, pxon, pxoff, color, alpha, mode, aa);
    if (dest->Extended(LICE_EXT_DASHEDLINE_ACCEL, &data)) return;
  }
#endif

  if (ClipLine(&x1, &y1, &x2, &y2, w, h))
  {
    if (y1 > y2) SWAP(y1, y2);
    if (pxon == 1 && pxoff == 1 && x1 == x2 && (mode&LICE_BLIT_MODE_MASK) == LICE_BLIT_MODE_COPY && alpha == 1.0f)
    {
      LICE_DottedVertLineFAST(dest, x1, y1, y2, color);
    }
    else
    {
      int aw = (int)(256.0f*alpha);
      if (x1 > x2) SWAP(x1, x2);

#ifdef LICE_FAVOR_SIZE

      LICE_COMBINEFUNC blitfunc=NULL;
      #define __LICE__ACTION(comb) blitfunc=comb::doPix;

#else

  #define __LICE__ACTION(COMBFUNC) __LICE_LineClass<COMBFUNC>::DashedLine(dest, x1, y1, x2, y2, pxon, pxoff, color, aw);
#endif

      __LICE_ACTION_CONSTANTALPHA(mode, aw, false);

#ifdef LICE_FAVOR_SIZE
      if (blitfunc) __LICE_LineClass::DashedLine(dest, x1, y1, x2, y2, pxon, pxoff, color, aw, blitfunc);
#endif

#undef __LICE__ACTION
    }
  }
}

bool LICE_ClipLine(int* pX1, int* pY1, int* pX2, int* pY2, int xLo, int yLo, int xHi, int yHi)
{
    int x1 = *pX1-xLo;
    int y1 = *pY1-yLo;
    int x2 = *pX2-xLo;
    int y2 = *pY2-yLo;
    bool onscreen = ClipLine(&x1, &y1, &x2, &y2, xHi-xLo, yHi-yLo);
    *pX1 = x1+xLo;
    *pY1 = y1+yLo;
    *pX2 = x2+xLo;
    *pY2 = y2+yLo;
    return onscreen;
}

bool LICE_ClipFLine(float* px1, float* py1, float* px2, float* py2, float xlo, float ylo, float xhi, float yhi)
{
  float x1 = *px1-xlo;
  float y1 = *py1-ylo;
  float x2 = *px2-xlo;
  float y2 = *py2-ylo;
  bool onscreen = ClipFLine(&x1, &y1, &x2, &y2, xhi-xlo, yhi-ylo);
  *px1 = x1+xlo;
  *py1 = y1+ylo;
  *px2 = x2+xlo;
  *py2 = y2+ylo;
  return onscreen;
}


#include "lice_bezier.h"

static void DoBezierFillSegment(LICE_IBitmap* dest, int x1, int y1, int x2, int y2, int yfill, LICE_pixel color, float alpha, int mode)
{
  if (x2 < x1) return;
  if (x2 == x1)
  {
    if (y1 > y2) SWAP(y1,y2);
    int ylo = lice_min(y1,yfill);
    int yhi = lice_max(y2,yfill+1);
    LICE_FillRect(dest, x1, ylo, 1, yhi-ylo+1, color, alpha, mode);
    return;
  }

  if ((y1 < yfill) == (y2 < yfill))
  {
    if (y1 < yfill) ++yfill;
    int x[4] = { x1, x1, x2, x2 };
    int y[4] = { y1, yfill, y2, yfill };
    LICE_FillConvexPolygon(dest, x, y, 4, color, alpha, mode);
  }
  else
  {
    int x = x1+(int)((double)(yfill-y1)*(double)(x2-x1)/(double)(y2-y1));
    int yf = yfill;
    if (y1 < yfill) ++yf;
    LICE_FillTriangle(dest, x1, y1, x1, yf, x, yf, color, alpha, mode);
    yf = yfill;
    if (y2 < yfill) ++yf;
    LICE_FillTriangle(dest, x, yf, x2, yf, x2, y2, color, alpha, mode);
  }
}

static void DoBezierFillSegmentX(LICE_IBitmap* dest, int x1, int y1, int x2, int y2, int xfill, LICE_pixel color, float alpha, int mode)
{
  if (y2 < y1) return;
  if (y2 == y1)
  {
    if (x1 > x2) SWAP(x1,x2);
    int xlo = lice_min(x1,xfill);
    int xhi = lice_max(x2,xfill+1);
    LICE_FillRect(dest, xlo, y1, xhi-xlo+1, 1, color, alpha, mode);
    return;
  }

  if ((x1 < xfill) == (x2 < xfill))
  {
    if (x1 < xfill) ++xfill;
    int x[4] = { x1, xfill, x2, xfill };
    int y[4] = { y1, y1, y2+1, y2+1 };
    LICE_FillConvexPolygon(dest, x, y, 4, color, alpha, mode);
  }
  else
  {
    int y = y1+(int)((double)(xfill-x1)*(double)(y2-y1)/(double)(x2-x1));
    int xf = xfill;
    if (x1 < xfill) ++xf;
    LICE_FillTriangle(dest, x1, y1, xf, y1, xf, y, color, alpha, mode);
    xf = xfill;
    if (x2 < xfill) ++xf;
    LICE_FillTriangle(dest, xf, y, xf, y2, x2, y2, color, alpha, mode);
  }
}


// quadratic bezier ... NOT TESTED YET
// attempt to draw segments no longer than tol px
void LICE_DrawQBezier(LICE_IBitmap* dest, double xstart, double ystart, double xctl, double yctl, double xend, double yend,
  LICE_pixel color, float alpha, int mode, bool aa, double tol)
{
  if (!dest) return;

  int w = dest->getWidth();

  const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
  if (__sc)
  {
    __LICE_SCU(w);
    if (!IGNORE_SCALING(mode))
    {
      __LICE_SC(xstart);
      __LICE_SC(ystart);
      __LICE_SC(xctl);
      __LICE_SC(yctl);
      __LICE_SC(xend);
      __LICE_SC(yend);
    }
    mode|=LICE_BLIT_IGNORE_SCALING;
  }




  if (xstart > xend)
  {
    SWAP(xstart, xend);
    SWAP(ystart, yend);
  }

  double len = sqrt((xctl-xstart)*(xctl-xstart)+(yctl-ystart)*(yctl-ystart));
  len += sqrt((xend-xctl)*(xend-xctl)+(yend-yctl)*(yend-yctl));

  double xlo = xstart;
  double xhi = xend;
  double ylo = ystart;
  double yhi = yend;
  double tlo = 0.0;
  double thi = 1.0;

  if (xlo < 0.0f)
  {
    xlo = 0.0f;
    ylo = LICE_Bezier_GetY(xstart, xctl, xend, ystart, yctl, yend, xlo, &tlo);
  }
  if (xhi >= (float)w)
  {
    xhi = (float)(w-1);
    yhi = LICE_Bezier_GetY(xstart, xctl, xend, ystart, yctl, yend, xhi, &thi);
  }
  if (xlo > xhi) return;

  len *= (thi-tlo);
  if (tol <= 0.0f) tol = 1.0f;
  int nsteps = (int)(len/tol);
  if (nsteps <= 0) nsteps = 1;

  double dt = (thi-tlo)/(double)nsteps;
  double t = tlo+dt;

  double lastx = xlo;
  double lasty = ylo;
  double x, y;
  int i;
  for (i = 1; i < nsteps; ++i)
  {
    LICE_Bezier(xstart, xctl, xend, ystart, yctl, yend, t, &x, &y);
    LICE_FLine(dest, lastx, lasty, x, y, color, alpha, mode, aa);
    lastx = x;
    lasty = y;
    t += dt;
  }
  LICE_FLine(dest, lastx, lasty, xhi, yhi, color, alpha, mode, aa);

}

int LICE_CBezPrep(int dest_w, double xstart, double ystart, double xctl1, double yctl1,
  double xctl2, double yctl2, double xend, double yend, double tol, bool xbasis,
  double* ax, double* bx, double* cx, double* dx, double* ay, double* by, double* cy, double* dy,
  double* xlo, double* xhi, double* ylo, double* yhi, double* tlo, double* thi)
{
  const int w = dest_w;

  if ((xbasis && xstart > xend) || (!xbasis && ystart > yend))
  {
    SWAP(xstart, xend);
    SWAP(xctl1, xctl2);
    SWAP(ystart, yend);
    SWAP(yctl1, yctl2);
  }

  double len = sqrt((xctl1-xstart)*(xctl1-xstart)+(yctl1-ystart)*(yctl1-ystart));
  len += sqrt((xctl2-xctl1)*(xctl2-xctl1)+(yctl2-yctl1)*(yctl2-yctl1));
  len += sqrt((xend-xctl2)*(xend-xctl2)+(yend-yctl2)*(yend-yctl2));

  LICE_CBezier_GetCoeffs(xstart, xctl1, xctl2, xend, ystart, yctl1, yctl2, yend, ax, bx, cx, ay, by, cy);
  *dx = xstart;
  *dy = ystart;

  *xlo = xstart;
  *xhi = xend;
  *ylo = ystart;
  *yhi = yend;
  *tlo = 0.0;
  *thi = 1.0;

  if (*xlo < 0.0f)
  {
    *xlo = 0.0f;
    *ylo = LICE_CBezier_GetY(xstart, xctl1, xctl2, xend, ystart, yctl1, yctl2, yend, *xlo, (double*)NULL, (double*)NULL, (double*)NULL, tlo);
  }
  if (*xhi > w)
  {
    *xhi = w;
    *yhi = LICE_CBezier_GetY(xstart, xctl1, xctl2, xend, ystart, yctl1, yctl2, yend, *xhi, (double*)NULL, (double*)(double*)NULL, thi, (double*)NULL);
  }
  if ((xbasis && *xlo > *xhi) || (!xbasis && *ylo > *yhi))
  {
    return 0;
  }

  len *= (*thi-*tlo);
  if (tol <= 0.0f) tol = 1.0f;
  int nsteps = (int)(len/tol);
  if (nsteps <= 0) nsteps = 1;
  return nsteps;
}

#define __LICE_SC_BEZ \
    __LICE_SC(destbm_w); \
    if (!IGNORE_SCALING(mode)) { \
      __LICE_SC(xstart); \
      __LICE_SC(ystart); \
      __LICE_SC(xctl1); \
      __LICE_SC(yctl1); \
      __LICE_SC(xctl2); \
      __LICE_SC(yctl2); \
      __LICE_SC(xend); \
      __LICE_SC(yend); \
    }


void LICE_DrawCBezier(LICE_IBitmap* dest, double xstart, double ystart, double xctl1, double yctl1,
  double xctl2, double yctl2, double xend, double yend, LICE_pixel color, float alpha, int mode, bool aa, double tol)
{
  if (!dest) return;
  int destbm_w = dest->getWidth();
  const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
  if (__sc)
  {
    __LICE_SC_BEZ
    mode|=LICE_BLIT_IGNORE_SCALING;
  }

#ifndef DISABLE_LICE_EXTENSIONS
  if (dest->Extended(LICE_EXT_SUPPORTS_ID, (void*) LICE_EXT_DRAWCBEZIER_ACCEL))
  {
    LICE_Ext_DrawCBezier_acceldata data(xstart, ystart, xctl1, yctl1, xctl2, yctl2, xend, yend, color, alpha, mode, aa);
    if (dest->Extended(LICE_EXT_DRAWCBEZIER_ACCEL, &data)) return;
  }
#endif

  double ax, bx, cx, dx, ay, by, cy, dy;
  double xlo, xhi, ylo, yhi;
  double tlo, thi;
  int nsteps = LICE_CBezPrep(destbm_w, xstart, ystart, xctl1, yctl1, xctl2, yctl2, xend, yend, tol, true,
    &ax, &bx, &cx, &dx, &ay, &by, &cy, &dy, &xlo, &xhi, &ylo, &yhi, &tlo, &thi);
  if (!nsteps) return;

  double dt = (thi-tlo)/(double)nsteps;
  double t = tlo+dt;

  double lastx = xlo;
  double lasty = ylo;
  double x, y;
  int i;
  for (i = 1; i < nsteps-1; ++i)
  {
    EVAL_CBEZXY(x, y, ax, bx, cx, dx, ay, by, cy, dy, t);
    LICE_FLine(dest, lastx, lasty, x, y, color, alpha, mode, aa);
    lastx = x;
    lasty = y;
    t += dt;
  }
  LICE_FLine(dest, lastx, lasty, xhi, yhi, color, alpha, mode, aa);
}

void LICE_DrawThickCBezier(LICE_IBitmap* dest, double xstart, double ystart, double xctl1, double yctl1,
  double xctl2, double yctl2, double xend, double yend, LICE_pixel color, float alpha, int mode, int wid, double tol)
{
  if (!dest) return;
  int destbm_w = dest->getWidth();
  const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
  if (__sc)
  {
    __LICE_SC_BEZ
    mode|=LICE_BLIT_IGNORE_SCALING;
  }

  double ax, bx, cx, dx, ay, by, cy, dy;
  double xlo, xhi, ylo, yhi;
  double tlo, thi;
  int nsteps = LICE_CBezPrep(destbm_w, xstart, ystart, xctl1, yctl1, xctl2, yctl2, xend, yend, tol, true,
                        &ax, &bx, &cx, &dx, &ay, &by, &cy, &dy, &xlo, &xhi, &ylo, &yhi, &tlo, &thi);
  if (!nsteps) return;

  double dt = (thi-tlo)/(double)nsteps;
  double t = tlo+dt;

  double lastx = xlo;
  double lasty = ylo;
  double x, y;
  bool last_xmaj=false;
  int i;
  for (i = 1; i < nsteps; ++i)
  {
    if (i == nsteps-1)
    {
      x = xhi;
      y = yhi;
    }
    else
    {
      EVAL_CBEZXY(x, y, ax, bx, cx, dx, ay, by, cy, dy, t);
    }
    LICE_ThickFLine(dest, lastx, lasty, x, y, color, alpha, mode, wid);

    bool xmaj = fabs(x-lastx) > fabs(y-lasty);
    if (i>1 && xmaj != last_xmaj)
    {
      //int color = LICE_RGBA(255,0,0,0);
      if (wid>2)
      {
        // tested this with w=3, w=4, w=8 and all looked pretty decent
        double r = wid*.5 - 1;
        if (r<0) r=0;
        LICE_FillCircle(dest,floor(lastx+0.5),floor(lasty+0.5),.5+r*.707,color,alpha,mode,true);
      }
      else
      {
        const int ix = (int)floor(lastx+0.5), iy = (int)floor(lasty);
        const double da = lasty - iy;
        LICE_PutPixel(dest,ix,iy,color,alpha * (1.0-da),mode);
        LICE_PutPixel(dest,ix,iy+1,color,alpha*da,mode);
      }
    }

    last_xmaj = xmaj;
    lastx = x;
    lasty = y;
    t += dt;
  }
}

void LICE_FillCBezier(LICE_IBitmap* dest, double xstart, double ystart, double xctl1, double yctl1,
  double xctl2, double yctl2, double xend, double yend, int yfill, LICE_pixel color, float alpha, int mode, double tol)
{
  if (!dest) return;
  int destbm_w = dest->getWidth();
  const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
  if (__sc)
  {
    __LICE_SC_BEZ
    if (!IGNORE_SCALING(mode))
    {
      __LICE_SC(yfill);
      mode|=LICE_BLIT_IGNORE_SCALING;
    }
  }


  double ax, bx, cx, dx, ay, by, cy, dy;
  double xlo, xhi, ylo, yhi;
  double tlo, thi;
  int nsteps = LICE_CBezPrep(destbm_w, xstart, ystart, xctl1, yctl1, xctl2, yctl2, xend, yend, tol, true,
    &ax, &bx, &cx, &dx, &ay, &by, &cy, &dy, &xlo, &xhi, &ylo, &yhi, &tlo, &thi);
  if (!nsteps) return;

  double dt = (thi-tlo)/(double)nsteps;
  double t = tlo+dt;

  int lastfillx = (int)xlo;
  int lastfilly = (int)(ylo+0.5f);
  double x, y;
  int i;
  for (i = 1; i < nsteps-1; ++i)
  {
    EVAL_CBEZXY(x, y, ax, bx, cx, dx, ay, by, cy, dy, t);
    if ((int)x >= lastfillx)
    {
      int xi = (int)x;
      int yi = (int)(y+0.5f);
      DoBezierFillSegment(dest, lastfillx, lastfilly, xi, yi, yfill, color, alpha, mode);
      lastfillx = xi+1;
      lastfilly = yi;
    }
    t += dt;
  }
  if ((int)(xhi-1.0f) >= lastfillx)
  {
    DoBezierFillSegment(dest, lastfillx, lastfilly, (int)(xhi-1.0f),(int)(yhi+0.5f), yfill, color, alpha, mode);
  }
}

void LICE_FillCBezierX(LICE_IBitmap* dest, double xstart, double ystart, double xctl1, double yctl1,
  double xctl2, double yctl2, double xend, double yend, int xfill, LICE_pixel color, float alpha, int mode, double tol)
{
  if (!dest) return;

  int destbm_w = dest->getWidth();
  const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
  if (__sc)
  {
    __LICE_SC_BEZ
    if (!IGNORE_SCALING(mode))
    {
      __LICE_SC(xfill);
      mode|=LICE_BLIT_IGNORE_SCALING;
    }
  }

  double ax, bx, cx, dx, ay, by, cy, dy;
  double xlo, xhi, ylo, yhi;
  double tlo, thi;
  int nsteps = LICE_CBezPrep(destbm_w, xstart, ystart, xctl1, yctl1, xctl2, yctl2, xend, yend, tol, false,
    &ax, &bx, &cx, &dx, &ay, &by, &cy, &dy, &xlo, &xhi, &ylo, &yhi, &tlo, &thi);
  if (!nsteps) return;

  double dt = (thi-tlo)/(double)nsteps;
  double t = tlo+dt;

  int lastfillx = (int)(xlo+0.5f);
  int lastfilly = (int)ylo;
  double x, y;
  int i;
  for (i = 1; i < nsteps-1; ++i)
  {
    EVAL_CBEZXY(x, y, ax, bx, cx, dx, ay, by, cy, dy, t);
    if ((int)y >= lastfilly)
    {
      int xi = (int)(x+0.5f);
      int yi = (int)y;
      DoBezierFillSegmentX(dest, lastfillx, lastfilly, xi, yi, xfill, color, alpha, mode);
      lastfillx = xi;
      lastfilly = yi+1;
    }
    t += dt;
  }
  if ((int)(yhi-1.0f) >= lastfilly)
  {
    DoBezierFillSegmentX(dest, lastfillx, lastfilly, (int)(xhi+0.5),(int)(yhi-1.0f), xfill, color, alpha, mode);
  }
}


void LICE_DrawRect(LICE_IBitmap *dest, int x, int y, int w, int h, LICE_pixel color, float alpha, int mode)
{
  const int __sc = IGNORE_SCALING(mode) ? 0 : (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
  if (__sc>0)
  {
    double x1 = x, y1 = y, x2 = x+w, y2 = y+h;
    const double amt = 1.0 - 256.0/__sc;
    x1 += amt;
    y1 += amt;
    x2 -= amt;
    y2 -= amt;
    LICE_FLine(dest, x1, y1, x2, y1, color, alpha, mode, true);
    LICE_FLine(dest, x2, y1, x2, y2, color, alpha, mode, true);
    LICE_FLine(dest, x2, y2, x1, y2, color, alpha, mode, true);
    LICE_FLine(dest, x1, y2, x1, y1, color, alpha, mode, true);
  }
  else
  {
    LICE_Line(dest, x, y, x+w, y, color, alpha, mode, false);
    LICE_Line(dest, x+w, y, x+w, y+h, color, alpha, mode, false);
    LICE_Line(dest, x+w, y+h, x, y+h, color, alpha, mode, false);
    LICE_Line(dest, x, y+h, x, y, color, alpha, mode, false);
  }
}

void LICE_BorderedRect(LICE_IBitmap *dest, int x, int y, int w, int h, LICE_pixel bgcolor, LICE_pixel fgcolor, float alpha, int mode)
{
  LICE_FillRect(dest, x+1, y+1, w-1, h-1, bgcolor, alpha, mode);
  LICE_DrawRect(dest, x, y, w, h, fgcolor, alpha, mode);
}


#ifndef LICE_FAVOR_SIZE_EXTREME
template<class COMBFUNC>
#endif
class _LICE_Fill
{

#ifdef LICE_FAVOR_SIZE_EXTREME
  #define DOPIX(pout,r,g,b,a,ia) combFunc(pout,r,g,b,a,ia);
#else
    #define DOPIX(pout,r,g,b,a,ia) COMBFUNC::doPix(pout,r,g,b,a,ia);
#endif

public:

  // da, db are [0..65536]
  static void FillClippedTrapezoid(int wid, int span, LICE_pixel *px, int y, int xa, int xb, int da, int db, int a, int b, int astep, int bstep, int cr, int cg, int cb, int ca, int aw
#ifdef LICE_FAVOR_SIZE_EXTREME
                          , LICE_COMBINEFUNC combFunc
#endif
    )
  {
    if (!da && !db)
    {
      while (y-->0)
      {
        LICE_pixel* xpx = px;
        int x=xb;
        while (x--)
        {
          DOPIX((LICE_pixel_chan*)xpx, cr, cg, cb, ca, aw)
          ++xpx;
        }
        px += span;
      }
      return;
    }


    while (y-->0)
    {
      int x1=lice_max(xa,0);
      int x2=lice_min(xb,wid);
      LICE_pixel* xpx = px + x1;
      int cnt=x2-x1;
      while (cnt-->0)
      {
        DOPIX((LICE_pixel_chan*)xpx, cr, cg, cb, ca, aw)
        ++xpx;
      }

      a += da;
      b += db;
      if (a >= 65536)
      {
        int na = a>>16;
        a &= 65535;
        if (astep<0)na=-na;
        xa += na;
      }
      if (b >= 65536)
      {
        int nb = b>>16;
        b &= 65535;
        if (bstep<0)nb=-nb;
        xb += nb;
      }
      px += span;
    }
  }
};


template <class COMBFUNC> class _LICE_FillFast
{
public:

  // da, db are [0..65536]
  static void FillClippedTrapezoidFAST(int wid, int span, LICE_pixel *px, int y, int xa, int xb, int da, int db, int a, int b, int astep, int bstep, LICE_pixel color)
  {
    if (!da && !db)
    {
      while (y-->0)
      {
        LICE_pixel* xpx = px;
        int x=xb;
        while (x--)
        {
          COMBFUNC::doPixFAST(xpx, color);
          ++xpx;
        }
        px += span;
      }
      return;
    }


    while (y-->0)
    {
      int x1=lice_max(xa,0);
      int x2=lice_min(xb,wid);
      LICE_pixel* xpx = px + x1;
      int cnt=x2-x1;
      while (cnt-->0)
      {
        COMBFUNC::doPixFAST(xpx, color);
        ++xpx;
      }

      a += da;
      b += db;
      if (a >= 65536)
      {
        int na = a>>16;
        a &= 65535;
        if (astep<0)na=-na;
        xa += na;
      }
      if (b >= 65536)
      {
        int nb = b>>16;
        b &= 65535;
        if (bstep<0)nb=-nb;
        xb += nb;
      }
      px += span;
    }
  }
};

static double FindXOnSegment(int x1, int y1, int x2, int y2, int ty)
{
  if (y1 > y2)
  {
    SWAP(x1, x2);
    SWAP(y1, y2);
  }
  if (ty <= y1) return x1;
  if (ty >= y2) return x2;
  const double dxdy = (x2-x1)/(double)(y2-y1);
  return x1+(ty-y1)*dxdy;
}

void LICE_FillTrapezoidF(LICE_IBitmap* dest, double fx1a, double fx1b, int y1, double fx2a, double fx2b, int y2, LICE_pixel color, float alpha, int mode)
{
  if (!dest) return;
  if (y1 > y2)
  {
    SWAP(y1, y2);
    SWAP(fx1a, fx2a);
    SWAP(fx1b, fx2b);
  }
  if (fx1a > fx1b) SWAP(fx1a, fx1b);
  if (fx2a > fx2b) SWAP(fx2a, fx2b);

  int w = dest->getWidth();
  int h = dest->getHeight();

  const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
  if (__sc>0)
  {
    __LICE_SCU(w);
    __LICE_SCU(h);
    if (!IGNORE_SCALING(mode))
    {
      __LICE_SC(fx1a);
      __LICE_SC(fx1b);
      __LICE_SC(fx2a);
      __LICE_SC(fx2b);
      __LICE_SC(y1);
      __LICE_SC(y2);
    }
  }

  if (fx1b < 0 && fx2b < 0) return;
  if (fx1a >= w && fx2a >= w) return;

  if (fx1a <= 0 && fx2a <= 0) fx1a = fx2a = 0;
  if (fx1b >= w-1 && fx2b >= w-1) fx1b = fx2b = w-1;

  if (y2 < 0 || y1 >= h) return;

  int aw = (int)(alpha*256.0f);

  double idy = y2==y1 ? 0.0 : (65536.0/(y2-y1));

  const double maxv=(double)(1<<29);
  double tmp = (fx2a-fx1a)*idy;
  if (tmp > maxv) tmp=maxv;
  else if (tmp < -maxv) tmp=-maxv;
  int dxady = (int)floor(tmp+0.5);

  tmp = ((fx2b-fx1b)*idy);
  if (tmp > maxv) tmp=maxv;
  else if (tmp < -maxv) tmp=-maxv;
  int dxbdy = (int)floor(tmp+0.5);

  int astep = 1;
  int bstep = 1;
  if (dxady < 0)
  {
    dxady = -dxady;
    astep = -1;
  }
  if (dxbdy < 0)
  {
    dxbdy = -dxbdy;
    bstep = -1;
  }

  int x1a = (int)floor(fx1a);
  int x1b = (int)floor(fx1b);
  int a = (int) floor((fx1a-x1a)*65536.0*astep+0.5);
  int b = (int) floor((fx1b-x1b)*65536.0*bstep+0.5);

  if (y1<0)
  {
    a -= dxady*y1;
    b -= dxbdy*y1;
    y1=0;
  }
  if (a< 0 || a >= 65536)
  {
    int na = a>>16;
    a &= 65535;
    if (astep<0)na=-na;
    x1a += na;
  }
  if (b < 0 || b >= 65536)
  {
    int nb = b>>16;
    b &= 65535;
    if (bstep<0)nb=-nb;
    x1b += nb;
  }
  const int extra = __sc> 0 && !IGNORE_SCALING(mode) ? (__sc/256 - 1) : 0;
  if (y2 > h-1-extra) y2 = h-1-extra;

  int wid = w;
  int span = dest->getRowSpan();
  LICE_pixel* px = dest->getBits()+y1*span;
  int y = y2-y1 + 1 + extra;

  x1b++; // from now on draw [x1a,x1b)

  if (!dxady && !dxbdy)
  {
    if (x1a<0)x1a=0;
    x1b = lice_min(x1b,wid)-x1a;
    px+=x1a;
    if (x1b<1) return;
  }

  if ((mode&LICE_BLIT_MODE_MASK) == LICE_BLIT_MODE_COPY && aw==256)
  {
    _LICE_FillFast<_LICE_CombinePixelsClobberFAST>::FillClippedTrapezoidFAST(wid,span,px,y, x1a, x1b, dxady, dxbdy, a,b, astep,bstep, color);
  }
  else if ((mode&LICE_BLIT_MODE_MASK) == LICE_BLIT_MODE_COPY && aw==128)
  {
    color = (color>>1)&0x7f7f7f7f;
    _LICE_FillFast<_LICE_CombinePixelsHalfMix2FAST>::FillClippedTrapezoidFAST(wid,span,px,y,  x1a, x1b, dxady, dxbdy, a,b, astep,bstep, color);
  }
  else if ((mode&LICE_BLIT_MODE_MASK) == LICE_BLIT_MODE_COPY && aw==64)
  {
    color = (color>>2)&0x3f3f3f3f;
    _LICE_FillFast<_LICE_CombinePixelsQuarterMix2FAST>::FillClippedTrapezoidFAST(wid,span,px,y,  x1a, x1b, dxady, dxbdy, a,b, astep,bstep, color);
  }
  else if ((mode&LICE_BLIT_MODE_MASK) == LICE_BLIT_MODE_COPY && aw==192)
  {
    color = ((color>>1)&0x7f7f7f7f)+((color>>2)&0x3f3f3f3f);
    _LICE_FillFast<_LICE_CombinePixelsThreeQuarterMix2FAST>::FillClippedTrapezoidFAST(wid,span,px,y,  x1a, x1b, dxady, dxbdy,a,b, astep,bstep, color);
  }
  else
  {
    int cr = LICE_GETR(color), cg = LICE_GETG(color), cb = LICE_GETB(color), ca = LICE_GETA(color);
#ifdef LICE_FAVOR_SIZE_EXTREME

    LICE_COMBINEFUNC blitfunc=NULL;
#define __LICE__ACTION(comb) blitfunc=comb::doPix;
#else
#define __LICE__ACTION(COMBFUNC) _LICE_Fill<COMBFUNC>::FillClippedTrapezoid(wid,span,px,y,  x1a, x1b, dxady, dxbdy, a,b, astep,bstep, cr,cg,cb,ca, aw);
#endif

    __LICE_ACTION_CONSTANTALPHA(mode, aw, false);

#ifdef LICE_FAVOR_SIZE_EXTREME
      if (blitfunc) _LICE_Fill::FillClippedTrapezoid(wid,span,px,y,  x1a, x1b, dxady, dxbdy, a,b, astep,bstep, cr,cg,cb,ca, aw, blitfunc);
#endif

#undef __LICE__ACTION
  }
}

void LICE_FillTrapezoid(LICE_IBitmap* dest, int x1a, int x1b, int y1, int x2a, int x2b, int y2, LICE_pixel color, float alpha, int mode)
{
  LICE_FillTrapezoidF(dest,x1a,x1b,y1,x2a,x2b,y2,color,alpha,mode);
}

static int _ysort(const void* a, const void* b)
{
  int* xya = (int*)a;
  int* xyb = (int*)b;
  if (xya[1] < xyb[1]) return -1;
  if (xya[1] > xyb[1]) return 1;
  if (xya[0] < xyb[0]) return -1;
  if (xya[0] > xyb[0]) return 1;
  return 0;
}

#define _X(i) xy[2*(i)]
#define _Y(i) xy[2*(i)+1]

static int FindNextEdgeVertex(int* xy, int a, int n, int dir)
{
  bool init = false;
  double dxdy_best = 0.0f;
  int i, ilo = a;

  for (i = a+1; i < n; ++i)
  {
    if (_Y(i) == _Y(a)) continue;
    const double dxdy = (_X(i)-_X(a))/(double)(_Y(i)-_Y(a));
    if (!init || dxdy == dxdy_best || (dir < 0 && dxdy < dxdy_best) || (dir > 0 && dxdy > dxdy_best))
    {
      init = true;
      ilo = i;
      dxdy_best = dxdy;
    }
  }
  return ilo;
}

void LICE_FillConvexPolygon(LICE_IBitmap* dest, const int* x, const int* y, int npoints, LICE_pixel color, float alpha, int mode)
{
  if (!dest) return;
  if (npoints < 3) return;

  int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();

  if (IGNORE_SCALING(mode))
  {
    const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
    if (__sc)
    {
      __LICE_SCU(destbm_w);
      __LICE_SCU(destbm_h);
    }
  }

  int* xy = 0;
  int xyt[1024]; // use stack space if small
  bool usestack = npoints <= (int) (sizeof(xyt)/sizeof(int)/2);
  if (usestack) xy = xyt;
  else xy = (int*)malloc(npoints*sizeof(int)*2);

  int i;
  {
    int min_x=destbm_w,max_x=0;
    for (i = 0; i < npoints; ++i)
    {
      int tx = x[i], ty=y[i];
      if (tx < min_x) min_x=tx;
      if (tx > max_x) max_x=tx;
      _X(i) = tx;
      if (dest->isFlipped()) ty = destbm_h-ty-1;
      _Y(i) = ty;
    }
    qsort(xy, npoints, 2*sizeof(int), _ysort);  // sorts by y, at same y sorts by x


    int ty=_Y(0);
    if (ty == _Y(npoints-1))
    {
      // special case 1px high polygon
      if (ty >= 0 && ty < dest->getHeight() && min_x <= max_x)
      {
        LICE_FillTrapezoid(dest,min_x,max_x,ty,min_x,max_x,ty,color,alpha,mode);
      }
      if (!usestack) free(xy);

      return;
    }
  }

  int a1, b1;   // index of previous vertex L and R
  int a2, b2;   // index of next vertex L and R
  int y1;   // top and bottom of current trapezoid

  a1 = b1 = 0;
  y1 = _Y(0);

  for (i = 1; i < npoints && _Y(i) == y1; ++i)
  {
    if (_X(i) == _X(0)) a1 = i;
    b1 = i;
  }

  a2 = FindNextEdgeVertex(xy, a1, npoints, -1);
  b2 = FindNextEdgeVertex(xy, b1, npoints, 1);

  while (a1 != a2 || b1 != b2)
  {
    int y_a2 = _Y(a2);
    int y_b2 = _Y(b2);

    int y2 = lice_min(y_a2, y_b2);
    double x1a = FindXOnSegment(_X(a1), _Y(a1), _X(a2), y_a2, y1);
    double x1b = FindXOnSegment(_X(b1), _Y(b1), _X(b2), y_b2, y1);
    double x2a = FindXOnSegment(_X(a1), _Y(a1), _X(a2), y_a2, y2);
    double x2b = FindXOnSegment(_X(b1), _Y(b1), _X(b2), y_b2, y2);

    LICE_FillTrapezoidF(dest, x1a, x1b, y1, x2a, x2b, y2, color, alpha, mode);

    bool dir = y1<=y2; // should always be true

    y1 = y2;
    if (y_a2 == y1)
    {
      a1 = a2;
      a2 = FindNextEdgeVertex(xy, a2, npoints, -1);
    }
    if (y_b2 == y1)
    {
      b1 = b2;
      b2 = FindNextEdgeVertex(xy, b2, npoints, 1);
    }

    if (dir) y1++;
    else y1--;
  }

  if (!usestack) free(xy);
}

#undef _X
#undef _Y


void LICE_FillTriangle(LICE_IBitmap *dest, int x1, int y1, int x2, int y2, int x3, int y3, LICE_pixel color, float alpha, int mode)
{
  if (!dest) return;

  int x[3] = { x1, x2, x3 };
  int y[3] = { y1, y2, y3 };
  LICE_FillConvexPolygon(dest, x, y, 3, color, alpha, mode);
}

void LICE_ThickFLine(LICE_IBitmap* dest, double x1, double y1, double x2, double y2, LICE_pixel color, float alpha, int mode, int wid) // always AA. wid is not affected by scaling (1 is always normal line, 2 is always 2 physical pixels, etc)
{
  if (!dest || wid<1) return;
  if (wid==1)
  {
    LICE_Line(dest,(float)x1,(float)y1,(float)x2,float(y2),color,alpha,mode,true);
    return;
  }

  int w = dest->getWidth();
  int h = dest->getHeight();
  if (dest->isFlipped())
  {
    y1 = (h-1)-y1;
    y2 = (h-1)-y2;
  }

  const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
  if (__sc>0)
  {
    __LICE_SCU(w);
    __LICE_SCU(h);
    if (!IGNORE_SCALING(mode))
    {
      __LICE_SC(x1);
      __LICE_SC(x2);
      __LICE_SC(y1);
      __LICE_SC(y2);
    }
  }

  bool steep = fabs(y2-y1) >= fabs(x2-x1);

  if (ClipFLine(&x1, &y1, &x2, &y2, w, h))
  {
    if (x1 != x2 || y1 != y2)
    {
      int span = dest->getRowSpan();
      int aw = (int)(256.0f*alpha);

      double a1, a2, b1, b2, da, db;
      int astep, bstep;
      double dx = x2-x1;
      double dy = y2-y1;

      int b_max;
      if (!steep)
      {
        a1 = x1;
        a2 = x2;
        b1 = y1;
        b2 = y2;
        da = dx;
        db = dy;
        astep = 1;
        bstep = span;
        b_max = h;
      }
      else
      {
        a1 = y1;
        a2 = y2;
        b1 = x1;
        b2 = x2;
        da = dy;
        db = dx;
        astep = span;
        bstep = 1;
        b_max = w;
      }

      if (da < 0.0)
      {
        da = -da;
        db = -db;
        SWAP(a1, a2);
        SWAP(b1, b2);
      }
      if (db < 0.0)
      {
        bstep = -bstep;
      }

      int n = (int)(floor(a2)-ceil(a1));
      double dbda = db/da;

      double ta = ceil(a1);
      double tb = b1+(ta-a1)*dbda;
      double bf = tb-floor(tb);
      int err = (int)(bf*65536.0);
      if (bstep < 0) err = 65535-err;
      int derr = (int)(fabs(dbda)*65536.0);

      int b_pos = (int) tb;
      LICE_pixel *px = dest->getBits() + (int)ta*astep+b_pos*abs(bstep);

      if (bstep < 0) { px -= bstep; b_pos++; }

#ifdef LICE_FAVOR_SIZE

      LICE_COMBINEFUNC blitfunc=NULL;
      #define __LICE__ACTION(comb) blitfunc=comb::doPix;

#else
      #define __LICE__ACTION(COMBFUNC) \
        __LICE_LineClass<COMBFUNC>::LICE_FLineImplFill(px,n,err,derr,astep,bstep, color, aw, wid, b_pos, b_max)
#endif

      __LICE_ACTION_NOSRCALPHA(mode, aw, false);

#ifdef LICE_FAVOR_SIZE
      if (blitfunc)
      {
        __LICE_LineClass::LICE_FLineImplFill(px,n,err,derr,astep,bstep, color, aw, wid, b_pos, b_max, blitfunc);
      }
#endif

  #undef __LICE__ACTION
    }
  }
}
