1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: rasterconvert3d.cxx,v $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************/
32 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_basegfx.hxx"
35 #include <basegfx/raster/rasterconvert3d.hxx>
36 #include <basegfx/polygon/b3dpolygon.hxx>
37 #include <basegfx/polygon/b3dpolypolygon.hxx>
38 #include <basegfx/point/b3dpoint.hxx>
40 //////////////////////////////////////////////////////////////////////////////
41 // implementations of the 3D raster converter
45 void RasterConverter3D::addArea(const B3DPolygon
& rFill
, const B3DHomMatrix
* pViewToEye
)
47 const sal_uInt32
nPointCount(rFill
.count());
49 for(sal_uInt32
a(0); a
< nPointCount
; a
++)
51 addEdge(rFill
, a
, (a
+ 1) % nPointCount
, pViewToEye
);
55 void RasterConverter3D::addArea(const B3DPolyPolygon
& rFill
, const B3DHomMatrix
* pViewToEye
)
57 const sal_uInt32
nPolyCount(rFill
.count());
59 for(sal_uInt32
a(0); a
< nPolyCount
; a
++)
61 addArea(rFill
.getB3DPolygon(a
), pViewToEye
);
65 RasterConverter3D::RasterConverter3D()
66 : InterpolatorProvider3D(),
70 RasterConverter3D::~RasterConverter3D()
73 void RasterConverter3D::rasterconvertB3DArea(sal_Int32 nStartLine
, sal_Int32 nStopLine
)
75 if(maLineEntries
.size())
77 OSL_ENSURE(nStopLine
>= nStartLine
, "nStopLine is bigger than nStartLine (!)");
79 // sort global entries by Y, X once. After this, the vector
80 // is seen as frozen. Pointers to it's entries will be used in the following code.
81 ::std::sort(maLineEntries
.begin(), maLineEntries
.end());
84 ::std::vector
< RasterConversionLineEntry3D
>::iterator
aCurrentEntry(maLineEntries
.begin());
85 ::std::vector
< RasterConversionLineEntry3D
* > aCurrentLine
;
86 ::std::vector
< RasterConversionLineEntry3D
* > aNextLine
;
87 ::std::vector
< RasterConversionLineEntry3D
* >::iterator aRasterConversionLineEntry3D
;
88 sal_uInt32
nPairCount(0);
90 // get scanlines first LineNumber as start
91 sal_Int32
nLineNumber(::std::max(aCurrentEntry
->getY(), nStartLine
));
93 while((aCurrentLine
.size() || aCurrentEntry
!= maLineEntries
.end()) && (nLineNumber
< nStopLine
))
95 // add all entries which start at current line to current scanline
96 while(aCurrentEntry
!= maLineEntries
.end())
98 const sal_Int32
nCurrentLineNumber(aCurrentEntry
->getY());
100 if(nCurrentLineNumber
> nLineNumber
)
102 // line is below current one, done (since array is sorted)
107 // less or equal. Line is above or at current one. Advance it exactly to
109 const sal_uInt32
nStep(nLineNumber
- nCurrentLineNumber
);
111 if(!nStep
|| aCurrentEntry
->decrementRasterConversionLineEntry3D(nStep
))
113 // add when exactly on current line or when incremet to it did not
114 // completely consume it
117 aCurrentEntry
->incrementRasterConversionLineEntry3D(nStep
, *this);
120 aCurrentLine
.push_back(&(*(aCurrentEntry
)));
127 // sort current scanline using comparator. Only X is used there
128 // since all entries are already in one processed line. This needs to be done
129 // everytime since not only new spans may have benn added or old removed,
130 // but incrementing may also have changed the order
131 ::std::sort(aCurrentLine
.begin(), aCurrentLine
.end(), lineComparator());
133 // process current scanline
134 aRasterConversionLineEntry3D
= aCurrentLine
.begin();
138 while(aRasterConversionLineEntry3D
!= aCurrentLine
.end())
140 RasterConversionLineEntry3D
& rPrevScanRasterConversionLineEntry3D(**aRasterConversionLineEntry3D
++);
143 if(aRasterConversionLineEntry3D
!= aCurrentLine
.end())
145 // work on span from rPrevScanRasterConversionLineEntry3D to aRasterConversionLineEntry3D, fLineNumber is valid
146 processLineSpan(rPrevScanRasterConversionLineEntry3D
, **aRasterConversionLineEntry3D
, nLineNumber
, nPairCount
++);
149 // increment to next line
150 if(rPrevScanRasterConversionLineEntry3D
.decrementRasterConversionLineEntry3D(1))
152 rPrevScanRasterConversionLineEntry3D
.incrementRasterConversionLineEntry3D(1, *this);
153 aNextLine
.push_back(&rPrevScanRasterConversionLineEntry3D
);
157 // copy back next scanline if count has changed
158 if(aNextLine
.size() != aCurrentLine
.size())
160 aCurrentLine
= aNextLine
;
163 // increment fLineNumber
169 void RasterConverter3D::addEdge(const B3DPolygon
& rFill
, sal_uInt32 a
, sal_uInt32 b
, const B3DHomMatrix
* pViewToEye
)
171 B3DPoint
aStart(rFill
.getB3DPoint(a
));
172 B3DPoint
aEnd(rFill
.getB3DPoint(b
));
173 sal_Int32
nYStart(fround(aStart
.getY()));
174 sal_Int32
nYEnd(fround(aEnd
.getY()));
180 ::std::swap(aStart
, aEnd
);
181 ::std::swap(nYStart
, nYEnd
);
185 const sal_uInt32
nYDelta(nYEnd
- nYStart
);
186 const double fInvYDelta(1.0 / nYDelta
);
187 maLineEntries
.push_back(RasterConversionLineEntry3D(
188 aStart
.getX(), (aEnd
.getX() - aStart
.getX()) * fInvYDelta
,
189 aStart
.getZ(), (aEnd
.getZ() - aStart
.getZ()) * fInvYDelta
,
192 // if extra interpolation data is used, add it to the last created entry
193 RasterConversionLineEntry3D
& rEntry
= maLineEntries
[maLineEntries
.size() - 1];
195 if(rFill
.areBColorsUsed())
197 rEntry
.setColorIndex(addColorInterpolator(rFill
.getBColor(a
), rFill
.getBColor(b
), fInvYDelta
));
200 if(rFill
.areNormalsUsed())
202 rEntry
.setNormalIndex(addNormalInterpolator(rFill
.getNormal(a
), rFill
.getNormal(b
), fInvYDelta
));
205 if(rFill
.areTextureCoordinatesUsed())
209 const double fEyeA(((*pViewToEye
) * aStart
).getZ());
210 const double fEyeB(((*pViewToEye
) * aEnd
).getZ());
212 rEntry
.setInverseTextureIndex(addInverseTextureInterpolator(
213 rFill
.getTextureCoordinate(a
),
214 rFill
.getTextureCoordinate(b
),
215 fEyeA
, fEyeB
, fInvYDelta
));
219 rEntry
.setTextureIndex(addTextureInterpolator(
220 rFill
.getTextureCoordinate(a
),
221 rFill
.getTextureCoordinate(b
),
228 void RasterConverter3D::rasterconvertB3DEdge(const B3DPolygon
& rLine
, sal_uInt32 nA
, sal_uInt32 nB
, sal_Int32 nStartLine
, sal_Int32 nStopLine
, sal_uInt16 nLineWidth
)
230 B3DPoint
aStart(rLine
.getB3DPoint(nA
));
231 B3DPoint
aEnd(rLine
.getB3DPoint(nB
));
232 const double fZBufferLineAdd(0x00ff);
233 static bool bForceToPolygon(false);
235 if(nLineWidth
> 1 || bForceToPolygon
)
237 // this is not a hairline anymore, in most cases since it's an oversampled
238 // hairline to get e.g. AA for Z-Buffering. Create fill geometry.
239 if(!aStart
.equal(aEnd
))
242 maLineEntries
.clear();
244 B2DVector
aVector(aEnd
.getX() - aStart
.getX(), aEnd
.getY() - aStart
.getY());
246 const B2DVector
aPerpend(getPerpendicular(aVector
) * ((static_cast<double>(nLineWidth
) + 0.5) * 0.5));
247 const double fZStartWithAdd(aStart
.getZ() + fZBufferLineAdd
);
248 const double fZEndWithAdd(aEnd
.getZ() + fZBufferLineAdd
);
251 aPolygon
.append(B3DPoint(aStart
.getX() + aPerpend
.getX(), aStart
.getY() + aPerpend
.getY(), fZStartWithAdd
));
252 aPolygon
.append(B3DPoint(aEnd
.getX() + aPerpend
.getX(), aEnd
.getY() + aPerpend
.getY(), fZEndWithAdd
));
253 aPolygon
.append(B3DPoint(aEnd
.getX() - aPerpend
.getX(), aEnd
.getY() - aPerpend
.getY(), fZEndWithAdd
));
254 aPolygon
.append(B3DPoint(aStart
.getX() - aPerpend
.getX(), aStart
.getY() - aPerpend
.getY(), fZStartWithAdd
));
255 aPolygon
.setClosed(true);
257 addArea(aPolygon
, 0);
262 // it's a hairline. Use direct RasterConversionLineEntry creation to
263 // rasterconvert lines as similar to areas as possible to avoid Z-Fighting
264 sal_Int32
nYStart(fround(aStart
.getY()));
265 sal_Int32
nYEnd(fround(aEnd
.getY()));
269 // horizontal line, check X
270 const sal_Int32
nXStart(static_cast<sal_Int32
>(aStart
.getX()));
271 const sal_Int32
nXEnd(static_cast<sal_Int32
>(aEnd
.getX()));
276 maLineEntries
.clear();
278 // horizontal line, create vertical entries. These will be sorted by
279 // X anyways, so no need to distinguish the case here
280 maLineEntries
.push_back(RasterConversionLineEntry3D(
282 aStart
.getZ() + fZBufferLineAdd
, 0.0,
284 maLineEntries
.push_back(RasterConversionLineEntry3D(
286 aEnd
.getZ() + fZBufferLineAdd
, 0.0,
293 maLineEntries
.clear();
297 ::std::swap(aStart
, aEnd
);
298 ::std::swap(nYStart
, nYEnd
);
301 const sal_uInt32
nYDelta(static_cast<sal_uInt32
>(nYEnd
- nYStart
));
302 const double fInvYDelta(1.0 / nYDelta
);
304 // non-horizontal line, create two parallell entries. These will be sorted by
305 // X anyways, so no need to distinguish the case here
306 maLineEntries
.push_back(RasterConversionLineEntry3D(
307 aStart
.getX(), (aEnd
.getX() - aStart
.getX()) * fInvYDelta
,
308 aStart
.getZ() + fZBufferLineAdd
, (aEnd
.getZ() - aStart
.getZ()) * fInvYDelta
,
311 RasterConversionLineEntry3D
& rEntry
= maLineEntries
[maLineEntries
.size() - 1];
313 // need to choose a X-Distance for the 2nd edge which guarantees all pixels
314 // of the line to be set. This is exactly the X-Increment for one Y-Step.
315 // Same is true for Z, so in both cases, add one increment to them. To also
316 // guarantee one pixel per line, add a minimum of one for X.
317 const double fDistanceX(fabs(rEntry
.getX().getInc()) >= 1.0 ? rEntry
.getX().getInc() : 1.0);
319 maLineEntries
.push_back(RasterConversionLineEntry3D(
320 rEntry
.getX().getVal() + fDistanceX
, rEntry
.getX().getInc(),
321 rEntry
.getZ().getVal() + rEntry
.getZ().getInc(), rEntry
.getZ().getInc(),
326 if(maLineEntries
.size())
328 rasterconvertB3DArea(nStartLine
, nStopLine
);
332 void RasterConverter3D::rasterconvertB3DPolyPolygon(const B3DPolyPolygon
& rFill
, const B3DHomMatrix
* pViewToEye
, sal_Int32 nStartLine
, sal_Int32 nStopLine
)
335 maLineEntries
.clear();
336 addArea(rFill
, pViewToEye
);
337 rasterconvertB3DArea(nStartLine
, nStopLine
);
340 void RasterConverter3D::rasterconvertB3DPolygon(const B3DPolygon
& rLine
, sal_Int32 nStartLine
, sal_Int32 nStopLine
, sal_uInt16 nLineWidth
)
342 const sal_uInt32
nPointCount(rLine
.count());
346 const sal_uInt32
nEdgeCount(rLine
.isClosed() ? nPointCount
: nPointCount
- 1);
348 for(sal_uInt32
a(0); a
< nEdgeCount
; a
++)
350 rasterconvertB3DEdge(rLine
, a
, (a
+ 1) % nPointCount
, nStartLine
, nStopLine
, nLineWidth
);
354 } // end of namespace basegfx
356 //////////////////////////////////////////////////////////////////////////////