
static void 
#ifdef PL_PF_MULTITEX
PLMTexTri
#else
PLTexTri
#endif
(LICE_pixel *gmem, int swidth, pl_Face *TriFace, pl_ZBuffer *zbuf, int zfb_width, bool zb_update,
                     int solidalpha, int solidcomb, LICE_IBitmap *tex, pl_Float *texscales, int texalpha, int texcomb, int texmap
#ifdef PL_PF_MULTITEX
                     , LICE_IBitmap *tex2, int tex2alpha, int tex2comb, int texmap2
#endif
                     
                     ) 
{
  pl_sInt32 C1[3], C3[3], C2[3], dC2[3]={0}, dCL[3]={0},dC1[3]={0},  dX2=0, dX1=0;
  pl_Float dZ2=0, dZL=0,dZ1=0;

  PUTFACE_SORT(); 


  solidcomb&=LICE_BLIT_MODE_MASK;
  if (solidcomb == 0 && solidalpha == 256) solidcomb=-1;
  else if (solidalpha==0) solidcomb=-2; // ignore
  int solidalpha2=(256-solidalpha)*256;


  pl_Float dU2=0,dV2=0,dUL=0,dVL=0;
  pl_Float dU1=0, dV1=0;
  bool bilinear = (texcomb&LICE_BLIT_FILTER_MASK)==LICE_BLIT_FILTER_BILINEAR;
  texcomb&=LICE_BLIT_MODE_MASK|LICE_BLIT_USE_ALPHA;
  if (texcomb==LICE_BLIT_MODE_COPY && texalpha==256) texcomb=-1;
  else if (texalpha==0) texcomb=-2;
  int texalpha2=(256-texalpha);

  int tex_rowspan=0;
  LICE_pixel *texture=NULL;
  int tex_w=16,tex_h=16;  

#if defined(PLUSH_NO_SOLIDGOURAUD) || defined(PLUSH_NO_TEXTURE)
  if (tex)
#endif
  {
    texture=tex->getBits();
    tex_rowspan = tex->getRowSpan();
    if (tex->isFlipped())
    {
      texture += tex_rowspan*(tex->getHeight()-1);
      tex_rowspan=-tex_rowspan;
    }
    tex_w=tex->getWidth();
    tex_h=tex->getHeight();  
    tex_rowspan *= 4;
  }
  pl_sInt32 MappingU_Max=tex_w<<16,  MappingV_Max=tex_h<<16;
  texscales[0]*=MappingU_Max;
  texscales[1]*=MappingV_Max;
  tex_w *= 4;

#ifdef PL_PF_MULTITEX

  pl_Float dU2_2=0,dV2_2=0,dUL_2=0,dVL_2=0;
  pl_Float dU1_2=0, dV1_2=0;
  int tex_w_2=16,tex_h_2=16; 
  bool bilinear2 = (tex2comb&LICE_BLIT_FILTER_MASK)==LICE_BLIT_FILTER_BILINEAR;
  tex2comb&=LICE_BLIT_MODE_MASK|LICE_BLIT_USE_ALPHA;
  if (tex2comb==LICE_BLIT_MODE_COPY && tex2alpha==256) tex2comb=-1;
  else if (tex2alpha==0) tex2comb=-2;
  int tex2alpha2=(256-tex2alpha);
  LICE_pixel *texture_2=NULL;
  int tex_rowspan_2 = 0;
  pl_sInt32 MappingU_Max_2,  MappingV_Max_2;

#ifdef PLUSH_NO_TEXTURE
  if (tex2)
#endif
  {
    tex_w_2=tex2->getWidth();
    tex_h_2=tex2->getHeight();  
    texture_2=tex2->getBits();
    tex_rowspan_2 = tex2->getRowSpan();
    if (tex2->isFlipped())
    {
      texture_2 += tex_rowspan_2*(tex2->getHeight()-1);
      tex_rowspan_2=-tex_rowspan_2;
    }
    tex_rowspan_2 *= 4;
  }
  MappingU_Max_2=tex_w_2<<16;
  MappingV_Max_2=tex_h_2<<16;
  texscales[2]*=MappingU_Max_2;
  texscales[3]*=MappingV_Max_2;
  tex_w_2 *= 4;
#endif


  pl_uChar nm = TriFace->Material->PerspectiveCorrect;
  pl_uChar nmb = 0; while (nm) { nmb++; nm >>= 1; }
  nmb = plMin(6,nmb);
  nm = 1<<nmb;


  pl_Float Z1 = TriFace->Scrz[i0];
  pl_Float Z2 = TriFace->Scrz[i1];
  pl_Float Z3 = TriFace->Scrz[i2];

  pl_Float MappingU1=TriFace->MappingU[texmap][i0]*texscales[0]*Z1;
  pl_Float MappingV1=TriFace->MappingV[texmap][i0]*texscales[1]*Z1;
  pl_Float MappingU2=TriFace->MappingU[texmap][i1]*texscales[0]*Z2;
  pl_Float MappingV2=TriFace->MappingV[texmap][i1]*texscales[1]*Z2;
  pl_Float MappingU3=TriFace->MappingU[texmap][i2]*texscales[0]*Z3;
  pl_Float MappingV3=TriFace->MappingV[texmap][i2]*texscales[1]*Z3;

#ifdef PL_PF_MULTITEX
  pl_Float MappingU1_2=TriFace->MappingU[texmap2][i0]*texscales[2]*Z1;
  pl_Float MappingV1_2=TriFace->MappingV[texmap2][i0]*texscales[3]*Z1;
  pl_Float MappingU2_2=TriFace->MappingU[texmap2][i1]*texscales[2]*Z2;
  pl_Float MappingV2_2=TriFace->MappingV[texmap2][i1]*texscales[3]*Z2;
  pl_Float MappingU3_2=TriFace->MappingU[texmap2][i2]*texscales[2]*Z3;
  pl_Float MappingV3_2=TriFace->MappingV[texmap2][i2]*texscales[3]*Z3;
#endif

  int a;
  for(a=0;a<3;a++)
  {
    C1[a] = (pl_sInt32) (TriFace->Shades[i0][a]*(1<<24));
    C2[a] = (pl_sInt32) (TriFace->Shades[i1][a]*(1<<24));
    C3[a] = (pl_sInt32) (TriFace->Shades[i2][a]*(1<<24));
  }
  
  pl_Float U1, U2;
  U1 = U2 = MappingU1;
  pl_Float V1,V2;
  V1 = V2 = MappingV1;
#ifdef PL_PF_MULTITEX
  pl_Float U1_2, U2_2;
  U1_2 = U2_2 = MappingU1_2;
  pl_Float V1_2, V2_2;
  V1_2 = V2_2 = MappingV1_2;
#endif

  pl_sInt32 X2,X1;
  X2 = X1 = Scrx[i0];
  pl_sInt32 Y0 = Scry[i0];
  pl_sInt32 Y1 = Scry[i1];
  pl_sInt32 Y2 = Scry[i2];


  {
    pl_sInt32 dY = Y2-Y0;
    if (dY) {
      dX2 = (Scrx[i2] - X1) / dY;

      pl_Float v = 1.0/dY;
      for(a=0;a<3;a++) dC2[a] = (pl_sInt32) ((C3[a] - C1[a]) * v);
      dZ2 = (Z3 - Z1) * v;
      dU2 = (MappingU3 - U1) * v;
      dV2 = (MappingV3 - V1) * v;
  #ifdef PL_PF_MULTITEX
      dU2_2 = (MappingU3_2 - U1_2) * v;
      dV2_2 = (MappingV3_2 - V1_2) * v;
  #endif
    }
    dY = Y1-Y0;
    if (dY) {
      dX1 = (Scrx[i1] - X1) / dY;
      pl_Float v=1.0/dY;
      dZ1 = (Z2 - Z1) * v;
      for(a=0;a<3;a++) dC1[a] = (pl_sInt32) ((C2[a] - C1[a]) * v);
      dU1 = (MappingU2 - U1) * v;
      dV1 = (MappingV2 - V1) * v;
  #ifdef PL_PF_MULTITEX
      dU1_2 = (MappingU2_2 - U1_2) * v;
      dV1_2 = (MappingV2_2 - V1_2) * v;
  #endif
      if (dX2 < dX1) {
        SWAP(dX1,dX2,pl_sInt32);
        SWAP(dU1,dU2,pl_Float);
        SWAP(dV1,dV2,pl_Float);
  #ifdef PL_PF_MULTITEX
        SWAP(dU1_2,dU2_2,pl_Float);
        SWAP(dV1_2,dV2_2,pl_Float);
  #endif
        SWAP(dZ1,dZ2,pl_Float);
        for(a=0;a<3;a++)
          SWAP(dC1[a],dC2[a],pl_sInt32);
        stat = 2;
      } else stat = 1;
      Z2 = Z1;
      C2[0] = C1[0];
      C2[1] = C1[1];
      C2[2] = C1[2];

    } else {
      if (Scrx[i1] > X1) {
        X2 = Scrx[i1];
        U2 = MappingU2;
        V2 = MappingV2;
  #ifdef PL_PF_MULTITEX
        U2_2 = MappingU2_2;
        V2_2 = MappingV2_2;
  #endif
        stat = 2|4;
      } else {
        X1 = Scrx[i1];
        SWAP(Z1,Z2,pl_Float)
        for(a=0;a<3;a++) SWAP(C1[a],C2[a],pl_sInt32);
        U1 = MappingU2;
        V1 = MappingV2;
  #ifdef PL_PF_MULTITEX
        U1_2 = MappingU2_2;
        V1_2 = MappingV2_2;
  #endif
        stat = 1|8;
      }
    }
    pl_sInt32 tmp = (dX1-dX2)*dY;
    if (tmp) {
      pl_Float v=(1<<XPOS_BITS)/(double)tmp;
      dUL = ((dU1-dU2)*dY)*v;
      dVL = ((dV1-dV2)*dY)*v;
  #ifdef PL_PF_MULTITEX
      dUL_2 = ((dU1_2-dU2_2)*dY)*v;
      dVL_2 = ((dV1_2-dV2_2)*dY)*v;
  #endif
      dZL = ((dZ1-dZ2)*dY)*v;
      for(a=0;a<3;a++) dCL[a] = (pl_sInt32) ( ((dC1[a]-dC2[a])*dY)*v);
    } else {
      tmp = X2-X1;
      if (tmp) {
        pl_Float v=(1<<XPOS_BITS)/(double)tmp;
        dUL = (U2-U1)*v;
        dVL = (V2-V1)*v;
  #ifdef PL_PF_MULTITEX
        dUL_2 = (U2_2-U1_2)*v;
        dVL_2 = (V2_2-V1_2)*v;
  #endif
        dZL = (Z2-Z1)*v;
        for(a=0;a<3;a++) dCL[a] = (pl_sInt32) ((C2[a]-C1[a])*v);
      }
    }
  }

  gmem += (Y0 * swidth);
  zbuf += (Y0 * zfb_width);


  pl_Float pdZL = dZL * nm;
  dUL *= nm;
  dVL *= nm;
#ifdef PL_PF_MULTITEX
  dUL_2 *= nm;
  dVL_2 *= nm;
#endif
  Y1 -= Y0;
  Y0 = Y2-Y0;
  while (Y0--) {
    if (!Y1--) {
      pl_sInt32 dY = Y2-Scry[i1];
      if (dY) {
        DO_STAT_XDELTAS

        pl_Float tmp=1.0/dY;
        dZ1 = (Z3-Z1)*tmp;
        for(a=0;a<3;a++) dC1[a] = (pl_sInt32)((C3[a]-C1[a])*tmp);
        dV1 = (MappingV3 - V1)*tmp;
        dU1 = (MappingU3 - U1)*tmp;
#ifdef PL_PF_MULTITEX
        dV1_2 = (MappingV3_2 - V1_2)*tmp;
        dU1_2 = (MappingU3_2 - U1_2)*tmp;
#endif
      }
    }
    pl_sInt32 XL1 = (X1+(1<<(XPOS_BITS-1)))>>XPOS_BITS;
    pl_sInt32 Xlen = ((X2+(1<<(XPOS_BITS-1)))>>XPOS_BITS) - XL1;
    if (Xlen > 0) { 
      pl_sInt32 iUL, iVL, idUL, idVL, iULnext, iVLnext;
      pl_Float UL = U1;
      pl_Float VL = V1;
#ifdef PL_PF_MULTITEX
      pl_sInt32 iUL_2, iVL_2, idUL_2, idVL_2, iULnext_2, iVLnext_2;
      pl_Float UL_2 = U1_2;
      pl_Float VL_2 = V1_2;
#endif
      pl_sInt32 CL[3] = {C1[0],C1[1], C1[2]};
      pl_Float pZL,ZL;
      pl_Float t = 1.0f / (pZL = ZL = Z1);     
      gmem += XL1;
      zbuf += XL1;

      XL1 += Xlen; // update to new line end pos so we can adjust gmem/zbuf later
      iULnext = ((pl_sInt32) (UL*t));
      iVLnext = ((pl_sInt32) (VL*t));
#ifdef PL_PF_MULTITEX
      iULnext_2 = ((pl_sInt32) (UL_2*t));
      iVLnext_2 = ((pl_sInt32) (VL_2*t));
#endif
      do {
        UL += dUL;
        VL += dVL;
        iUL = iULnext;
        iVL = iVLnext;
        pZL += pdZL;
        t = 1.0f/pZL;
        iULnext = ((pl_sInt32) (UL*t));
        iVLnext = ((pl_sInt32) (VL*t));
        idUL = (iULnext - iUL)>>nmb;
        idVL = (iVLnext - iVL)>>nmb;
        if (idUL>MappingU_Max) idUL=MappingU_Max;
        else if (idUL<-MappingU_Max) idUL=-MappingU_Max;
        if (idVL>MappingV_Max) idVL=MappingV_Max;
        else if (idVL<-MappingV_Max) idVL=-MappingV_Max;

        // todo: this is slow as shit, should we force textures to be powers of two? hehe
        if (iUL<0)  do iUL+=MappingU_Max; while (iUL<0);
        else while (iUL >= MappingU_Max) iUL-=MappingU_Max;
        if (iVL<0)  do iVL+=MappingV_Max; while (iVL<0);
        else while (iVL >= MappingV_Max) iVL-=MappingV_Max;

#ifdef PL_PF_MULTITEX
        UL_2 += dUL_2;
        VL_2 += dVL_2;
        iUL_2 = iULnext_2;
        iVL_2 = iVLnext_2;
        iULnext_2 = ((pl_sInt32) (UL_2*t));
        iVLnext_2 = ((pl_sInt32) (VL_2*t));
        idUL_2 = (iULnext_2 - iUL_2)>>nmb;
        idVL_2 = (iVLnext_2 - iVL_2)>>nmb;
        if (idUL_2>MappingU_Max_2) idUL_2=MappingU_Max_2;
        else if (idUL_2<-MappingU_Max_2) idUL_2=-MappingU_Max_2;
        if (idVL_2>MappingV_Max_2) idVL_2=MappingV_Max_2;
        else if (idVL_2<-MappingV_Max_2) idVL_2=-MappingV_Max_2;

        // todo: this is slow as shit, should we force textures to be powers of two? hehe
        if (iUL_2<0)  do iUL_2+=MappingU_Max_2; while (iUL_2<0);
        else while (iUL_2 >= MappingU_Max_2) iUL_2-=MappingU_Max_2;
        if (iVL_2<0)  do iVL_2+=MappingV_Max_2; while (iVL_2<0);
        else while (iVL_2 >= MappingV_Max_2) iVL_2-=MappingV_Max_2;

#endif

        pl_uInt n = nm;
        Xlen -= n;  
        if (Xlen < 0) n += Xlen;
        if (zfb_width) do {
            if (*zbuf < ZL) {
              if (zb_update) *zbuf = (pl_ZBuffer) ZL;

 #ifdef PL_PF_MULTITEX
             TextureMakePixel2((LICE_pixel_chan *)gmem,solidcomb,solidalpha,solidalpha2,CL, bilinear, 
               iUL,iVL,tex_w,tex_h,texture,tex_rowspan,texcomb,texalpha,texalpha2,
                bilinear2, iUL_2,iVL_2,
                tex_w_2,tex_h_2,
                texture_2,tex_rowspan_2,tex2comb,tex2alpha,tex2alpha2);
 #else
            TextureMakePixel((LICE_pixel_chan *)gmem,solidcomb,solidalpha,solidalpha2,CL, bilinear, iUL,iVL,
              tex_w,tex_h,
              texture,tex_rowspan,texcomb,texalpha,texalpha2);
 #endif
 
            }
            zbuf++;
            gmem++;
            ZL += dZL;
            CL[0] += dCL[0];
            CL[1] += dCL[1];
            CL[2] += dCL[2];
            iUL += idUL;
            iVL += idVL;

            if (iUL<0) iUL+=MappingU_Max;
            else if (iUL >= MappingU_Max) iUL -= MappingU_Max;
            if (iVL<0) iVL+=MappingV_Max;
            else if (iVL >= MappingV_Max) iVL -= MappingV_Max;
#ifdef PL_PF_MULTITEX
            iUL_2 += idUL_2;
            iVL_2 += idVL_2;

            if (iUL_2<0) iUL_2+=MappingU_Max_2;
            else if (iUL_2 >= MappingU_Max_2) iUL_2 -= MappingU_Max_2;
            if (iVL_2<0) iVL_2+=MappingV_Max_2;
            else if (iVL_2 >= MappingV_Max_2) iVL_2 -= MappingV_Max_2;
#endif
          } while (--n);
        else do {

 #ifdef PL_PF_MULTITEX
             TextureMakePixel2((LICE_pixel_chan *)gmem,solidcomb,solidalpha,solidalpha2,CL, bilinear, 
               iUL,iVL,tex_w,tex_h,texture,tex_rowspan,texcomb,texalpha,texalpha2,
                bilinear2, iUL_2,iVL_2,
                tex_w_2,tex_h_2,
                texture_2,tex_rowspan_2,tex2comb,tex2alpha,tex2alpha2);
 #else
            TextureMakePixel((LICE_pixel_chan *)gmem,solidcomb,solidalpha,solidalpha2,CL, bilinear, iUL,iVL,
              tex_w,tex_h,
              texture,tex_rowspan,texcomb,texalpha,texalpha2);
 #endif


            gmem++;
            CL[0] += dCL[0];
            CL[1] += dCL[1];
            CL[2] += dCL[2];
            iUL += idUL;
            iVL += idVL;

            if (iUL<0) iUL+=MappingU_Max;
            else if (iUL >= MappingU_Max) iUL -= MappingU_Max;
            if (iVL<0) iVL+=MappingV_Max;
            else if (iVL >= MappingV_Max) iVL -= MappingV_Max;

#ifdef PL_PF_MULTITEX
            iUL_2 += idUL_2;
            iVL_2 += idVL_2;

            if (iUL_2<0) iUL_2+=MappingU_Max_2;
            else if (iUL_2 >= MappingU_Max_2) iUL_2 -= MappingU_Max_2;
            if (iVL_2<0) iVL_2+=MappingV_Max_2;
            else if (iVL_2 >= MappingV_Max_2) iVL_2 -= MappingV_Max_2;
#endif

          } while (--n);
      } while (Xlen > 0);
      gmem += swidth-XL1;
      zbuf += zfb_width-XL1;
    } else { // xlen <=0 ,no drawing
      gmem += swidth;
      zbuf += zfb_width;
    }
    Z1 += dZ1;
    U1 += dU1;
    V1 += dV1;
#ifdef PL_PF_MULTITEX
    U1_2 += dU1_2;
    V1_2 += dV1_2;
#endif
    X1 += dX1;
    X2 += dX2;
    C1[0] += dC1[0];
    C1[1] += dC1[1];
    C1[2] += dC1[2];
  }
}



