📄 scanconverter.cpp
字号:
////////////////////////////////////////////////////////////////////////
//
// ScanConverter.cpp
//
// Copyright (c) 2003 Nokia Mobile Phones Ltd. All rights reserved.
//
////////////////////////////////////////////////////////////////////////
#include "Face.h"
#include "MathLookup.h"
#include "ScanConverter.h"
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
TIntersectionBuffer::TIntersectionBuffer()
{
Reset();
}
////////////////////////////////////////////////////////////////////////
void TIntersectionBuffer::Reset()
{
iMinY = numEntries - 1;
iMaxY = 0;
}
////////////////////////////////////////////////////////////////////////
void TIntersectionBuffer::ScanEdge
(
const TScreenVertex &aVertexA,
const TScreenVertex &aVertexB, TMathLookup &aMath
)
{
TInt screenYA = aVertexA.iScreenY;
TInt screenYB = aVertexB.iScreenY;
TInt pixelYA = screenYA >> Geometry3D::screenCoordUnityLog;
TInt pixelYB = screenYB >> Geometry3D::screenCoordUnityLog;
if ( ( pixelYB - pixelYA ) < 1 )
{
// Edge doesn't cross any scanlines!
return;
}
//
// Update extrema as necessary:
//
if ( pixelYB > iMaxY )
{
iMaxY = pixelYB;
}
if ( pixelYA < iMinY )
{
iMinY = pixelYA;
}
TInt screenXA = aVertexA.iScreenX;
TInt screenXB = aVertexB.iScreenX;
TInt deltaX = screenXB - screenXA;
TInt deltaY = screenYB - screenYA;
TInt recipDeltaY;
TInt downshift;
aMath.GetReciprocal(deltaY, recipDeltaY, downshift);
// Adjust downshift to leave results in correct fixed-point units:
downshift -= interpolationUnityLog;
TInt downshiftBias = 1 << ( downshift - 1 );
// Calculate start x value (= intersection of edge with first scanline):
TInt startErrorY = ( -screenYA ) & Geometry3D::screenCoordFractionMask;
TInt startErrorYDeltaX = ( ( startErrorY * deltaX ) + Geometry3D::screenCoordBias )
>> Geometry3D::screenCoordUnityLog;
TInt startErrorX = ( startErrorYDeltaX * recipDeltaY ) >> downshift;
TInt interpX = startErrorX + ( screenXA << resultDownshift );
// Calculate scanline x increment (= gradient of edge):
TInt stepX = ( ( deltaX * recipDeltaY ) + downshiftBias ) >> downshift;
for ( TInt y = pixelYA ; y < pixelYB ; y++ )
{
iEntry[y] = interpX >> resultDownshift;
interpX += stepX;
}
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
TScanConverter::TScanConverter(const TSize& aSize)
{
iSize = aSize;
iScreenPtr = NULL;
iLeftX = 0;
iRightX = iSize.iWidth;
iTopY = 0;
iBottomY = iSize.iHeight;
// Set camera field-of-view to be 60 degrees from top to bottom of
// the screen. (Angle is arbitrary - the larger the angle, the
// stronger the "fish-eye" effect of projection.)
TReal halfHeight = iSize.iHeight * 0.5;
iCamera.SetFieldOfView(60.0, halfHeight);
iCamera.SetBounds(iLeftX, iTopY, iRightX, iBottomY, iSize.iWidth >> 1, iSize.iHeight >> 1);
}
////////////////////////////////////////////////////////////////////////
void TScanConverter::ClearScreen(TUint16 aFillColor)
{
TInt count = iSize.iWidth * iSize.iHeight;
TUint16 * screenPtrRov = iScreenPtr;
for ( TInt i = 0 ; i < count ; i++ )
{
*screenPtrRov = aFillColor;
screenPtrRov++;
}
}
////////////////////////////////////////////////////////////////////////
void TScanConverter::TransformVerts
(
TInt aNumVerts,
const TVector3 * aSrcVertPtr,
TAffineTransform &aAffine,
TScreenVertex * aDestVertPtr,
TVector3 &aCameraInModelSpace
)
{
iCamera.TransformVerts(aNumVerts, aSrcVertPtr, aAffine, aDestVertPtr, aCameraInModelSpace);
}
////////////////////////////////////////////////////////////////////////
void TScanConverter::ClipAndRender(TClipFace &aFaceA, TClipFace &aFaceB, TMathLookup &aMath)
{
iCamera.ClipAndRender(aFaceA, aFaceB, aMath, *this);
}
////////////////////////////////////////////////////////////////////////
void TScanConverter::ResetScan()
{
iLeftBuffer.Reset();
iRightBuffer.Reset();
}
////////////////////////////////////////////////////////////////////////
void TScanConverter::ScanEdge
(
const TScreenVertex &aVertexA,
const TScreenVertex &aVertexB,
TMathLookup &aMath
)
{
if ( aVertexA.iScreenY > aVertexB.iScreenY )
{
iRightBuffer.ScanEdge(aVertexB,aVertexA,aMath);
}
else
{
iLeftBuffer.ScanEdge(aVertexA,aVertexB,aMath);
}
}
////////////////////////////////////////////////////////////////////////
void TScanConverter::Fill(TUint16 aFlatColor)
{
TInt minY = iLeftBuffer.iMinY;
TInt maxY = iLeftBuffer.iMaxY;
//
// Clamping in y: these tests (and the corresponding tests in x)
// are for added security only, and are intended to allow the
// system to continue running despite overfow errors elsewhere.
//
if ( minY < iTopY )
{
minY = iTopY;
}
if ( maxY > iBottomY )
{
maxY = iBottomY;
}
TUint16 * scanLinePtr = &iScreenPtr[ iSize.iWidth * minY ];
for ( TInt y = minY ; y < maxY ; y++ )
{
TInt xL = iLeftBuffer.iEntry[ y ] >> Geometry3D::screenCoordUnityLog;
TInt xR = iRightBuffer.iEntry[ y ] >> Geometry3D::screenCoordUnityLog;
//
// Clamping in x: see comments for clamping in y
//
if ( xL < iLeftX )
{
xL = iLeftX;
}
if ( xR > iRightX )
{
xR = iRightX;
}
TUint16 * scanPtr = &scanLinePtr[ xL ];
scanLinePtr += iSize.iWidth;
for ( TInt x = xL ; x < xR ; x++ )
{
*scanPtr = aFlatColor;
scanPtr++;
}
}
}
////////////////////////////////////////////////////////////////////////
void TScanConverter::PlotPixel(TInt aX, TInt aY, TUint16 aFillColor)
{
if ( ( aX >= 0 ) && ( aX < iSize.iWidth ) && ( aY >= 0 ) && ( aY < iSize.iHeight ) )
{
TInt pixelIndex = ( iSize.iWidth * aY ) + aX;
iScreenPtr[ pixelIndex ] = aFillColor;
}
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -