#include "plush.h" #include "../lice/lice_combine.h" //#define PLUSH_NO_SOLIDFLAT // make non-texturemapped flat shading optimized engine //#define PLUSH_NO_SOLIDGOURAUD // disable non-texturemapped gouraud optimized engine //#define PLUSH_NO_TEXTURE // disable single-texture optimized engine //#define PLUSH_NO_MULTITEXTURE // disable multitexture (this can do any of em) #define XPOS_BITS 19 // allows 2^13 max screen width, or 8192px #define SWAP(a,b,t) { t ____tmp=(a); (a)=(b); (b)=____tmp; } #define PUTFACE_SORT() \ int i0 = 0; int i1 = 1; int i2 = 2; int stat; \ if (TriFace->Scry[0] > TriFace->Scry[1]) { i0 = 1; i1 = 0; } \ if (TriFace->Scry[i0] > TriFace->Scry[2]) { SWAP(i0,i2,int); } \ if (TriFace->Scry[i1] > TriFace->Scry[i2]) { SWAP(i1,i2,int); } \ int Scrx[3] = {(int)(TriFace->Scrx[0]*(1<Scrx[1]*(1<Scrx[2]*(1<Scry[0]+0.5), (int) (TriFace->Scry[1]+0.5), (int) (TriFace->Scry[2]+0.5)}; \ #define DO_STAT_XDELTAS \ if (stat & 1) { \ dX1 = (Scrx[i2]-(X1 = Scrx[i1]))/dY; \ if (stat & 8) dX2 = (Scrx[i2]-(X2 = Scrx[i0]))/dY; \ } \ else if (stat & 2) { \ dX2 = (Scrx[i2]-(X2 = Scrx[i1]))/dY; \ if (stat & 4) dX1 = (Scrx[i2]-(X1 = Scrx[i0]))/dY; \ } static inline void OverlayBlend(int &red, int &green, int &blue, int &alpha, int r, int g, int b, int a, int usea) { int da=(256-usea)*128; int srcr = r*usea+da, srcg = g*usea+da, srcb = b*usea+da, srca = usea*a + da; red = ( red*( (red*(32768-srcr))/256 + srcr ) )/32768; green = ( green*( (green*(32768-srcg))/256 + srcg ) )/32768; blue = ( blue*( (blue*(32768-srcb))/256 + srcb ) )/32768; alpha = ( alpha*( (alpha*(32768-srca))/256 + srca ) )/32768; } static inline void MulBlend(int &red, int &green, int &blue, int &alpha, int r, int g, int b, int a, int ta) { int ta2=(256-ta)*256; red = (r*ta*red + red*ta2)/65536; green = (g*ta*green + green*ta2)/65536; blue = (b*ta*blue + blue*ta2)/65536; alpha = (a*ta*alpha + alpha*ta2)/65536; } static inline void AdjustHSV(int &red, int &green, int &blue, int r, int g, int b, int texalpha) { int h,s,v; __LICE_RGB2HSV(red,green,blue,&h,&s,&v); h+=(((r+r/2) - 192) * texalpha)/256; if (h<0)h+=384; else if (h>=384) h-=384; s+=((g-128)*texalpha)/256; if (s&~0xff) { if (s<0)s=0; else s=255; } v+=((b-128)*texalpha)/256; if (v&~0xff) { if (v<0)v=0; else v=255; } __LICE_HSV2RGB(h,s,v,&red,&green,&blue); } static inline void DodgeBlend(int &red, int &green, int &blue, int &alpha, int r, int g, int b, int a, int ta) { int src_r = 256-r*ta/256; int src_g = 256-g*ta/256; int src_b = 256-b*ta/256; int src_a = 256-(a*ta)/256; red = src_r > 1 ? 256*red / src_r : 256*red; green = src_g > 1 ? 256*green / src_g : 256*green; blue = src_b > 1 ? 256*blue / src_b : 256*blue; alpha = src_a > 1 ? 256*alpha / src_a : 256*alpha; } static void inline DoTextureCombine(int texcomb, int r, int g, int b, int a, int &red, int &green, int &blue, int &alpha, int texalpha, int texalpha2) { switch (texcomb) { case LICE_BLIT_MODE_COPY: red = (r*texalpha + red*texalpha2) >> 8; green = (g*texalpha + green*texalpha2) >> 8; blue = (b*texalpha + blue*texalpha2) >> 8; alpha = (a*texalpha + alpha*texalpha2) >> 8; break; case LICE_BLIT_MODE_ADD: red += (r*texalpha) >> 8; green += (g*texalpha) >> 8; blue += (b*texalpha) >> 8; alpha += (a*texalpha) >> 8; break; case LICE_BLIT_MODE_MUL: MulBlend(red,green,blue,alpha,r,g,b,a,texalpha); break; case LICE_BLIT_MODE_DODGE: DodgeBlend(red,green,blue,alpha,r,g,b,a,texalpha); break; case LICE_BLIT_MODE_OVERLAY: OverlayBlend(red,green,blue,alpha,r,g,b,a, texalpha); break; case LICE_BLIT_MODE_HSVADJ: AdjustHSV(red,green,blue,r,g,b,texalpha); break; case LICE_BLIT_MODE_COPY|LICE_BLIT_USE_ALPHA: { int ta=(texalpha*(a+1)); int ta2=(65536-ta); red = (r*ta + red*ta2) >> 16; green = (g*ta + green*ta2) >> 16; blue = (b*ta + blue*ta2) >> 16; alpha = (a*ta + alpha*ta2) >> 16; } break; case LICE_BLIT_MODE_ADD|LICE_BLIT_USE_ALPHA: { int ta=(texalpha*(a+1)); red += (r*ta) >> 16; green += (g*ta) >> 16; blue += (b*ta) >> 16; alpha += (a*ta) >> 16; } break; case LICE_BLIT_MODE_DODGE|LICE_BLIT_USE_ALPHA: { int ta=(texalpha*(a+1))/256; DodgeBlend(red,green,blue,alpha,r,g,b,a,ta); } break; case LICE_BLIT_MODE_MUL|LICE_BLIT_USE_ALPHA: MulBlend(red,green,blue,alpha,r,g,b,a,(texalpha*(a+1))/256); break; case LICE_BLIT_MODE_OVERLAY|LICE_BLIT_USE_ALPHA: OverlayBlend(red,green,blue,alpha,r,g,b,a, (texalpha*(a+1))/256); break; case LICE_BLIT_MODE_HSVADJ|LICE_BLIT_USE_ALPHA: AdjustHSV(red,green,blue,r,g,b,(texalpha*(a+1))/256); break; case -2: break; default: red=r; green=g; blue=b; alpha=a; break; } } static void inline TextureMakePixelSolidCombine(int &red, int &green, int &blue, int &alpha, pl_sInt32 *CL, int solidcomb, int solidalpha, int solidalpha2, LICE_pixel_chan *gmemptr) { switch (solidcomb) { case LICE_BLIT_MODE_COPY: red = ((CL[0]>>8)*solidalpha + gmemptr[LICE_PIXEL_R]*solidalpha2)>>16; green = ((CL[1]>>8)*solidalpha + gmemptr[LICE_PIXEL_G]*solidalpha2)>>16; blue = ((CL[2]>>8)*solidalpha + gmemptr[LICE_PIXEL_B]*solidalpha2)>>16; alpha = solidalpha; break; case LICE_BLIT_MODE_ADD: red = gmemptr[LICE_PIXEL_R] + (((CL[0]>>8)*solidalpha)>>16); green = gmemptr[LICE_PIXEL_G] + (((CL[1]>>8)*solidalpha)>>16); blue = gmemptr[LICE_PIXEL_B] + (((CL[2]>>8)*solidalpha)>>16); alpha = gmemptr[LICE_PIXEL_A] + solidalpha; break; case LICE_BLIT_MODE_DODGE: red=gmemptr[LICE_PIXEL_R]; green=gmemptr[LICE_PIXEL_G]; blue=gmemptr[LICE_PIXEL_B]; alpha=gmemptr[LICE_PIXEL_A]; DodgeBlend(red,green,blue,alpha,CL[0]>>16,CL[1]>>16,CL[2]>>16,solidalpha,solidalpha); break; case LICE_BLIT_MODE_MUL: red=gmemptr[LICE_PIXEL_R]; green=gmemptr[LICE_PIXEL_G]; blue=gmemptr[LICE_PIXEL_B]; alpha=gmemptr[LICE_PIXEL_A]; MulBlend(red,green,blue,alpha,CL[0]>>16,CL[1]>>16,CL[2]>>16,solidalpha,solidalpha); break; case LICE_BLIT_MODE_OVERLAY: red=gmemptr[LICE_PIXEL_R]; green=gmemptr[LICE_PIXEL_G]; blue=gmemptr[LICE_PIXEL_B]; alpha=gmemptr[LICE_PIXEL_A]; OverlayBlend(red,green,blue,alpha,CL[0]>>16,CL[1]>>16,CL[2]>>16,solidalpha, solidalpha); break; case LICE_BLIT_MODE_HSVADJ: red=gmemptr[LICE_PIXEL_R]; green=gmemptr[LICE_PIXEL_G]; blue=gmemptr[LICE_PIXEL_B]; alpha=gmemptr[LICE_PIXEL_A]; AdjustHSV(red,green,blue,CL[0]>>16,CL[1]>>16,CL[2]>>16,solidalpha); break; case -2: red=gmemptr[LICE_PIXEL_R]; green=gmemptr[LICE_PIXEL_G]; blue=gmemptr[LICE_PIXEL_B]; alpha=gmemptr[LICE_PIXEL_A]; break; default: red=CL[0]>>16; green=CL[1]>>16; blue=CL[2]>>16; alpha=solidalpha; break; } } static void inline TextureMakePixel2(LICE_pixel_chan *gmemptr, int solidcomb, int solidalpha, int solidalpha2, pl_sInt32 *CL, bool bilinear, pl_sInt32 iUL, pl_sInt32 iVL, pl_sInt32 texwidth, pl_sInt32 texheight, LICE_pixel *texture, int tex_rowspan, int texcomb, int texalpha, int texalpha2, bool bilinear2, pl_sInt32 iUL_2, pl_sInt32 iVL_2, pl_sInt32 texwidth_2, pl_sInt32 texheight_2, LICE_pixel *texture2, int tex_rowspan_2, int tex2comb, int tex2alpha, int tex2alpha2) { int red,green,blue,alpha; TextureMakePixelSolidCombine(red,green,blue,alpha,CL,solidcomb,solidalpha,solidalpha2,gmemptr); int r,g,b,a; #if defined(PLUSH_NO_TEXTURE) if (texture) #endif { const int xpos=(iUL>>14)&~3; const int ypos=iVL>>16; const LICE_pixel_chan *rd = ((LICE_pixel_chan*)texture) + xpos+ypos*tex_rowspan; if (bilinear) { __LICE_BilinearFilterI_2(&r,&g,&b,&a,rd, ypos < texheight - 1 ? rd+tex_rowspan : ((LICE_pixel_chan *)texture)+xpos, xpos < texwidth - 4 ? 4 : 4-texwidth, iUL&65535,iVL&65535); } else { r=rd[LICE_PIXEL_R]; g=rd[LICE_PIXEL_G]; b=rd[LICE_PIXEL_B]; a=rd[LICE_PIXEL_A]; } DoTextureCombine(texcomb, r,g,b,a, red,green,blue,alpha,texalpha,texalpha2); } #ifdef PLUSH_NO_TEXTURE if (texture2) #endif { const int xpos=(iUL_2>>14)&~3; const int ypos=iVL_2>>16; const LICE_pixel_chan *rd = ((LICE_pixel_chan*)texture2) + xpos+ypos*tex_rowspan_2; if (bilinear2) { __LICE_BilinearFilterI_2(&r,&g,&b,&a,rd, ypos < texheight_2 - 1 ? rd+tex_rowspan_2 : ((LICE_pixel_chan *)texture2)+xpos, xpos < texwidth_2 - 4 ? 4 : 4-texwidth_2, iUL_2&65535,iVL_2&65535); } else { r=rd[LICE_PIXEL_R]; g=rd[LICE_PIXEL_G]; b=rd[LICE_PIXEL_B]; a=rd[LICE_PIXEL_A]; } DoTextureCombine(tex2comb, r,g,b,a, red,green,blue,alpha,tex2alpha,tex2alpha2); } _LICE_MakePixelClamp(gmemptr, red,green,blue,alpha); } static void inline TextureMakePixel(LICE_pixel_chan *gmemptr, int solidcomb, int solidalpha, int solidalpha2, pl_sInt32 *CL, bool bilinear, pl_sInt32 iUL, pl_sInt32 iVL, pl_sInt32 texwidth, pl_sInt32 texheight, LICE_pixel *texture, int tex_rowspan, int texcomb, int texalpha, int texalpha2) { int red,green,blue,alpha; if ( #ifdef PLUSH_NO_SOLIDGOURAUD !texture|| #endif texcomb!=-1) TextureMakePixelSolidCombine(red,green,blue,alpha,CL,solidcomb,solidalpha,solidalpha2,gmemptr); #ifdef PLUSH_NO_SOLIDGOURAUD if (texture) #endif { int r,g,b,a; const int xpos=(iUL>>14)&~3; const int ypos=iVL>>16; const LICE_pixel_chan *rd = ((LICE_pixel_chan*)texture) + xpos+ypos*tex_rowspan; if (bilinear) { __LICE_BilinearFilterI_2(&r,&g,&b,&a,rd, ypos < texheight - 1 ? rd+tex_rowspan : ((LICE_pixel_chan *)texture)+xpos, xpos < texwidth - 4 ? 4 : 4-texwidth, iUL&65535,iVL&65535); } else { r=rd[LICE_PIXEL_R]; g=rd[LICE_PIXEL_G]; b=rd[LICE_PIXEL_B]; a=rd[LICE_PIXEL_A]; } DoTextureCombine(texcomb, r,g,b,a, red,green,blue,alpha,texalpha,texalpha2); } _LICE_MakePixelClamp(gmemptr, red,green,blue,alpha); } #ifndef PLUSH_NO_TEXTURE #include "pl_pf_tex.h" #endif #ifndef PLUSH_NO_MULTITEXTURE #define PL_PF_MULTITEX #include "pl_pf_tex.h" #endif template class PLSolidPutFace { public: #ifndef PLUSH_NO_SOLIDGOURAUD static void SolidGouraud(LICE_pixel *gmem, int swidth, pl_Face *TriFace, int alpha, pl_ZBuffer *zbuf, int zfb_width, bool zb_update) { pl_Float dZL=0, dZ1=0, dZ2=0; pl_sInt32 dX1=0, dX2=0, C1[3], C2[3], dC1[3]={0}, dC2[3]={0}, dCL[3]={0}, C3[3]; PUTFACE_SORT(); 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_sInt32 X2,X1; X2 = X1 = Scrx[i0]; pl_Float Z1 = TriFace->Scrz[i0]; pl_Float Z2 = TriFace->Scrz[i1]; pl_Float Z3 = TriFace->Scrz[i2]; 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; for(a=0;a<3;a++) dC2[a] = (C3[a] - C1[a]) / dY; dZ2 = (Z3 - Z1) / dY; } dY = Y1 - Y0; if (dY) { dX1 = (Scrx[i1] - X1) / dY; for(a=0;a<3;a++) dC1[a] = (C2[a] - C1[a]) / dY; dZ1 = (Z2 - Z1) / dY; if (dX2 < dX1) { SWAP(dX2,dX1,pl_sInt32); for(a=0;a<3;a++) SWAP(dC1[a],dC2[a],pl_sInt32); SWAP(dZ1,dZ2,pl_Float); 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]; stat = 2|4; } else { for(a=0;a<3;a++) SWAP(C1[a],C2[a],pl_sInt32); SWAP(Z1,Z2,pl_Float); X1 = Scrx[i1]; stat = 1|8; } } pl_sInt32 tmp = (dX1-dX2)*dY; if (tmp) { double v=(1<>XPOS_BITS; pl_sInt32 XL2 = ((X2+(1<<(XPOS_BITS-1)))>>XPOS_BITS) - XL1; if (XL2 > 0) { gmem += XL1; XL1 += XL2; pl_sInt32 CL[3] = {C1[0],C1[1],C1[2]}; if (zbuf) { pl_Float ZL = Z1; zbuf += XL1-XL2; do { if (*zbuf < ZL) { if (zb_update) *zbuf = (pl_ZBuffer) ZL; Comb::doPix((LICE_pixel_chan *)gmem,CL[0]>>16,CL[1]>>16,CL[2]>>16,255,alpha); } gmem++; zbuf++; ZL += dZL; CL[0] += dCL[0]; CL[1] += dCL[1]; CL[2] += dCL[2]; } while (--XL2); zbuf -= XL1; } else do { Comb::doPix((LICE_pixel_chan *)gmem,CL[0]>>16,CL[1]>>16,CL[2]>>16,255,alpha); gmem++; CL[0] += dCL[0]; CL[1] += dCL[1]; CL[2] += dCL[2]; } while (--XL2); gmem -= XL1; } gmem += swidth; zbuf += zfb_width; X1 += dX1; X2 += dX2; C1[0] += dC1[0]; C1[1] += dC1[1]; C1[2] += dC1[2]; Z1 += dZ1; Y0++; } } #endif #ifndef PLUSH_NO_SOLIDFLAT static void Solid(LICE_pixel *gmem, int swidth, pl_Face *TriFace, int alpha, pl_ZBuffer *zbuf, int zfb_width, bool zb_update) { pl_sInt32 dX1=0, dX2=0; pl_Float dZL=0, dZ1=0, dZ2=0; PUTFACE_SORT(); int col0 = (int) (TriFace->Shades[0][0]*255.0); int col1 = (int) (TriFace->Shades[0][1]*255.0); int col2 = (int) (TriFace->Shades[0][2]*255.0); pl_sInt32 X1,X2; X2 = X1 = Scrx[i0]; pl_sInt32 Y0 = Scry[i0]; pl_sInt32 Y1 = Scry[i1]; pl_sInt32 Y2 = Scry[i2]; pl_Float Z1 = TriFace->Scrz[i0]; pl_Float Z2 = TriFace->Scrz[i1]; pl_Float Z3 = TriFace->Scrz[i2]; { pl_sInt32 dY = Y2-Y0; if (dY) { dX2 = (Scrx[i2] - X1) / dY; dZ2 = (Z3 - Z1) / dY; } dY = Y1-Y0; if (dY) { dX1 = (Scrx[i1] - X1) / dY; dZ1 = (Z2 - Z1) / dY; if (dX2 < dX1) { SWAP(dX1,dX2,pl_sInt32); SWAP(dZ1,dZ2,pl_Float); stat = 2; } else stat = 1; Z2 = Z1; } else { if (Scrx[i1] > X1) { X2 = Scrx[i1]; stat = 2|4; } else { X1 = Scrx[i1]; SWAP(Z1,Z2,pl_Float); stat = 1|8; } } if (zbuf) { pl_sInt32 tmp=(dX1-dX2)*dY; if (tmp) dZL = ((dZ1-dZ2)*dY)*(double)(1<>XPOS_BITS; pl_sInt32 XL2 = ((X2+(1<<(XPOS_BITS-1)))>>XPOS_BITS) - XL1; if (XL2 > 0) { gmem += XL1; XL1 += XL2; if (zbuf) { pl_Float ZL = Z1; zbuf += XL1-XL2; do { if (*zbuf < ZL) { if (zb_update) *zbuf = (pl_ZBuffer) ZL; Comb::doPix((LICE_pixel_chan *)gmem,col0,col1,col2,255,alpha); } gmem++; zbuf++; ZL += dZL; } while (--XL2); zbuf -= XL1; } else { do { Comb::doPix((LICE_pixel_chan *)gmem,col0,col1,col2,255,alpha); gmem++; } while (--XL2); } gmem -= XL1; } gmem += swidth; zbuf += zfb_width; Z1 += dZ1; X1 += dX1; X2 += dX2; Y0++; } } #endif }; void pl_Cam::PutFace(pl_Face *TriFace) { LICE_pixel *gmem = m_fBuffer.m_buf; if (WDL_NOT_NORMALLY(!gmem)) return; int zfb_width = 0; int zBufferable = TriFace->Material->zBufferable; pl_ZBuffer *zb = NULL; if (zBufferable && zBuffer.GetSize() && WDL_NORMALLY(zBuffer.GetSize() >= m_fBuffer.m_w*m_fBuffer.m_h) ) { zfb_width = m_fBuffer.m_w; zb = zBuffer.Get(); } int swidth = m_fBuffer.m_span; if (m_fBuffer.m_flipped) { gmem += swidth*(m_fBuffer.m_h-1); swidth=-swidth; } pl_Mat *mat=TriFace->Material; #ifndef PLUSH_NO_MULTITEXTURE #ifndef PLUSH_NO_TEXTURE if (mat->Texture&&mat->Texture2) #else #ifndef PLUSH_NO_SOLIDGOURAUD if (mat->Texture||mat->Texture2) #endif #endif { pl_Float texsc[4]; memcpy(texsc,mat->TexScaling,sizeof(mat->TexScaling)); memcpy(texsc+2,mat->Tex2Scaling,sizeof(mat->Tex2Scaling)); int tidx = mat->TexMapIdx; if (tidx<0 || tidx>=PLUSH_MAX_MAPCOORDS)tidx=PLUSH_MAX_MAPCOORDS-1; int tidx2 = mat->Tex2MapIdx; if (tidx2<0 || tidx2>=PLUSH_MAX_MAPCOORDS)tidx2=PLUSH_MAX_MAPCOORDS-1; PLMTexTri(gmem,swidth,TriFace,zb,zfb_width,zBufferable!=2,(int) (mat->SolidOpacity*256.0),mat->SolidCombineMode, mat->Texture,texsc,(int) (mat->TexOpacity*256.0),mat->TexCombineMode,tidx, mat->Texture2,(int) (mat->Tex2Opacity*256.0),mat->Tex2CombineMode,tidx2 ); return; } #endif #ifndef PLUSH_NO_TEXTURE #ifndef PLUSH_NO_SOLIDGOURAUD if (mat->Texture||mat->Texture2) #endif { LICE_IBitmap *tex=mat->Texture ? mat->Texture : mat->Texture2; int talpha = (int) (mat->Texture ? mat->TexOpacity*256.0 : mat->Tex2Opacity*256.0); int tcomb = (int) (mat->Texture ? mat->TexCombineMode : mat->Tex2CombineMode); int tidx = (mat->Texture ? mat->TexMapIdx: mat->Tex2MapIdx); if (tidx<0 || tidx>=PLUSH_MAX_MAPCOORDS)tidx=PLUSH_MAX_MAPCOORDS-1; pl_Float texsc[2]; memcpy(texsc,mat->Texture ? mat->TexScaling : mat->Tex2Scaling,sizeof(texsc)); PLTexTri(gmem,swidth,TriFace,zb,zfb_width,zBufferable!=2,(int) (mat->SolidOpacity*256.0),mat->SolidCombineMode,tex,texsc,talpha,tcomb,tidx); return; } #endif int alpha=(int) (mat->SolidOpacity*256.0); if (!alpha) return; #ifndef PLUSH_NO_SOLIDGOURAUD #ifndef PLUSH_NO_SOLIDFLAT if (mat->Smoothing) #endif { #define __LICE__ACTION(comb) PLSolidPutFace::SolidGouraud(gmem,swidth,TriFace,alpha,zb,zfb_width, zBufferable!=2); __LICE_ACTION_CONSTANTALPHA(mat->SolidCombineMode,alpha,true); #undef __LICE__ACTION return; } #endif #ifndef PLUSH_NO_SOLIDFLAT #define __LICE__ACTION(comb) PLSolidPutFace::Solid(gmem,swidth,TriFace,alpha,zb,zfb_width, zBufferable!=2); __LICE_ACTION_CONSTANTALPHA(mat->SolidCombineMode,alpha,true); #undef __LICE__ACTION #endif // PLUSH_NO_SOLIDFLAT }