1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_basegfx.hxx"
31 #include <basegfx/raster/rasterconvert3d.hxx>
32 #include <basegfx/polygon/b3dpolygon.hxx>
33 #include <basegfx/polygon/b3dpolypolygon.hxx>
34 #include <basegfx/point/b3dpoint.hxx>
36 //////////////////////////////////////////////////////////////////////////////
37 // implementations of the 3D raster converter
41 void RasterConverter3D::addArea(const B3DPolygon
& rFill
, const B3DHomMatrix
* pViewToEye
)
43 const sal_uInt32
nPointCount(rFill
.count());
45 for(sal_uInt32
a(0); a
< nPointCount
; a
++)
47 addEdge(rFill
, a
, (a
+ 1) % nPointCount
, pViewToEye
);
51 void RasterConverter3D::addArea(const B3DPolyPolygon
& rFill
, const B3DHomMatrix
* pViewToEye
)
53 const sal_uInt32
nPolyCount(rFill
.count());
55 for(sal_uInt32
a(0); a
< nPolyCount
; a
++)
57 addArea(rFill
.getB3DPolygon(a
), pViewToEye
);
61 RasterConverter3D::RasterConverter3D()
62 : InterpolatorProvider3D(),
66 RasterConverter3D::~RasterConverter3D()
69 void RasterConverter3D::rasterconvertB3DArea(sal_Int32 nStartLine
, sal_Int32 nStopLine
)
71 if(maLineEntries
.size())
73 OSL_ENSURE(nStopLine
>= nStartLine
, "nStopLine is bigger than nStartLine (!)");
75 // sort global entries by Y, X once. After this, the vector
76 // is seen as frozen. Pointers to it's entries will be used in the following code.
77 ::std::sort(maLineEntries
.begin(), maLineEntries
.end());
80 ::std::vector
< RasterConversionLineEntry3D
>::iterator
aCurrentEntry(maLineEntries
.begin());
81 ::std::vector
< RasterConversionLineEntry3D
* > aCurrentLine
;
82 ::std::vector
< RasterConversionLineEntry3D
* > aNextLine
;
83 ::std::vector
< RasterConversionLineEntry3D
* >::iterator aRasterConversionLineEntry3D
;
84 sal_uInt32
nPairCount(0);
86 // get scanlines first LineNumber as start
87 sal_Int32
nLineNumber(::std::max(aCurrentEntry
->getY(), nStartLine
));
89 while((aCurrentLine
.size() || aCurrentEntry
!= maLineEntries
.end()) && (nLineNumber
< nStopLine
))
91 // add all entries which start at current line to current scanline
92 while(aCurrentEntry
!= maLineEntries
.end())
94 const sal_Int32
nCurrentLineNumber(aCurrentEntry
->getY());
96 if(nCurrentLineNumber
> nLineNumber
)
98 // line is below current one, done (since array is sorted)
103 // less or equal. Line is above or at current one. Advance it exactly to
105 const sal_uInt32
nStep(nLineNumber
- nCurrentLineNumber
);
107 if(!nStep
|| aCurrentEntry
->decrementRasterConversionLineEntry3D(nStep
))
109 // add when exactly on current line or when incremet to it did not
110 // completely consume it
113 aCurrentEntry
->incrementRasterConversionLineEntry3D(nStep
, *this);
116 aCurrentLine
.push_back(&(*(aCurrentEntry
)));
123 // sort current scanline using comparator. Only X is used there
124 // since all entries are already in one processed line. This needs to be done
125 // everytime since not only new spans may have benn added or old removed,
126 // but incrementing may also have changed the order
127 ::std::sort(aCurrentLine
.begin(), aCurrentLine
.end(), lineComparator());
129 // process current scanline
130 aRasterConversionLineEntry3D
= aCurrentLine
.begin();
134 while(aRasterConversionLineEntry3D
!= aCurrentLine
.end())
136 RasterConversionLineEntry3D
& rPrevScanRasterConversionLineEntry3D(**aRasterConversionLineEntry3D
++);
139 if(aRasterConversionLineEntry3D
!= aCurrentLine
.end())
141 // work on span from rPrevScanRasterConversionLineEntry3D to aRasterConversionLineEntry3D, fLineNumber is valid
142 processLineSpan(rPrevScanRasterConversionLineEntry3D
, **aRasterConversionLineEntry3D
, nLineNumber
, nPairCount
++);
145 // increment to next line
146 if(rPrevScanRasterConversionLineEntry3D
.decrementRasterConversionLineEntry3D(1))
148 rPrevScanRasterConversionLineEntry3D
.incrementRasterConversionLineEntry3D(1, *this);
149 aNextLine
.push_back(&rPrevScanRasterConversionLineEntry3D
);
153 // copy back next scanline if count has changed
154 if(aNextLine
.size() != aCurrentLine
.size())
156 aCurrentLine
= aNextLine
;
159 // increment fLineNumber
165 void RasterConverter3D::addEdge(const B3DPolygon
& rFill
, sal_uInt32 a
, sal_uInt32 b
, const B3DHomMatrix
* pViewToEye
)
167 B3DPoint
aStart(rFill
.getB3DPoint(a
));
168 B3DPoint
aEnd(rFill
.getB3DPoint(b
));
169 sal_Int32
nYStart(fround(aStart
.getY()));
170 sal_Int32
nYEnd(fround(aEnd
.getY()));
176 ::std::swap(aStart
, aEnd
);
177 ::std::swap(nYStart
, nYEnd
);
181 const sal_uInt32
nYDelta(nYEnd
- nYStart
);
182 const double fInvYDelta(1.0 / nYDelta
);
183 maLineEntries
.push_back(RasterConversionLineEntry3D(
184 aStart
.getX(), (aEnd
.getX() - aStart
.getX()) * fInvYDelta
,
185 aStart
.getZ(), (aEnd
.getZ() - aStart
.getZ()) * fInvYDelta
,
188 // if extra interpolation data is used, add it to the last created entry
189 RasterConversionLineEntry3D
& rEntry
= maLineEntries
[maLineEntries
.size() - 1];
191 if(rFill
.areBColorsUsed())
193 rEntry
.setColorIndex(addColorInterpolator(rFill
.getBColor(a
), rFill
.getBColor(b
), fInvYDelta
));
196 if(rFill
.areNormalsUsed())
198 rEntry
.setNormalIndex(addNormalInterpolator(rFill
.getNormal(a
), rFill
.getNormal(b
), fInvYDelta
));
201 if(rFill
.areTextureCoordinatesUsed())
205 const double fEyeA(((*pViewToEye
) * aStart
).getZ());
206 const double fEyeB(((*pViewToEye
) * aEnd
).getZ());
208 rEntry
.setInverseTextureIndex(addInverseTextureInterpolator(
209 rFill
.getTextureCoordinate(a
),
210 rFill
.getTextureCoordinate(b
),
211 fEyeA
, fEyeB
, fInvYDelta
));
215 rEntry
.setTextureIndex(addTextureInterpolator(
216 rFill
.getTextureCoordinate(a
),
217 rFill
.getTextureCoordinate(b
),
224 void RasterConverter3D::rasterconvertB3DEdge(const B3DPolygon
& rLine
, sal_uInt32 nA
, sal_uInt32 nB
, sal_Int32 nStartLine
, sal_Int32 nStopLine
, sal_uInt16 nLineWidth
)
226 B3DPoint
aStart(rLine
.getB3DPoint(nA
));
227 B3DPoint
aEnd(rLine
.getB3DPoint(nB
));
228 const double fZBufferLineAdd(0x00ff);
229 static bool bForceToPolygon(false);
231 if(nLineWidth
> 1 || bForceToPolygon
)
233 // this is not a hairline anymore, in most cases since it's an oversampled
234 // hairline to get e.g. AA for Z-Buffering. Create fill geometry.
235 if(!aStart
.equal(aEnd
))
238 maLineEntries
.clear();
240 B2DVector
aVector(aEnd
.getX() - aStart
.getX(), aEnd
.getY() - aStart
.getY());
242 const B2DVector
aPerpend(getPerpendicular(aVector
) * ((static_cast<double>(nLineWidth
) + 0.5) * 0.5));
243 const double fZStartWithAdd(aStart
.getZ() + fZBufferLineAdd
);
244 const double fZEndWithAdd(aEnd
.getZ() + fZBufferLineAdd
);
247 aPolygon
.append(B3DPoint(aStart
.getX() + aPerpend
.getX(), aStart
.getY() + aPerpend
.getY(), fZStartWithAdd
));
248 aPolygon
.append(B3DPoint(aEnd
.getX() + aPerpend
.getX(), aEnd
.getY() + aPerpend
.getY(), fZEndWithAdd
));
249 aPolygon
.append(B3DPoint(aEnd
.getX() - aPerpend
.getX(), aEnd
.getY() - aPerpend
.getY(), fZEndWithAdd
));
250 aPolygon
.append(B3DPoint(aStart
.getX() - aPerpend
.getX(), aStart
.getY() - aPerpend
.getY(), fZStartWithAdd
));
251 aPolygon
.setClosed(true);
253 addArea(aPolygon
, 0);
258 // it's a hairline. Use direct RasterConversionLineEntry creation to
259 // rasterconvert lines as similar to areas as possible to avoid Z-Fighting
260 sal_Int32
nYStart(fround(aStart
.getY()));
261 sal_Int32
nYEnd(fround(aEnd
.getY()));
265 // horizontal line, check X
266 const sal_Int32
nXStart(static_cast<sal_Int32
>(aStart
.getX()));
267 const sal_Int32
nXEnd(static_cast<sal_Int32
>(aEnd
.getX()));
272 maLineEntries
.clear();
274 // horizontal line, create vertical entries. These will be sorted by
275 // X anyways, so no need to distinguish the case here
276 maLineEntries
.push_back(RasterConversionLineEntry3D(
278 aStart
.getZ() + fZBufferLineAdd
, 0.0,
280 maLineEntries
.push_back(RasterConversionLineEntry3D(
282 aEnd
.getZ() + fZBufferLineAdd
, 0.0,
289 maLineEntries
.clear();
293 ::std::swap(aStart
, aEnd
);
294 ::std::swap(nYStart
, nYEnd
);
297 const sal_uInt32
nYDelta(static_cast<sal_uInt32
>(nYEnd
- nYStart
));
298 const double fInvYDelta(1.0 / nYDelta
);
300 // non-horizontal line, create two parallell entries. These will be sorted by
301 // X anyways, so no need to distinguish the case here
302 maLineEntries
.push_back(RasterConversionLineEntry3D(
303 aStart
.getX(), (aEnd
.getX() - aStart
.getX()) * fInvYDelta
,
304 aStart
.getZ() + fZBufferLineAdd
, (aEnd
.getZ() - aStart
.getZ()) * fInvYDelta
,
307 RasterConversionLineEntry3D
& rEntry
= maLineEntries
[maLineEntries
.size() - 1];
309 // need to choose a X-Distance for the 2nd edge which guarantees all pixels
310 // of the line to be set. This is exactly the X-Increment for one Y-Step.
311 // Same is true for Z, so in both cases, add one increment to them. To also
312 // guarantee one pixel per line, add a minimum of one for X.
313 const double fDistanceX(fabs(rEntry
.getX().getInc()) >= 1.0 ? rEntry
.getX().getInc() : 1.0);
315 maLineEntries
.push_back(RasterConversionLineEntry3D(
316 rEntry
.getX().getVal() + fDistanceX
, rEntry
.getX().getInc(),
317 rEntry
.getZ().getVal() + rEntry
.getZ().getInc(), rEntry
.getZ().getInc(),
322 if(maLineEntries
.size())
324 rasterconvertB3DArea(nStartLine
, nStopLine
);
328 void RasterConverter3D::rasterconvertB3DPolyPolygon(const B3DPolyPolygon
& rFill
, const B3DHomMatrix
* pViewToEye
, sal_Int32 nStartLine
, sal_Int32 nStopLine
)
331 maLineEntries
.clear();
332 addArea(rFill
, pViewToEye
);
333 rasterconvertB3DArea(nStartLine
, nStopLine
);
336 void RasterConverter3D::rasterconvertB3DPolygon(const B3DPolygon
& rLine
, sal_Int32 nStartLine
, sal_Int32 nStopLine
, sal_uInt16 nLineWidth
)
338 const sal_uInt32
nPointCount(rLine
.count());
342 const sal_uInt32
nEdgeCount(rLine
.isClosed() ? nPointCount
: nPointCount
- 1);
344 for(sal_uInt32
a(0); a
< nEdgeCount
; a
++)
346 rasterconvertB3DEdge(rLine
, a
, (a
+ 1) % nPointCount
, nStartLine
, nStopLine
, nLineWidth
);
350 } // end of namespace basegfx
352 //////////////////////////////////////////////////////////////////////////////