fthrconv.cpp

Go to the documentation of this file.
00001 // $Id: fthrconv.cpp 751 2006-03-31 15:43:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 #include "camtypes.h"
00100 #include "fthrconv.h"
00101 #include "bshadow.h"
00102 
00104 //
00105 //                              Shadow convolution (modified from bshadow.cpp code)
00106 //
00108 const double HalfX = 0.4999999999999 ;
00109 
00110 //
00111 // The following three functions rely on the rounding more being
00112 // round to nearest.
00113 //
00114 inline UINT32 FloorSqrt( const double D )
00115 {
00116 #if defined(_M_IX86)
00117     UINT32 I ;
00118     __asm   fld     D
00119     __asm   fsqrt
00120     __asm   fsub    HalfX
00121     __asm   fistp   I
00122     return I ;
00123 #else
00124     return (UINT32)sqrt(D) ;
00125 #endif
00126 }
00127 
00128 /******************************************************************************************************/
00129 
00130 /*
00131  Modification:-
00132  Function used to expect the bitmap of an object to be the dimensions of its bounding
00133  rectangle (ie bbox coords pixel aligned and dimensions converted to pixels, at current zoom)
00134 
00135  Given such a bitmap it expected to generate a bitmap which was nBlur pixels greater on all
00136  sides (ie dimensions increased by 2*nBlur) to cater for the amount of blurring which would
00137  extend beyond the dimensions of the src bitmap for any parts of the object which touched the
00138  src bitmaps border
00139 
00140  Feathering doesn't require this blurring outside the objects outline. Also we don't always
00141  pass in a full bitmap of the object.
00142 
00143  Modified the function to expect the src bitmap (ie pForegroundBits) to include the extra
00144  feathersized region which is needed to ensure that the bitmap lying nBlur pixels within the
00145  borders of the pForegroundBits is properly shadowed.
00146 
00147  Hence the intermediate version of the src bmp (from which the convolution is calculated)
00148  merely differs from pForeGroundBits in width, by DWORD alignment.
00149 
00150  The destination bitmap into which the convolution calculations are place, ForeGroundSize -
00151  2*nBlur pixels, wide.(DWORD aligned?).
00152 
00153  Thus the destination bitmap is the same dimensions as the viewable rectangle
00154 
00155 ALSO 
00156 changed to return lpBitmapInfo and modify a LPBYTE*
00157 
00158 USED to expect blur to be entire blur region (ie twice feather size)
00159 ie (from old code)
00160     double fNewBlur = fBlur/2.0 ;
00161     if ( fNewBlur>MAX_SHADOW_BLUR )
00162         fNewBlur = MAX_SHADOW_BLUR ;
00163     UINT32 nBlur = (UINT32)fNewBlur ;
00164   
00165 */
00166 LPBITMAPINFO Shadow32BppBitmap(const UINT32 nBlur, LPBITMAPINFO pSrcInfo, LPBYTE pSrcBits32, LPBYTE* pDestBits)
00167 {
00168     ERROR2IF(pSrcInfo->bmiHeader.biBitCount!=32, NULL, "Only supports 32bpp bitmap feathering");
00169 
00170     // Size of the original src bitmap
00171     CSize SrcBmpSize(pSrcInfo->bmiHeader.biWidth, pSrcInfo->bmiHeader.biHeight);
00172     CSize InnerBmpSizeCheck(SrcBmpSize.cx - 2*nBlur,SrcBmpSize.cy - 2*nBlur);
00173     // check convolution code will be OK
00174     if(!(InnerBmpSizeCheck.cx>1 && InnerBmpSizeCheck.cy>1))
00175     {
00176         // Gavin's CompileCode asm function (called from GenerateWallShadow) can't handle this
00177         ENSURE(FALSE, "Conv code cannot create bmp with width or height of 1.");
00178         return NULL;
00179     }
00180 
00182     // The pSrcBits32 have to be DWORD aligned
00184     // NB: OffscreenBMP's always 32Bpp. However if feathering an OffscreenBMP, the byte
00185     // width of pSrcInfo (ie pSrcInfo->bmiHeader.biWidth / 4) is won't always be DWORD
00186     // aligned (ie won't necessarily be an exact multiple of 4)
00187     // See note in GRenderRegion::CreateOffscreenState where buffer allocated
00188     const UINT32 DWordWidth = DIBUtil::ScanlineSize(SrcBmpSize.cx, 8);
00189     // Could be up to 3 pixels wider than the source
00190     UINT32 DWordPadding = DWordWidth - SrcBmpSize.cx;
00191     BOOL DWordAligned = (DWordPadding==0)? TRUE: FALSE;
00192 
00193     CSize DWordSrcBmpSize(DWordWidth, SrcBmpSize.cy);
00194 
00196     // Copy src into DWORD aligned 8bpp bmp to pass into gavin's routine (pBitmapToShadow)
00198     BYTE* pBitmapToShadow = new BYTE[DWordSrcBmpSize.cx*DWordSrcBmpSize.cy];
00199     // If the src bmp requires no dword alignment. then we simply need to transfer T value of BGRT
00200     // pixel in the 32bpp src (ie 4th BYTE of every 4 BYTES) to pBitmapToShadow
00201     //
00202     // NB if src bitmap is the offscreen bmp, then it will be DWORD aligned. Also, our background
00203     // bits are pre-initialised to 0x000000FF. Hence anything outside the nodes path in the offscreen
00204     // bitmap will already have a T value of 0xFF.
00205     //
00206     // For non-DWORD aligned src bmps, we need to ensure that the DWORD padded bytes get set to 0xFF
00207 
00208     // Now, set up the pointers to do the transfer of bits from one bitmap to the other
00209     // and move the destination pointer into position
00210 //  CONST BYTE* pSrc  = (CONST BYTE *)pSrcBits32 + 3 ;  // T value of pSrcBits32 BGRT value
00211     CONST BYTE* pSrc  = (CONST BYTE *)pSrcBits32;   // R value of pSrcBits32 BGRT value
00212     BYTE* pDest = (BYTE *)pBitmapToShadow;
00213 
00214     UINT32 ForegroundScanlineSize = SrcBmpSize.cx * 4;
00215     // transfer the source bitmap into this larger bitmap to be shadowed
00216     for ( UINT32 i=0 ; i<(UINT32)DWordSrcBmpSize.cy ; i++ )
00217     {
00218         CONST BYTE* pNextSrcLine  = pSrc +ForegroundScanlineSize;
00219               BYTE* pNextDestLine = pDest+DWordSrcBmpSize.cx;
00220         for ( UINT32 j=0 ; j<(UINT32)SrcBmpSize.cx ; j++ )
00221         {
00222             *pDest++ = *pSrc;
00223             pSrc += 4;
00224         }
00225 
00226         // set dword padding bits to background colour expected by convolution code
00227         if (!DWordAligned)
00228         {
00229             for(j=0; j<DWordPadding; j++)
00230                 *pDest++ = 0xFF;        // NB corresponds to memset(,0xFF,..) from bshadow.cpp code
00231         }
00232 
00233         pSrc  = pNextSrcLine;
00234         pDest = pNextDestLine;
00235     }
00236     
00238     // Allocate dib for convolved bmp and set up info to pass to convolution function 
00240     // Bitmap to shadow info headers
00241     BITMAPINFOHEADER SourceBI;
00242     SourceBI.biBitCount = 8;
00243     SourceBI.biWidth    = SrcBmpSize.cx;
00244     SourceBI.biHeight   = SrcBmpSize.cy;
00245     SourceBI.biPlanes   = 1;
00246 
00247     // Alloc a DIB to shadow into (also sets up info header)
00248     CSize InnerBmpSize(SrcBmpSize.cx - 2*nBlur,SrcBmpSize.cy - 2*nBlur);
00249     LPBITMAPINFO pDestInfo = AllocDIB( InnerBmpSize.cx, InnerBmpSize.cy, 8, pDestBits, NULL, TRUE);
00250     if(pDestInfo==NULL)
00251     {
00252         ENSURE(FALSE,"Failed to allocate space for shadow bitmap!");
00253         delete [] pBitmapToShadow;
00254         return NULL;
00255     }
00256     pDestInfo->bmiHeader.biXPelsPerMeter = pSrcInfo->bmiHeader.biXPelsPerMeter;
00257     pDestInfo->bmiHeader.biYPelsPerMeter = pSrcInfo->bmiHeader.biYPelsPerMeter;
00258 
00260     // set up the row & columns - a circular patch
00262     DWORD Left [CBitmapShadow::MAX_ROW_OFFSETS] ;
00263     DWORD Right[CBitmapShadow::MAX_ROW_OFFSETS] ;
00264     DWORD Low  [CBitmapShadow::MAX_ROW_OFFSETS] ;
00265     DWORD High [CBitmapShadow::MAX_ROW_OFFSETS] ;
00266     UINT32 nSize = nBlur*2+1 ;
00267     double S  = nBlur ;
00268     const double R2 = nBlur * nBlur;
00269     UINT32 nLine = nBlur ;
00270     UINT32 nArea = 0 ;
00271     UINT32 nRows = 0 ;
00272     for ( UINT32 r=0 ; r<nSize ; ++r )
00273     {
00274         const double Radius2 = R2-S*S ;
00275         if ( Radius2>=0 )
00276         {
00277             const UINT32 nRadius = FloorSqrt(Radius2) ;
00278              Left[nRows] = nLine-nRadius ;
00279             Right[nRows] = nLine+nRadius+1 ;
00280             if ( Left[nRows]<Right[nRows] )
00281             {
00282                   Low[nRows] = (nBlur-nRadius  )*DWordSrcBmpSize.cx+r ;
00283                  High[nRows] = (nBlur+nRadius+1)*DWordSrcBmpSize.cx+r ;
00284                 nArea += Right[nRows]-Left[nRows] ;
00285                 nRows++ ;
00286             }
00287         }
00288         S-- ;
00289         nLine += DWordSrcBmpSize.cx ;
00290     }
00291 
00292     UINT32 nTableSize = nArea*255 ;
00293     UINT32 nInc = 0xffffffffu/nTableSize ;
00294     UINT32 nShift = 0 ;
00295     while ( nTableSize>=CBitmapShadow::TABLE_SIZE )
00296     {
00297         nTableSize >>= 1 ;
00298         nShift++ ;
00299     }
00300     nInc <<= nShift ;
00301     BYTE* pTranslationTable = new BYTE[nTableSize+1] ;
00302     UINT32 nCount = 0 ;
00303     for ( i=0 ; i<=nTableSize ; ++i )
00304     {
00305         pTranslationTable[i] = nCount>>24 ;
00306         nCount += nInc ;
00307     }
00308 
00309 
00311     // call gavin's routine to do the shadowing
00313     CBitmapShadow::GenerateWallShadow(
00314         &SourceBI, pBitmapToShadow,
00315         &pDestInfo->bmiHeader, *pDestBits,
00316         nRows, Left,Right,
00317         nRows, Low,High,
00318         nShift,pTranslationTable
00319     ) ; 
00320 
00322     // clean up intermediate bitmap and translation table
00324     delete [] pBitmapToShadow;
00325     delete [] pTranslationTable;
00326 
00327     return pDestInfo;
00328 }
00329 
00330 
00331 LPBITMAPINFO Shadow8BppBitmap(const UINT32 nBlur, LPBITMAPINFO pSrcInfo, LPBYTE pSrcBits8, LPBYTE* pDestBits)
00332 {
00333     ERROR2IF(pSrcInfo->bmiHeader.biBitCount!=8, NULL, "Only supports 8bpp bitmap feathering");
00334 
00335     // Size of the original src bitmap
00336     CSize SrcBmpSize(pSrcInfo->bmiHeader.biWidth, pSrcInfo->bmiHeader.biHeight);
00337     CSize InnerBmpSizeCheck(SrcBmpSize.cx - 2*nBlur,SrcBmpSize.cy - 2*nBlur);
00338     // check convolution code will be OK
00339     if(!(InnerBmpSizeCheck.cx>1 && InnerBmpSizeCheck.cy>1))
00340     {
00341         // Gavin's CompileCode asm function (called from GenerateWallShadow) can't handle this
00342         ENSURE(FALSE, "Conv code cannot create bmp with width or height of 1.");
00343         return NULL;
00344     }
00345 
00347     // The pSrcBits8 must already be DWORD aligned
00349     const UINT32 DWordWidth = DIBUtil::ScanlineSize(SrcBmpSize.cx, 8);
00350     // Could be up to 3 pixels wider than the source
00351     UINT32 DWordPadding = DWordWidth - SrcBmpSize.cx;
00352     BOOL DWordAligned = (DWordPadding==0)? TRUE: FALSE;
00353 
00354     CSize DWordSrcBmpSize(DWordWidth, SrcBmpSize.cy);
00355     BYTE* pBitmapToShadow=NULL;
00356     if(DWordAligned)
00357     {
00358         pBitmapToShadow = pSrcBits8;
00359     }
00360     else
00361     {
00362         // assuming that 8bpp buffer is actually dword aligned
00363         // NB all buffers allocated by DIBUtil::Alloc dib are actually DWORD aligned even though
00364         // the bitmap info width/heigth info doesn't reflect this
00365 
00366         pBitmapToShadow = pSrcBits8;
00367     }
00368     
00370     // Allocate dib for convolved bmp and set up info to pass to convolution function 
00372     // Bitmap to shadow info headers
00373     BITMAPINFOHEADER SourceBI;
00374     SourceBI.biBitCount = 8;
00375     SourceBI.biWidth    = SrcBmpSize.cx;
00376     SourceBI.biHeight   = SrcBmpSize.cy;
00377     SourceBI.biPlanes   = 1;
00378 
00379     // Alloc a DIB to shadow into (also sets up info header)
00380     CSize InnerBmpSize(SrcBmpSize.cx - 2*nBlur,SrcBmpSize.cy - 2*nBlur);
00381     LPBITMAPINFO pDestInfo = AllocDIB( InnerBmpSize.cx, InnerBmpSize.cy, 8, pDestBits, NULL, TRUE);
00382     if(pDestInfo==NULL)
00383     {
00384         ENSURE(FALSE,"Failed to allocate space for shadow bitmap!");
00385         return NULL;
00386     }
00387     pDestInfo->bmiHeader.biXPelsPerMeter = pSrcInfo->bmiHeader.biXPelsPerMeter;
00388     pDestInfo->bmiHeader.biYPelsPerMeter = pSrcInfo->bmiHeader.biYPelsPerMeter;
00389 
00391     // set up the row & columns - a circular patch
00393     DWORD Left [CBitmapShadow::MAX_ROW_OFFSETS] ;
00394     DWORD Right[CBitmapShadow::MAX_ROW_OFFSETS] ;
00395     DWORD Low  [CBitmapShadow::MAX_ROW_OFFSETS] ;
00396     DWORD High [CBitmapShadow::MAX_ROW_OFFSETS] ;
00397     UINT32 nSize = nBlur*2+1 ;
00398     double S  = nBlur ;
00399     const double R2 = nBlur * nBlur;
00400     UINT32 nLine = nBlur ;
00401     UINT32 nArea = 0 ;
00402     UINT32 nRows = 0 ;
00403     for ( UINT32 r=0 ; r<nSize ; ++r )
00404     {
00405         const double Radius2 = R2-S*S ;
00406         if ( Radius2>=0 )
00407         {
00408             const UINT32 nRadius = FloorSqrt(Radius2) ;
00409              Left[nRows] = nLine-nRadius ;
00410             Right[nRows] = nLine+nRadius+1 ;
00411             if ( Left[nRows]<Right[nRows] )
00412             {
00413                   Low[nRows] = (nBlur-nRadius  )*DWordSrcBmpSize.cx+r ;
00414                  High[nRows] = (nBlur+nRadius+1)*DWordSrcBmpSize.cx+r ;
00415                 nArea += Right[nRows]-Left[nRows] ;
00416                 nRows++ ;
00417             }
00418         }
00419         S-- ;
00420         nLine += DWordSrcBmpSize.cx ;
00421     }
00422 
00423     UINT32 nTableSize = nArea*255 ;
00424     UINT32 nInc = 0xffffffffu/nTableSize ;
00425     UINT32 nShift = 0 ;
00426     while ( nTableSize>=CBitmapShadow::TABLE_SIZE )
00427     {
00428         nTableSize >>= 1 ;
00429         nShift++ ;
00430     }
00431     nInc <<= nShift ;
00432     BYTE* pTranslationTable = new BYTE[nTableSize+1] ;
00433     UINT32 nCount = 0 ;
00434     for (UINT32 i=0 ; i<=nTableSize ; ++i )
00435     {
00436         pTranslationTable[i] = nCount>>24 ;
00437         nCount += nInc ;
00438     }
00439 
00440 
00442     // call gavin's routine to do the shadowing
00444     CBitmapShadow::GenerateWallShadow(
00445         &SourceBI, pBitmapToShadow,
00446         &pDestInfo->bmiHeader, *pDestBits,
00447         nRows, Left,Right,
00448         nRows, Low,High,
00449         nShift,pTranslationTable
00450     ) ; 
00451 
00453     // clean up intermediate bitmap and translation table
00455 //  delete [] pBitmapToShadow;
00456     delete [] pTranslationTable;
00457 
00458     return pDestInfo;
00459 }

Generated on Sat Nov 10 03:45:24 2007 for Camelot by  doxygen 1.4.4