update dev300-m58
[ooovba.git] / basegfx / source / raster / rasterconvert3d.cxx
blob58b84aca6dab1d83368af13045690667126e3de1
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: rasterconvert3d.cxx,v $
11 * $Revision: 1.2 $
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
43 namespace basegfx
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(),
67 maLineEntries()
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());
83 // local parameters
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)
103 break;
105 else
107 // less or equal. Line is above or at current one. Advance it exactly to
108 // current line
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
115 if(nStep)
117 aCurrentEntry->incrementRasterConversionLineEntry3D(nStep, *this);
120 aCurrentLine.push_back(&(*(aCurrentEntry)));
124 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();
135 aNextLine.clear();
136 nPairCount = 0;
138 while(aRasterConversionLineEntry3D != aCurrentLine.end())
140 RasterConversionLineEntry3D& rPrevScanRasterConversionLineEntry3D(**aRasterConversionLineEntry3D++);
142 // look for 2nd span
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
164 nLineNumber++;
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()));
176 if(nYStart != nYEnd)
178 if(nYStart > nYEnd)
180 ::std::swap(aStart, aEnd);
181 ::std::swap(nYStart, nYEnd);
182 ::std::swap(a, b);
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,
190 nYStart, nYDelta));
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())
207 if(pViewToEye)
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));
217 else
219 rEntry.setTextureIndex(addTextureInterpolator(
220 rFill.getTextureCoordinate(a),
221 rFill.getTextureCoordinate(b),
222 fInvYDelta));
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))
241 reset();
242 maLineEntries.clear();
244 B2DVector aVector(aEnd.getX() - aStart.getX(), aEnd.getY() - aStart.getY());
245 aVector.normalize();
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);
250 B3DPolygon aPolygon;
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);
260 else
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()));
267 if(nYStart == nYEnd)
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()));
273 if(nXStart != nXEnd)
275 reset();
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(
281 aStart.getX(), 0.0,
282 aStart.getZ() + fZBufferLineAdd, 0.0,
283 nYStart, 1));
284 maLineEntries.push_back(RasterConversionLineEntry3D(
285 aEnd.getX(), 0.0,
286 aEnd.getZ() + fZBufferLineAdd, 0.0,
287 nYStart, 1));
290 else
292 reset();
293 maLineEntries.clear();
295 if(nYStart > nYEnd)
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,
309 nYStart, nYDelta));
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(),
322 nYStart, nYDelta));
326 if(maLineEntries.size())
328 rasterconvertB3DArea(nStartLine, nStopLine);
332 void RasterConverter3D::rasterconvertB3DPolyPolygon(const B3DPolyPolygon& rFill, const B3DHomMatrix* pViewToEye, sal_Int32 nStartLine, sal_Int32 nStopLine)
334 reset();
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());
344 if(nPointCount)
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 //////////////////////////////////////////////////////////////////////////////
357 // eof