Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <basegfx/raster/rasterconvert3d.hxx>
30 : : #include <basegfx/polygon/b3dpolygon.hxx>
31 : : #include <basegfx/polygon/b3dpolypolygon.hxx>
32 : : #include <basegfx/point/b3dpoint.hxx>
33 : :
34 : : //////////////////////////////////////////////////////////////////////////////
35 : : // implementations of the 3D raster converter
36 : :
37 : : namespace basegfx
38 : : {
39 : 551 : void RasterConverter3D::addArea(const B3DPolygon& rFill, const B3DHomMatrix* pViewToEye)
40 : : {
41 : 551 : const sal_uInt32 nPointCount(rFill.count());
42 : :
43 [ + + ]: 2755 : for(sal_uInt32 a(0); a < nPointCount; a++)
44 : : {
45 : 2204 : addEdge(rFill, a, (a + 1) % nPointCount, pViewToEye);
46 : : }
47 : 551 : }
48 : :
49 : 551 : void RasterConverter3D::addArea(const B3DPolyPolygon& rFill, const B3DHomMatrix* pViewToEye)
50 : : {
51 : 551 : const sal_uInt32 nPolyCount(rFill.count());
52 : :
53 [ + + ]: 1102 : for(sal_uInt32 a(0); a < nPolyCount; a++)
54 : : {
55 [ + - ]: 551 : addArea(rFill.getB3DPolygon(a), pViewToEye);
56 : : }
57 : 551 : }
58 : :
59 : 15 : RasterConverter3D::RasterConverter3D()
60 : : : InterpolatorProvider3D(),
61 [ + - ]: 15 : maLineEntries()
62 : 15 : {}
63 : :
64 : 15 : RasterConverter3D::~RasterConverter3D()
65 [ - + ]: 15 : {}
66 : :
67 : 641 : void RasterConverter3D::rasterconvertB3DArea(sal_Int32 nStartLine, sal_Int32 nStopLine)
68 : : {
69 [ + - ]: 641 : if(!maLineEntries.empty())
70 : : {
71 : : OSL_ENSURE(nStopLine >= nStartLine, "nStopLine is bigger than nStartLine (!)");
72 : :
73 : : // sort global entries by Y, X once. After this, the vector
74 : : // is seen as frozen. Pointers to it's entries will be used in the following code.
75 [ + - ]: 641 : ::std::sort(maLineEntries.begin(), maLineEntries.end());
76 : :
77 : : // local parameters
78 : 641 : ::std::vector< RasterConversionLineEntry3D >::iterator aCurrentEntry(maLineEntries.begin());
79 [ + - ]: 641 : ::std::vector< RasterConversionLineEntry3D* > aCurrentLine;
80 [ + - ]: 641 : ::std::vector< RasterConversionLineEntry3D* > aNextLine;
81 : 641 : ::std::vector< RasterConversionLineEntry3D* >::iterator aRasterConversionLineEntry3D;
82 : 641 : sal_uInt32 nPairCount(0);
83 : :
84 : : // get scanlines first LineNumber as start
85 [ + - ]: 641 : sal_Int32 nLineNumber(::std::max(aCurrentEntry->getY(), nStartLine));
86 : :
87 [ + + ][ + - ]: 52875 : while((aCurrentLine.size() || aCurrentEntry != maLineEntries.end()) && (nLineNumber < nStopLine))
[ + + ][ + + ]
[ + + ]
[ + + # # ]
88 : : {
89 : : // add all entries which start at current line to current scanline
90 [ + - ][ + + ]: 54515 : while(aCurrentEntry != maLineEntries.end())
91 : : {
92 : 29244 : const sal_Int32 nCurrentLineNumber(aCurrentEntry->getY());
93 : :
94 [ + + ]: 29244 : if(nCurrentLineNumber > nLineNumber)
95 : : {
96 : : // line is below current one, done (since array is sorted)
97 : 26963 : break;
98 : : }
99 : : else
100 : : {
101 : : // less or equal. Line is above or at current one. Advance it exactly to
102 : : // current line
103 : 2281 : const sal_uInt32 nStep(nLineNumber - nCurrentLineNumber);
104 : :
105 [ - + ][ # # ]: 2281 : if(!nStep || aCurrentEntry->decrementRasterConversionLineEntry3D(nStep))
[ + - ]
106 : : {
107 : : // add when exactly on current line or when incremet to it did not
108 : : // completely consume it
109 [ - + ]: 2281 : if(nStep)
110 : : {
111 [ # # ]: 0 : aCurrentEntry->incrementRasterConversionLineEntry3D(nStep, *this);
112 : : }
113 : :
114 [ + - ]: 2281 : aCurrentLine.push_back(&(*(aCurrentEntry)));
115 : : }
116 : : }
117 : :
118 [ + - ]: 2281 : aCurrentEntry++;
119 : : }
120 : :
121 : : // sort current scanline using comparator. Only X is used there
122 : : // since all entries are already in one processed line. This needs to be done
123 : : // everytime since not only new spans may have benn added or old removed,
124 : : // but incrementing may also have changed the order
125 [ + - ]: 52234 : ::std::sort(aCurrentLine.begin(), aCurrentLine.end(), lineComparator());
126 : :
127 : : // process current scanline
128 : 52234 : aRasterConversionLineEntry3D = aCurrentLine.begin();
129 : 52234 : aNextLine.clear();
130 : 52234 : nPairCount = 0;
131 : :
132 [ + - ][ + + ]: 156702 : while(aRasterConversionLineEntry3D != aCurrentLine.end())
133 : : {
134 [ + - ]: 104468 : RasterConversionLineEntry3D& rPrevScanRasterConversionLineEntry3D(**aRasterConversionLineEntry3D++);
135 : :
136 : : // look for 2nd span
137 [ + + ][ + - ]: 104468 : if(aRasterConversionLineEntry3D != aCurrentLine.end())
138 : : {
139 : : // work on span from rPrevScanRasterConversionLineEntry3D to aRasterConversionLineEntry3D, fLineNumber is valid
140 [ + - ]: 52234 : processLineSpan(rPrevScanRasterConversionLineEntry3D, **aRasterConversionLineEntry3D, nLineNumber, nPairCount++);
141 : : }
142 : :
143 : : // increment to next line
144 [ + + ]: 104468 : if(rPrevScanRasterConversionLineEntry3D.decrementRasterConversionLineEntry3D(1))
145 : : {
146 [ + - ]: 102295 : rPrevScanRasterConversionLineEntry3D.incrementRasterConversionLineEntry3D(1, *this);
147 [ + - ]: 102295 : aNextLine.push_back(&rPrevScanRasterConversionLineEntry3D);
148 : : }
149 : : }
150 : :
151 : : // copy back next scanline if count has changed
152 [ + + ]: 52234 : if(aNextLine.size() != aCurrentLine.size())
153 : : {
154 [ + - ]: 1590 : aCurrentLine = aNextLine;
155 : : }
156 : :
157 : : // increment fLineNumber
158 : 52234 : nLineNumber++;
159 : 641 : }
160 : : }
161 : 641 : }
162 : :
163 : 2204 : void RasterConverter3D::addEdge(const B3DPolygon& rFill, sal_uInt32 a, sal_uInt32 b, const B3DHomMatrix* pViewToEye)
164 : : {
165 [ + - ]: 2204 : B3DPoint aStart(rFill.getB3DPoint(a));
166 [ + - ]: 2204 : B3DPoint aEnd(rFill.getB3DPoint(b));
167 : 2204 : sal_Int32 nYStart(fround(aStart.getY()));
168 : 2204 : sal_Int32 nYEnd(fround(aEnd.getY()));
169 : :
170 [ + + ]: 2204 : if(nYStart != nYEnd)
171 : : {
172 [ + + ]: 2157 : if(nYStart > nYEnd)
173 : : {
174 [ + - ]: 1075 : ::std::swap(aStart, aEnd);
175 : 1075 : ::std::swap(nYStart, nYEnd);
176 : 1075 : ::std::swap(a, b);
177 : : }
178 : :
179 : 2157 : const sal_uInt32 nYDelta(nYEnd - nYStart);
180 : 2157 : const double fInvYDelta(1.0 / nYDelta);
181 : : maLineEntries.push_back(RasterConversionLineEntry3D(
182 : 2157 : aStart.getX(), (aEnd.getX() - aStart.getX()) * fInvYDelta,
183 : 2157 : aStart.getZ(), (aEnd.getZ() - aStart.getZ()) * fInvYDelta,
184 [ + - ]: 2157 : nYStart, nYDelta));
185 : :
186 : : // if extra interpolation data is used, add it to the last created entry
187 : 2157 : RasterConversionLineEntry3D& rEntry = maLineEntries[maLineEntries.size() - 1];
188 : :
189 [ + + ][ + - ]: 2157 : if(rFill.areBColorsUsed())
190 : : {
191 [ + - ][ + - ]: 264 : rEntry.setColorIndex(addColorInterpolator(rFill.getBColor(a), rFill.getBColor(b), fInvYDelta));
[ + - ]
192 : : }
193 : :
194 [ + - ][ - + ]: 2157 : if(rFill.areNormalsUsed())
195 : : {
196 [ # # ][ # # ]: 0 : rEntry.setNormalIndex(addNormalInterpolator(rFill.getNormal(a), rFill.getNormal(b), fInvYDelta));
[ # # ]
197 : : }
198 : :
199 [ + - ][ + + ]: 2157 : if(rFill.areTextureCoordinatesUsed())
200 : : {
201 [ + - ]: 264 : if(pViewToEye)
202 : : {
203 [ + - ]: 264 : const double fEyeA(((*pViewToEye) * aStart).getZ());
204 [ + - ]: 264 : const double fEyeB(((*pViewToEye) * aEnd).getZ());
205 : :
206 : : rEntry.setInverseTextureIndex(addInverseTextureInterpolator(
207 : : rFill.getTextureCoordinate(a),
208 : : rFill.getTextureCoordinate(b),
209 [ + - ][ + - ]: 264 : fEyeA, fEyeB, fInvYDelta));
[ + - ]
210 : : }
211 : : else
212 : : {
213 : : rEntry.setTextureIndex(addTextureInterpolator(
214 : : rFill.getTextureCoordinate(a),
215 : : rFill.getTextureCoordinate(b),
216 [ # # ][ # # ]: 0 : fInvYDelta));
[ # # ]
217 : : }
218 : : }
219 : 2204 : }
220 : 2204 : }
221 : :
222 : 90 : void RasterConverter3D::rasterconvertB3DEdge(const B3DPolygon& rLine, sal_uInt32 nA, sal_uInt32 nB, sal_Int32 nStartLine, sal_Int32 nStopLine, sal_uInt16 nLineWidth)
223 : : {
224 [ + - ]: 90 : B3DPoint aStart(rLine.getB3DPoint(nA));
225 [ + - ]: 90 : B3DPoint aEnd(rLine.getB3DPoint(nB));
226 : 90 : const double fZBufferLineAdd(0x00ff);
227 : : static bool bForceToPolygon(false);
228 : :
229 [ + - ][ - + ]: 90 : if(nLineWidth > 1 || bForceToPolygon)
230 : : {
231 : : // this is not a hairline anymore, in most cases since it's an oversampled
232 : : // hairline to get e.g. AA for Z-Buffering. Create fill geometry.
233 [ # # ]: 0 : if(!aStart.equal(aEnd))
234 : : {
235 : 0 : reset();
236 : 0 : maLineEntries.clear();
237 : :
238 : 0 : B2DVector aVector(aEnd.getX() - aStart.getX(), aEnd.getY() - aStart.getY());
239 [ # # ]: 0 : aVector.normalize();
240 [ # # ]: 0 : const B2DVector aPerpend(getPerpendicular(aVector) * ((static_cast<double>(nLineWidth) + 0.5) * 0.5));
241 : 0 : const double fZStartWithAdd(aStart.getZ() + fZBufferLineAdd);
242 : 0 : const double fZEndWithAdd(aEnd.getZ() + fZBufferLineAdd);
243 : :
244 [ # # ]: 0 : B3DPolygon aPolygon;
245 [ # # ]: 0 : aPolygon.append(B3DPoint(aStart.getX() + aPerpend.getX(), aStart.getY() + aPerpend.getY(), fZStartWithAdd));
246 [ # # ]: 0 : aPolygon.append(B3DPoint(aEnd.getX() + aPerpend.getX(), aEnd.getY() + aPerpend.getY(), fZEndWithAdd));
247 [ # # ]: 0 : aPolygon.append(B3DPoint(aEnd.getX() - aPerpend.getX(), aEnd.getY() - aPerpend.getY(), fZEndWithAdd));
248 [ # # ]: 0 : aPolygon.append(B3DPoint(aStart.getX() - aPerpend.getX(), aStart.getY() - aPerpend.getY(), fZStartWithAdd));
249 [ # # ]: 0 : aPolygon.setClosed(true);
250 : :
251 [ # # ][ # # ]: 0 : addArea(aPolygon, 0);
252 : 0 : }
253 : : }
254 : : else
255 : : {
256 : : // it's a hairline. Use direct RasterConversionLineEntry creation to
257 : : // rasterconvert lines as similar to areas as possible to avoid Z-Fighting
258 : 90 : sal_Int32 nYStart(fround(aStart.getY()));
259 : 90 : sal_Int32 nYEnd(fround(aEnd.getY()));
260 : :
261 [ + + ]: 90 : if(nYStart == nYEnd)
262 : : {
263 : : // horizontal line, check X
264 : 13 : const sal_Int32 nXStart(static_cast<sal_Int32>(aStart.getX()));
265 : 13 : const sal_Int32 nXEnd(static_cast<sal_Int32>(aEnd.getX()));
266 : :
267 [ + - ]: 13 : if(nXStart != nXEnd)
268 : : {
269 : 13 : reset();
270 : 13 : maLineEntries.clear();
271 : :
272 : : // horizontal line, create vertical entries. These will be sorted by
273 : : // X anyways, so no need to distinguish the case here
274 : : maLineEntries.push_back(RasterConversionLineEntry3D(
275 : 13 : aStart.getX(), 0.0,
276 : 13 : aStart.getZ() + fZBufferLineAdd, 0.0,
277 [ + - ]: 13 : nYStart, 1));
278 : : maLineEntries.push_back(RasterConversionLineEntry3D(
279 : 13 : aEnd.getX(), 0.0,
280 : 13 : aEnd.getZ() + fZBufferLineAdd, 0.0,
281 [ + - ]: 13 : nYStart, 1));
282 : : }
283 : : }
284 : : else
285 : : {
286 : 77 : reset();
287 : 77 : maLineEntries.clear();
288 : :
289 [ + + ]: 77 : if(nYStart > nYEnd)
290 : : {
291 [ + - ]: 47 : ::std::swap(aStart, aEnd);
292 : 47 : ::std::swap(nYStart, nYEnd);
293 : : }
294 : :
295 : 77 : const sal_uInt32 nYDelta(static_cast<sal_uInt32>(nYEnd - nYStart));
296 : 77 : const double fInvYDelta(1.0 / nYDelta);
297 : :
298 : : // non-horizontal line, create two parallell entries. These will be sorted by
299 : : // X anyways, so no need to distinguish the case here
300 : : maLineEntries.push_back(RasterConversionLineEntry3D(
301 : 77 : aStart.getX(), (aEnd.getX() - aStart.getX()) * fInvYDelta,
302 : 77 : aStart.getZ() + fZBufferLineAdd, (aEnd.getZ() - aStart.getZ()) * fInvYDelta,
303 [ + - ]: 77 : nYStart, nYDelta));
304 : :
305 : 77 : RasterConversionLineEntry3D& rEntry = maLineEntries[maLineEntries.size() - 1];
306 : :
307 : : // need to choose a X-Distance for the 2nd edge which guarantees all pixels
308 : : // of the line to be set. This is exactly the X-Increment for one Y-Step.
309 : : // Same is true for Z, so in both cases, add one increment to them. To also
310 : : // guarantee one pixel per line, add a minimum of one for X.
311 [ + + ]: 77 : const double fDistanceX(fabs(rEntry.getX().getInc()) >= 1.0 ? rEntry.getX().getInc() : 1.0);
312 : :
313 : : maLineEntries.push_back(RasterConversionLineEntry3D(
314 : 77 : rEntry.getX().getVal() + fDistanceX, rEntry.getX().getInc(),
315 : 77 : rEntry.getZ().getVal() + rEntry.getZ().getInc(), rEntry.getZ().getInc(),
316 [ + - ]: 90 : nYStart, nYDelta));
317 : : }
318 : : }
319 : :
320 [ + - ]: 90 : if(!maLineEntries.empty())
321 : : {
322 [ + - ]: 90 : rasterconvertB3DArea(nStartLine, nStopLine);
323 : 90 : }
324 : 90 : }
325 : :
326 : 551 : void RasterConverter3D::rasterconvertB3DPolyPolygon(const B3DPolyPolygon& rFill, const B3DHomMatrix* pViewToEye, sal_Int32 nStartLine, sal_Int32 nStopLine)
327 : : {
328 : 551 : reset();
329 : 551 : maLineEntries.clear();
330 : 551 : addArea(rFill, pViewToEye);
331 : 551 : rasterconvertB3DArea(nStartLine, nStopLine);
332 : 551 : }
333 : :
334 : 30 : void RasterConverter3D::rasterconvertB3DPolygon(const B3DPolygon& rLine, sal_Int32 nStartLine, sal_Int32 nStopLine, sal_uInt16 nLineWidth)
335 : : {
336 : 30 : const sal_uInt32 nPointCount(rLine.count());
337 : :
338 [ + - ]: 30 : if(nPointCount)
339 : : {
340 [ - + ]: 30 : const sal_uInt32 nEdgeCount(rLine.isClosed() ? nPointCount : nPointCount - 1);
341 : :
342 [ + + ]: 120 : for(sal_uInt32 a(0); a < nEdgeCount; a++)
343 : : {
344 : 90 : rasterconvertB3DEdge(rLine, a, (a + 1) % nPointCount, nStartLine, nStopLine, nLineWidth);
345 : : }
346 : : }
347 : 30 : }
348 : : } // end of namespace basegfx
349 : :
350 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|