LCOV - code coverage report
Current view: top level - basegfx/source/raster - rasterconvert3d.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 146 0.0 %
Date: 2014-04-14 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10