/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "Engine/StdH.h" #include #include #include #include #include #include #if USE_MMX_INTRINSICS #include #endif // asm shortcuts #define O offset #define Q qword ptr #define D dword ptr #define W word ptr #define B byte ptr extern INDEX tex_bProgressiveFilter; // filter mipmaps in creation time (not afterwards) // returns number of mip-maps to skip from original texture INDEX ClampTextureSize( PIX pixClampSize, PIX pixClampDimension, PIX pixSizeU, PIX pixSizeV) { __int64 pixMaxSize = (__int64)pixSizeU * (__int64)pixSizeV; PIX pixMaxDimension = Max( pixSizeU, pixSizeV); INDEX ctSkipMips = 0; while( (pixMaxSize>pixClampSize || pixMaxDimension>pixClampDimension) && pixMaxDimension>1) { ctSkipMips++; pixMaxDimension >>=1; pixMaxSize >>=2; } return ctSkipMips; } // retrives memory offset of a specified mip-map or a size of all mip-maps (IN PIXELS!) // (zero offset means first, i.e. largest mip-map) PIX GetMipmapOffset( INDEX iMipLevel, PIX pixWidth, PIX pixHeight) { PIX pixTexSize = 0; PIX pixMipSize = pixWidth*pixHeight; INDEX iMips = GetNoOfMipmaps( pixWidth, pixHeight); iMips = Min( iMips, iMipLevel); while( iMips>0) { pixTexSize +=pixMipSize; pixMipSize>>=2; iMips--; } return pixTexSize; } // return offset, pointer and dimensions of mipmap of specified size inside texture or shadowmap mipmaps INDEX GetMipmapOfSize( PIX pixWantedSize, ULONG *&pulFrame, PIX &pixWidth, PIX &pixHeight) { INDEX iMipOffset = 0; while( pixWidth>1 && pixHeight>1) { const PIX pixCurrentSize = pixWidth*pixHeight; if( pixCurrentSize <= pixWantedSize) break; // found pulFrame += pixCurrentSize; pixWidth >>=1; pixHeight>>=1; iMipOffset++; } // done return iMipOffset; } // adds 8-bit opaque alpha channel to 24-bit bitmap (in place supported) void AddAlphaChannel( UBYTE *pubSrcBitmap, ULONG *pulDstBitmap, PIX pixSize, UBYTE *pubAlphaBitmap) { UBYTE ubR,ubG,ubB, ubA=255; // loop backwards thru all bitmap pixels for( INDEX iPix=(pixSize-1); iPix>=0; iPix--) { ubR = pubSrcBitmap[iPix*3 +0]; ubG = pubSrcBitmap[iPix*3 +1]; ubB = pubSrcBitmap[iPix*3 +2]; if( pubAlphaBitmap!=NULL) ubA = pubAlphaBitmap[iPix]; else ubA = 255; // for the sake of forced RGBA internal formats! pulDstBitmap[iPix] = ByteSwap( RGBAToColor( ubR,ubG,ubB, ubA)); } } // removes 8-bit alpha channel from 32-bit bitmap (in place supported) void RemoveAlphaChannel( ULONG *pulSrcBitmap, UBYTE *pubDstBitmap, PIX pixSize) { UBYTE ubR,ubG,ubB; // loop thru all bitmap pixels for( INDEX iPix=0; iPix=0 && iFlipType<4); // no flipping ? PIX pixSize = pixWidth*pixHeight; if( iFlipType==0) { // copy bitmap only if needed INDEX ctBPP = (bAlphaChannel ? 4 : 3); if( pubSrc!=pubDst) memcpy( pubDst, pubSrc, pixSize*ctBPP); return; } // prepare images without alpha channels ULONG *pulNew = NULL; ULONG *pulNewSrc = (ULONG*)pubSrc; ULONG *pulNewDst = (ULONG*)pubDst; if( !bAlphaChannel) { pulNew = (ULONG*)AllocMemory( pixSize *BYTES_PER_TEXEL); AddAlphaChannel( pubSrc, pulNew, pixSize); pulNewSrc = pulNew; pulNewDst = pulNew; } // prepare half-width and half-height rounded const PIX pixHalfWidth = (pixWidth+1) /2; const PIX pixHalfHeight = (pixHeight+1)/2; // flip horizontal if( iFlipType==2 || iFlipType==3) { // for each row for( INDEX iRow=0; iRow1 && pixHeight>1); ASSERT( pixWidth == 1L<>=1; pixHeight>>=1; if( bBilinear) // type of filtering? { // BILINEAR #if (defined USE_PORTABLE_C) UBYTE *src = (UBYTE *) pulSrcMipmap; UBYTE *dest = (UBYTE *) pulDstMipmap; for (int i = 0 ; i < pixHeight; i++) { for (int j = 0; j < pixWidth; j++) { // Grab pixels from image UWORD upleft[4]; UWORD upright[4]; UWORD downleft[4]; UWORD downright[4]; upleft[0] = *(src + 0); upleft[1] = *(src + 1); upleft[2] = *(src + 2); upleft[3] = *(src + 3); upright[0] = *(src + 4); upright[1] = *(src + 5); upright[2] = *(src + 6); upright[3] = *(src + 7); downleft[0] = *(src + pixWidth*8 + 0); downleft[1] = *(src + pixWidth*8 + 1); downleft[2] = *(src + pixWidth*8 + 2); downleft[3] = *(src + pixWidth*8 + 3); downright[0] = *(src + pixWidth*8 + 4); downright[1] = *(src + pixWidth*8 + 5); downright[2] = *(src + pixWidth*8 + 6); downright[3] = *(src + pixWidth*8 + 7); UWORD answer[4]; answer[0] = upleft[0] + upright[0] + downleft[0] + downright[0] + 2; answer[1] = upleft[1] + upright[1] + downleft[1] + downright[1] + 2; answer[2] = upleft[2] + upright[2] + downleft[2] + downright[2] + 2; answer[3] = upleft[3] + upright[3] + downleft[3] + downright[3] + 2; answer[0] /= 4; answer[1] /= 4; answer[2] /= 4; answer[3] /= 4; *(dest + 0) = answer[0]; *(dest + 1) = answer[1]; *(dest + 2) = answer[2]; *(dest + 3) = answer[3]; src += 8; dest += 4; } src += 8*pixWidth; } #elif (defined __MSVC_INLINE__) __asm { pxor mm0,mm0 mov ebx,D [pixWidth] mov esi,D [pulSrcMipmap] mov edi,D [pulDstMipmap] mov edx,D [pixHeight] rowLoop: mov ecx,D [pixWidth] pixLoopN: movd mm1,D [esi+ 0] // up-left movd mm2,D [esi+ 4] // up-right movd mm3,D [esi+ ebx*8 +0] // down-left movd mm4,D [esi+ ebx*8 +4] // down-right punpcklbw mm1,mm0 punpcklbw mm2,mm0 punpcklbw mm3,mm0 punpcklbw mm4,mm0 paddw mm1,mm2 paddw mm1,mm3 paddw mm1,mm4 paddw mm1,Q [mmRounder] psrlw mm1,2 packuswb mm1,mm0 movd D [edi],mm1 // advance to next pixel add esi,4*2 add edi,4 dec ecx jnz pixLoopN // advance to next row lea esi,[esi+ ebx*8] // skip one row in source mip-map dec edx jnz rowLoop emms } #elif (defined __GNU_INLINE_X86_32__) __asm__ __volatile__ ( "pxor %%mm0, %%mm0 \n\t" "movl %[pulSrcMipmap], %%esi \n\t" "movl %[pulDstMipmap], %%edi \n\t" "movl %[pixHeight], %%edx \n\t" "0: \n\t" // rowLoop "movl %[pixWidth], %%ecx \n\t" "1: \n\t" // pixLoopN "movd 0(%%esi), %%mm1 \n\t" // up-left "movd 4(%%esi), %%mm2 \n\t" // up-right "movd 0(%%esi, %[pixWidth], 8), %%mm3 \n\t" // down-left "movd 4(%%esi, %[pixWidth], 8), %%mm4 \n\t" // down-right "punpcklbw %%mm0, %%mm1 \n\t" "punpcklbw %%mm0, %%mm2 \n\t" "punpcklbw %%mm0, %%mm3 \n\t" "punpcklbw %%mm0, %%mm4 \n\t" "paddw %%mm2, %%mm1 \n\t" "paddw %%mm3, %%mm1 \n\t" "paddw %%mm4, %%mm1 \n\t" "paddw (" ASMSYM(mmRounder) "), %%mm1 \n\t" "psrlw $2, %%mm1 \n\t" "packuswb %%mm0, %%mm1 \n\t" "movd %%mm1, (%%edi) \n\t" // advance to next pixel "addl $8, %%esi \n\t" "addl $4, %%edi \n\t" "decl %%ecx \n\t" "jnz 1b \n\t" // pixLoopN // advance to next row // skip one row in source mip-map "leal 0(%%esi, %[pixWidth], 8), %%esi \n\t" "decl %%edx \n\t" "jnz 0b \n\t" // rowLoop "emms \n\t" : // no outputs. : [pixWidth] "r" (pixWidth), [pulSrcMipmap] "g" (pulSrcMipmap), [pulDstMipmap] "g" (pulDstMipmap), [pixHeight] "g" (pixHeight) : FPU_REGS, MMX_REGS, "ecx", "edx", "esi", "edi", "cc", "memory" ); #else #error Write inline asm for your platform. #endif } else { // NEAREST-NEIGHBOUR but with border preserving ULONG ulRowModulo = pixWidth*2 *BYTES_PER_TEXEL; #if (defined USE_PORTABLE_C) PIX offset = 0; ulRowModulo /= 4; for (int q = 0; q < 2; q++) { for (PIX i = pixHeight / 2; i > 0; i--) { for (PIX j = pixWidth / 2; j > 0; j--) { *pulDstMipmap = *(pulSrcMipmap + offset); pulSrcMipmap += 2; pulDstMipmap++; } for (PIX j = pixWidth / 2; j > 0; j--) { *pulDstMipmap = *(pulSrcMipmap + offset + 1); pulSrcMipmap += 2; pulDstMipmap++; } pulSrcMipmap += ulRowModulo; } offset = pixWidth * 2; } #elif (defined __MSVC_INLINE__) __asm { xor ebx,ebx mov esi,D [pulSrcMipmap] mov edi,D [pulDstMipmap] // setup upper half mov edx,D [pixHeight] shr edx,1 halfLoop: mov ecx,D [pixWidth] shr ecx,1 leftLoop: mov eax,D [esi+ ebx*8+ 0] // upper-left (or lower-left) mov D [edi],eax // advance to next pixel add esi,4*2 add edi,4 sub ecx,1 jg leftLoop // do right row half mov ecx,D [pixWidth] shr ecx,1 jz halfEnd rightLoop: mov eax,D [esi+ ebx*8+ 4] // upper-right (or lower-right) mov D [edi],eax // advance to next pixel add esi,4*2 add edi,4 sub ecx,1 jg rightLoop halfEnd: // advance to next row add esi,D [ulRowModulo] // skip one row in source mip-map sub edx,1 jg halfLoop // do eventual lower half loop (if not yet done) mov edx,D [pixHeight] shr edx,1 jz fullEnd cmp ebx,D [pixWidth] mov ebx,D [pixWidth] jne halfLoop fullEnd: } #elif (defined __GNU_INLINE_X86_32__) ULONG tmp, tmp2; __asm__ __volatile__ ( "xorl %[xbx], %[xbx] \n\t" "movl %[pulSrcMipmap], %%esi \n\t" "movl %[pulDstMipmap], %%edi \n\t" // setup upper half "movl %[pixHeight], %%eax \n\t" "movl %%eax, %[xdx] \n\t" "shrl $1, %[xdx] \n\t" "0: \n\t" // halfLoop "movl %[pixWidth], %%ecx \n\t" "shrl $1, %%ecx \n\t" "1: \n\t" // leftLoop "movl 0(%%esi, %[xbx], 8), %%eax \n\t" // upper-left (or lower-left) "movl %%eax, (%%edi) \n\t" // advance to next pixel "addl $8, %%esi \n\t" "addl $4, %%edi \n\t" "subl $1, %%ecx \n\t" "jg 1b \n\t" // leftLoop // do right row half "movl %[pixWidth], %%ecx \n\t" "shrl $1, %%ecx \n\t" "jz 3f \n\t" // halfEnd "2: \n\t" // rightLoop "movl 4(%%esi, %[xbx], 8), %%eax \n\t" // upper-right (or lower-right) "movl %%eax, (%%edi) \n\t" // advance to next pixel "addl $8, %%esi \n\t" "addl $4, %%edi \n\t" "subl $1, %%ecx \n\t" "jg 2b \n\t" // rightLoop "3: \n\t" // halfEnd // advance to next row "addl %[ulRowModulo], %%esi \n\t" // skip one row in source mip-map "subl $1, %[xdx] \n\t" "jg 0b \n\t" // halfLoop // do eventual lower half loop (if not yet done) "movl %[pixHeight], %%eax \n\t" "movl %%eax, %[xdx] \n\t" "shrl $1, %[xdx] \n\t" "jz 4f \n\t" // fullEnd "cmpl %[pixWidth], %[xbx] \n\t" "movl %[pixWidth], %[xbx] \n\t" "jne 0b \n\t" // halfLoop "4: \n\t" // fullEnd : [xbx] "=&r" (tmp), [xdx] "=&g" (tmp2) : [pulSrcMipmap] "g" (pulSrcMipmap), [pulDstMipmap] "g" (pulDstMipmap), [pixHeight] "g" (pixHeight), [pixWidth] "g" (pixWidth), [ulRowModulo] "g" (ulRowModulo) : "eax", "ecx", "esi", "edi", "cc", "memory" ); #else #error Write inline asm for your platform. #endif } } // makes ALL lower mipmaps (to size of 1x1!) of a specified 32-bit bitmap // and returns pointer to newely created and mipmaped image // (only first ctFineMips number of mip-maps will be filtered with bilinear subsampling, while // all others will be downsampled with nearest-neighbour method) void MakeMipmaps( INDEX ctFineMips, ULONG *pulMipmaps, PIX pixWidth, PIX pixHeight, INDEX iFilter/*=NONE*/) { ASSERT( pixWidth>0 && pixHeight>0); _pfGfxProfile.StartTimer( CGfxProfile::PTI_MAKEMIPMAPS); // prepare some variables INDEX ctMipmaps = 1; PIX pixTexSize = 0; PIX pixCurrWidth = pixWidth; PIX pixCurrHeight = pixHeight; ULONG *pulSrcMipmap, *pulDstMipmap; // determine filtering mode (-1=prefiltering, 0=none, 1=postfiltering) INDEX iFilterMode = 0; if( iFilter!=0) { iFilterMode = -1; if( !tex_bProgressiveFilter) iFilterMode = +1; } // loop thru mip-map levels while( pixCurrWidth>1 && pixCurrHeight>1) { // determine mip size PIX pixMipSize = pixCurrWidth*pixCurrHeight; pulSrcMipmap = pulMipmaps + pixTexSize; pulDstMipmap = pulSrcMipmap + pixMipSize; // do pre filter is required if( iFilterMode<0) FilterBitmap( iFilter, pulSrcMipmap, pulSrcMipmap, pixCurrWidth, pixCurrHeight); // create one mipmap MakeOneMipmap( pulSrcMipmap, pulDstMipmap, pixCurrWidth, pixCurrHeight, ctMipmaps0) FilterBitmap( iFilter, pulSrcMipmap, pulSrcMipmap, pixCurrWidth, pixCurrHeight); // advance to next mipmap pixTexSize += pixMipSize; pixCurrWidth >>=1; pixCurrHeight >>=1; ctMipmaps++; } // all done _pfGfxProfile.StopTimer( CGfxProfile::PTI_MAKEMIPMAPS); } // mipmap colorization table (from 1024 to 1) static COLOR _acolMips[10] = { C_RED, C_GREEN, C_BLUE, C_CYAN, C_MAGENTA, C_YELLOW, C_RED, C_GREEN, C_BLUE, C_WHITE }; // colorize mipmaps void ColorizeMipmaps( INDEX i1stMipmapToColorize, ULONG *pulMipmaps, PIX pixWidth, PIX pixHeight) { // prepare ... ULONG *pulSrcMipmap = pulMipmaps + GetMipmapOffset( i1stMipmapToColorize, pixWidth, pixHeight); ULONG *pulDstMipmap; PIX pixCurrWidth = pixWidth >>i1stMipmapToColorize; PIX pixCurrHeight = pixHeight>>i1stMipmapToColorize; PIX pixMipSize; // skip too large textures const PIX pixMaxDim = Max( pixCurrWidth, pixCurrHeight); if( pixMaxDim>1024) return; INDEX iTableOfs = 10-FastLog2(pixMaxDim); // loop thru mip-map levels while( pixCurrWidth>1 && pixCurrHeight>1) { // prepare current mip-level pixMipSize = pixCurrWidth*pixCurrHeight; pulDstMipmap = pulSrcMipmap + pixMipSize; // mask mipmap const ULONG ulColorMask = ByteSwap( _acolMips[iTableOfs] | 0x3F3F3FFF); for( INDEX iPix=0; iPix>=1; pixCurrHeight >>=1; iTableOfs++; } } // calculates standard deviation of a bitmap DOUBLE CalcBitmapDeviation( ULONG *pulBitmap, PIX pixSize) { UBYTE ubR,ubG,ubB; ULONG ulSumR =0, ulSumG =0, ulSumB =0; __int64 mmSumR2=0, mmSumG2=0, mmSumB2=0; // calculate sum and sum^2 for( INDEX iPix=0; iPix=pixWidth && pixCanvasHeight>=pixHeight); SLONG slModulo = (pixCanvasWidth-pixWidth) *BYTES_PER_TEXEL; SLONG slWidthModulo = pixWidth*BYTES_PER_TEXEL +slModulo; // if bitmap is smaller than 4x2 pixels if( pixWidth<4 || pixHeight<2) { // don't dither it at all, rather copy only (if needed) if( pulDst!=pulSrc) memcpy( pulDst, pulSrc, pixCanvasWidth*pixCanvasHeight *BYTES_PER_TEXEL); goto theEnd; } // determine proper dither type switch( iDitherType) { // low dithers case 1: pulDitherTable = &ulDither2[0][0]; mmShifter = 2; #ifdef __GNUC__ mmMask = 0x3F3F3F3F3F3F3F3Fll; #else mmMask = 0x3F3F3F3F3F3F3F3F; #endif goto ditherOrder; case 2: pulDitherTable = &ulDither2[0][0]; mmShifter = 1; #ifdef __GNUC__ mmMask = 0x7F7F7F7F7F7F7F7Fll; #else mmMask = 0x7F7F7F7F7F7F7F7F; #endif goto ditherOrder; case 3: #ifdef __GNUC__ mmErrDiffMask = 0x0003000300030003ll; #else mmErrDiffMask = 0x0003000300030003; #endif goto ditherError; // medium dithers case 4: pulDitherTable = &ulDither2[0][0]; mmShifter = 0; #ifdef __GNUC__ mmMask = 0xFFFFFFFFFFFFFFFFll; #else mmMask = 0xFFFFFFFFFFFFFFFF; #endif goto ditherOrder; case 5: pulDitherTable = &ulDither3[0][0]; mmShifter = 1; #ifdef __GNUC__ mmMask = 0x7F7F7F7F7F7F7F7Fll; #else mmMask = 0x7F7F7F7F7F7F7F7F; #endif goto ditherOrder; case 6: pulDitherTable = &ulDither4[0][0]; mmShifter = 1; #ifdef __GNUC__ mmMask = 0x7F7F7F7F7F7F7F7Fll; #else mmMask = 0x7F7F7F7F7F7F7F7F; #endif goto ditherOrder; case 7: #ifdef __GNUC__ mmErrDiffMask = 0x0007000700070007ll; #else mmErrDiffMask = 0x0007000700070007; #endif goto ditherError; // high dithers case 8: pulDitherTable = &ulDither3[0][0]; mmShifter = 0; #ifdef __GNUC__ mmMask = 0xFFFFFFFFFFFFFFFFll; #else mmMask = 0xFFFFFFFFFFFFFFFF; #endif goto ditherOrder; case 9: pulDitherTable = &ulDither4[0][0]; mmShifter = 0; #ifdef __GNUC__ mmMask = 0xFFFFFFFFFFFFFFFFll; #else mmMask = 0xFFFFFFFFFFFFFFFF; #endif goto ditherOrder; case 10: #ifdef __GNUC__ mmErrDiffMask = 0x000F000F000F000Fll; #else mmErrDiffMask = 0x000F000F000F000F; #endif goto ditherError; default: // improper dither type ASSERTALWAYS( "Improper dithering type."); // if bitmap copying is needed if( pulDst!=pulSrc) memcpy( pulDst, pulSrc, pixCanvasWidth*pixCanvasHeight *BYTES_PER_TEXEL); goto theEnd; } // ------------------------------- ordered matrix dithering routine ditherOrder: #if (defined USE_PORTABLE_C) union uConv { ULONG val; DWORD dwords[2]; UWORD words[4]; WORD iwords[4]; UBYTE bytes[8]; }; for (int i=0; i>= mmShifter; } dith.val &= mmMask; uConv* src = (uConv*)(pulSrc+i*pixWidth); uConv* dst = (uConv*)(pulDst+i*pixWidth); for (int j=0; j>4; p5.words[k] = (p1.words[k]*5)>>4; p7.words[k] = (p1.words[k]*7)>>4; } for (int k=0; k<4; k++) { p1.words[k] -= (p3.words[k] + p5.words[k] + p7.words[k]);} for (int k=0; k<4; k++) { IncrementByteWithClip( src[k + step] , p7.words[k]); IncrementByteWithClip( src[pixCanvasWidth*4 -step +k], p5.words[k]); IncrementByteWithClip( src[pixCanvasWidth*4 +0 +k], p3.words[k]); IncrementByteWithClip( src[pixCanvasWidth*4 +step +k], p1.words[k]); } } } #endif #elif (defined __MSVC_INLINE__) __asm { pxor mm0,mm0 mov esi,D [pulDst] mov ebx,D [pixCanvasWidth] mov edx,D [pixHeight] dec edx // need not to dither last row rowLoopE: // left to right mov ecx,D [pixWidth] dec ecx pixLoopEL: movd mm1,D [esi] punpcklbw mm1,mm0 pand mm1,Q [mmErrDiffMask] // determine errors movq mm3,mm1 movq mm5,mm1 movq mm7,mm1 pmullw mm3,Q [mmW3] pmullw mm5,Q [mmW5] pmullw mm7,Q [mmW7] psrlw mm3,4 // *3/16 psrlw mm5,4 // *5/16 psrlw mm7,4 // *7/16 psubw mm1,mm3 psubw mm1,mm5 psubw mm1,mm7 // *rest/16 packuswb mm1,mm0 packuswb mm3,mm0 packuswb mm5,mm0 packuswb mm7,mm0 // spread errors paddusb mm7,Q [esi+ +4] paddusb mm3,Q [esi+ ebx*4 -4] paddusb mm5,Q [esi+ ebx*4 +0] paddusb mm1,Q [esi+ ebx*4 +4] // !!!! possible memory leak? movd D [esi+ +4],mm7 movd D [esi+ ebx*4 -4],mm3 movd D [esi+ ebx*4 +0],mm5 movd D [esi+ ebx*4 +4],mm1 // advance to next pixel add esi,4 dec ecx jnz pixLoopEL // advance to next row add esi,D [slWidthModulo] dec edx jz allDoneE // right to left mov ecx,D [pixWidth] dec ecx pixLoopER: movd mm1,D [esi] punpcklbw mm1,mm0 pand mm1,Q [mmErrDiffMask] // determine errors movq mm3,mm1 movq mm5,mm1 movq mm7,mm1 pmullw mm3,Q [mmW3] pmullw mm5,Q [mmW5] pmullw mm7,Q [mmW7] psrlw mm3,4 // *3/16 psrlw mm5,4 // *5/16 psrlw mm7,4 // *7/16 psubw mm1,mm3 psubw mm1,mm5 psubw mm1,mm7 // *rest/16 packuswb mm1,mm0 packuswb mm3,mm0 packuswb mm5,mm0 packuswb mm7,mm0 // spread errors paddusb mm7,Q [esi+ -4] paddusb mm1,Q [esi+ ebx*4 -4] paddusb mm5,Q [esi+ ebx*4 +0] paddusb mm3,Q [esi+ ebx*4 +4] // !!!! possible memory leak? movd D [esi+ -4],mm7 movd D [esi+ ebx*4 -4],mm1 movd D [esi+ ebx*4 +0],mm5 movd D [esi+ ebx*4 +4],mm3 // revert to previous pixel sub esi,4 dec ecx jnz pixLoopER // advance to next row lea esi,[esi+ ebx*4] dec edx jnz rowLoopE allDoneE: emms; } #elif (defined __GNU_INLINE_X86_32__) __asm__ __volatile__ ( "pxor %%mm0, %%mm0 \n\t" "movl %[pulDst], %%esi \n\t" "movl %[pixHeight], %%edx \n\t" "decl %%edx \n\t" // need not to dither last row "0: \n\t" // rowLoopE // left to right "movl %[pixWidth], %%ecx \n\t" "decl %%ecx \n\t" "1: \n\t" // pixLoopEL "movd (%%esi), %%mm1 \n\t" "punpcklbw %%mm0, %%mm1 \n\t" "pand (" ASMSYM(mmErrDiffMask) "), %%mm1 \n\t" // determine errors "movq %%mm1, %%mm3 \n\t" "movq %%mm1, %%mm5 \n\t" "movq %%mm1, %%mm7 \n\t" "pmullw (" ASMSYM(mmW3) "), %%mm3 \n\t" "pmullw (" ASMSYM(mmW5) "), %%mm5 \n\t" "pmullw (" ASMSYM(mmW7) "), %%mm7 \n\t" "psrlw $4, %%mm3 \n\t" // *3/16 "psrlw $4, %%mm5 \n\t" // *5/16 "psrlw $4, %%mm7 \n\t" // *7/16 "psubw %%mm3,%%mm1 \n\t" "psubw %%mm5,%%mm1 \n\t" "psubw %%mm7,%%mm1 \n\t" // *rest/16 "packuswb %%mm0,%%mm1 \n\t" "packuswb %%mm0,%%mm3 \n\t" "packuswb %%mm0,%%mm5 \n\t" "packuswb %%mm0,%%mm7 \n\t" // spread errors "paddusb 4(%%esi), %%mm7 \n\t" "paddusb -4(%%esi, %[pixCanvasWidth], 4), %%mm3 \n\t" "paddusb 0(%%esi, %[pixCanvasWidth], 4), %%mm5 \n\t" "paddusb 4(%%esi, %[pixCanvasWidth], 4), %%mm1 \n\t" // !!!! possible memory leak? "movd %%mm7, 4(%%esi) \n\t" "movd %%mm3, -4(%%esi, %[pixCanvasWidth], 4) \n\t" "movd %%mm5, 0(%%esi, %[pixCanvasWidth], 4) \n\t" "movd %%mm1, 4(%%esi, %[pixCanvasWidth], 4) \n\t" // advance to next pixel "addl $4, %%esi \n\t" "decl %%ecx \n\t" "jnz 1b \n\t" // pixLoopEL // advance to next row "addl %[slWidthModulo], %%esi \n\t" "decl %%edx \n\t" "jz 3f \n\t" // allDoneE // right to left "movl %[pixWidth], %%ecx \n\t" "decl %%ecx \n\t" "2: \n\t" // pixLoopER "movd (%%esi), %%mm1 \n\t" "punpcklbw %%mm0, %%mm1 \n\t" "pand (" ASMSYM(mmErrDiffMask) "), %%mm1 \n\t" // determine errors "movq %%mm1, %%mm3 \n\t" "movq %%mm1, %%mm5 \n\t" "movq %%mm1, %%mm7 \n\t" "pmullw (" ASMSYM(mmW3) "), %%mm3 \n\t" "pmullw (" ASMSYM(mmW5) "), %%mm5 \n\t" "pmullw (" ASMSYM(mmW7) "), %%mm7 \n\t" "psrlw $4, %%mm3 \n\t" // *3/16 "psrlw $4, %%mm5 \n\t" // *5/16 "psrlw $4, %%mm7 \n\t" // *7/16 "psubw %%mm3, %%mm1 \n\t" "psubw %%mm5, %%mm1 \n\t" "psubw %%mm7, %%mm1 \n\t" // *rest/16 "packuswb %%mm0, %%mm1 \n\t" "packuswb %%mm0, %%mm3 \n\t" "packuswb %%mm0, %%mm5 \n\t" "packuswb %%mm0, %%mm7 \n\t" // spread errors "paddusb -4(%%esi), %%mm7 \n\t" "paddusb -4(%%esi, %[pixCanvasWidth], 4), %%mm1 \n\t" "paddusb 0(%%esi, %[pixCanvasWidth], 4), %%mm5 \n\t" "paddusb 4(%%esi, %[pixCanvasWidth], 4), %%mm3 \n\t" // !!!! possible memory leak? "movd %%mm7, -4(%%esi) \n\t" "movd %%mm1, -4(%%esi, %[pixCanvasWidth], 4) \n\t" "movd %%mm5, 0(%%esi, %[pixCanvasWidth], 4) \n\t" "movd %%mm3, 4(%%esi, %[pixCanvasWidth], 4) \n\t" // revert to previous pixel "subl $4, %%esi \n\t" "decl %%ecx \n\t" "jnz 2b \n\t" // pixLoopER // advance to next row "leal 0(%%esi, %[pixCanvasWidth], 4), %%esi \n\t" "decl %%edx \n\t" "jnz 0b \n\t" // rowLoopE "3: \n\t" // allDoneE "emms \n\t" : // no outputs. : [pulDst] "g" (pulDst), [pixCanvasWidth] "r" (pixCanvasWidth), [pixHeight] "g" (pixHeight), [pixWidth] "g" (pixWidth), [slWidthModulo] "g" (slWidthModulo) : FPU_REGS, MMX_REGS, "ecx", "edx", "esi", "cc", "memory" ); #else #error Write inline asm for your platform. #endif goto theEnd; // all done theEnd: _pfGfxProfile.StopTimer( CGfxProfile::PTI_DITHERBITMAP); } // performs dithering of a 32-bit mipmaps (can be in-place) void DitherMipmaps( INDEX iDitherType, ULONG *pulSrc, ULONG *pulDst, PIX pixWidth, PIX pixHeight) { // safety check ASSERT( pixWidth>0 && pixHeight>0); // loop thru mipmaps PIX pixMipSize; while( pixWidth>0 && pixHeight>0) { // dither one mipmap DitherBitmap( iDitherType, pulSrc, pulDst, pixWidth, pixHeight); // advance to next mipmap pixMipSize = pixWidth*pixHeight; pulSrc += pixMipSize; pulDst += pixMipSize; pixWidth >>=1; pixHeight>>=1; } } // blur/sharpen filters static INDEX aiFilters[6][3] = { { 0, 1, 16 }, // minimum { 0, 2, 8 }, // low { 1, 2, 7 }, // medium { 1, 2, 3 }, // high { 3, 4, 5 }, // maximum { 1, 1, 1 }}; // // temp for middle pixels, vertical/horizontal edges, and corners __int64 mmMc, mmMe, mmMm; // corner, edge, middle __int64 mmEch, mmEm; // corner-high, middle #define mmEcl mmMc // corner-low #define mmEe mmMe // edge __int64 mmCm; // middle #define mmCc mmMc // corner #define mmCe mmEch // edge __int64 mmInvDiv; #if (defined __GNUC__) __int64 mmAdd = 0x0007000700070007ll; #else __int64 mmAdd = 0x0007000700070007; #endif // temp rows for in-place filtering support extern "C" { ULONG aulRows[2048]; } // FilterBitmap() INTERNAL: generates convolution filter matrix if needed static INDEX iLastFilter; static void GenerateConvolutionMatrix( INDEX iFilter) { // same as last? if( iLastFilter==iFilter) return; // update filter iLastFilter = iFilter; INDEX iFilterAbs = Abs(iFilter) -1; // convert convolution values to MMX format INDEX iMc = aiFilters[iFilterAbs][0]; // corner INDEX iMe = aiFilters[iFilterAbs][1]; // edge INDEX iMm = aiFilters[iFilterAbs][2]; // middle // negate values for sharpen filter case if( iFilter<0) { iMm += (iMe+iMc) *8; // (4*Edge + 4*Corner) *2 iMe = -iMe; iMc = -iMc; } // find values for edge and corner cases INDEX iEch = iMc + iMe; INDEX iEm = iMm + iMe; INDEX iCm = iEch + iEm; // prepare divider __int64 mm = ((__int64)ceil(65536.0f/(iMc*4+iMe*4+iMm))) & 0xFFFF; mmInvDiv = (mm<<48) | (mm<<32) | (mm<<16) | mm; // prepare filter values mm = iMc & 0xFFFF; mmMc = (mm<<48) | (mm<<32) | (mm<<16) | mm; mm = iMe & 0xFFFF; mmMe = (mm<<48) | (mm<<32) | (mm<<16) | mm; mm = iMm & 0xFFFF; mmMm = (mm<<48) | (mm<<32) | (mm<<16) | mm; mm = iEch & 0xFFFF; mmEch= (mm<<48) | (mm<<32) | (mm<<16) | mm; mm = iEm & 0xFFFF; mmEm = (mm<<48) | (mm<<32) | (mm<<16) | mm; mm = iCm & 0xFFFF; mmCm = (mm<<48) | (mm<<32) | (mm<<16) | mm; } extern "C" { ULONG *FB_pulSrc = NULL; ULONG *FB_pulDst = NULL; PIX FB_pixWidth = 0; PIX FB_pixHeight = 0; PIX FB_pixCanvasWidth = 0; SLONG FB_slModulo1 = 0; SLONG FB_slCanvasWidth = 0; } #ifdef USE_PORTABLE_C typedef SWORD ExtPix[4]; static inline void extpix_fromi64(ExtPix &pix, const __int64 i64) { //memcpy(pix, i64, sizeof (ExtPix)); pix[0] = ((i64 >> 0) & 0xFFFF); pix[1] = ((i64 >> 16) & 0xFFFF); pix[2] = ((i64 >> 32) & 0xFFFF); pix[3] = ((i64 >> 48) & 0xFFFF); } static inline void extend_pixel(const ULONG ul, ExtPix &pix) { pix[0] = ((ul >> 0) & 0xFF); pix[1] = ((ul >> 8) & 0xFF); pix[2] = ((ul >> 16) & 0xFF); pix[3] = ((ul >> 24) & 0xFF); } static inline ULONG unextend_pixel(const ExtPix &pix) { return ( (((ULONG) ((pix[0] >= 255) ? 255 : ((pix[0] <= 0) ? 0 : pix[0]))) << 0) | (((ULONG) ((pix[1] >= 255) ? 255 : ((pix[1] <= 0) ? 0 : pix[1]))) << 8) | (((ULONG) ((pix[2] >= 255) ? 255 : ((pix[2] <= 0) ? 0 : pix[2]))) << 16) | (((ULONG) ((pix[3] >= 255) ? 255 : ((pix[3] <= 0) ? 0 : pix[3]))) << 24) ); } static inline void extpix_add(ExtPix &p1, const ExtPix &p2) { p1[0] = (SWORD) (((SLONG) p1[0]) + ((SLONG) p2[0])); p1[1] = (SWORD) (((SLONG) p1[1]) + ((SLONG) p2[1])); p1[2] = (SWORD) (((SLONG) p1[2]) + ((SLONG) p2[2])); p1[3] = (SWORD) (((SLONG) p1[3]) + ((SLONG) p2[3])); } static inline void extpix_mul(ExtPix &p1, const ExtPix &p2) { p1[0] = (SWORD) (((SLONG) p1[0]) * ((SLONG) p2[0])); p1[1] = (SWORD) (((SLONG) p1[1]) * ((SLONG) p2[1])); p1[2] = (SWORD) (((SLONG) p1[2]) * ((SLONG) p2[2])); p1[3] = (SWORD) (((SLONG) p1[3]) * ((SLONG) p2[3])); } static inline void extpix_adds(ExtPix &p1, const ExtPix &p2) { SLONG x0 = (((SLONG) ((SWORD) p1[0])) + ((SLONG) ((SWORD) p2[0]))); SLONG x1 = (((SLONG) ((SWORD) p1[1])) + ((SLONG) ((SWORD) p2[1]))); SLONG x2 = (((SLONG) ((SWORD) p1[2])) + ((SLONG) ((SWORD) p2[2]))); SLONG x3 = (((SLONG) ((SWORD) p1[3])) + ((SLONG) ((SWORD) p2[3]))); p1[0] = (SWORD) ((x0 <= -32768) ? -32768 : ((x0 >= 32767) ? 32767 : x0)); p1[1] = (SWORD) ((x1 <= -32768) ? -32768 : ((x1 >= 32767) ? 32767 : x1)); p1[2] = (SWORD) ((x2 <= -32768) ? -32768 : ((x2 >= 32767) ? 32767 : x2)); p1[3] = (SWORD) ((x3 <= -32768) ? -32768 : ((x3 >= 32767) ? 32767 : x3)); } static inline void extpix_mulhi(ExtPix &p1, const ExtPix &p2) { p1[0] = (SWORD) (((((SLONG) p1[0]) * ((SLONG) p2[0])) >> 16) & 0xFFFF); p1[1] = (SWORD) (((((SLONG) p1[1]) * ((SLONG) p2[1])) >> 16) & 0xFFFF); p1[2] = (SWORD) (((((SLONG) p1[2]) * ((SLONG) p2[2])) >> 16) & 0xFFFF); p1[3] = (SWORD) (((((SLONG) p1[3]) * ((SLONG) p2[3])) >> 16) & 0xFFFF); } #endif // applies filter to bitmap void FilterBitmap( INDEX iFilter, ULONG *pulSrc, ULONG *pulDst, PIX pixWidth, PIX pixHeight, PIX pixCanvasWidth, PIX pixCanvasHeight) { _pfGfxProfile.StartTimer( CGfxProfile::PTI_FILTERBITMAP); ASSERT( iFilter>=-6 && iFilter<=+6); // adjust canvas size if( pixCanvasWidth ==0) pixCanvasWidth = pixWidth; if( pixCanvasHeight==0) pixCanvasHeight = pixHeight; ASSERT( pixCanvasWidth>=pixWidth && pixCanvasHeight>=pixHeight); // if bitmap is smaller than 4x4 if( pixWidth<4 || pixHeight<4) { // don't blur it at all, but eventually only copy if( pulDst!=pulSrc) memcpy( pulDst, pulSrc, pixCanvasWidth*pixCanvasHeight *BYTES_PER_TEXEL); _pfGfxProfile.StopTimer( CGfxProfile::PTI_FILTERBITMAP); return; } // prepare convolution matrix and row modulo iFilter = Clamp( iFilter, -6, 6); GenerateConvolutionMatrix( iFilter); SLONG slModulo1 = (pixCanvasWidth-pixWidth+1) *BYTES_PER_TEXEL; SLONG slCanvasWidth = pixCanvasWidth *BYTES_PER_TEXEL; // lets roll ... #if (defined USE_MMX_INTRINSICS) slModulo1 /= BYTES_PER_TEXEL; // C++ handles incrementing by sizeof type slCanvasWidth /= BYTES_PER_TEXEL; // C++ handles incrementing by sizeof type ULONG *src = pulSrc; ULONG *dst = pulDst; ULONG *rowptr = aulRows; __m64 rmm0 = _mm_setzero_si64(); __m64 rmmCm = _mm_set_pi32(((int *)((char*)&mmCm))[0],((int *)((char*)&mmCm))[1]); __m64 rmmCe = _mm_set_pi32(((int *)((char*)&mmCe))[0],((int *)((char*)&mmCe))[1]); __m64 rmmCc = _mm_set_pi32(((int *)((char*)&mmCc))[0],((int *)((char*)&mmCc))[1]); __m64 rmmEch = _mm_set_pi32(((int *)((char*)&mmEch))[0],((int *)((char*)&mmEch))[1]); __m64 rmmEcl = _mm_set_pi32(((int *)((char*)&mmEcl))[0],((int *)((char*)&mmEcl))[1]); __m64 rmmEe = _mm_set_pi32(((int *)((char*)&mmEe))[0],((int *)((char*)&mmEe))[1]); __m64 rmmEm = _mm_set_pi32(((int *)((char*)&mmEm))[0],((int *)((char*)&mmEm))[1]); __m64 rmmMm = _mm_set_pi32(((int *)((char*)&mmMm))[0],((int *)((char*)&mmMm))[1]); __m64 rmmMe = _mm_set_pi32(((int *)((char*)&mmMe))[0],((int *)((char*)&mmMe))[1]); __m64 rmmMc = _mm_set_pi32(((int *)((char*)&mmMc))[0],((int *)((char*)&mmMc))[1]); __m64 rmmAdd = _mm_set_pi32(((int *)((char*)&mmAdd))[0],((int *)((char*)&mmAdd))[1]); __m64 rmmInvDiv = _mm_set_pi32(((int *)((char*)&mmInvDiv))[0],((int *)((char*)&mmInvDiv))[1]); // ----------------------- process upper left corner __m64 rmm1 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[0]), rmm0); __m64 rmm2 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[1]), rmm0); __m64 rmm3 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[pixCanvasWidth]), rmm0); __m64 rmm4 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[pixCanvasWidth+1]), rmm0); __m64 rmm5 = _mm_setzero_si64(); __m64 rmm6 = _mm_setzero_si64(); __m64 rmm7 = _mm_setzero_si64(); rmm2 = _mm_add_pi16(rmm2, rmm3); rmm1 = _mm_mullo_pi16(rmm1, rmmCm); rmm2 = _mm_mullo_pi16(rmm2, rmmCe); rmm4 = _mm_mullo_pi16(rmm4, rmmCc); rmm1 = _mm_add_pi16(rmm1, rmm2); rmm1 = _mm_add_pi16(rmm1, rmm4); rmm1 = _mm_adds_pi16(rmm1, rmmAdd); rmm1 = _mm_mulhi_pi16(rmm1, rmmInvDiv); rmm1 = _mm_packs_pu16(rmm1, rmm0); *(rowptr++) = _mm_cvtsi64_si32(rmm1); src++; // ----------------------- process upper edge pixels for (PIX i = pixWidth - 2; i != 0; i--) { rmm1 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[-1]), rmm0); rmm2 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[0]), rmm0); rmm3 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[1]), rmm0); rmm4 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[pixCanvasWidth-1]), rmm0); rmm5 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[pixCanvasWidth]), rmm0); rmm6 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[pixCanvasWidth+1]), rmm0); rmm1 = _mm_add_pi16(rmm1, rmm3); rmm4 = _mm_add_pi16(rmm4, rmm6); rmm1 = _mm_mullo_pi16(rmm1, rmmEch); rmm2 = _mm_mullo_pi16(rmm2, rmmEm); rmm4 = _mm_mullo_pi16(rmm4, rmmEcl); rmm5 = _mm_mullo_pi16(rmm5, rmmEe); rmm1 = _mm_add_pi16(rmm1, rmm2); rmm1 = _mm_add_pi16(rmm1, rmm4); rmm1 = _mm_add_pi16(rmm1, rmm5); rmm1 = _mm_adds_pi16(rmm1, rmmAdd); rmm1 = _mm_mulhi_pi16(rmm1, rmmInvDiv); rmm1 = _mm_packs_pu16(rmm1, rmm0); *(rowptr++) = _mm_cvtsi64_si32(rmm1); src++; } // ----------------------- process upper right corner rmm1 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[-1]), rmm0); rmm2 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[0]), rmm0); rmm3 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[pixCanvasWidth-1]), rmm0); rmm4 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[pixCanvasWidth]), rmm0); rmm1 = _mm_add_pi16(rmm1, rmm4); rmm1 = _mm_mullo_pi16(rmm1, rmmCe); rmm2 = _mm_mullo_pi16(rmm2, rmmCm); rmm3 = _mm_mullo_pi16(rmm3, rmmCc); rmm1 = _mm_add_pi16(rmm1, rmm2); rmm1 = _mm_add_pi16(rmm1, rmm3); rmm1 = _mm_adds_pi16(rmm1, rmmAdd); rmm1 = _mm_mulhi_pi16(rmm1, rmmInvDiv); rmm1 = _mm_packs_pu16(rmm1, rmm0); *rowptr = _mm_cvtsi64_si32(rmm1); // ----------------------- process bitmap middle pixels dst += slCanvasWidth; src += slModulo1; // for each row for (size_t i = pixHeight-2; i != 0; i--) // rowLoop { rowptr = aulRows; // process left edge pixel rmm1 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[-pixCanvasWidth]), rmm0); rmm2 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[(-pixCanvasWidth)+1]), rmm0); rmm3 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[0]), rmm0); rmm4 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[1]), rmm0); rmm5 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[pixCanvasWidth]), rmm0); rmm6 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[pixCanvasWidth+1]), rmm0); rmm1 = _mm_add_pi16(rmm1, rmm5); rmm2 = _mm_add_pi16(rmm2, rmm6); rmm1 = _mm_mullo_pi16(rmm1, rmmEch); rmm2 = _mm_mullo_pi16(rmm2, rmmEcl); rmm3 = _mm_mullo_pi16(rmm3, rmmEm); rmm4 = _mm_mullo_pi16(rmm4, rmmEe); rmm1 = _mm_add_pi16(rmm1, rmm2); rmm1 = _mm_add_pi16(rmm1, rmm3); rmm1 = _mm_add_pi16(rmm1, rmm4); rmm1 = _mm_adds_pi16(rmm1, rmmAdd); rmm1 = _mm_mulhi_pi16(rmm1, rmmInvDiv); rmm1 = _mm_packs_pu16(rmm1, rmm0); dst[-pixCanvasWidth] = *rowptr; *(rowptr++) = _mm_cvtsi64_si32(rmm1); src++; dst++; // for each pixel in current row for (size_t j = pixWidth-2; j != 0; j--) // pixLoop { // prepare upper convolution row rmm1 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[(-pixCanvasWidth)-1]), rmm0); rmm2 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[-pixCanvasWidth]), rmm0); rmm3 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[(-pixCanvasWidth)+1]), rmm0); // prepare middle convolution row rmm4 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[-1]), rmm0); rmm5 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[0]), rmm0); rmm6 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[1]), rmm0); // free some registers rmm1 = _mm_add_pi16(rmm1, rmm3); rmm2 = _mm_add_pi16(rmm2, rmm4); rmm5 = _mm_mullo_pi16(rmm5, rmmMm); // prepare lower convolution row rmm3 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[pixCanvasWidth-1]), rmm0); rmm4 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[pixCanvasWidth]), rmm0); rmm7 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[pixCanvasWidth+1]), rmm0); // calc weightened value rmm2 = _mm_add_pi16(rmm2, rmm6); rmm1 = _mm_add_pi16(rmm1, rmm3); rmm2 = _mm_add_pi16(rmm2, rmm4); rmm1 = _mm_add_pi16(rmm1, rmm7); rmm2 = _mm_mullo_pi16(rmm2, rmmMe); rmm1 = _mm_mullo_pi16(rmm1, rmmMc); rmm2 = _mm_add_pi16(rmm2, rmm5); rmm1 = _mm_add_pi16(rmm1, rmm2); // calc and store wightened value rmm1 = _mm_adds_pi16(rmm1, rmmAdd); rmm1 = _mm_mulhi_pi16(rmm1, rmmInvDiv); rmm1 = _mm_packs_pu16(rmm1, rmm0); dst[-pixCanvasWidth] = *rowptr; *(rowptr++) = _mm_cvtsi64_si32(rmm1); // advance to next pixel src++; dst++; } // process right edge pixel rmm1 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[(-pixCanvasWidth)-1]), rmm0); rmm2 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[-pixCanvasWidth]), rmm0); rmm3 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[-1]), rmm0); rmm4 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[0]), rmm0); rmm5 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[pixCanvasWidth-1]), rmm0); rmm6 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[pixCanvasWidth]), rmm0); rmm1 = _mm_add_pi16(rmm1, rmm5); rmm2 = _mm_add_pi16(rmm2, rmm6); rmm1 = _mm_mullo_pi16(rmm1, rmmEcl); rmm2 = _mm_mullo_pi16(rmm2, rmmEch); rmm3 = _mm_mullo_pi16(rmm3, rmmEe); rmm4 = _mm_mullo_pi16(rmm4, rmmEm); rmm1 = _mm_add_pi16(rmm1, rmm2); rmm1 = _mm_add_pi16(rmm1, rmm3); rmm1 = _mm_add_pi16(rmm1, rmm4); rmm1 = _mm_adds_pi16(rmm1, rmmAdd); rmm1 = _mm_mulhi_pi16(rmm1, rmmInvDiv); rmm1 = _mm_packs_pu16(rmm1, rmm0); dst[-pixCanvasWidth] = *rowptr; *rowptr = _mm_cvtsi64_si32(rmm1); // advance to next row src += slModulo1; dst += slModulo1; } // ----------------------- process lower left corner rowptr = aulRows; rmm1 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[-pixCanvasWidth]), rmm0); rmm2 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[(-pixCanvasWidth)+1]), rmm0); rmm3 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[0]), rmm0); rmm4 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[1]), rmm0); rmm1 = _mm_add_pi16(rmm1, rmm4); rmm1 = _mm_mullo_pi16(rmm1, rmmCe); rmm2 = _mm_mullo_pi16(rmm2, rmmCc); rmm3 = _mm_mullo_pi16(rmm3, rmmCm); rmm1 = _mm_add_pi16(rmm1, rmm2); rmm1 = _mm_add_pi16(rmm1, rmm3); rmm1 = _mm_adds_pi16(rmm1, rmmAdd); rmm1 = _mm_mulhi_pi16(rmm1, rmmInvDiv); rmm1 = _mm_packs_pu16(rmm1, rmm0); dst[-pixCanvasWidth] = *rowptr; dst[0] = _mm_cvtsi64_si32(rmm1); src++; dst++; rowptr++; // ----------------------- process lower edge pixels for (size_t i = pixWidth-2; i != 0; i--) // lowerLoop { // for each pixel rmm1 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[(-pixCanvasWidth)-1]), rmm0); rmm2 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[-pixCanvasWidth]), rmm0); rmm3 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[(-pixCanvasWidth)+1]), rmm0); rmm4 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[-1]), rmm0); rmm5 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[0]), rmm0); rmm6 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[1]), rmm0); rmm1 = _mm_add_pi16(rmm1, rmm3); rmm4 = _mm_add_pi16(rmm4, rmm6); rmm1 = _mm_mullo_pi16(rmm1, rmmEcl); rmm2 = _mm_mullo_pi16(rmm2, rmmEe); rmm4 = _mm_mullo_pi16(rmm4, rmmEch); rmm5 = _mm_mullo_pi16(rmm5, rmmEm); rmm1 = _mm_add_pi16(rmm1, rmm2); rmm1 = _mm_add_pi16(rmm1, rmm4); rmm1 = _mm_add_pi16(rmm1, rmm5); rmm1 = _mm_adds_pi16(rmm1, rmmAdd); rmm1 = _mm_mulhi_pi16(rmm1, rmmInvDiv); rmm1 = _mm_packs_pu16(rmm1, rmm0); dst[-pixCanvasWidth] = *rowptr; dst[0] = _mm_cvtsi64_si32(rmm1); // advance to next pixel src++; dst++; rowptr++; } // ----------------------- lower right corners rmm1 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[(-pixCanvasWidth)-1]), rmm0); rmm2 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[-pixCanvasWidth]), rmm0); rmm3 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[-1]), rmm0); rmm4 = _mm_unpacklo_pi8(_mm_cvtsi32_si64(src[0]), rmm0); rmm2 = _mm_add_pi16(rmm2, rmm3); rmm1 = _mm_mullo_pi16(rmm1, rmmCc); rmm2 = _mm_mullo_pi16(rmm2, rmmCe); rmm4 = _mm_mullo_pi16(rmm4, rmmCm); rmm1 = _mm_add_pi16(rmm1, rmm2); rmm1 = _mm_add_pi16(rmm1, rmm4); rmm1 = _mm_adds_pi16(rmm1, rmmAdd); rmm1 = _mm_mulhi_pi16(rmm1, rmmInvDiv); rmm1 = _mm_packs_pu16(rmm1, rmm0); dst[-pixCanvasWidth] = *rowptr; dst[0] = _mm_cvtsi64_si32(rmm1); _mm_empty(); // we're done, clear out the MMX registers! #elif (defined USE_PORTABLE_C) slModulo1 /= BYTES_PER_TEXEL; // C++ handles incrementing by sizeof type slCanvasWidth /= BYTES_PER_TEXEL; // C++ handles incrementing by sizeof type ULONG *src = pulSrc; ULONG *dst = pulDst; ULONG *rowptr = aulRows; ExtPix rmm1={0}, rmm2={0}, rmm3={0}, rmm4={0}, rmm5={0}, rmm6={0}, rmm7={0}; #define EXTPIXFROMINT64(x) ExtPix r##x; extpix_fromi64(r##x, x); EXTPIXFROMINT64(mmCm); EXTPIXFROMINT64(mmCe); EXTPIXFROMINT64(mmCc); EXTPIXFROMINT64(mmEch); EXTPIXFROMINT64(mmEcl); EXTPIXFROMINT64(mmEe); EXTPIXFROMINT64(mmEm); EXTPIXFROMINT64(mmMm); EXTPIXFROMINT64(mmMe); EXTPIXFROMINT64(mmMc); EXTPIXFROMINT64(mmAdd); EXTPIXFROMINT64(mmInvDiv); #undef EXTPIXFROMINT64 // ----------------------- process upper left corner extend_pixel(src[0], rmm1); extend_pixel(src[1], rmm2); extend_pixel(src[pixCanvasWidth], rmm3); extend_pixel(src[pixCanvasWidth+1], rmm4); extpix_add(rmm2, rmm3); extpix_mul(rmm1, rmmCm); extpix_mul(rmm2, rmmCe); extpix_mul(rmm4, rmmCc); extpix_add(rmm1, rmm2); extpix_add(rmm1, rmm4); extpix_adds(rmm1, rmmAdd); extpix_mulhi(rmm1, rmmInvDiv); *(rowptr++) = unextend_pixel(rmm1); src++; // ----------------------- process upper edge pixels for (PIX i = pixWidth - 2; i != 0; i--) { extend_pixel(src[-1], rmm1); extend_pixel(src[0], rmm2); extend_pixel(src[1], rmm3); extend_pixel(src[pixCanvasWidth-1], rmm4); extend_pixel(src[pixCanvasWidth], rmm5); extend_pixel(src[pixCanvasWidth+1], rmm6); extpix_add(rmm1, rmm3); extpix_add(rmm4, rmm6); extpix_mul(rmm1, rmmEch); extpix_mul(rmm2, rmmEm); extpix_mul(rmm4, rmmEcl); extpix_mul(rmm5, rmmEe); extpix_add(rmm1, rmm2); extpix_add(rmm1, rmm4); extpix_add(rmm1, rmm5); extpix_adds(rmm1, rmmAdd); extpix_mulhi(rmm1, rmmInvDiv); *(rowptr++) = unextend_pixel(rmm1); src++; } // ----------------------- process upper right corner extend_pixel(src[-1], rmm1); extend_pixel(src[0], rmm2); extend_pixel(src[pixCanvasWidth-1], rmm3); extend_pixel(src[pixCanvasWidth], rmm4); extpix_add(rmm1, rmm4); extpix_mul(rmm1, rmmCe); extpix_mul(rmm2, rmmCm); extpix_mul(rmm3, rmmCc); extpix_add(rmm1, rmm2); extpix_add(rmm1, rmm3); extpix_adds(rmm1, rmmAdd); extpix_mulhi(rmm1, rmmInvDiv); *rowptr = unextend_pixel(rmm1); // ----------------------- process bitmap middle pixels dst += slCanvasWidth; src += slModulo1; // for each row for (size_t i = pixHeight-2; i != 0; i--) // rowLoop { rowptr = aulRows; // process left edge pixel extend_pixel(src[-pixCanvasWidth], rmm1); extend_pixel(src[(-pixCanvasWidth)+1], rmm2); extend_pixel(src[0], rmm3); extend_pixel(src[1], rmm4); extend_pixel(src[pixCanvasWidth], rmm5); extend_pixel(src[pixCanvasWidth+1], rmm6); extpix_add(rmm1, rmm5); extpix_add(rmm2, rmm6); extpix_mul(rmm1, rmmEch); extpix_mul(rmm2, rmmEcl); extpix_mul(rmm3, rmmEm); extpix_mul(rmm4, rmmEe); extpix_add(rmm1, rmm2); extpix_add(rmm1, rmm3); extpix_add(rmm1, rmm4); extpix_adds(rmm1, rmmAdd); extpix_mulhi(rmm1, rmmInvDiv); dst[-pixCanvasWidth] = *rowptr; *(rowptr++) = unextend_pixel(rmm1); src++; dst++; // for each pixel in current row for (size_t j = pixWidth-2; j != 0; j--) // pixLoop { // prepare upper convolution row extend_pixel(src[(-pixCanvasWidth)-1], rmm1); extend_pixel(src[-pixCanvasWidth], rmm2); extend_pixel(src[(-pixCanvasWidth)+1], rmm3); // prepare middle convolution row extend_pixel(src[-1], rmm4); extend_pixel(src[0], rmm5); extend_pixel(src[1], rmm6); // free some registers extpix_add(rmm1, rmm3); extpix_add(rmm2, rmm4); extpix_mul(rmm5, rmmMm); // prepare lower convolution row extend_pixel(src[pixCanvasWidth-1], rmm3); extend_pixel(src[pixCanvasWidth], rmm4); extend_pixel(src[pixCanvasWidth+1], rmm7); // calc weightened value extpix_add(rmm2, rmm6); extpix_add(rmm1, rmm3); extpix_add(rmm2, rmm4); extpix_add(rmm1, rmm7); extpix_mul(rmm2, rmmMe); extpix_mul(rmm1, rmmMc); extpix_add(rmm2, rmm5); extpix_add(rmm1, rmm2); // calc and store wightened value extpix_adds(rmm1, rmmAdd); extpix_mulhi(rmm1, rmmInvDiv); dst[-pixCanvasWidth] = *rowptr; *(rowptr++) = unextend_pixel(rmm1); // advance to next pixel src++; dst++; } // process right edge pixel extend_pixel(src[(-pixCanvasWidth)-1], rmm1); extend_pixel(src[-pixCanvasWidth], rmm2); extend_pixel(src[-1], rmm3); extend_pixel(src[0], rmm4); extend_pixel(src[pixCanvasWidth-1], rmm5); extend_pixel(src[pixCanvasWidth], rmm6); extpix_add(rmm1, rmm5); extpix_add(rmm2, rmm6); extpix_mul(rmm1, rmmEcl); extpix_mul(rmm2, rmmEch); extpix_mul(rmm3, rmmEe); extpix_mul(rmm4, rmmEm); extpix_add(rmm1, rmm2); extpix_add(rmm1, rmm3); extpix_add(rmm1, rmm4); extpix_adds(rmm1, rmmAdd); extpix_mulhi(rmm1, rmmInvDiv); dst[-pixCanvasWidth] = *rowptr; *rowptr = unextend_pixel(rmm1); // advance to next row src += slModulo1; dst += slModulo1; } // ----------------------- process lower left corner rowptr = aulRows; extend_pixel(src[-pixCanvasWidth], rmm1); extend_pixel(src[(-pixCanvasWidth)+1], rmm2); extend_pixel(src[0], rmm3); extend_pixel(src[1], rmm4); extpix_add(rmm1, rmm4); extpix_mul(rmm1, rmmCe); extpix_mul(rmm2, rmmCc); extpix_mul(rmm3, rmmCm); extpix_add(rmm1, rmm2); extpix_add(rmm1, rmm3); extpix_adds(rmm1, rmmAdd); extpix_mulhi(rmm1, rmmInvDiv); dst[-pixCanvasWidth] = *rowptr; dst[0] = unextend_pixel(rmm1); src++; dst++; rowptr++; // ----------------------- process lower edge pixels for (size_t i = pixWidth-2; i != 0; i--) // lowerLoop { // for each pixel extend_pixel(src[(-pixCanvasWidth)-1], rmm1); extend_pixel(src[-pixCanvasWidth], rmm2); extend_pixel(src[(-pixCanvasWidth)+1], rmm3); extend_pixel(src[-1], rmm4); extend_pixel(src[0], rmm5); extend_pixel(src[1], rmm6); extpix_add(rmm1, rmm3); extpix_add(rmm4, rmm6); extpix_mul(rmm1, rmmEcl); extpix_mul(rmm2, rmmEe); extpix_mul(rmm4, rmmEch); extpix_mul(rmm5, rmmEm); extpix_add(rmm1, rmm2); extpix_add(rmm1, rmm4); extpix_add(rmm1, rmm5); extpix_adds(rmm1, rmmAdd); extpix_mulhi(rmm1, rmmInvDiv); dst[-pixCanvasWidth] = *rowptr; dst[0] = unextend_pixel(rmm1); // advance to next pixel src++; dst++; rowptr++; } // ----------------------- lower right corners extend_pixel(src[(-pixCanvasWidth)-1], rmm1); extend_pixel(src[-pixCanvasWidth], rmm2); extend_pixel(src[-1], rmm3); extend_pixel(src[0], rmm4); extpix_add(rmm2, rmm3); extpix_mul(rmm1, rmmCc); extpix_mul(rmm2, rmmCe); extpix_mul(rmm4, rmmCm); extpix_add(rmm1, rmm2); extpix_add(rmm1, rmm4); extpix_adds(rmm1, rmmAdd); extpix_mulhi(rmm1, rmmInvDiv); dst[-pixCanvasWidth] = *rowptr; dst[0] = unextend_pixel(rmm1); #elif (defined __MSVC_INLINE__) __asm { cld mov eax,D [pixCanvasWidth] // EAX = positive row offset mov edx,eax neg edx // EDX = negative row offset pxor mm0,mm0 mov esi,D [pulSrc] mov edi,D [pulDst] xor ebx,ebx // ----------------------- process upper left corner movd mm1,D [esi+ +0] movd mm2,D [esi+ +4] movd mm3,D [esi+ eax*4 +0] movd mm4,D [esi+ eax*4 +4] punpcklbw mm1,mm0 punpcklbw mm2,mm0 punpcklbw mm3,mm0 punpcklbw mm4,mm0 paddw mm2,mm3 pmullw mm1,Q [mmCm] pmullw mm2,Q [mmCe] pmullw mm4,Q [mmCc] paddw mm1,mm2 paddw mm1,mm4 paddsw mm1,Q [mmAdd] pmulhw mm1,Q [mmInvDiv] packuswb mm1,mm0 movd D [ebx+ aulRows],mm1 add esi,4 add ebx,4 // ----------------------- process upper edge pixels mov ecx,D [pixWidth] sub ecx,2 // for each pixel upperLoop: movd mm1,D [esi+ -4] movd mm2,D [esi+ +0] movd mm3,D [esi+ +4] movd mm4,D [esi+ eax*4 -4] movd mm5,D [esi+ eax*4 +0] movd mm6,D [esi+ eax*4 +4] punpcklbw mm1,mm0 punpcklbw mm2,mm0 punpcklbw mm3,mm0 punpcklbw mm4,mm0 punpcklbw mm5,mm0 punpcklbw mm6,mm0 paddw mm1,mm3 paddw mm4,mm6 pmullw mm1,Q [mmEch] pmullw mm2,Q [mmEm] pmullw mm4,Q [mmEcl] pmullw mm5,Q [mmEe] paddw mm1,mm2 paddw mm1,mm4 paddw mm1,mm5 paddsw mm1,Q [mmAdd] pmulhw mm1,Q [mmInvDiv] packuswb mm1,mm0 movd D [ebx+ aulRows],mm1 // advance to next pixel add esi,4 add ebx,4 dec ecx jnz upperLoop // ----------------------- process upper right corner movd mm1,D [esi+ -4] movd mm2,D [esi+ +0] movd mm3,D [esi+ eax*4 -4] movd mm4,D [esi+ eax*4 +0] punpcklbw mm1,mm0 punpcklbw mm2,mm0 punpcklbw mm3,mm0 punpcklbw mm4,mm0 paddw mm1,mm4 pmullw mm1,Q [mmCe] pmullw mm2,Q [mmCm] pmullw mm3,Q [mmCc] paddw mm1,mm2 paddw mm1,mm3 paddsw mm1,Q [mmAdd] pmulhw mm1,Q [mmInvDiv] packuswb mm1,mm0 movd D [ebx+ aulRows],mm1 // ----------------------- process bitmap middle pixels add esi,D [slModulo1] add edi,D [slCanvasWidth] mov ebx,D [pixHeight] sub ebx,2 // for each row rowLoop: push ebx xor ebx,ebx // process left edge pixel movd mm1,D [esi+ edx*4 +0] movd mm2,D [esi+ edx*4 +4] movd mm3,D [esi+ +0] movd mm4,D [esi+ +4] movd mm5,D [esi+ eax*4 +0] movd mm6,D [esi+ eax*4 +4] punpcklbw mm1,mm0 punpcklbw mm2,mm0 punpcklbw mm3,mm0 punpcklbw mm4,mm0 punpcklbw mm5,mm0 punpcklbw mm6,mm0 paddw mm1,mm5 paddw mm2,mm6 pmullw mm1,Q [mmEch] pmullw mm2,Q [mmEcl] pmullw mm3,Q [mmEm] pmullw mm4,Q [mmEe] paddw mm1,mm2 paddw mm1,mm3 paddw mm1,mm4 paddsw mm1,Q [mmAdd] pmulhw mm1,Q [mmInvDiv] packuswb mm1,mm0 movd mm2,D [ebx+ aulRows] movd D [ebx+ aulRows],mm1 movd D [edi+ edx*4],mm2 add esi,4 add edi,4 add ebx,4 // for each pixel in current row mov ecx,D [pixWidth] sub ecx,2 pixLoop: // prepare upper convolution row movd mm1,D [esi+ edx*4 -4] movd mm2,D [esi+ edx*4 +0] movd mm3,D [esi+ edx*4 +4] punpcklbw mm1,mm0 punpcklbw mm2,mm0 punpcklbw mm3,mm0 // prepare middle convolution row movd mm4,D [esi+ -4] movd mm5,D [esi+ +0] movd mm6,D [esi+ +4] punpcklbw mm4,mm0 punpcklbw mm5,mm0 punpcklbw mm6,mm0 // free some registers paddw mm1,mm3 paddw mm2,mm4 pmullw mm5,Q [mmMm] // prepare lower convolution row movd mm3,D [esi+ eax*4 -4] movd mm4,D [esi+ eax*4 +0] movd mm7,D [esi+ eax*4 +4] punpcklbw mm3,mm0 punpcklbw mm4,mm0 punpcklbw mm7,mm0 // calc weightened value paddw mm2,mm6 paddw mm1,mm3 paddw mm2,mm4 paddw mm1,mm7 pmullw mm2,Q [mmMe] pmullw mm1,Q [mmMc] paddw mm2,mm5 paddw mm1,mm2 // calc and store wightened value paddsw mm1,Q [mmAdd] pmulhw mm1,Q [mmInvDiv] packuswb mm1,mm0 movd mm2,D [ebx+ aulRows] movd D [ebx+ aulRows],mm1 movd D [edi+ edx*4],mm2 // advance to next pixel add esi,4 add edi,4 add ebx,4 dec ecx jnz pixLoop // process right edge pixel movd mm1,D [esi+ edx*4 -4] movd mm2,D [esi+ edx*4 +0] movd mm3,D [esi+ -4] movd mm4,D [esi+ +0] movd mm5,D [esi+ eax*4 -4] movd mm6,D [esi+ eax*4 +0] punpcklbw mm1,mm0 punpcklbw mm2,mm0 punpcklbw mm3,mm0 punpcklbw mm4,mm0 punpcklbw mm5,mm0 punpcklbw mm6,mm0 paddw mm1,mm5 paddw mm2,mm6 pmullw mm1,Q [mmEcl] pmullw mm2,Q [mmEch] pmullw mm3,Q [mmEe] pmullw mm4,Q [mmEm] paddw mm1,mm2 paddw mm1,mm3 paddw mm1,mm4 paddsw mm1,Q [mmAdd] pmulhw mm1,Q [mmInvDiv] packuswb mm1,mm0 movd mm2,D [ebx+ aulRows] movd D [ebx+ aulRows],mm1 movd D [edi+ edx*4],mm2 // advance to next row add esi,D [slModulo1] add edi,D [slModulo1] pop ebx dec ebx jnz rowLoop // ----------------------- process lower left corner xor ebx,ebx movd mm1,D [esi+ edx*4 +0] movd mm2,D [esi+ edx*4 +4] movd mm3,D [esi+ +0] movd mm4,D [esi+ +4] punpcklbw mm1,mm0 punpcklbw mm2,mm0 punpcklbw mm3,mm0 punpcklbw mm4,mm0 paddw mm1,mm4 pmullw mm1,Q [mmCe] pmullw mm2,Q [mmCc] pmullw mm3,Q [mmCm] paddw mm1,mm2 paddw mm1,mm3 paddsw mm1,Q [mmAdd] pmulhw mm1,Q [mmInvDiv] packuswb mm1,mm0 movd mm2,D [ebx+ aulRows] movd D [edi],mm1 movd D [edi+ edx*4],mm2 add esi,4 add edi,4 add ebx,4 // ----------------------- process lower edge pixels mov ecx,D [pixWidth] sub ecx,2 // for each pixel lowerLoop: movd mm1,D [esi+ edx*4 -4] movd mm2,D [esi+ edx*4 +0] movd mm3,D [esi+ edx*4 +4] movd mm4,D [esi+ -4] movd mm5,D [esi+ +0] movd mm6,D [esi+ +4] punpcklbw mm1,mm0 punpcklbw mm2,mm0 punpcklbw mm3,mm0 punpcklbw mm4,mm0 punpcklbw mm5,mm0 punpcklbw mm6,mm0 paddw mm1,mm3 paddw mm4,mm6 pmullw mm1,Q [mmEcl] pmullw mm2,Q [mmEe] pmullw mm4,Q [mmEch] pmullw mm5,Q [mmEm] paddw mm1,mm2 paddw mm1,mm4 paddw mm1,mm5 paddsw mm1,Q [mmAdd] pmulhw mm1,Q [mmInvDiv] packuswb mm1,mm0 movd mm2,D [ebx+ aulRows] movd D [edi],mm1 movd D [edi+ edx*4],mm2 // advance to next pixel add esi,4 add edi,4 add ebx,4 dec ecx jnz lowerLoop // ----------------------- lower right corners movd mm1,D [esi+ edx*4 -4] movd mm2,D [esi+ edx*4 +0] movd mm3,D [esi+ -4] movd mm4,D [esi+ +0] punpcklbw mm1,mm0 punpcklbw mm2,mm0 punpcklbw mm3,mm0 punpcklbw mm4,mm0 paddw mm2,mm3 pmullw mm1,Q [mmCc] pmullw mm2,Q [mmCe] pmullw mm4,Q [mmCm] paddw mm1,mm2 paddw mm1,mm4 paddsw mm1,Q [mmAdd] pmulhw mm1,Q [mmInvDiv] packuswb mm1,mm0 movd mm2,D [ebx+ aulRows] movd D [edi],mm1 movd D [edi+ edx*4],mm2 emms } #elif (defined __GNU_INLINE_X86_32__) FB_pulSrc = pulSrc; FB_pulDst = pulDst; FB_pixWidth = pixWidth; FB_pixHeight = pixHeight; FB_pixCanvasWidth = pixCanvasWidth; FB_slModulo1 = slModulo1; FB_slCanvasWidth = slCanvasWidth; __asm__ __volatile__ ( "pushl %%ebx \n\t" "cld \n\t" "movl (" ASMSYM(FB_pixCanvasWidth) "), %%eax \n\t" // EAX = positive row offset "movl %%eax, %%edx \n\t" "negl %%edx \n\t" // EDX = negative row offset "pxor %%mm0, %%mm0 \n\t" "movl (" ASMSYM(FB_pulSrc) "), %%esi \n\t" "movl (" ASMSYM(FB_pulDst) "), %%edi \n\t" "xorl %%ebx, %%ebx \n\t" // ----------------------- process upper left corner "movd 0(%%esi), %%mm1 \n\t" "movd 4(%%esi), %%mm2 \n\t" "movd 0(%%esi, %%eax, 4), %%mm3 \n\t" "movd 4(%%esi, %%eax, 4), %%mm4 \n\t" "punpcklbw %%mm0, %%mm1 \n\t" "punpcklbw %%mm0, %%mm2 \n\t" "punpcklbw %%mm0, %%mm3 \n\t" "punpcklbw %%mm0, %%mm4 \n\t" "paddw %%mm3, %%mm2 \n\t" "pmullw (" ASMSYM(mmCm) "), %%mm1 \n\t" "pmullw (" ASMSYM(mmEch) "), %%mm2 \n\t" "pmullw (" ASMSYM(mmMc) "), %%mm4 \n\t" "paddw %%mm2, %%mm1 \n\t" "paddw %%mm4, %%mm1 \n\t" "paddsw (" ASMSYM(mmAdd) "), %%mm1 \n\t" "pmulhw (" ASMSYM(mmInvDiv) "), %%mm1 \n\t" "packuswb %%mm0, %%mm1 \n\t" "movd %%mm1, " ASMSYM(aulRows) "(%%ebx) \n\t" "add $4, %%esi \n\t" "add $4, %%ebx \n\t" // ----------------------- process upper edge pixels "movl (" ASMSYM(FB_pixWidth) "), %%ecx \n\t" "subl $2, %%ecx \n\t" // for each pixel "0: \n\t" // upperLoop "movd -4(%%esi), %%mm1 \n\t" "movd 0(%%esi), %%mm2 \n\t" "movd 4(%%esi), %%mm3 \n\t" "movd -4(%%esi, %%eax, 4), %%mm4 \n\t" "movd 0(%%esi, %%eax, 4), %%mm5 \n\t" "movd 4(%%esi, %%eax, 4), %%mm6 \n\t" "punpcklbw %%mm0, %%mm1 \n\t" "punpcklbw %%mm0, %%mm2 \n\t" "punpcklbw %%mm0, %%mm3 \n\t" "punpcklbw %%mm0, %%mm4 \n\t" "punpcklbw %%mm0, %%mm5 \n\t" "punpcklbw %%mm0, %%mm6 \n\t" "paddw %%mm3, %%mm1 \n\t" "paddw %%mm6, %%mm4 \n\t" "pmullw (" ASMSYM(mmEch) "), %%mm1 \n\t" "pmullw (" ASMSYM(mmEm) "), %%mm2 \n\t" "pmullw (" ASMSYM(mmMc) "), %%mm4 \n\t" "pmullw (" ASMSYM(mmMe) "), %%mm5 \n\t" "paddw %%mm2, %%mm1 \n\t" "paddw %%mm4, %%mm1 \n\t" "paddw %%mm5, %%mm1 \n\t" "paddsw (" ASMSYM(mmAdd) "), %%mm1 \n\t" "pmulhw (" ASMSYM(mmInvDiv) "), %%mm1 \n\t" "packuswb %%mm0, %%mm1 \n\t" "movd %%mm1, " ASMSYM(aulRows) "(%%ebx) \n\t" // advance to next pixel "addl $4, %%esi \n\t" "addl $4, %%ebx \n\t" "decl %%ecx \n\t" "jnz 0b \n\t" // upperLoop // ----------------------- process upper right corner "movd -4(%%esi), %%mm1 \n\t" "movd 0(%%esi), %%mm2 \n\t" "movd -4(%%esi, %%eax, 4), %%mm3 \n\t" "movd 0(%%esi, %%eax, 4), %%mm4 \n\t" "punpcklbw %%mm0, %%mm1 \n\t" "punpcklbw %%mm0, %%mm2 \n\t" "punpcklbw %%mm0, %%mm3 \n\t" "punpcklbw %%mm0, %%mm4 \n\t" "paddw %%mm4, %%mm1 \n\t" "pmullw (" ASMSYM(mmEch) "), %%mm1 \n\t" "pmullw (" ASMSYM(mmCm) "), %%mm2 \n\t" "pmullw (" ASMSYM(mmMc) "), %%mm3 \n\t" "paddw %%mm2, %%mm1 \n\t" "paddw %%mm3, %%mm1 \n\t" "paddsw (" ASMSYM(mmAdd) "), %%mm1 \n\t" "pmulhw (" ASMSYM(mmInvDiv) "), %%mm1 \n\t" "packuswb %%mm0, %%mm1 \n\t" "movd %%mm1, " ASMSYM(aulRows) "(%%ebx) \n\t" // ----------------------- process bitmap middle pixels "addl (" ASMSYM(FB_slModulo1) "), %%esi \n\t" "addl (" ASMSYM(FB_slCanvasWidth) "), %%edi \n\t" "movl (" ASMSYM(FB_pixHeight) "), %%ebx \n\t" "subl $2, %%ebx \n\t" // for each row "1: \n\t" // rowLoop "pushl %%ebx \n\t" "xorl %%ebx, %%ebx \n\t" // process left edge pixel "movd 0(%%esi, %%edx, 4), %%mm1 \n\t" "movd 4(%%esi, %%edx, 4), %%mm2 \n\t" "movd 0(%%esi), %%mm3 \n\t" "movd 4(%%esi), %%mm4 \n\t" "movd 0(%%esi, %%eax, 4), %%mm5 \n\t" "movd 4(%%esi, %%eax, 4), %%mm6 \n\t" "punpcklbw %%mm0, %%mm1 \n\t" "punpcklbw %%mm0, %%mm2 \n\t" "punpcklbw %%mm0, %%mm3 \n\t" "punpcklbw %%mm0, %%mm4 \n\t" "punpcklbw %%mm0, %%mm5 \n\t" "punpcklbw %%mm0, %%mm6 \n\t" "paddw %%mm5, %%mm1 \n\t" "paddw %%mm6, %%mm2 \n\t" "pmullw (" ASMSYM(mmEch) "), %%mm1 \n\t" "pmullw (" ASMSYM(mmMc) "), %%mm2 \n\t" "pmullw (" ASMSYM(mmEm) "), %%mm3 \n\t" "pmullw (" ASMSYM(mmMe) "), %%mm4 \n\t" "paddw %%mm2, %%mm1 \n\t" "paddw %%mm3, %%mm1 \n\t" "paddw %%mm4, %%mm1 \n\t" "paddsw (" ASMSYM(mmAdd) "), %%mm1 \n\t" "pmulhw (" ASMSYM(mmInvDiv) "), %%mm1 \n\t" "packuswb %%mm0, %%mm1 \n\t" "movd " ASMSYM(aulRows) "(%%ebx), %%mm2 \n\t" "movd %%mm1, " ASMSYM(aulRows) "(%%ebx) \n\t" "movd %%mm2, 0(%%edi, %%edx, 4) \n\t" "add $4, %%esi \n\t" "add $4, %%edi \n\t" "add $4, %%ebx \n\t" // for each pixel in current row "mov (" ASMSYM(FB_pixWidth) "), %%ecx \n\t" "sub $2, %%ecx \n\t" "2: \n\t" // pixLoop // prepare upper convolution row "movd -4(%%esi, %%edx, 4), %%mm1 \n\t" "movd 0(%%esi, %%edx, 4), %%mm2 \n\t" "movd 4(%%esi, %%edx, 4), %%mm3 \n\t" "punpcklbw %%mm0, %%mm1 \n\t" "punpcklbw %%mm0, %%mm2 \n\t" "punpcklbw %%mm0, %%mm3 \n\t" // prepare middle convolution row "movd -4(%%esi), %%mm4 \n\t" "movd 0(%%esi), %%mm5 \n\t" "movd 4(%%esi), %%mm6 \n\t" "punpcklbw %%mm0, %%mm4 \n\t" "punpcklbw %%mm0, %%mm5 \n\t" "punpcklbw %%mm0, %%mm6 \n\t" // free some registers "paddw %%mm3, %%mm1 \n\t" "paddw %%mm4, %%mm2 \n\t" "pmullw (" ASMSYM(mmMm) "), %%mm5 \n\t" // prepare lower convolution row "movd -4(%%esi, %%eax, 4), %%mm3 \n\t" "movd 0(%%esi, %%eax, 4), %%mm4 \n\t" "movd 4(%%esi, %%eax, 4), %%mm7 \n\t" "punpcklbw %%mm0, %%mm3 \n\t" "punpcklbw %%mm0, %%mm4 \n\t" "punpcklbw %%mm0, %%mm7 \n\t" // calc weightened value "paddw %%mm6, %%mm2 \n\t" "paddw %%mm3, %%mm1 \n\t" "paddw %%mm4, %%mm2 \n\t" "paddw %%mm7, %%mm1 \n\t" "pmullw (" ASMSYM(mmMe) "), %%mm2 \n\t" "pmullw (" ASMSYM(mmMc) "), %%mm1 \n\t" "paddw %%mm5, %%mm2 \n\t" "paddw %%mm2, %%mm1 \n\t" // calc and store wightened value "paddsw (" ASMSYM(mmAdd) "), %%mm1 \n\t" "pmulhw (" ASMSYM(mmInvDiv) "), %%mm1 \n\t" "packuswb %%mm0, %%mm1 \n\t" "movd " ASMSYM(aulRows) "(%%ebx), %%mm2 \n\t" "movd %%mm1, " ASMSYM(aulRows) "(%%ebx) \n\t" "movd %%mm2, (%%edi, %%edx, 4) \n\t" // advance to next pixel "addl $4, %%esi \n\t" "addl $4, %%edi \n\t" "addl $4, %%ebx \n\t" "decl %%ecx \n\t" "jnz 2b \n\t" // pixLoop // process right edge pixel "movd -4(%%esi, %%edx, 4), %%mm1 \n\t" "movd 0(%%esi, %%edx, 4), %%mm2 \n\t" "movd -4(%%esi), %%mm3 \n\t" "movd 0(%%esi), %%mm4 \n\t" "movd -4(%%esi, %%eax, 4), %%mm5 \n\t" "movd 0(%%esi, %%eax, 4), %%mm6 \n\t" "punpcklbw %%mm0, %%mm1 \n\t" "punpcklbw %%mm0, %%mm2 \n\t" "punpcklbw %%mm0, %%mm3 \n\t" "punpcklbw %%mm0, %%mm4 \n\t" "punpcklbw %%mm0, %%mm5 \n\t" "punpcklbw %%mm0, %%mm6 \n\t" "paddw %%mm5, %%mm1 \n\t" "paddw %%mm6, %%mm2 \n\t" "pmullw (" ASMSYM(mmMc) "), %%mm1 \n\t" "pmullw (" ASMSYM(mmEch) "), %%mm2 \n\t" "pmullw (" ASMSYM(mmMe) "), %%mm3 \n\t" "pmullw (" ASMSYM(mmEm) "), %%mm4 \n\t" "paddw %%mm2, %%mm1 \n\t" "paddw %%mm3, %%mm1 \n\t" "paddw %%mm4, %%mm1 \n\t" "paddsw (" ASMSYM(mmAdd) "), %%mm1 \n\t" "pmulhw (" ASMSYM(mmInvDiv) "), %%mm1 \n\t" "packuswb %%mm0, %%mm1 \n\t" "movd " ASMSYM(aulRows) "(%%ebx), %%mm2 \n\t" "movd %%mm1, " ASMSYM(aulRows) "(%%ebx) \n\t" "movd %%mm2, 0(%%edi, %%edx, 4) \n\t" // advance to next row "addl (" ASMSYM(FB_slModulo1) "), %%esi \n\t" // slModulo1 "addl (" ASMSYM(FB_slModulo1) "), %%edi \n\t" // slModulo1 "popl %%ebx \n\t" "decl %%ebx \n\t" "jnz 1b \n\t" // rowLoop // ----------------------- process lower left corner "xorl %%ebx, %%ebx \n\t" "movd 0(%%esi, %%edx, 4), %%mm1 \n\t" "movd 4(%%esi, %%edx, 4), %%mm2 \n\t" "movd 0(%%esi), %%mm3 \n\t" "movd 4(%%esi), %%mm4 \n\t" "punpcklbw %%mm0, %%mm1 \n\t" "punpcklbw %%mm0, %%mm2 \n\t" "punpcklbw %%mm0, %%mm3 \n\t" "punpcklbw %%mm0, %%mm4 \n\t" "paddw %%mm4, %%mm1 \n\t" "pmullw (" ASMSYM(mmEch) "), %%mm1 \n\t" "pmullw (" ASMSYM(mmMc) "), %%mm2 \n\t" "pmullw (" ASMSYM(mmCm) "), %%mm3 \n\t" "paddw %%mm2, %%mm1 \n\t" "paddw %%mm3, %%mm1 \n\t" "paddsw (" ASMSYM(mmAdd) "), %%mm1 \n\t" "pmulhw (" ASMSYM(mmInvDiv) "), %%mm1 \n\t" "packuswb %%mm0, %%mm1 \n\t" "movd " ASMSYM(aulRows) "(%%ebx), %%mm2 \n\t" "movd %%mm1, (%%edi) \n\t" "movd %%mm2, 0(%%edi, %%edx, 4) \n\t" "add $4, %%esi \n\t" "add $4, %%edi \n\t" "add $4, %%ebx \n\t" // ----------------------- process lower edge pixels "movl (" ASMSYM(FB_pixWidth) "), %%ecx \n\t" // pixWidth "subl $2, %%ecx \n\t" // for each pixel "3: \n\t" // lowerLoop "movd -4(%%esi, %%edx, 4), %%mm1 \n\t" "movd 0(%%esi, %%edx, 4), %%mm2 \n\t" "movd 4(%%esi, %%edx, 4), %%mm3 \n\t" "movd -4(%%esi), %%mm4 \n\t" "movd 0(%%esi), %%mm5 \n\t" "movd 4(%%esi), %%mm6 \n\t" "punpcklbw %%mm0, %%mm1 \n\t" "punpcklbw %%mm0, %%mm2 \n\t" "punpcklbw %%mm0, %%mm3 \n\t" "punpcklbw %%mm0, %%mm4 \n\t" "punpcklbw %%mm0, %%mm5 \n\t" "punpcklbw %%mm0, %%mm6 \n\t" "paddw %%mm3, %%mm1 \n\t" "paddw %%mm6, %%mm4 \n\t" "pmullw (" ASMSYM(mmMc) "), %%mm1 \n\t" "pmullw (" ASMSYM(mmMe) "), %%mm2 \n\t" "pmullw (" ASMSYM(mmEch) "), %%mm4 \n\t" "pmullw (" ASMSYM(mmEm) "), %%mm5 \n\t" "paddw %%mm2, %%mm1 \n\t" "paddw %%mm4, %%mm1 \n\t" "paddw %%mm5, %%mm1 \n\t" "paddsw (" ASMSYM(mmAdd) "), %%mm1 \n\t" "pmulhw (" ASMSYM(mmInvDiv) "), %%mm1 \n\t" "packuswb %%mm0, %%mm1 \n\t" "movd " ASMSYM(aulRows) "(%%ebx), %%mm2 \n\t" "movd %%mm1, (%%edi) \n\t" "movd %%mm2, 0(%%edi, %%edx, 4) \n\t" // advance to next pixel "addl $4, %%esi \n\t" "addl $4, %%edi \n\t" "addl $4, %%ebx \n\t" "decl %%ecx \n\t" "jnz 3b \n\t" // lowerLoop // ----------------------- lower right corners "movd -4(%%esi, %%edx, 4), %%mm1 \n\t" "movd 0(%%esi, %%edx, 4), %%mm2 \n\t" "movd -4(%%esi), %%mm3 \n\t" "movd 0(%%esi), %%mm4 \n\t" "punpcklbw %%mm0, %%mm1 \n\t" "punpcklbw %%mm0, %%mm2 \n\t" "punpcklbw %%mm0, %%mm3 \n\t" "punpcklbw %%mm0, %%mm4 \n\t" "paddw %%mm3, %%mm2 \n\t" "pmullw (" ASMSYM(mmMc) "), %%mm1 \n\t" "pmullw (" ASMSYM(mmEch) "), %%mm2 \n\t" "pmullw (" ASMSYM(mmCm) "), %%mm4 \n\t" "paddw %%mm2, %%mm1 \n\t" "paddw %%mm4, %%mm1 \n\t" "paddsw (" ASMSYM(mmAdd) "), %%mm1 \n\t" "pmulhw (" ASMSYM(mmInvDiv) "), %%mm1 \n\t" "packuswb %%mm0, %%mm1 \n\t" "movd " ASMSYM(aulRows) "(%%ebx), %%mm2 \n\t" "movd %%mm1, (%%edi) \n\t" "movd %%mm2, 0(%%edi, %%edx, 4) \n\t" "emms \n\t" "popl %%ebx \n\t" : // no outputs. : // inputs are all globals. : FPU_REGS, MMX_REGS, "eax", "ecx", "edx", "esi", "edi", "cc", "memory" ); #else #error Write inline asm for your platform. #endif // all done (finally) _pfGfxProfile.StopTimer( CGfxProfile::PTI_FILTERBITMAP); } // saturate color of bitmap void AdjustBitmapColor( ULONG *pulSrc, ULONG *pulDst, PIX pixWidth, PIX pixHeight, SLONG const slHueShift, SLONG const slSaturation) { for( INDEX i=0; i<(pixWidth*pixHeight); i++) { pulDst[i] = ByteSwap( AdjustColor( ByteSwap(pulSrc[i]), slHueShift, slSaturation)); } } // create mip-map table for texture or shadow of given dimensions void MakeMipmapTable( PIX pixU, PIX pixV, MipmapTable &mmt) { mmt.mmt_pixU = pixU; mmt.mmt_pixV = pixV; // start at first mip map PIX pixCurrentU = mmt.mmt_pixU; PIX pixCurrentV = mmt.mmt_pixV; INDEX iMipmapCurrent = 0; SLONG slOffsetCurrent = 0; // while the mip-map is not zero-sized while (pixCurrentU>0 && pixCurrentV>0) { // remember its offset mmt.mmt_aslOffsets[iMipmapCurrent] = slOffsetCurrent; // go to next mip map slOffsetCurrent+=pixCurrentU*pixCurrentV; iMipmapCurrent++; pixCurrentU>>=1; pixCurrentV>>=1; } // remember number of mip maps and total size mmt.mmt_ctMipmaps = iMipmapCurrent; mmt.mmt_slTotalSize = slOffsetCurrent; } // TRIANGLE MASK RENDERING (FOR MODEL CLUSTER SHADOWS) ROUTINES static ULONG *_pulTexture; static PIX _pixTexWidth, _pixTexHeight; BOOL _bSomeDarkExists = FALSE; // set texture that will be used for all subsequent triangles void SetTriangleTexture( ULONG *pulCurrentMipmap, PIX pixMipWidth, PIX pixMipHeight) { _pulTexture = pulCurrentMipmap; _pixTexWidth = pixMipWidth; _pixTexHeight = pixMipHeight; } // render one triangle to mask plane for shadow casting purposes void DrawTriangle_Mask( UBYTE *pubMaskPlane, SLONG slMaskWidth, SLONG slMaskHeight, struct PolyVertex2D *ppv2Vtx1, struct PolyVertex2D *ppv2Vtx2, struct PolyVertex2D *ppv2Vtx3, BOOL bTransparency) { struct PolyVertex2D *pUpper = ppv2Vtx1; struct PolyVertex2D *pMiddle = ppv2Vtx2; struct PolyVertex2D *pLower = ppv2Vtx3; struct PolyVertex2D *pTmp; // sort vertices by J position if( pUpper->pv2_fJ > pMiddle->pv2_fJ) { pTmp = pUpper; pUpper = pMiddle; pMiddle = pTmp; } if( pUpper->pv2_fJ > pLower->pv2_fJ) { pTmp = pUpper; pUpper = pLower; pLower = pTmp; } if( pMiddle->pv2_fJ > pLower->pv2_fJ) { pTmp = pMiddle; pMiddle = pLower; pLower = pTmp; } // determine vertical deltas FLOAT fDJShort1 = pMiddle->pv2_fJ - pUpper->pv2_fJ; FLOAT fDJShort2 = pLower->pv2_fJ - pMiddle->pv2_fJ; FLOAT fDJLong = pLower->pv2_fJ - pUpper->pv2_fJ; if( fDJLong == 0) return; // determine horizontal deltas FLOAT fDIShort1 = pMiddle->pv2_fI - pUpper->pv2_fI; FLOAT fDIShort2 = pLower->pv2_fI - pMiddle->pv2_fI; FLOAT fDILong = pLower->pv2_fI - pUpper->pv2_fI; // determine U/K, V/K and 1/K deltas FLOAT fD1oKShort1 = pMiddle->pv2_f1oK - pUpper->pv2_f1oK; FLOAT fD1oKShort2 = pLower->pv2_f1oK - pMiddle->pv2_f1oK; FLOAT fD1oKLong = pLower->pv2_f1oK - pUpper->pv2_f1oK; FLOAT fDUoKShort1 = pMiddle->pv2_fUoK - pUpper->pv2_fUoK; FLOAT fDUoKShort2 = pLower->pv2_fUoK - pMiddle->pv2_fUoK; FLOAT fDUoKLong = pLower->pv2_fUoK - pUpper->pv2_fUoK; FLOAT fDVoKShort1 = pMiddle->pv2_fVoK - pUpper->pv2_fVoK; FLOAT fDVoKShort2 = pLower->pv2_fVoK - pMiddle->pv2_fVoK; FLOAT fDVoKLong = pLower->pv2_fVoK - pUpper->pv2_fVoK; // determine stepping factors; FLOAT f1oDJShort1, f1oDJShort2, f1oDJLong; if( fDJShort1 != 0) f1oDJShort1 = 1 / fDJShort1; else f1oDJShort1 = 0; if( fDJShort2 != 0) f1oDJShort2 = 1 / fDJShort2; else f1oDJShort2 = 0; if( fDJLong != 0) f1oDJLong = 1 / fDJLong; else f1oDJLong = 0; FLOAT fDIoDJShort1 = fDIShort1 * f1oDJShort1; FLOAT fDIoDJShort2 = fDIShort2 * f1oDJShort2; FLOAT fDIoDJLong = fDILong * f1oDJLong; FLOAT fMaxWidth = fDIoDJLong*fDJShort1 + pUpper->pv2_fI - pMiddle->pv2_fI; // determine drawing direction and factors by direction SLONG direction = +1; if( fMaxWidth > 0) direction = -1; // find start and end values for J PIX pixUpJ = FloatToInt(pUpper->pv2_fJ +0.5f); PIX pixMdJ = FloatToInt(pMiddle->pv2_fJ +0.5f); PIX pixDnJ = FloatToInt(pLower->pv2_fJ +0.5f); // clip vertically if( pixDnJ<0 || pixUpJ>=slMaskHeight) return; if( pixUpJ<0) pixUpJ=0; if( pixDnJ>slMaskHeight) pixDnJ=slMaskHeight; if( pixMdJ<0) pixMdJ=0; if( pixMdJ>slMaskHeight) pixMdJ=slMaskHeight; SLONG fixWidth = slMaskWidth<<11; // find prestepped I FLOAT fPrestepUp = (FLOAT)pixUpJ - pUpper->pv2_fJ; FLOAT fPrestepMd = (FLOAT)pixMdJ - pMiddle->pv2_fJ; SLONG fixILong = FloatToInt((pUpper->pv2_fI + fPrestepUp * fDIoDJLong )*2048.0f) +fixWidth*pixUpJ; SLONG fixIShort1 = FloatToInt((pUpper->pv2_fI + fPrestepUp * fDIoDJShort1)*2048.0f) +fixWidth*pixUpJ; SLONG fixIShort2 = FloatToInt((pMiddle->pv2_fI + fPrestepMd * fDIoDJShort2)*2048.0f) +fixWidth*pixMdJ; // convert steps from floats to fixints (21:11) SLONG fixDIoDJLong = FloatToInt(fDIoDJLong *2048.0f) +fixWidth; SLONG fixDIoDJShort1 = FloatToInt(fDIoDJShort1*2048.0f) +fixWidth; SLONG fixDIoDJShort2 = FloatToInt(fDIoDJShort2*2048.0f) +fixWidth; // find row counter and max delta J SLONG ctJShort1 = pixMdJ - pixUpJ; SLONG ctJShort2 = pixDnJ - pixMdJ; SLONG ctJLong = pixDnJ - pixUpJ; FLOAT currK, curr1oK, currUoK, currVoK; PIX pixJ = pixUpJ; // if model has texture and texture has alpha channel, do complex mapping thru texture's alpha channel if( _pulTexture!=NULL && bTransparency) { // calculate some texture variables FLOAT fD1oKoDJShort1 = fD1oKShort1 * f1oDJShort1; FLOAT fD1oKoDJShort2 = fD1oKShort2 * f1oDJShort2; FLOAT fD1oKoDJLong = fD1oKLong * f1oDJLong; FLOAT fDUoKoDJShort1 = fDUoKShort1 * f1oDJShort1; FLOAT fDUoKoDJShort2 = fDUoKShort2 * f1oDJShort2; FLOAT fDUoKoDJLong = fDUoKLong * f1oDJLong; FLOAT fDVoKoDJShort1 = fDVoKShort1 * f1oDJShort1; FLOAT fDVoKoDJShort2 = fDVoKShort2 * f1oDJShort2; FLOAT fDVoKoDJLong = fDVoKLong * f1oDJLong; ;// FactOverDI = (DFoDJ * (J2-J1) + fact1 - fact2) * 1/width FLOAT f1oMaxWidth = 1 / fMaxWidth; FLOAT fD1oKoDI = (fD1oKoDJLong * fDJShort1 + pUpper->pv2_f1oK - pMiddle->pv2_f1oK) * f1oMaxWidth; FLOAT fDUoKoDI = (fDUoKoDJLong * fDJShort1 + pUpper->pv2_fUoK - pMiddle->pv2_fUoK) * f1oMaxWidth; FLOAT fDVoKoDI = (fDVoKoDJLong * fDJShort1 + pUpper->pv2_fVoK - pMiddle->pv2_fVoK) * f1oMaxWidth; if( direction == -1) { fD1oKoDI = -fD1oKoDI; fDUoKoDI = -fDUoKoDI; fDVoKoDI = -fDVoKoDI; } // find prestepped U/K, V/K, 1/K FLOAT f1oKLong = pUpper->pv2_f1oK + fPrestepUp * fD1oKoDJLong; FLOAT f1oKShort1 = pUpper->pv2_f1oK + fPrestepUp * fD1oKoDJShort1; FLOAT f1oKShort2 = pMiddle->pv2_f1oK + fPrestepMd * fD1oKoDJShort2; FLOAT fUoKLong = pUpper->pv2_fUoK + fPrestepUp * fDUoKoDJLong; FLOAT fUoKShort1 = pUpper->pv2_fUoK + fPrestepUp * fDUoKoDJShort1; FLOAT fUoKShort2 = pMiddle->pv2_fUoK + fPrestepMd * fDUoKoDJShort2; FLOAT fVoKLong = pUpper->pv2_fVoK + fPrestepUp * fDVoKoDJLong; FLOAT fVoKShort1 = pUpper->pv2_fVoK + fPrestepUp * fDVoKoDJShort1; FLOAT fVoKShort2 = pMiddle->pv2_fVoK + fPrestepMd * fDVoKoDJShort2; // render upper triangle part PIX pixTexU, pixTexV; while( ctJShort1>0) { SLONG currI = fixILong>>11; SLONG countI = abs( currI - (fixIShort1>>11)); if( countI==0) goto nextLine1; curr1oK = f1oKLong; currUoK = fUoKLong; currVoK = fVoKLong; if( direction == -1) currI--; if( countI>0) _bSomeDarkExists = TRUE; while( countI>0) { currK = 1.0f/curr1oK; pixTexU = (FloatToInt(currUoK*currK)) & (_pixTexWidth -1); pixTexV = (FloatToInt(currVoK*currK)) & (_pixTexHeight-1); if( _pulTexture[pixTexV*_pixTexWidth+pixTexU] & ((CT_rAMASK<<7)&CT_rAMASK)) pubMaskPlane[currI] = 0; curr1oK += fD1oKoDI; currUoK += fDUoKoDI; currVoK += fDVoKoDI; currI += direction; countI--; } nextLine1: pixJ++; f1oKLong += fD1oKoDJLong; f1oKShort1 += fD1oKoDJShort1; fUoKLong += fDUoKoDJLong; fUoKShort1 += fDUoKoDJShort1; fVoKLong += fDVoKoDJLong; fVoKShort1 += fDVoKoDJShort1; fixILong += fixDIoDJLong; fixIShort1 += fixDIoDJShort1; ctJShort1--; } // render lower triangle part while( ctJShort2>0) { SLONG currI = fixILong>>11; SLONG countI = abs( currI - (fixIShort2>>11)); if( countI==0) goto nextLine2; curr1oK = f1oKLong; currUoK = fUoKLong; currVoK = fVoKLong; if( direction == -1) currI--; if( countI>0) _bSomeDarkExists = TRUE; while( countI>0) { currK = 1.0f/curr1oK; pixTexU = (FloatToInt(currUoK*currK)) & (_pixTexWidth -1); pixTexV = (FloatToInt(currVoK*currK)) & (_pixTexHeight-1); if( _pulTexture[pixTexV*_pixTexWidth+pixTexU] & CT_rAMASK) pubMaskPlane[currI] = 0; curr1oK += fD1oKoDI; currUoK += fDUoKoDI; currVoK += fDVoKoDI; currI += direction; countI--; } nextLine2: pixJ++; f1oKLong += fD1oKoDJLong; f1oKShort2 += fD1oKoDJShort2; fUoKLong += fDUoKoDJLong; fUoKShort2 += fDUoKoDJShort2; fVoKLong += fDVoKoDJLong; fVoKShort2 += fDVoKoDJShort2; fixILong += fixDIoDJLong; fixIShort2 += fixDIoDJShort2; ctJShort2--; } } // simple flat mapping (no texture at all) else { // render upper triangle part while( ctJShort1>0) { SLONG currI = fixILong>>11; SLONG countI = abs( currI - (fixIShort1>>11)); if( direction == -1) currI--; if( countI>0) _bSomeDarkExists = TRUE; while( countI>0) { pubMaskPlane[currI] = 0; currI += direction; countI--; } pixJ++; fixILong += fixDIoDJLong; fixIShort1 += fixDIoDJShort1; ctJShort1--; } // render lower triangle part while( ctJShort2>0) { SLONG currI = fixILong>>11; SLONG countI = abs( currI - (fixIShort2>>11)); if( countI>0) _bSomeDarkExists = TRUE; if( direction == -1) currI--; while( countI>0) { pubMaskPlane[currI] = 0; currI += direction; countI--; } pixJ++; fixILong += fixDIoDJLong; fixIShort2 += fixDIoDJShort2; ctJShort2--; } } } // --------------------------------------------------------------------------------------------- #if 0 // bilinear filtering of lower mipmap // row loop UBYTE r,g,b,a; for( PIX v=0; v>=2; gRes >>=2; bRes >>=2; aRes >>=2; pulDstMipmap[v*pixCurrWidth+u] = RGBAToColor( rRes,gRes,bRes,aRes); } } // nearest-neighbouring of lower mipmap (with border preservance) // row loop PIX u,v; for( v=0; v4 && pixHeight>4 /*&& tex_bBicubicMipmaps*/) { for( INDEX j=0; j>8, slG>>8, slB>>8, slA>>8); pulDstMipmap[j*pixWidth+i] = ByteSwap(col); } } } // bilinear! else { } #endif