graphicsdeviceinterface/gdi/sgdi/LINE.CPP
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphicsdeviceinterface/gdi/sgdi/LINE.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,545 @@
+// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <gdi.h>
+
+#ifdef __ARMCC__
+#pragma arm
+#pragma O3
+#pragma Otime
+#endif
+
+EXPORT_C TLinearDDA::TLinearDDA():
+	iCount(0),
+	iDifference(),
+	iFinish(),
+	iGradient(0),
+	iInc(),
+	iPos(),
+	iStart(),
+	iBoundingRect(),
+	iBoundingRectSet(EFalse),
+	iInsideX(EFalse),
+	iInsideY(EFalse),
+	iStatus(EComplete)
+/** Constructs the default linear DDA.
+
+No start or end point is defined for the line. */
+	{}
+
+ 
+EXPORT_C TLinearDDA::TLinearDDA(const TLinearDDA& aLine):
+	iCount(aLine.iCount),
+	iDifference(aLine.iDifference),
+	iFinish(aLine.iFinish),
+	iGradient(aLine.iGradient),
+	iInc(aLine.iInc),
+	iPos(aLine.iPos),
+	iStart(aLine.iStart),
+	iBoundingRect(aLine.iBoundingRect),
+	iBoundingRectSet(aLine.iBoundingRectSet),
+	iInsideX(aLine.iInsideX),
+	iInsideY(aLine.iInsideY),
+	iStatus(aLine.iStatus)
+/** Copy constructs a linear DDA from the specified linear DDA.
+
+@param aLine The linear DDA to be copied. */
+	{}
+
+ 
+EXPORT_C void TLinearDDA::Construct(const TPoint& aStart,const TPoint& aFinish,TLineMode aMode)
+/** Constructs a linear DDA, setting the start and end points of the line.
+
+@param aStart The start point of the line. 
+@param aFinish The end point of the line. 
+@param aMode The mode of the line; defaults to centred. */
+	{
+	iStart=aStart;
+	iFinish=aFinish;
+	iDifference=(iFinish-iStart).AsSize();
+	iDifference.iWidth=Abs(iDifference.iWidth);
+	iDifference.iHeight=Abs(iDifference.iHeight);
+	iInc.iX=(iStart.iX>iFinish.iX)?-1:1;
+	iInc.iY=(iStart.iY>iFinish.iY)?-1:1;
+	if(iDifference.iWidth)
+		iGradient=(iFinish.iY-iStart.iY)/(iFinish.iX-iStart.iX);
+	iPos=iStart;
+	if(!iGradient)
+		iCount=iDifference.iWidth;
+	else
+		iCount=iDifference.iHeight;
+	if(aMode==ECenter)
+		iCount>>=1;
+	else
+		if(iCount)
+			iCount--;
+	iStatus=EInitialised;
+	if(aStart==aFinish)
+		iStatus=EComplete;
+	iBoundingRectSet=EFalse;
+	iInsideX = EFalse;
+	iInsideY = EFalse;
+	}
+
+ 
+EXPORT_C TBool TLinearDDA::SingleStep(TPoint& aPosition)
+/** Gets the pixel co-ordinates of the next pixel on the pixel line.
+
+The function is called repeatedly until the whole line has been traversed or, 
+if JumpToRect() has been called, until the part of the line inside the rectangle 
+has been traversed. Note that, for performance reasons, JumpToRect() may fail 
+to detect the intersection of the line with the rectangle accurately and 
+SingleStep() may return more points than strictly necessary.
+
+@param aPosition On entry to the first call, this can be a reference to any 
+point. On return from the first call, this is the position of the first pixel 
+in the line, as specified during construction of this object. On return from 
+subsequent calls, this is the position of subsequent pixels in the line, as 
+calculated by the function. On return from the final call, this is the position 
+of the last pixel in the line, as specified during construction of this object.
+@return ETrue, when the position of the last pixel is returned; EFalse, 
+otherwise. */
+    {
+    switch (iStatus)
+        {
+        case EInitialised:
+            aPosition = iStart;
+            iStatus = ECurrent;
+            return EFalse;
+        case ECurrent:
+            if (iDifference.iHeight == 0) // horizontal line
+                {
+                iPos.iX += iInc.iX;
+                if (iPos.iX == iFinish.iX)
+                    {
+                    iStatus = EComplete;
+                    }
+                }
+            else if (iDifference.iWidth == 0) // vertical line
+                {
+                iPos.iY += iInc.iY;
+                if (iPos.iY == iFinish.iY)
+                    {
+                    iStatus = EComplete;
+                    }
+                }
+            else // diagonal stripes
+                {
+                if (!iGradient)
+                    {
+                    iCount -= iDifference.iHeight;
+                    iPos.iX += iInc.iX;
+                    if (iCount < 0)
+                        {
+                        iCount += iDifference.iWidth;
+                        iPos.iY += iInc.iY;
+                        }
+                    }
+                else
+                    {
+                    iCount -= iDifference.iWidth;
+                    iPos.iY += iInc.iY;
+                    if (iCount < 0)
+                        {
+                        iCount += iDifference.iHeight;
+                        iPos.iX += iInc.iX;
+                        }
+                    }
+                if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
+                    {
+                    iStatus = EComplete;
+                    }
+                }
+            // common
+            aPosition = iPos;
+            if (iStatus == EComplete)
+                {
+                return ETrue;
+                }
+            if(iBoundingRectSet)
+                {
+                if (iPos.iX >= iBoundingRect.iTl.iX && iPos.iX < iBoundingRect.iBr.iX)
+                    iInsideX = ETrue;
+                else
+                    if (iInsideX)
+                        {
+                        iStatus=EComplete;
+                        return(ETrue);
+                        }
+                if (iPos.iY >= iBoundingRect.iTl.iY && iPos.iY < iBoundingRect.iBr.iY)
+                    iInsideY = ETrue;
+                else
+                    if (iInsideY)
+                        {
+                        iStatus=EComplete;
+                        return(ETrue);
+                        }
+                }
+            return EFalse;
+        default:
+            aPosition = iFinish;
+            return ETrue;
+        }
+    }
+ 
+EXPORT_C TBool TLinearDDA::NextStep(TPoint& aPosition)
+/** Gets the pixel co-ordinates of the start of the next scan line.
+
+The best line that joins the start and end points is formed from all the scan 
+lines returned by this function.
+
+The function is called repeatedly until the start position of all scanlines 
+has been returned.
+
+The start and end points passed to the constructor of this object define the 
+boundaries of the line. Successive scan lines move from the start point to 
+the end point.
+
+@param aPosition On entry to the first call, this can be a reference to any 
+point. On return from the first call, this is the position of the pixel that 
+defines the leftmost position of the first scan line. On return from subsequent 
+calls, this is the position of the pixel that defines the leftmost position 
+of the next scan line. On return from the final call, this is the position 
+of the last pixel in the line, as specified during construction. 
+@return ETrue, when the position of the last pixel is returned; EFalse, 
+otherwise. */
+    {
+    if (!iDifference.iHeight) // horizontal line
+        {
+        iPos = iFinish;
+        iStatus = EComplete;
+        aPosition = iFinish;
+        return ETrue;
+        }
+    if (!iDifference.iWidth || iGradient || (iStatus != ECurrent))
+        {
+        return SingleStep(aPosition);
+        }
+    // !iGradient && (iStatus != EInitialised)
+    if(iBoundingRectSet)
+        { // slower version
+        while ((iCount - iDifference.iHeight) >= 0)
+            {
+            if (SingleStep(aPosition))
+                return ETrue;
+            }
+        return SingleStep(aPosition);
+        }
+    // faster version avoids function calls
+    TBool lastLoop = EFalse;
+    do {
+        if ((iCount - iDifference.iHeight) < 0)
+            {
+            lastLoop = ETrue;
+            }
+        iCount -= iDifference.iHeight;
+        iPos.iX += iInc.iX;
+        if (iCount < 0)
+            {
+            iCount += iDifference.iWidth;
+            iPos.iY += iInc.iY;
+            }
+
+        if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
+            {
+            aPosition = iFinish;
+            iStatus = EComplete;
+            return ETrue;
+            }
+        }
+        while (!lastLoop);
+    aPosition = iPos;
+    return EFalse;
+    }
+ 
+EXPORT_C TBool TLinearDDA::SingleScanline(TPoint& aStartPosition,TPoint& aEndPosition)
+/** Gets the start and end pixel co-ordinates that define the next scan line.
+
+The best line that joins the start and end points is formed from all the scan 
+lines returned by this function.
+
+The function is called repeatedly until the position of all scanlines has 
+been returned.
+
+The start and end points passed to the constructor of this object define the 
+boundaries of the line. Successive scan lines move from the start point to 
+the end point.
+
+@param aStartPosition On entry to the first call, this can be a reference 
+to any point. On return from the first call, this is the position of the pixel 
+that defines the leftmost position of the first scan line. On return from 
+subsequent calls, this is the position of the pixel that defines the leftmost 
+position of the next scan line. On return from the final call, either this 
+or aEndPosition is set to the end point, as specified during construction.
+@param aEndPosition On entry to the first call, this can be a reference to 
+any point. On return from the first call, this is the position of the pixel 
+that defines the rightmost position of the first scan line. On return from 
+subsequent calls, this is the position of the pixel that defines the rightmost 
+position of the next scan line. On return from the final call, either this 
+or aStartPosition is set to the end point, as specified during construction.
+@return ETrue, when the position of the last scan line includes the end point; 
+EFalse, otherwise. */
+    {
+    TBool done=EFalse;
+    if(iDifference.iHeight==0)
+        {
+        aStartPosition=iStart;
+        aEndPosition=iFinish;
+        return(ETrue);
+        }
+    if(iDifference.iWidth==0 || iGradient)
+        {
+        done=SingleStep(aStartPosition);
+        aEndPosition=aStartPosition;
+        return(done);
+        }
+    // !iGradient
+    done=SingleStep(aStartPosition);
+    aEndPosition=aStartPosition;
+    while(iCount-iDifference.iHeight>=0 && !done)
+        {
+        iCount -= iDifference.iHeight;
+        iPos.iX += iInc.iX;
+        if (iCount < 0)
+            {
+            iCount += iDifference.iWidth;
+            iPos.iY += iInc.iY;
+            }
+
+        if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
+            {
+            iStatus = EComplete;
+            done = ETrue;
+            }
+        }
+    aEndPosition = iPos;
+    return done;
+    }
+ 
+EXPORT_C void TLinearDDA::JumpToRect(const TRect& aRect)
+/** Jumps to start of a clipping rectangle.
+
+This will accelerate the linear DDA to the vicinity of the specified rectangle. 
+It is NOT guaranteed to reach the rectangle, but will reduce co-ordinates 
+that are 1000's out to co-ordinates that are 10's out. Because of this, failure 
+to intersect the rectangle may not be detected. If it is, or the line has 
+not been constructed or has been run to completion, then a subsequent call 
+to the stepping functions returns ETrue.
+
+@param aRect The rectangle to be jumped to. */
+	{
+	if(aRect.IsEmpty() || iStatus!=EInitialised) return;
+	iBoundingRect=aRect;
+	iBoundingRectSet=ETrue;
+
+	TInt nearestx = 0;
+	if (iStart.iX < aRect.iTl.iX)
+		nearestx = aRect.iTl.iX;
+	else if (iStart.iX >= aRect.iBr.iX)
+		nearestx = aRect.iBr.iX;
+	else
+		iInsideX = ETrue;
+	TInt nearesty = 0;
+	if (iStart.iY < aRect.iTl.iY)
+		nearesty = aRect.iTl.iY;
+	else if (iStart.iY >= aRect.iBr.iY)
+		nearesty = aRect.iBr.iY;
+	else
+		iInsideY = ETrue;
+	if (iInsideX && iInsideY)
+		return;
+
+	TInt dummy;
+	if(!iGradient)
+		{
+		if (iInsideX)
+			return;
+		JumpToXCoord(nearestx,dummy);
+		}
+	else
+		{
+		if (iInsideY)
+			return;
+		JumpToYCoord(dummy,nearesty);
+		}
+	}
+
+ 
+EXPORT_C void TLinearDDA::JumpToXCoord(const TInt aXCoord,TInt& aYCoord)
+/** Jumps to x co-ordinate.
+
+The other co-ordinate of the intersection is returned through a reference 
+argument. After a jump call, the line is ready to continue through calls to 
+the stepping functions.
+
+This function accelerates the Linear DDA stepping functions (e.g. SingleStep()) 
+making them return EFalse when they reach the specified co-ordinate. If the 
+line does not cross the co-ordinate, has not been constructed, has been run 
+to completion or the intersection is the end point of the line then the stepping 
+functions will return ETrue.
+
+@param aXCoord x co-ordinate to jump to 
+@param aYCoord On return, this parameter holds the y co-ordinate which corresponds 
+to the specified x co-ordinate */
+	{
+	if(iStatus==EComplete) return; // not constructed
+	if((iStart.iX<aXCoord && iFinish.iX<aXCoord) || (iStart.iX>aXCoord && iFinish.iX>aXCoord))
+		return; // no intersection
+	aYCoord=iStart.iY;
+	if(iStart.iX==aXCoord) return; // trivial first intersection
+	iStatus=ECurrent;
+	if(iDifference.iHeight==0) // horizontal line
+		iPos.iX=aXCoord;
+	else
+		{
+		if(!iGradient)
+			{
+			TInt64 numsteps=Abs(aXCoord-iPos.iX);
+			TInt64 tempcount=TInt64(iCount)-(TInt64(iDifference.iHeight)*numsteps);
+			numsteps=Abs(tempcount/iDifference.iWidth);
+			tempcount+=numsteps*iDifference.iWidth;
+			while(tempcount<0)
+				{
+				tempcount+=iDifference.iWidth;
+				numsteps++;
+				}
+			iCount = I64INT(tempcount);
+			iPos.iY += (iInc.iY * I64INT(numsteps));
+			iPos.iX=aXCoord;
+			aYCoord=iPos.iY;
+			}
+		else
+			{
+			while(iPos.iX!=aXCoord)
+				{
+				iCount-=iDifference.iWidth;
+				if(iCount<0)
+					{
+					iCount+=iDifference.iHeight;
+					iPos.iX+=iInc.iX;
+					}
+				iPos.iY+=iInc.iY;
+				}
+			aYCoord=iPos.iY;
+			}
+		}
+    if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
+        {
+        iStatus=EComplete;
+        }
+	}
+
+ 
+EXPORT_C void TLinearDDA::JumpToYCoord(TInt& aXCoord,const TInt aYCoord)
+/** Jumps to a y co-ordinate.
+
+The other co-ordinate of the intersection is returned through a reference 
+argument. After a jump call, the line is ready to continue through calls to 
+the stepping functions.
+
+This function accelerates the Linear DDA stepping functions (e.g. SingleStep()) 
+making them return EFalse when they reach the specified co-ordinate. If the 
+line does not cross the co-ordinate, has not been constructed, has been run 
+to completion or the intersection is the end point of the line then they will 
+return ETrue. 
+
+@param aXCoord On return, this parameter holds the x co-ordinate which corresponds 
+to the specified y co-ordinate. 
+@param aYCoord y co-ordinate to jump to */
+	{
+	if(iStatus==EComplete) return; // not constructed
+	if((iStart.iY<aYCoord && iFinish.iY<aYCoord) || (iStart.iY>aYCoord && iFinish.iY>aYCoord))
+		return; // no intersection
+	aXCoord=iStart.iX;
+	if(iStart.iY==aYCoord) return; // trivial first intersection
+	iStatus=ECurrent;
+	if(iDifference.iWidth==0) // vertical line
+		iPos.iY=aYCoord;
+	else
+		{
+		if(!iGradient)
+			{
+			while(iPos.iY!=aYCoord)
+				{
+				iCount-=iDifference.iHeight;
+				if(iCount<0)
+					{
+					iCount+=iDifference.iWidth;
+					iPos.iY+=iInc.iY;
+					}
+				iPos.iX+=iInc.iX;
+				}
+			aXCoord=iPos.iX;
+			}
+		else
+			{
+			TInt64 numsteps=Abs(aYCoord-iPos.iY);
+			TInt64 tempcount=TInt64(iCount)-(TInt64(iDifference.iWidth)*numsteps);
+			numsteps=Abs(tempcount/iDifference.iHeight);
+			tempcount+=numsteps*iDifference.iHeight;
+			while (tempcount<0)
+				{
+				tempcount+=iDifference.iHeight;
+				numsteps++;
+				}
+			iCount = I64INT(tempcount);
+			iPos.iX += (iInc.iX * I64INT(numsteps));
+			iPos.iY=aYCoord;
+			aXCoord=iPos.iX;
+			}
+		}
+    if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
+        {
+        iStatus=EComplete;
+        }
+	}
+
+void TLinearDDA::UpdatePosition()
+	{
+	}
+
+EXPORT_C void TLinearDDA::JumpToXCoord2(TInt aXCoord,TInt& aYCoord)
+/**
+Jumps to x co-ordinate.
+
+This works in the same way as TLinearDDA::JumpToXCoord except that it make sure
+that using the NextStep function does not return the same value twice.
+
+@param aXCoord x co-ordinate to jump to
+@param aYCoord On return, this parameter holds the y co-ordinate which corresponds
+to the specified x co-ordinate
+@see TLinearDDA::JumpToXCoord(TInt, TInt&)
+*/
+	{
+	JumpToXCoord(aXCoord,aYCoord);
+	iStatus=ECurrent;
+	}
+
+EXPORT_C void TLinearDDA::JumpToYCoord2(TInt& aXCoord,TInt aYCoord)
+/**
+Jumps to a y co-ordinate.
+
+This works in the same way as TLinearDDA::JumpToYCoord except that it make sure
+that using the NextStep function does not return the same value twice.
+
+@param aXCoord On return, this parameter holds the x co-ordinate which corresponds
+to the specified y co-ordinate.
+@param aYCoord y co-ordinate to jump to
+@see TLinearDDA::JumpToYCoord(TInt&, TInt)
+*/ 
+	{
+	JumpToYCoord(aXCoord,aYCoord);
+	iStatus=ECurrent;
+	}