summaryrefslogtreecommitdiff
path: root/basebmp
diff options
context:
space:
mode:
Diffstat (limited to 'basebmp')
-rw-r--r--basebmp/inc/basebmp/clippedlinerenderer.hxx6
-rw-r--r--basebmp/inc/basebmp/linerenderer.hxx6
-rw-r--r--basebmp/inc/basebmp/polypolygonrenderer.hxx360
-rw-r--r--basebmp/inc/basebmp/scaleimage.hxx29
-rw-r--r--basebmp/source/bitmapdevice.cxx116
-rw-r--r--basebmp/source/makefile.mk7
-rw-r--r--basebmp/source/polypolygonrenderer.cxx135
-rw-r--r--basebmp/test/bmpdemo.cxx25
-rw-r--r--basebmp/test/filltest.cxx6
-rw-r--r--basebmp/test/makefile.mk5
-rw-r--r--basebmp/test/polytest.cxx317
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;
+