diff options
author | Thorsten Behrens <thb@openoffice.org> | 2006-07-27 10:35:32 +0000 |
---|---|---|
committer | Thorsten Behrens <thb@openoffice.org> | 2006-07-27 10:35:32 +0000 |
commit | 8c044545bbfd533f94743a7d6cb76da5844a9e3e (patch) | |
tree | a3df72dd0c7e673d673d017e0ec6268687b38a66 /basebmp | |
parent | 3df3d44e8776a1384a6a3bd7209a6ed09b5f347a (diff) |
#i65904# Dumped basegfx polygon raster converter in favor of a specialized solution; constructing all accessors with passed parameter now for the BitmapRenderer; significantly improved test coverage for polygon rasterizing
Diffstat (limited to 'basebmp')
-rw-r--r-- | basebmp/inc/basebmp/clippedlinerenderer.hxx | 6 | ||||
-rw-r--r-- | basebmp/inc/basebmp/linerenderer.hxx | 6 | ||||
-rw-r--r-- | basebmp/inc/basebmp/polypolygonrenderer.hxx | 360 | ||||
-rw-r--r-- | basebmp/inc/basebmp/scaleimage.hxx | 29 | ||||
-rw-r--r-- | basebmp/source/bitmapdevice.cxx | 116 | ||||
-rw-r--r-- | basebmp/source/makefile.mk | 7 | ||||
-rw-r--r-- | basebmp/source/polypolygonrenderer.cxx | 135 | ||||
-rw-r--r-- | basebmp/test/bmpdemo.cxx | 25 | ||||
-rw-r--r-- | basebmp/test/filltest.cxx | 6 | ||||
-rw-r--r-- | basebmp/test/makefile.mk | 5 | ||||
-rw-r--r-- | basebmp/test/polytest.cxx | 317 |
11 files changed, 897 insertions, 115 deletions
diff --git a/basebmp/inc/basebmp/clippedlinerenderer.hxx b/basebmp/inc/basebmp/clippedlinerenderer.hxx index 72b768f66fef..0f26309c30d5 100644 --- a/basebmp/inc/basebmp/clippedlinerenderer.hxx +++ b/basebmp/inc/basebmp/clippedlinerenderer.hxx @@ -4,9 +4,9 @@ * * $RCSfile: clippedlinerenderer.hxx,v $ * - * $Revision: 1.6 $ + * $Revision: 1.7 $ * - * last change: $Author: thb $ $Date: 2006-07-11 11:38:54 $ + * last change: $Author: thb $ $Date: 2006-07-27 11:35:31 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. @@ -209,7 +209,7 @@ inline bool prepareClip( sal_Int32 a1, pixel, the pixel closer to pt1 will be chosen. Giving true here makes renderClippedLine() choose pt2 in those cases. */ -template< class Iterator, class Accessor > +template< class Iterator, class Accessor > inline void renderClippedLine( basegfx::B2IPoint aPt1, basegfx::B2IPoint aPt2, const basegfx::B2IRange& rClipRect, diff --git a/basebmp/inc/basebmp/linerenderer.hxx b/basebmp/inc/basebmp/linerenderer.hxx index c151c0d1010b..df58c6f56742 100644 --- a/basebmp/inc/basebmp/linerenderer.hxx +++ b/basebmp/inc/basebmp/linerenderer.hxx @@ -4,9 +4,9 @@ * * $RCSfile: linerenderer.hxx,v $ * - * $Revision: 1.4 $ + * $Revision: 1.5 $ * - * last change: $Author: thb $ $Date: 2006-07-11 11:38:55 $ + * last change: $Author: thb $ $Date: 2006-07-27 11:35:31 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. @@ -79,7 +79,7 @@ namespace basebmp pixel, the pixel closer to pt1 will be chosen. Giving true here makes renderClippedLine() choose pt2 in those cases. */ -template< class Iterator, class Accessor > +template< class Iterator, class Accessor > inline void renderLine( const basegfx::B2IPoint& rPt1, const basegfx::B2IPoint& rPt2, typename Accessor::value_type color, diff --git a/basebmp/inc/basebmp/polypolygonrenderer.hxx b/basebmp/inc/basebmp/polypolygonrenderer.hxx new file mode 100644 index 000000000000..2a02c96ceca0 --- /dev/null +++ b/basebmp/inc/basebmp/polypolygonrenderer.hxx @@ -0,0 +1,360 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: polypolygonrenderer.hxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: thb $ $Date: 2006-07-27 11:35:31 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#ifndef INCLUDED_BASEBMP_POLYPOLYGONRENDERER_HXX +#define INCLUDED_BASEBMP_POLYPOLYGONRENDERER_HXX + +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/range/b2irange.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <vigra/diff2d.hxx> +#include <vigra/iteratortraits.hxx> + +#include <vector> + + +namespace basebmp +{ + namespace detail + { + /// convert int32 to 32:32 fixed point + inline sal_Int64 toFractional( sal_Int32 v ) { return (sal_Int64)v << 32; } + /// convert double to 32:32 fixed point + inline sal_Int64 toFractional( double v ) { return (sal_Int64)(v*SAL_MAX_UINT32 + (v < 0.0 ? -0.5 : 0.5 )); } + /// convert 32:32 fixed point to int32 (truncate) + inline sal_Int32 toInteger( sal_Int64 v ) { return v < 0 ? ~((~v) >> 32) : v >> 32; } + /// convert 32:32 fixed point to int32 (properly rounded) + inline sal_Int32 toRoundedInteger( sal_Int64 v ) { return toInteger(v) + ((v&0x80000000) >> 31); } + + /** internal vertex store - + + Different from B2DPoint, since we don't need floating + point coords, but orientation of vertex and y counter + */ + struct Vertex + { + sal_Int32 mnYCounter; + sal_Int64 mnX; + sal_Int64 mnXDelta; + + bool mbDownwards; // needed for nonzero winding rule + // fills + + Vertex() : + mnYCounter(0), + mnX(0), + mnXDelta(0), + mbDownwards(true) + {} + Vertex( basegfx::B2DPoint const& rPt1, + basegfx::B2DPoint const& rPt2, + bool bDownwards ) : + mnYCounter( basegfx::fround(rPt2.getY()) - + basegfx::fround(rPt1.getY()) ), + mnX( toFractional( basegfx::fround(rPt1.getX()) )), + mnXDelta( toFractional( + ((rPt2.getX() - rPt1.getX()) / + (double)mnYCounter) )), + mbDownwards(bDownwards) + {} + }; + + typedef std::vector< std::vector<Vertex> > VectorOfVectorOfVertices; + typedef std::vector< Vertex* > VectorOfVertexPtr; + + /// non-templated setup of GET + sal_uInt32 setupGlobalEdgeTable( VectorOfVectorOfVertices& rGET, + basegfx::B2DPolyPolygon const& rPoly, + sal_Int32 nMinY ); + /// sort rAETSrc, copy not-yet-ended edges over to rAETDest + void sortAET( VectorOfVertexPtr& rAETSrc, + VectorOfVertexPtr& rAETDest ); + + /// For the STL algorithms + struct RasterConvertVertexComparator + { + bool operator()( const Vertex& rLHS, + const Vertex& rRHS ) const + { + return rLHS.mnX < rRHS.mnX; + } + + bool operator()( const Vertex* pLHS, + const Vertex* pRHS ) const + { + return pLHS->mnX < pRHS->mnX; + } + }; + + } // namespace detail + + + /** Raster-convert a poly-polygon. + + This algorithm does not perform antialiasing, and thus + internally works with integer vertex coordinates. + + @param begin + Left, top edge of the destination bitmap. This position is + considered (0,0) relative to all polygon vertices + + @param ad + Accessor to set pixel values + + @param fillColor + Color to use for filling + + @param rClipRect + Clipping rectangle, relative to the begin iterator. No pixel outside + this clip rect will be modified. + + @param rPoly + Polygon to fill + */ + template< class DestIterator, class DestAccessor, typename T > inline + void renderClippedPolyPolygon( DestIterator begin, + DestAccessor ad, + T fillColor, + const basegfx::B2IRange& rClipRect, + basegfx::B2DPolyPolygon const& rPoly ) + { + const sal_Int32 nClipX1( std::max((sal_Int32)0,rClipRect.getMinX()) ); + const sal_Int32 nClipX2( rClipRect.getMaxX() ); + const sal_Int32 nClipY1( std::max((sal_Int32)0,rClipRect.getMinY()) ); + const sal_Int32 nClipY2( rClipRect.getMaxY() ); + const sal_Int64 nClipX1_frac( detail::toFractional(nClipX1) ); + const sal_Int64 nClipX2_frac( detail::toFractional(nClipX2) ); + + basegfx::B2DRange const aPolyBounds( basegfx::tools::getRange(rPoly) ); + + const sal_Int32 nMinY( basegfx::fround(aPolyBounds.getMinY()) ); + const sal_Int32 nMaxY( + std::min( + nClipY2-1, + basegfx::fround(aPolyBounds.getMaxY()))); + + if( nMinY > nMaxY ) + return; // really, nothing to do then. + + detail::VectorOfVectorOfVertices aGET; // the Global Edge Table + aGET.resize( nMaxY - nMinY + 1 ); + + sal_uInt32 const nVertexCount( + detail::setupGlobalEdgeTable( aGET, rPoly, nMinY ) ); + + + // Perform actual scan conversion + //---------------------------------------------------------------------- + + if( aGET.empty() ) + return; + + detail::VectorOfVertexPtr aAET1; // the Active Edge Table + detail::VectorOfVertexPtr aAET2; + detail::VectorOfVertexPtr* pAET = &aAET1; + detail::VectorOfVertexPtr* pAETOther = &aAET2; + aAET1.reserve( nVertexCount ); + aAET2.reserve( nVertexCount ); + + // current scanline - initially, points to first scanline + // within the clip rect, or to the polygon's first scanline + // (whichever is greater) + DestIterator aScanline( begin + + vigra::Diff2D( + 0, + std::max(nMinY, + nClipY1)) ); + detail::RasterConvertVertexComparator aComp; + + + // now process each of the nMaxY - nMinY + 1 scanlines + // ------------------------------------------------------------ + + for( sal_Int32 y=nMinY; y <= nMaxY; ++y ) + { + if( !aGET[y-nMinY].empty() ) + { + // merge AET with current scanline's new vertices (both + // are already correctly sorted) + detail::VectorOfVectorOfVertices::value_type::iterator vertex=aGET[y-nMinY].begin(); + detail::VectorOfVectorOfVertices::value_type::iterator const end=aGET[y-nMinY].end(); + while( vertex != end ) + { + // find insertion pos by binary search, and put ptr + // into active edge vector + pAET->insert( std::lower_bound( pAET->begin(), + pAET->end(), + &(*vertex), + aComp ), + &(*vertex) ); + + ++vertex; + } + } + + // with less than two active edges, no fill visible + if( pAET->size() >= 2 ) + { + typename vigra::IteratorTraits<DestIterator>::row_iterator + rowIter( aScanline.rowIterator() ); + + // process each span in current scanline, with + // even-odd fill rule + detail::VectorOfVertexPtr::iterator currVertex( pAET->begin() ); + detail::VectorOfVertexPtr::iterator const lastVertex( pAET->end()-1 ); + sal_uInt32 nVertexCount(0); + while( currVertex != lastVertex ) + { + // TODO(P1): might be worth a try to extend the + // size()==2 case also to the actual filling + // here. YMMV. + detail::Vertex& rV1( **currVertex ); + detail::Vertex const& rV2( **++currVertex ); + + // even/odd fillrule + if( !(nVertexCount & 0x01) && + y >= nClipY1 && + rV1.mnX < nClipX2_frac && + rV2.mnX > nClipX1_frac ) + { + // clip span to horizontal bounds + sal_Int32 const nStartX( + std::max( nClipX1, + std::min( nClipX2-1, + detail::toRoundedInteger(rV1.mnX) ))); + sal_Int32 const nEndX( + std::max( nClipX1, + std::min( nClipX2, + detail::toRoundedInteger(rV2.mnX) ))); + + typename vigra::IteratorTraits<DestIterator>::row_iterator + currPix( rowIter + nStartX); + typename vigra::IteratorTraits<DestIterator>::row_iterator + rowEnd( rowIter + nEndX ); + + // TODO(P2): Provide specialized span fill methods on the + // iterator/accessor + while( currPix != rowEnd ) + ad.set(fillColor, currPix++); + } + + // step vertices + rV1.mnX += rV1.mnXDelta; + --rV1.mnYCounter; + + ++nVertexCount; + } + + // step vertex also for the last one + detail::Vertex& rLastV( **currVertex ); + rLastV.mnX += rLastV.mnXDelta; + --rLastV.mnYCounter; + + + // prune AET from ended edges, and keep it sorted + // --------------------------------------------------------- + + pAETOther->clear(); + if( pAET->size() == 2 ) + { + // the case of exactly two active edges is both + // sufficiently common (all 'simple' polygons have + // it), and further more would complicate the + // generic case below (which works with a sliding + // triple of vertices). + if( !aComp(*(*pAET)[0], *(*pAET)[1]) ) + std::swap(*(*pAET)[0], *(*pAET)[1]); + + if( (*pAET)[0]->mnYCounter > 0 ) + pAETOther->push_back( (*pAET)[0] ); + if( (*pAET)[1]->mnYCounter > 0 ) + pAETOther->push_back( (*pAET)[1] ); + } + else + { + bool bFallbackTaken(false); + currVertex = pAET->begin(); + detail::VectorOfVertexPtr::iterator prevVertex( currVertex ); + while( currVertex != lastVertex ) + { + // try to get away with one linear swoop and + // simple neighbor swapping. this is an + // overwhelmingly common case - polygons with + // excessively crisscrossing edges (which on + // top of that cross more than one other edge + // per scanline) are seldom. And even if we + // get such a beast here, this extra loop has + // still only linear cost + if( aComp(**(currVertex+1),**currVertex) ) + { + std::swap(*currVertex, *(currVertex+1)); + + if( aComp(**currVertex,**prevVertex) ) + { + // one swap was not sufficient - + // fallback to generic sort algo, then + detail::sortAET(*pAET, *pAETOther); + bFallbackTaken = true; + break; + } + } + + if( (*currVertex)->mnYCounter > 0 ) + pAETOther->push_back( *currVertex ); + + prevVertex = currVertex++; + } + + // don't forget to add last vertex (loop above + // only deals with n-1 vertices) + if( !bFallbackTaken && (*currVertex)->mnYCounter > 0 ) + pAETOther->push_back( *currVertex ); + } + + std::swap( pAET, pAETOther ); + } + + if( y >= nClipY1 ) + ++aScanline.y; + } + } + +} // namespace basebmp + +#endif /* INCLUDED_BASEBMP_POLYPOLYGONRENDERER_HXX */ diff --git a/basebmp/inc/basebmp/scaleimage.hxx b/basebmp/inc/basebmp/scaleimage.hxx index f3231dec2e9b..af8557175e04 100644 --- a/basebmp/inc/basebmp/scaleimage.hxx +++ b/basebmp/inc/basebmp/scaleimage.hxx @@ -4,9 +4,9 @@ * * $RCSfile: scaleimage.hxx,v $ * - * $Revision: 1.1 $ + * $Revision: 1.2 $ * - * last change: $Author: thb $ $Date: 2006-07-14 14:22:58 $ + * last change: $Author: thb $ $Date: 2006-07-27 11:35:31 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. @@ -97,6 +97,29 @@ inline void scaleLine( SourceIter s_begin, } } +/** Scale an image using zero order interpolation (pixel replication) + + Source and destination range must be at least one pixel wide and + high. + + @param s_begin + Start iterator for source image + + @param s_end + End iterator for source image + + @param s_acc + Source accessor + + @param d_begin + Start iterator for destination image + + @param d_end + End iterator for destination image + + @param d_acc + Destination accessor + */ template< class SourceIter, class SourceAcc, class DestIter, class DestAcc > inline void scaleImage( SourceIter s_begin, @@ -142,6 +165,8 @@ inline void scaleImage( SourceIter s_begin, } } +/** Scale an image, range tuple version + */ template< class SourceIter, class SourceAcc, class DestIter, class DestAcc > inline void scaleImage( vigra::triple<SourceIter,SourceIter,SourceAcc> const& src, diff --git a/basebmp/source/bitmapdevice.cxx b/basebmp/source/bitmapdevice.cxx index 324422c23ac2..63d0a41c12e2 100644 --- a/basebmp/source/bitmapdevice.cxx +++ b/basebmp/source/bitmapdevice.cxx @@ -4,9 +4,9 @@ * * $RCSfile: bitmapdevice.cxx,v $ * - * $Revision: 1.23 $ + * $Revision: 1.24 $ * - * last change: $Author: thb $ $Date: 2006-07-21 20:57:06 $ + * last change: $Author: thb $ $Date: 2006-07-27 11:35:31 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. @@ -56,6 +56,7 @@ #include "basebmp/fillimage.hxx" #include "basebmp/scaleimage.hxx" #include "basebmp/clippedlinerenderer.hxx" +#include "basebmp/polypolygonrenderer.hxx" //#include "basebmp/genericintegerimageaccessor.hxx" #include "basebmp/tools.hxx" @@ -70,9 +71,7 @@ #include <basegfx/range/b2drange.hxx> #include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> -#include <basegfx/polygon/b2dpolygonclipper.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx> -#include <basegfx/polygon/b2dpolypolygonrasterconverter.hxx> #include <basegfx/point/b2ipoint.hxx> #include <basegfx/vector/b2ivector.hxx> @@ -173,85 +172,6 @@ namespace }; - // Polygon scanline conversion - //------------------------------------------------------------------------ - - template< class DestIterator, class DestAccessor > class Renderer : - public basegfx::B2DPolyPolygonRasterConverter - { - private: - basegfx::B2IRange bounds_; - typename DestAccessor::value_type fillColor_; - typename DestAccessor::value_type clearColor_; - DestIterator begin_; - DestAccessor accessor_; - - public: - Renderer(const basegfx::B2DPolyPolygon& rPolyPolyRaster, - typename DestAccessor::value_type fillColor, - const basegfx::B2IRange& bounds, - DestIterator begin, - DestAccessor accessor ) : - B2DPolyPolygonRasterConverter(rPolyPolyRaster, - basegfx::B2DRange(bounds) ), - bounds_(bounds), - fillColor_( fillColor ), - begin_( begin ), - accessor_( accessor ) - { - } - - virtual void span(const double& rfXLeft, - const double& rfXRight, - sal_Int32 nY, - bool bOn ) - { - if( !bOn || - nY < bounds_.getMinY() || - nY >= bounds_.getMaxY() || - rfXLeft >= bounds_.getMaxX() || - rfXRight < bounds_.getMinX() ) - { - return; - } - - // clip span to bitmap bounds - const sal_Int32 nStartX( std::max( bounds_.getMinX(), - std::min( bounds_.getMaxX()-1, - basegfx::fround( rfXLeft )))); - const sal_Int32 nEndX ( std::max( bounds_.getMinX(), - std::min( bounds_.getMaxX(), - basegfx::fround( rfXRight )))); - - DestIterator currIter( begin_ + vigra::Diff2D(0,nY) ); - typename vigra::IteratorTraits<DestIterator>::row_iterator - rowIter( currIter.rowIterator() + nStartX); - typename vigra::IteratorTraits<DestIterator>::row_iterator - rowEnd( currIter.rowIterator() + nEndX ); - - // TODO(P2): Provide specialized span fill methods on the - // iterator/accessor - while( rowIter != rowEnd ) - accessor_.set(fillColor_, rowIter++); - } - }; - - template< class DestIterator, class DestAccessor > - std::auto_ptr< Renderer< DestIterator, DestAccessor > > makeRenderer( - const basegfx::B2DPolyPolygon& rPolyPolyRaster, - typename DestAccessor::value_type fillColor, - const basegfx::B2IRange& outRange, - const DestIterator& begin, - const DestAccessor& acc ) - { - return std::auto_ptr< Renderer< DestIterator, DestAccessor > >( - new Renderer< DestIterator, DestAccessor >(rPolyPolyRaster, - fillColor, - outRange, - begin, - acc)); - } - // Actual BitmapDevice implementation (templatized by accessor and iterator) //-------------------------------------------------------------------------- @@ -396,6 +316,7 @@ namespace sal_Int32 nScanlineStride, sal_uInt8* pFirstScanline, dest_iterator_type begin, + raw_accessor_type rawAccessor, dest_accessor_type accessor, const RawMemorySharedArray& rMem, const PaletteMemorySharedVector& rPalette ) : @@ -406,15 +327,15 @@ namespace maToUInt32Converter(), maAccessor( accessor ), maColorBlendAccessor( accessor ), - maRawAccessor(), + maRawAccessor( rawAccessor ), maXorAccessor( accessor ), - maRawXorAccessor(), + maRawXorAccessor( rawAccessor ), maMaskedAccessor( accessor ), maMaskedColorBlendAccessor( maColorBlendAccessor ), maMaskedXorAccessor( accessor ), - maRawMaskedAccessor(), - maRawMaskedXorAccessor(), - maRawMaskedMaskAccessor() + maRawMaskedAccessor( rawAccessor ), + maRawMaskedXorAccessor( rawAccessor ), + maRawMaskedMaskAccessor( rawAccessor ) {} private: @@ -684,13 +605,12 @@ namespace if( rPoly.areControlVectorsUsed() ) aPoly = basegfx::tools::adaptiveSubdivideByCount( rPoly ); - makeRenderer( aPoly, - maColorLookup( maAccessor, - col), - rBounds, - begin, - acc )->rasterConvert( - basegfx::FillRule_NONZERO_WINDING_NUMBER ); + renderClippedPolyPolygon( begin, + acc, + maColorLookup( maAccessor, + col), + rBounds, + aPoly ); } virtual void fillPolyPolygon_i(const basegfx::B2DPolyPolygon& rPoly, @@ -1773,6 +1693,7 @@ BitmapDeviceSharedPtr createRenderer( sal_Int32 nScanlineFormat, sal_Int32 nScanlineStride, sal_uInt8* pFirstScanline, + typename FormatTraits::raw_accessor_type const& rRawAccessor, typename FormatTraits::accessor_selector::template wrap_accessor< typename FormatTraits::raw_accessor_type>::type const& rAccessor, boost::shared_array< sal_uInt8 > pMem, @@ -1809,6 +1730,7 @@ BitmapDeviceSharedPtr createRenderer( reinterpret_cast<typename Iterator::value_type*>( pFirstScanline), nScanlineStride), + rRawAccessor, rAccessor, pMem, pPal )); @@ -1851,6 +1773,7 @@ BitmapDeviceSharedPtr createRenderer( nScanlineFormat, nScanlineStride, pFirstScanline, + typename FormatTraits::raw_accessor_type(), typename FormatTraits::accessor_selector::template wrap_accessor< typename FormatTraits::raw_accessor_type>::type(), @@ -1879,6 +1802,7 @@ BitmapDeviceSharedPtr createRenderer( nScanlineFormat, nScanlineStride, pFirstScanline, + typename FormatTraits::raw_accessor_type(), typename FormatTraits::accessor_selector::template wrap_accessor< typename FormatTraits::raw_accessor_type>::type( @@ -2170,6 +2094,8 @@ BitmapDeviceSharedPtr BitmapDevice::getGenericRenderer() const getScanlineStride(), mpImpl->mpFirstScanline, PixelFormatTraits_GenericInteger::iterator_type(), + GenericIntegerImageRawAccessor<Color>( + const_cast<BitmapDevice*>(this)->shared_from_this()), GenericIntegerImageAccessor<Color>( const_cast<BitmapDevice*>(this)->shared_from_this()), getBuffer(), diff --git a/basebmp/source/makefile.mk b/basebmp/source/makefile.mk index da5006e0c07e..30d8433b363b 100644 --- a/basebmp/source/makefile.mk +++ b/basebmp/source/makefile.mk @@ -4,9 +4,9 @@ # # $RCSfile: makefile.mk,v $ # -# $Revision: 1.4 $ +# $Revision: 1.5 $ # -# last change: $Author: thb $ $Date: 2006-07-21 20:57:06 $ +# last change: $Author: thb $ $Date: 2006-07-27 11:35:31 $ # # The Contents of this file are made available subject to # the terms of GNU Lesser General Public License Version 2.1. @@ -51,7 +51,8 @@ CDEFS+= -DBASEBMP_NO_NESTED_TEMPLATE_PARAMETER SLOFILES = \ $(SLO)$/bitmapdevice.obj \ - $(SLO)$/debug.obj + $(SLO)$/debug.obj \ + $(SLO)$/polypolygonrenderer.obj # $(SLO)$/genericintegerimageaccessor.obj \ diff --git a/basebmp/source/polypolygonrenderer.cxx b/basebmp/source/polypolygonrenderer.cxx new file mode 100644 index 000000000000..c94e7fae137e --- /dev/null +++ b/basebmp/source/polypolygonrenderer.cxx @@ -0,0 +1,135 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: polypolygonrenderer.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: thb $ $Date: 2006-07-27 11:35:31 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#include "basebmp/polypolygonrenderer.hxx" + +#include <algorithm> + + +namespace basebmp +{ +namespace detail +{ + sal_uInt32 setupGlobalEdgeTable( VectorOfVectorOfVertices& rGET, + basegfx::B2DPolyPolygon const& rPolyPoly, + sal_Int32 nMinY ) + { + sal_uInt32 const nNumScanlines( rGET.size() ); + + // add all polygons to GET + for( sal_uInt32 i(0), nCount(rPolyPoly.count()); + i<nCount; + ++i ) + { + // add all vertices to GET + const basegfx::B2DPolygon& rPoly( rPolyPoly.getB2DPolygon(i) ); + for( sal_uInt32 k(0), nVertices(rPoly.count()); + k<nVertices; + ++k ) + { + const basegfx::B2DPoint& rP1( rPoly.getB2DPoint(k) ); + const basegfx::B2DPoint& rP2( rPoly.getB2DPoint( (k + 1) % nVertices ) ); + + const sal_Int32 nVertexYP1( basegfx::fround(rP1.getY()) ); + const sal_Int32 nVertexYP2( basegfx::fround(rP2.getY()) ); + + // insert only vertices which are not strictly + // horizontal. Strictly horizontal vertices don't add + // any information that is not already present - due + // to their adjacent vertices. + if(nVertexYP1 != nVertexYP2) + { + if( nVertexYP2 < nVertexYP1 ) + { + const sal_Int32 nStartScanline(nVertexYP2 - nMinY); + + // edge direction is upwards - add with swapped vertices + if( nStartScanline < nNumScanlines ) + rGET[ nStartScanline ].push_back( Vertex(rP2, rP1, false) ); + } + else + { + const sal_Int32 nStartScanline(nVertexYP1 - nMinY); + + if( nStartScanline < nNumScanlines ) + rGET[ nStartScanline ].push_back( Vertex(rP1, rP2, true) ); + } + } + } + } + + // now sort all scanlines individually, with increasing x + // coordinates + VectorOfVectorOfVertices::iterator aIter( rGET.begin() ); + const VectorOfVectorOfVertices::iterator aEnd( rGET.end() ); + sal_uInt32 nVertexCount(0); + RasterConvertVertexComparator aComp; + while( aIter != aEnd ) + { + std::sort( aIter->begin(), + aIter->end(), + aComp ); + nVertexCount += aIter->size(); + + ++aIter; + } + + return nVertexCount; + } + + void sortAET( VectorOfVertexPtr& rAETSrc, + VectorOfVertexPtr& rAETDest ) + { + static RasterConvertVertexComparator aComp; + + rAETDest.clear(); + + // prune AET from ended edges + VectorOfVertexPtr::iterator iter( rAETSrc.begin() ); + VectorOfVertexPtr::iterator const end( rAETSrc.end() ); + while( iter != end ) + { + if( (*iter)->mnYCounter > 0 ) + rAETDest.push_back( *iter ); + ++iter; + } + + // stable sort is necessary, to avoid segment crossing where + // none was intended. + std::stable_sort( rAETDest.begin(), rAETDest.end(), aComp ); + } + +} // namespace detail +} // namespace basebmp diff --git a/basebmp/test/bmpdemo.cxx b/basebmp/test/bmpdemo.cxx index b8cb431a2321..7c472e0b972d 100644 --- a/basebmp/test/bmpdemo.cxx +++ b/basebmp/test/bmpdemo.cxx @@ -4,9 +4,9 @@ * * $RCSfile: bmpdemo.cxx,v $ * - * $Revision: 1.11 $ + * $Revision: 1.12 $ * - * last change: $Author: thb $ $Date: 2006-07-12 22:47:21 $ + * last change: $Author: thb $ $Date: 2006-07-27 11:35:32 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. @@ -1082,6 +1082,24 @@ void TestWindow::Paint( const Rectangle& rRect ) basebmp::Format::THIRTYTWO_BIT_TC_MASK )); { + ::rtl::OUString aSvg; + basegfx::B2DPolyPolygon aPoly; + + basegfx::tools::importFromSvgD( aPoly, + ::rtl::OUString::createFromAscii( + "m0 0 h7 v7 h-7 z" ) ); + basegfx::tools::importFromSvgD( aPoly, + ::rtl::OUString::createFromAscii( + "m2 2 h3 v3 h-3 z" ) ); + + pDevice->fillPolyPolygon( + aPoly, + basebmp::Color(0xFFFFFFFF), + basebmp::DrawMode_PAINT ); + } + +#if 0 + { basebmp::BitmapDeviceSharedPtr pMask( basebmp::createBitmapDevice( aTestSize, false, basebmp::Format::ONE_BIT_MSB_GREY )); @@ -1114,11 +1132,9 @@ void TestWindow::Paint( const Rectangle& rRect ) { const basebmp::Color aCol(0xFFFFFFFF); -#if 0 basegfx::B2DPolygon aRect = basegfx::tools::createPolygonFromRect( basegfx::B2DRange( 0,0,1001,1001 )); pDevice->drawPolygon( aRect, aCol, basebmp::DrawMode_PAINT ); -#endif const basegfx::B2IPoint aPt1(0,0); const basegfx::B2IPoint aPt2(0,800); @@ -1127,6 +1143,7 @@ void TestWindow::Paint( const Rectangle& rRect ) const basegfx::B2IPoint aPt3(0,1001); pDevice->drawLine( aPt1, aPt3, aCol, basebmp::DrawMode_PAINT ); } +#endif { pDevice->clear(basebmp::Color(0)); diff --git a/basebmp/test/filltest.cxx b/basebmp/test/filltest.cxx index c3ec1137c615..8f53aa9b685d 100644 --- a/basebmp/test/filltest.cxx +++ b/basebmp/test/filltest.cxx @@ -4,9 +4,9 @@ * * $RCSfile: filltest.cxx,v $ * - * $Revision: 1.4 $ + * $Revision: 1.5 $ * - * last change: $Author: thb $ $Date: 2006-06-02 16:14:23 $ + * last change: $Author: thb $ $Date: 2006-07-27 11:35:32 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. @@ -81,6 +81,7 @@ private: basegfx::tools::createPolygonFromRect( aRect )), aCol, DrawMode_PAINT ); + const basegfx::B2IPoint aPt1(1,1); CPPUNIT_ASSERT_MESSAGE("first pixel set", rDevice->getPixel(aPt1) == aCol); @@ -212,7 +213,6 @@ private: basegfx::tools::createPolygonFromRect(aLeftBottom)), aCol, DrawMode_PAINT ); - CPPUNIT_ASSERT_MESSAGE("number of rendered pixel is not 3", countPixel( rDevice, aCol ) == 3); diff --git a/basebmp/test/makefile.mk b/basebmp/test/makefile.mk index dc8f27a859a9..b21c41024972 100644 --- a/basebmp/test/makefile.mk +++ b/basebmp/test/makefile.mk @@ -4,9 +4,9 @@ # # $RCSfile: makefile.mk,v $ # -# $Revision: 1.5 $ +# $Revision: 1.6 $ # -# last change: $Author: thb $ $Date: 2006-07-12 15:09:45 $ +# last change: $Author: thb $ $Date: 2006-07-27 11:35:32 $ # # The Contents of this file are made available subject to # the terms of GNU Lesser General Public License Version 2.1. @@ -71,6 +71,7 @@ SHL1OBJS= \ $(SLO)$/filltest.obj \ $(SLO)$/linetest.obj \ $(SLO)$/masktest.obj \ + $(SLO)$/polytest.obj \ $(SLO)$/tools.obj SHL1TARGET= tests diff --git a/basebmp/test/polytest.cxx b/basebmp/test/polytest.cxx new file mode 100644 index 000000000000..243cf68c70be --- /dev/null +++ b/basebmp/test/polytest.cxx @@ -0,0 +1,317 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: polytest.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: thb $ $Date: 2006-07-27 11:35:32 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// autogenerated file with codegen.pl + +#include <cppunit/simpleheader.hxx> + +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/range/b2irange.hxx> +#include <basegfx/point/b2ipoint.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> + +#include <basebmp/color.hxx> +#include <basebmp/scanlineformats.hxx> +#include <basebmp/bitmapdevice.hxx> +#include <basebmp/debug.hxx> +#include "tools.hxx" + +#include <iostream> +#include <fstream> + +using namespace ::basebmp; + +namespace +{ +/* + std::ofstream output("32bpp_test.dump"); + debugDump( rDevice, output ); +*/ + +class PolyTest : public CppUnit::TestFixture +{ +private: + BitmapDeviceSharedPtr mpDevice1bpp; + BitmapDeviceSharedPtr mpDevice32bpp; + + void implTestEmpty(const BitmapDeviceSharedPtr& rDevice) + { + const Color aCol(0xFFFFFFFF); + const Color aBgCol(0); + rDevice->clear(aBgCol); + basegfx::B2DPolyPolygon aPoly; + ::rtl::OUString aSvg; + + basegfx::tools::importFromSvgD( + aPoly, + rtl::OUString::createFromAscii( + "m2 2 l7 7 z" ) ); + rDevice->fillPolyPolygon( + aPoly, + aCol, + DrawMode_PAINT ); + CPPUNIT_ASSERT_MESSAGE("number of rendered pixel is not 0", + countPixel( rDevice, aCol ) == 0); + + // -------------------------------------------------- + + rDevice->clear(aBgCol); + aPoly.clear(); + basegfx::tools::importFromSvgD( + aPoly, + rtl::OUString::createFromAscii( + "m7 2 l-6 6 z" ) ); + rDevice->fillPolyPolygon( + aPoly, + aCol, + DrawMode_PAINT ); + CPPUNIT_ASSERT_MESSAGE("number of rendered pixel is not 0(b)", + countPixel( rDevice, aCol ) == 0); + } + + void implTestHairline(const BitmapDeviceSharedPtr& rDevice) + { + const Color aCol(0xFFFFFFFF); + const Color aBgCol(0); + rDevice->clear(aBgCol); + basegfx::B2DPolyPolygon aPoly; + ::rtl::OUString aSvg; + + basegfx::tools::importFromSvgD( + aPoly, + rtl::OUString::createFromAscii( + "m2 2 h1 l7 7 h-1 z" ) ); + rDevice->fillPolyPolygon( + aPoly, + aCol, + DrawMode_PAINT ); + CPPUNIT_ASSERT_MESSAGE("number of rendered pixel is not 7", + countPixel( rDevice, aCol ) == 7); + + // -------------------------------------------------- + + rDevice->clear(aBgCol); + aPoly.clear(); + basegfx::tools::importFromSvgD( + aPoly, + rtl::OUString::createFromAscii( + "m7 2 h-1 l-6 6 h1 z" ) ); + rDevice->fillPolyPolygon( + aPoly, + aCol, + DrawMode_PAINT ); + CPPUNIT_ASSERT_MESSAGE("number of rendered pixel is not 6", + countPixel( rDevice, aCol ) == 6); + + // -------------------------------------------------- + + rDevice->clear(aBgCol); + aPoly.clear(); + basegfx::tools::importFromSvgD( + aPoly, + rtl::OUString::createFromAscii( + "m0 0 l7 7 h-1 l-5-7 z" ) ); + rDevice->fillPolyPolygon( + aPoly, + aCol, + DrawMode_PAINT ); + CPPUNIT_ASSERT_MESSAGE("number of rendered pixel is not 3", + countPixel( rDevice, aCol ) == 3); + } + + void implTestPolyPoly(const BitmapDeviceSharedPtr& rDevice) + { + const Color aCol(0xFFFFFFFF); + const Color aBgCol(0); + rDevice->clear(aBgCol); + basegfx::B2DPolyPolygon aPoly; + ::rtl::OUString aSvg; + + basegfx::tools::importFromSvgD( aPoly, + ::rtl::OUString::createFromAscii( + "m0 0 h7 v7 h-7 z" ) ); + basegfx::tools::importFromSvgD( aPoly, + ::rtl::OUString::createFromAscii( + "m2 2 v3 h3 v-3 z" ) ); + rDevice->fillPolyPolygon( + aPoly, + aCol, + DrawMode_PAINT ); + CPPUNIT_ASSERT_MESSAGE("number of rendered pixel is not 40", + countPixel( rDevice, aCol ) == 40); + } + + void implTestPolyPolyClip(const BitmapDeviceSharedPtr& rDevice) + { + const Color aCol(0xFFFFFFFF); + const Color aBgCol(0); + rDevice->clear(aBgCol); + basegfx::B2DPolyPolygon aPoly; + ::rtl::OUString aSvg; + + basegfx::tools::importFromSvgD( aPoly, + ::rtl::OUString::createFromAscii( + "m0 0 h7 v7 h-7 z" ) ); + basegfx::tools::importFromSvgD( aPoly, + ::rtl::OUString::createFromAscii( + "m2 2 v3 h3 v-3 z" ) ); + basegfx::B2DHomMatrix aMat; + aMat.translate(-3,-3); + aMat.rotate( 1.7 ); + aMat.translate(6,5); + aPoly.transform(aMat); + + rDevice->fillPolyPolygon( + aPoly, + aCol, + DrawMode_PAINT ); + CPPUNIT_ASSERT_MESSAGE("number of rendered pixel is not 39", + countPixel( rDevice, aCol ) == 39); + + BitmapDeviceSharedPtr pClippedDevice( + subsetBitmapDevice( rDevice, + basegfx::B2IRange(3,3,5,8) )); + + rDevice->clear(aBgCol); + pClippedDevice->fillPolyPolygon( + aPoly, + aCol, + DrawMode_PAINT ); + CPPUNIT_ASSERT_MESSAGE("number of rendered pixel is not 7", + countPixel( rDevice, aCol ) == 7); + } + + void implTestPolyPolyCrissCross(const BitmapDeviceSharedPtr& rDevice) + { + const Color aCol(0xFFFFFFFF); + const Color aBgCol(0); + rDevice->clear(aBgCol); + basegfx::B2DPolyPolygon aPoly; + ::rtl::OUString aSvg; + + basegfx::tools::importFromSvgD( aPoly, + ::rtl::OUString::createFromAscii( + "m0 0 v2 l10 2 v-2 z" ) ); + basegfx::tools::importFromSvgD( aPoly, + ::rtl::OUString::createFromAscii( + "m10 6 v-2 l-10 2 v2 z" ) ); + basegfx::tools::importFromSvgD( aPoly, + ::rtl::OUString::createFromAscii( + "m1 0 h1 v10 h-1 z" ) ); + basegfx::tools::importFromSvgD( aPoly, + ::rtl::OUString::createFromAscii( + "m4 0 h1 v10 h-1 z" ) ); + basegfx::tools::importFromSvgD( aPoly, + ::rtl::OUString::createFromAscii( + "m8 0 h1 v10 h-1 z" ) ); + rDevice->fillPolyPolygon( + aPoly, + aCol, + DrawMode_PAINT ); + CPPUNIT_ASSERT_MESSAGE("number of rendered pixel is not 46", + countPixel( rDevice, aCol ) == 46); + } + + +public: + void setUp() + { + const basegfx::B2ISize aSize(10,10); + mpDevice1bpp = createBitmapDevice( aSize, + true, + Format::ONE_BIT_MSB_PAL ); + mpDevice32bpp = createBitmapDevice( aSize, + true, + Format::THIRTYTWO_BIT_TC_MASK ); + } + + void testEmpty() + { + implTestEmpty( mpDevice1bpp ); + implTestEmpty( mpDevice32bpp ); + } + + void testHairline() + { + implTestHairline( mpDevice1bpp ); + implTestHairline( mpDevice32bpp ); + } + + void testPolyPoly() + { + implTestPolyPoly( mpDevice1bpp ); + implTestPolyPoly( mpDevice32bpp ); + } + + void testPolyPolyClip() + { + implTestPolyPolyClip(mpDevice1bpp); + implTestPolyPolyClip(mpDevice32bpp); + } + + void testPolyPolyCrissCross() + { + implTestPolyPolyCrissCross(mpDevice1bpp); + implTestPolyPolyCrissCross(mpDevice32bpp); + } + + // Change the following lines only, if you add, remove or rename + // member functions of the current class, + // because these macros are need by auto register mechanism. + + CPPUNIT_TEST_SUITE(PolyTest); + CPPUNIT_TEST(testEmpty); + CPPUNIT_TEST(testHairline); + CPPUNIT_TEST(testPolyPoly); + CPPUNIT_TEST(testPolyPolyClip); + CPPUNIT_TEST(testPolyPolyCrissCross); + CPPUNIT_TEST_SUITE_END(); +}; + +// ----------------------------------------------------------------------------- +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(PolyTest, "PolyTest"); +} + + +// ----------------------------------------------------------------------------- + +// this macro creates an empty function, which will called by the RegisterAllFunctions() +// to let the user the possibility to also register some functions by hand. +//NOADDITIONAL; + |