private void drawsegment_texture24(float leftadd,
                                     float rghtadd,
                                     int ytop,
                                     int ybottom) {
    ytop *= SCREEN_WIDTH;
    ybottom *= SCREEN_WIDTH;
//    int p = m_index;
    float iuf = iuadd;
    float ivf = ivadd;
    
    boolean tint = (m_fill & 0xFFFFFF) != 0xFFFFFF;
    int rtint = (m_fill >> 16) & 0xff;
    int gtint = (m_fill >> 8) & 0xff;
    int btint = m_fill & 0xFF;

    int ypixel = ytop/SCREEN_WIDTH;//ACCTEX
    int lastRowStart = m_texture.length - TEX_WIDTH - 2;//If we're past this index, we can't shift down a row w/o throwing an exception
    //      int exCount = 0;//counter for exceptions caught
    boolean accurateMode = parent.hints[ENABLE_ACCURATE_TEXTURES]; //bring this local since it will be accessed often
    float screenx = 0; float screeny = 0; float screenz = 0;
    float a = 0; float b = 0; float c = 0;

    //Interpolation length of 16 tends to look good except at a small angle; 8 looks okay then, except for the
    //above issue.  When viewing close to flat, as high as 32 is often acceptable.  Could add dynamic interpolation
    //settings based on triangle angle - currently we just pick a value and leave it (by default I have the
    //power set at 3, so every 8 pixels a true coordinate is calculated, which seems a decent compromise).

    int linearInterpPower = TEX_INTERP_POWER;
    int linearInterpLength = 1 << linearInterpPower;
    if (accurateMode){
      if(precomputeAccurateTexturing()){ //see if the precomputation goes well, if so finish the setup
        newax *= linearInterpLength;
        newbx *= linearInterpLength;
        newcx *= linearInterpLength;
        screenz = nearPlaneDepth;
        firstSegment = false;
      } else{
        accurateMode = false; //if the matrix inversion gave us garbage, revert to normal rendering (something is degenerate)
      }
    }


    while (ytop < ybottom) {//scanline loop
      int xstart = (int) (xleft + PIXEL_CENTER);
      if (xstart < 0){ xstart = 0; }

      int xpixel = xstart;//accurate mode

      int xend = (int) (xrght + PIXEL_CENTER);
      if (xend > SCREEN_WIDTH){ xend = SCREEN_WIDTH; }
      float xdiff = (xstart + PIXEL_CENTER) - xleft;
      int iu = (int) (iuf * xdiff + uleft);
      int iv = (int) (ivf * xdiff + vleft);
      float iz = izadd * xdiff + zleft;
      xstart+=ytop;
      xend+=ytop;

      if (accurateMode){
        //off by one (half, I guess) hack, w/o it the first rows are outside the texture - maybe a mistake somewhere?
        screenx = xmult*(xpixel+.5f-(SCREEN_WIDTH/2.0f));
        screeny = ymult*(ypixel+.5f-(SCREEN_HEIGHT/2.0f));
        a = screenx*ax+screeny*ay+screenz*az;//OPT - some of this could be brought out of the y-loop since
        b = screenx*bx+screeny*by+screenz*bz;//xpixel and ypixel just increment by the same numbers each iteration.
        c = screenx*cx+screeny*cy+screenz*cz;//Probably not a big bottleneck, though.
      }

      //Figure out whether triangle is going further into the screen or not as we move along scanline
      boolean goingIn = ( (newcx > 0) == (c > 0) )?false:true;

      //Set up linear interpolation between calculated texture points
      int interpCounter = 0;
      int deltaU = 0; int deltaV = 0;
      //float fdeltaU = 0; float fdeltaV = 0;//vars for floating point interpolating version of algorithm
      //float fiu = 0; float fiv = 0;
      float fu = 0; float fv = 0;
      float oldfu = 0; float oldfv = 0;


      //Bugfix (done): it's a Really Bad Thing to interpolate along a scanline when the triangle goes deeper into the screen,
      //because if the angle is severe enough the last control point for interpolation may cross the vanishing
      //point.  This leads to some pretty nasty artifacts, and ideally we should scan from right to left if the
      //triangle is better served that way, or (what we do now) precompute the offset that we'll need so that we end up
      //with a control point exactly at the furthest edge of the triangle.

      if (accurateMode&&goingIn){
        //IMPORTANT!!!  Results are horrid without this hack!
        //If polygon goes into the screen along scan line, we want to match the control point to the furthest point drawn
        //since the control points are less meaningful the closer you are to the vanishing point.
        //We'll do this by making the first control point lie before the start of the scanline (safe since it's closer to us)

        int rightOffset = (xend-xstart-1)%linearInterpLength; //"off by one" hack...probably means there's a small bug somewhere
        int leftOffset = linearInterpLength-rightOffset;
        float rightOffset2 = rightOffset / ((float)linearInterpLength);
        float leftOffset2 = leftOffset / ((float)linearInterpLength);
        interpCounter = leftOffset;

        //Take step to control point to the left of start pixel
        float ao = a-leftOffset2*newax;
        float bo = b-leftOffset2*newbx;
        float co = c-leftOffset2*newcx;
        float oneoverc = 65536.0f/co;
        oldfu = (ao*oneoverc); oldfv = (bo*oneoverc);

        //Now step to right control point
        a += rightOffset2*newax;
        b += rightOffset2*newbx;
        c += rightOffset2*newcx;
        oneoverc = 65536.0f/c;
        fu = a*oneoverc; fv = b*oneoverc;

        //Get deltas for interpolation
        deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
        deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
        iu = ( (int)oldfu )+(leftOffset-1)*deltaU; iv = ( (int)oldfv )+(leftOffset-1)*deltaV; //another "off-by-one" hack
      } else{
        //Otherwise the left edge is further, and we pin the first control point to it
        float preoneoverc = 65536.0f/c;
        fu = (a*preoneoverc);
        fv = (b*preoneoverc);
      }

      for ( ; xstart < xend; xstart++ ) {//pixel loop - keep trim, can execute thousands of times per frame
        //boolean drawBlack = false; //used to display control points
        if(accurateMode){
          /*  //Non-interpolating algorithm - slowest version, calculates exact coordinate for each pixel,
          //and casts from float->int
          float oneoverc = 65536.0f/c;  //a bit faster to pre-divide for next two steps
          iu = (int)(a*oneoverc);
          iv = (int)(b*oneoverc);
          a += newax;
          b += newbx;
          c += newcx;
          */

          //Float while calculating, int while interpolating
          if (interpCounter == linearInterpLength) interpCounter = 0;
          if (interpCounter == 0){
            //drawBlack = true;
            a += newax;
            b += newbx;
            c += newcx;
            float oneoverc = 65536.0f/c;
            oldfu = fu; oldfv = fv;
            fu = (a*oneoverc); fv = (b*oneoverc);
            iu = (int)oldfu; iv = (int)oldfv; //ints are used for interpolation, not actual computation
            deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
            deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
          } else{        //race through using linear interpolation if we're not at a control point
            iu += deltaU;
            iv += deltaV;
          }
          interpCounter++;

          /* //Floating point interpolating version - slower than int thanks to casts during interpolation steps
             if (interpCounter == 0) {
             interpCounter = linearInterpLength;
             a += newax;
             b += newbx;
             c += newcx;
             float oneoverc = 65536.0f/c;
             oldfu = fu;
             oldfv = fv;
             fu = (a*oneoverc);
             fv = (b*oneoverc);
             //oldu = u; oldv = v;
             fiu = oldfu;
             fiv = oldfv;
             fdeltaU = (fu-oldfu)/linearInterpLength;
             fdeltaV = (fv-oldfv)/linearInterpLength;
             }
             else{
             fiu += fdeltaU;
             fiv += fdeltaV;
             }
             interpCounter--;
             iu = (int)(fiu); iv = (int)(fiv);*/

        }

        // try-catch just in case pixel offset is out of range
        try{
          if (noDepthTest || (iz <= m_zbuffer[xstart])) {
            m_zbuffer[xstart] = iz;
            if (m_bilinear) {
              //We could (should?) add bounds checking on iu and iv here (keep in mind the 16 bit shift!).
              //This would also be the place to add looping texture mode (bounds check == clamped).
              //For looping/clamped textures, we'd also need to change PGraphics.textureVertex() to remove
              //the texture range check there (it constrains normalized texture coordinates from 0->1).

              int ofs = (iv >> 16) * TEX_WIDTH + (iu >> 16);
              int iui = (iu & 0xFFFF) >> 9;
              int ivi = (iv & 0xFFFF) >> 9;

              //if(ofs < 0) { ofs += TEX_WIDTH; }
              //if(ofs > m_texture.length-2) {ofs -= TEX_WIDTH; }

              // get texture pixels
              int pix0 = m_texture[ofs];
              int pix1 = m_texture[ofs + 1];
              if (ofs < lastRowStart) ofs+=TEX_WIDTH; //quick hack to thwart exceptions
              int pix2 = m_texture[ofs];
              int pix3 = m_texture[ofs + 1];

              // red
              int red0 = (pix0 & 0xFF0000);
              int red2 = (pix2 & 0xFF0000);
              int up = red0 + ((((pix1 & 0xFF0000) - red0) * iui) >> 7);
              int dn = red2 + ((((pix3 & 0xFF0000) - red2) * iui) >> 7);
              int red = up + (((dn-up) * ivi) >> 7);
              if (tint) red = ((red * rtint) >> 8) & 0xFF0000;

              // grn
              red0 = (pix0 & 0xFF00);
              red2 = (pix2 & 0xFF00);
              up = red0 + ((((pix1 & 0xFF00) - red0) * iui) >> 7);
              dn = red2 + ((((pix3 & 0xFF00) - red2) * iui) >> 7);
              int grn = up + (((dn-up) * ivi) >> 7);
              if (tint) grn = ((grn * gtint) >> 8) & 0xFF00;

              // blu
              red0 = (pix0 & 0xFF);
              red2 = (pix2 & 0xFF);
              up = red0 + ((((pix1 & 0xFF) - red0) * iui) >> 7);
              dn = red2 + ((((pix3 & 0xFF) - red2) * iui) >> 7);
              int blu = up + (((dn-up) * ivi) >> 7);
              if (tint) blu = ((blu * btint) >> 8) & 0xFF;

              //m_pixels[xstart] = (red & 0xFF0000) | (grn & 0xFF00) | (blu & 0xFF);
              m_pixels[xstart] = 0xFF000000 | 
                (red & 0xFF0000) | (grn & 0xFF00) | (blu & 0xFF);

            } else {
              m_pixels[xstart] = m_texture[(iv >> 16) * TEX_WIDTH + (iu >> 16)];
            }
//            m_stencil[xstart] = p;
          }
        } catch (Exception e) {/*exCount++;*/}
        iz+=izadd;
        xpixel++;//accurate mode
        if (!accurateMode){
          iu+=iuadd;
          iv+=ivadd;
        }
      }
      ypixel++; //accurate mode
      ytop+=SCREEN_WIDTH;
      xleft+=leftadd;
      xrght+=rghtadd;
      zleft+=zleftadd;
      uleft+=uleftadd;
      vleft+=vleftadd;
    }
    //if (exCount>0) System.out.println(exCount+" exceptions in this segment");
  }