private void scanline(int y, float l[], float r[]) {
    //System.out.println("scanline " + y);
    for (int i = 0; i < vertexCount; i++) {  // should be moved later
      sp[i] = 0; sdp[i] = 0;
    }

    // this rounding doesn't seem to be relevant with smooth
    int lx = (int) (l[TX] + 0.49999f);  // ceil(l[TX]-.5);
    if (lx < 0) lx = 0;
    int rx = (int) (r[TX] - 0.5f);
    if (rx > width1) rx = width1;

    if (lx > rx) return;

    if (smooth) {
      int mody = MODYRES(y);

      aaleft[mody] = lx;
      aaright[mody] = rx;

      if (firstModY == -1) {
        firstModY = mody;
        aaleftmin = lx; aaleftmax = lx;
        aarightmin = rx; aarightmax = rx;

      } else {
        if (aaleftmin > aaleft[mody]) aaleftmin = aaleft[mody];
        if (aaleftmax < aaleft[mody]) aaleftmax = aaleft[mody];
        if (aarightmin > aaright[mody]) aarightmin = aaright[mody];
        if (aarightmax < aaright[mody]) aarightmax = aaright[mody];
      }

      lastModY = mody;  // moved up here (before the return) 031001
      // not the eighth (or lastY) line, so not scanning this time
      if ((mody != SUBYRES1) && (y != lastY)) return;
        //lastModY = mody;  // eeK! this was missing
      //return;

      //if (y == lastY) {
      //System.out.println("y is lasty");
      //}
      //lastModY = mody;
      aaleftfull = aaleftmax/SUBXRES + 1;
      aarightfull = aarightmin/SUBXRES - 1;
    }

    // this is the setup, based on lx
    incrementalizeX(l, r, sp, sdp, lx);

    // scan in x, generating pixels
    // using parent.width to get actual pixel index
    // rather than scaled by smooth factor
    int offset = smooth ? parent.width * (y / SUBYRES) : parent.width*y;

    int truelx = 0, truerx = 0;
    if (smooth) {
      truelx = lx / SUBXRES;
      truerx = (rx + SUBXRES1) / SUBXRES;

      lx = aaleftmin / SUBXRES;
      rx = (aarightmax + SUBXRES1) / SUBXRES;
      if (lx < 0) lx = 0;
      if (rx > parent.width1) rx = parent.width1;
    }

    interpX = false;
    int tr, tg, tb, ta;

//    System.out.println("P2D interp uv " + interpUV + " " + 
//                       vertices[2][U] + " " + vertices[2][V]);    
    for (int x = lx; x <= rx; x++) {
      // map texture based on U, V coords in sp[U] and sp[V]
      if (interpUV) {
        int tu = (int) (sp[U] * twidth);
        int tv = (int) (sp[V] * theight);

        if (tu > twidth1) tu = twidth1;
        if (tv > theight1) tv = theight1;
        if (tu < 0) tu = 0;
        if (tv < 0) tv = 0;

        int txy = tv*twidth + tu;

        int tuf1 = (int) (255f * (sp[U]*twidth - (float)tu));
        int tvf1 = (int) (255f * (sp[V]*theight - (float)tv));

        // the closer sp[U or V] is to the decimal being zero
        // the more coverage it should get of the original pixel
        int tuf = 255 - tuf1;
        int tvf = 255 - tvf1;

        // this code sucks! filled with bugs and slow as hell!
        int pixel00 = tpixels[txy];
        int pixel01 = (tv < theight1) ?
          tpixels[txy + twidth] : tpixels[txy];
        int pixel10 = (tu < twidth1) ?
          tpixels[txy + 1] : tpixels[txy];
        int pixel11 = ((tv < theight1) && (tu < twidth1)) ?
          tpixels[txy + twidth + 1] : tpixels[txy];

        int p00, p01, p10, p11;
        int px0, px1; //, pxy;

        
        // calculate alpha component (ta)
        
        if (tformat == ALPHA) {
          px0 = (pixel00*tuf + pixel10*tuf1) >> 8;
          px1 = (pixel01*tuf + pixel11*tuf1) >> 8;
          ta = (((px0*tvf + px1*tvf1) >> 8) *
            (interpARGB ? ((int) (sp[A]*255)) : a2orig)) >> 8;

        } else if (tformat == ARGB) {
          p00 = (pixel00 >> 24) & 0xff;
          p01 = (pixel01 >> 24) & 0xff;
          p10 = (pixel10 >> 24) & 0xff;
          p11 = (pixel11 >> 24) & 0xff;

          px0 = (p00*tuf + p10*tuf1) >> 8;
          px1 = (p01*tuf + p11*tuf1) >> 8;
          ta = (((px0*tvf + px1*tvf1) >> 8) *
                (interpARGB ? ((int) (sp[A]*255)) : a2orig)) >> 8;

        } else {  // RGB image, no alpha
          ta = interpARGB ? ((int) (sp[A]*255)) : a2orig;
        }

        // calculate r,g,b components (tr, tg, tb)
        
        if ((tformat == RGB) || (tformat == ARGB)) {
          p00 = (pixel00 >> 16) & 0xff;  // red
          p01 = (pixel01 >> 16) & 0xff;
          p10 = (pixel10 >> 16) & 0xff;
          p11 = (pixel11 >> 16) & 0xff;

          px0 = (p00*tuf + p10*tuf1) >> 8;
          px1 = (p01*tuf + p11*tuf1) >> 8;
          tr = (((px0*tvf + px1*tvf1) >> 8) *
                (interpARGB ? ((int) (sp[R]*255)) : r2)) >> 8;
                
          p00 = (pixel00 >> 8) & 0xff;  // green
          p01 = (pixel01 >> 8) & 0xff;
          p10 = (pixel10 >> 8) & 0xff;
          p11 = (pixel11 >> 8) & 0xff;

          px0 = (p00*tuf + p10*tuf1) >> 8;
          px1 = (p01*tuf + p11*tuf1) >> 8;
          tg = (((px0*tvf + px1*tvf1) >> 8) *
                (interpARGB ? ((int) (sp[G]*255)) : g2)) >> 8;

          p00 = pixel00 & 0xff;  // blue
          p01 = pixel01 & 0xff;
          p10 = pixel10 & 0xff;
          p11 = pixel11 & 0xff;

          px0 = (p00*tuf + p10*tuf1) >> 8;
          px1 = (p01*tuf + p11*tuf1) >> 8;
          tb = (((px0*tvf + px1*tvf1) >> 8) *
                (interpARGB ? ((int) (sp[B]*255)) : b2)) >> 8;

        } else {  // alpha image, only use current fill color
          if (interpARGB) {
            tr = (int) (sp[R] * 255);
            tg = (int) (sp[G] * 255);
            tb = (int) (sp[B] * 255);

          } else {
            tr = r2;
            tg = g2;
            tb = b2;
          }
        }

        int weight = smooth ? coverage(x) : 255;
        if (weight != 255) ta = ta*weight >> 8;
        
        if ((ta == 254) || (ta == 255)) {  // if (ta & 0xf8) would be good
          // no need to blend
          pixels[offset+x] = 0xff000000 | (tr << 16) | (tg << 8) | tb;

        } else {
          // blend with pixel on screen
          int a1 = 255-ta;
          int r1 = (pixels[offset+x] >> 16) & 0xff;
          int g1 = (pixels[offset+x] >> 8) & 0xff;
          int b1 = (pixels[offset+x]) & 0xff;

          pixels[offset+x] = 0xff000000 |
            (((tr*ta + r1*a1) >> 8) << 16) |
            ((tg*ta + g1*a1) & 0xff00) |
            ((tb*ta + b1*a1) >> 8);
        }

      } else {  // no image applied
        int weight = smooth ? coverage(x) : 255;

        if (interpARGB) {
          r2 = (int) (sp[R] * 255);
          g2 = (int) (sp[G] * 255);
          b2 = (int) (sp[B] * 255);
          if (sp[A] != 1) weight = (weight * ((int) (sp[A] * 255))) >> 8;
          if (weight == 255) {
            rgba = 0xff000000 | (r2 << 16) | (g2 << 8) | b2;
          }
        } else {
          if (a2orig != 255) weight = (weight * a2orig) >> 8;
        }

        if (weight == 255) {
          // no blend, no aa, just the rgba
          pixels[offset+x] = rgba;
          //zbuffer[offset+x] = sp[Z];

        } else {
          int r1 = (pixels[offset+x] >> 16) & 0xff;
          int g1 = (pixels[offset+x] >> 8) & 0xff;
          int b1 = (pixels[offset+x]) & 0xff;
          a2 = weight;

          int a1 = 255 - a2;
          pixels[offset+x] = (0xff000000 |
                              ((r1*a1 + r2*a2) >> 8) << 16 |
                              // use & instead of >> and << below
                              ((g1*a1 + g2*a2) >> 8) << 8 |
                              ((b1*a1 + b2*a2) >> 8));
        }
      }

      // if smooth enabled, don't increment values
      // for the pixel in the stretch out version
      // of the scanline used to get smooth edges.
      if (!smooth || ((x >= truelx) && (x <= truerx))) {
        increment(sp, sdp);
      }
    }
    firstModY = -1;
    interpX = true;
  }