⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpolygonobject.cpp

📁 JAVA3D游戏
💻 CPP
字号:
    /*
    *
============================================================================
    *  Name     : CPolygonObject.cpp
    *  Part of  : Example3D
    *  Created  : 12/14/2003 by Forum Nokia
    *  Description:
    *     This is the project specification file for Example3D.
    *     Initial content was generated by Series 60 AppWizard.
    *
    *  Version  : 1.0.0
    *  Copyright: Forum Nokia
    *
============================================================================
    */

// INCLUDES
#include "CPolygonObject.h"
#include <e32math.h>
#include <e32svr.h>		// for debug prints

// CONSTANTS

const TInt KZShift = 23;
const TInt KZMul = ( 1 << KZShift );

// MEMBER FUNCTIONS

CPolygonObject* CPolygonObject::NewL( C3DBase* a3DBase, TInt aNumVertices, TInt aNumFaces )
	{
	CPolygonObject* self = new( ELeave )CPolygonObject( a3DBase, aNumVertices, aNumFaces );
	CleanupStack::PushL( self );
	self->ConstructL();
	CleanupStack::Pop( self );
	return self;
	}

CPolygonObject::~CPolygonObject()
	{
	delete iFace;
	delete iVertex;
	delete iRVertex;

	delete iDrawList;
	delete iFaceZ;
	delete iFaceN;
	}

CPolygonObject::CPolygonObject( C3DBase* a3DBase, TInt aNumVertices, TInt aNumFaces )
	: i3DBase( a3DBase )
	, iMaxNumVertices( aNumVertices )
	, iMaxNumFaces( aNumFaces )
	{
	}

void CPolygonObject::ConstructL()
	{
	iFace = new( ELeave )TFace[ iMaxNumFaces ];
	iVertex = new( ELeave )TVertex[ iMaxNumVertices ];
	iRVertex = new( ELeave )TVertex[ iMaxNumVertices ];

	iCos = i3DBase->CosTable();
	iSin = i3DBase->SinTable();

	iFaceN = new( ELeave )TInt[ iMaxNumFaces ];
	iFaceZ = new( ELeave )TInt[ iMaxNumFaces ];
	iDrawList = new( ELeave )TDrawFace[ iMaxNumFaces ];

	}


void CPolygonObject::Draw( const TBitmap& aScreen, TMatrix* aRotateMatrix )
	{
	// rotate matrix from C3DRenderer
	iRotateMatrix = aRotateMatrix;

	iScreen = aScreen;

	TFrustum& frustum = i3DBase->ViewFrustum();

	// rotate vertices to iRVertex list
	Rotate();
	
	// clipped triangle has more than 3 vertices:
	TDrawVertex polygon1[ 10 ];
	TDrawVertex polygon2[ 10 ];

	TBool clipped;
	TInt  inCount = 0;

	// polygon's vertex distance from clipping plane
	TInt d[ 10 ];

	TInt numDrawn = 0;

	TInt i;
	for( i=0; i<iNumFaces; i++ )
		{
		TBool visible = ETrue;
		clipped = EFalse;

		TFace& f = iFace[ i ];

		TVertex& v1 = iRVertex[ f.iV1 ];
		TVertex& v2 = iRVertex[ f.iV2 ];
		TVertex& v3 = iRVertex[ f.iV3 ];


		polygon1[ 0 ] = TDrawVertex( v1, f.iTx1, f.iTy1 );
		polygon1[ 1 ] = TDrawVertex( v2, f.iTx2, f.iTy2 );
		polygon1[ 2 ] = TDrawVertex( v3, f.iTx3, f.iTy3 );

		TDrawVertex* poly1 = polygon1;
		TDrawVertex* poly2 = polygon2;

		TInt numPoints = 3;


		for( TInt n=0; n<frustum.iNumPlanes; n++ )
			{
			TInt vn = numPoints;
			TInt p;

			for( p=0; p<numPoints; p++ )
				{
				TVertex& mv1 = frustum.iPlane[ n ].iNormal;
				TDrawVertex& mv2 = poly1[ p ];
				
				// calculate dot product to get point distance to plane:
				TInt l = mv1.iX * mv2.iX + mv1.iY * mv2.iY + mv1.iZ * mv2.iZ;
				l += frustum.iPlane[ n ].iDistance;
				if( l <= 0 ) vn--;
				d[ p ] = l;
				inCount++;
				}

			if( vn == numPoints )
				{
				// all visible, do not clip
				continue;
				}

			if( vn == 0 )
				{
				// none visible, do not draw, do not continue clipping
				visible = EFalse;
				break;
				}
			
			clipped = ETrue;

			TInt np = 0;

			for( TInt p1=0; p1<numPoints; p1++ )
				{
				
				TInt p0 = p1-1;
				TInt p2 = p1+1;
				if( p0<0 ) p0 += numPoints;
				if( p2>=numPoints ) p2 -= numPoints;

				TDrawVertex& dv0 = poly1[ p0 ];
				TDrawVertex& dv1 = poly1[ p1 ];
				TDrawVertex& dv2 = poly1[ p2 ];

				// if point is out of plane, check if one or more points can be
				// added to drawarea's edge in straight line to other points
				// ( actual clipping )
				if( d[ p1 ] < 0 )
					{
					
					if( d[ p0 ] > 0 )
						{
						TInt s = ( d[ p0 ] << KShift ) / ( d[ p0 ]-d[ p1 ] );
						poly2[ np ].iX = dv0.iX + ( ( s*( dv1.iX - dv0.iX ) ) >> KShift );
						poly2[ np ].iY = dv0.iY + ( ( s*( dv1.iY - dv0.iY ) ) >> KShift );
						poly2[ np ].iZ = dv0.iZ + ( ( s*( dv1.iZ - dv0.iZ ) ) >> KShift );
						poly2[ np ].iTx = dv0.iTx + ( ( s*( dv1.iTx - dv0.iTx ) ) >> KShift );
						poly2[ np ].iTy = dv0.iTy + ( ( s*( dv1.iTy - dv0.iTy ) ) >> KShift );
						np++;
						}
					if( d[ p2 ] > 0 )
						{
						TInt s = ( d[ p2 ] << KShift ) / ( d[ p2 ]-d[ p1 ] );
						poly2[ np ].iX = dv2.iX + ( ( s*( dv1.iX - dv2.iX ) ) >> KShift );
						poly2[ np ].iY = dv2.iY + ( ( s*( dv1.iY - dv2.iY ) ) >> KShift );
						poly2[ np ].iZ = dv2.iZ + ( ( s*( dv1.iZ - dv2.iZ ) ) >> KShift );
						poly2[ np ].iTx = dv2.iTx + ( ( s*( dv1.iTx - dv2.iTx ) ) >> KShift );
						poly2[ np ].iTy = dv2.iTy + ( ( s*( dv1.iTy - dv2.iTy ) ) >> KShift );
						np++;
						}
					

					}
				else
					{
					poly2[ np++ ] = poly1[ p1 ];
					}
				}

			numPoints = np;

			TDrawVertex* temp = poly1; 
			poly1 = poly2; 
			poly2 = temp;
			}
				
		TInt t;
		if( visible )
			{
			if( numDrawn < iMaxNumFaces )
				{
				// split polygon to triangles:
				// ( polygon draw other but triangles are not supported )
				for( t=0; t<numPoints-2; t++ )
					{
					iDrawList[ numDrawn++ ] = TDrawFace( poly1[ 0 ], poly1[ 1 + t ], poly1[ 2 + t ] );
					}
				}
			}
		}

	// draw if there's something to draw
	if( numDrawn > 0 )
		{
		// project vertices in iRVertex list to screen coordinates
		Project( iDrawList, numDrawn );

		// sort faces by their Z-values

		for( i=0; i<numDrawn; i++ )
			{
			TDrawFace& f = iDrawList[ i ];
			iFaceZ[ i ] = f.iV1.iZ + f.iV2.iZ + f.iV3.iZ;
			iFaceN[ i ] = i;
			}

		i3DBase->QSort( iFaceZ, iFaceN, 0, numDrawn-1 );


		// and draw faces from back to front
		for( i=numDrawn-1; i>=0; i-- )
			{
			TDrawFace& f = iDrawList[ iFaceN[ i ] ];
			// textured
			DrawTexTri( &f.iV1, &f.iV2, &f.iV3 );
			
			// textured, perspective correct
			//DrawTexTriZ( &f.iV1, &f.iV2, &f.iV3 );

			}

		}


	}

void CPolygonObject::SetTexture( TUint16* aTexture )
	{
	iTexture = aTexture;
	}


TInt CPolygonObject::AddVertex( const TVertex& aVertex )
	{
	__ASSERT_DEBUG( iNumVertices < iMaxNumVertices, User::Panic( _L("Too many vertices"), iNumVertices ) );

	iVertex[ iNumVertices++ ] = aVertex;

	return iNumVertices-1;
	}

void CPolygonObject::SetVertex( TInt aIndex, const TVertex& aVertex )
	{
	__ASSERT_DEBUG( aIndex < iNumVertices, User::Panic( _L("Illegal vertex index"), aIndex ) );

	iVertex[ aIndex ] = aVertex;
	}

TInt CPolygonObject::AddFace( const TFace& aFace )
	{
	__ASSERT_DEBUG( iNumFaces < iMaxNumFaces, User::Panic( _L("Too many faces"), iNumFaces ) );

	iFace[ iNumFaces++ ] = aFace;

	return iNumFaces;
	}

void CPolygonObject::Init()
	{
	//
	// Calculate bounding radius for object clipping
	//
	TInt r = 0;

	TInt i;
	for( i=0; i<iNumVertices; i++ )
		{
		TVertex& v = iVertex[ i ];
		TInt r2 = v.iX * v.iX + v.iY * v.iY + v.iZ * v.iZ;
		if( r2 > r ) r = r2;
		}
	TReal ra;
	Math::Sqrt( ra, r );
	iBoundingRadius = ( TInt )ra;
	

	}


void CPolygonObject::Rotate()
	{
	// multiply all vertices by rotate matrix
	// rotate matrix is calculated by C3DRenderer

	for( TInt i=0; i<iNumVertices; i++ )
		{
		iRVertex[ i ] = iVertex[ i ];
		iRVertex[ i ].MulMatrix( iRotateMatrix );
		}
	}


void CPolygonObject::Project( TDrawFace* aFaceList, TInt aNumFaces )
	{
	
	TInt i;
	TInt mx = iScreen.iSize.iWidth / 2;
	TInt my = iScreen.iSize.iHeight / 2;


	for( i=0; i<aNumFaces; i++ )
		{

		TDrawFace& f = aFaceList[ i ];


		f.iV1.iX <<= 9;
		f.iV1.iX /= f.iV1.iZ ;
		f.iV1.iX += mx;

		f.iV1.iY <<= 9;
		f.iV1.iY /= f.iV1.iZ ;
		f.iV1.iY += my;

		f.iV2.iX <<= 9;
		f.iV2.iX /= f.iV2.iZ ;
		f.iV2.iX += mx;

		f.iV2.iY <<= 9;
		f.iV2.iY /= f.iV2.iZ ;
		f.iV2.iY += my;

		f.iV3.iX <<= 9;
		f.iV3.iX /= f.iV3.iZ ;
		f.iV3.iX += mx;

		f.iV3.iY <<= 9;
		f.iV3.iY /= f.iV3.iZ ;
		f.iV3.iY += my;
		
		}

	}




	// disable warning of local variable may be used without initialized
	// these variables are always initialized but compiler doesn't know it.
#pragma warning( disable : 4701 )


void CPolygonObject::DrawTexTri( TDrawVertex* aV1, TDrawVertex* aV2, TDrawVertex* aV3 )
	{

	// backface culling ( only one side of triangle is visible )
	TInt z = ( aV3->iX - aV1->iX ) * ( aV3->iY - aV2->iY ) - ( aV3->iY - aV1->iY ) * ( aV3->iX - aV2->iX );
	if( z <= 0 )
		{
		return;
		}


	// calculate starting points and adders for triangle sides 
	// and texture coordinates

	if( aV1->iY > aV2->iY )
		{
		TDrawVertex* temp = aV1; aV1 = aV2; aV2 = temp;
		}

	if( aV2->iY > aV3->iY )
		{
		TDrawVertex* temp = aV2; aV2 = aV3; aV3 = temp;
		}

	if( aV1->iY > aV2->iY )
		{
		TDrawVertex* temp = aV1; aV1 = aV2; aV2 = temp;
		}

	TInt h1 = ( aV2->iY - aV1->iY );
	TInt h2 = ( aV3->iY - aV2->iY );
	TInt h3 = ( aV3->iY - aV1->iY );

	if( h3 == 0 ) return;

	TInt xAdd1;
	TInt xAdd2;
	TInt xAdd3;

	TInt txAdd1;
	TInt txAdd2;
	TInt txAdd3;

	TInt tyAdd1;
	TInt tyAdd2;
	TInt tyAdd3;

	if( h1 )
		{
		xAdd1 =  ( ( aV2->iX - aV1->iX ) << KShift ) / h1;
		txAdd1 = ( ( aV2->iTx - aV1->iTx ) << 8 ) / h1;
		tyAdd1 = ( ( aV2->iTy - aV1->iTy ) << 8 ) / h1;
		}
	if( h2 )
		{
		xAdd2 =  ( ( aV3->iX - aV2->iX ) << KShift ) / h2;
		txAdd2 = ( ( aV3->iTx - aV2->iTx ) << 8 ) / h2;
		tyAdd2 = ( ( aV3->iTy - aV2->iTy ) << 8 ) / h2;
		}
	if( h3 )
		{
		xAdd3 =  ( ( aV3->iX - aV1->iX ) << KShift ) / h3;
		txAdd3 = ( ( aV3->iTx - aV1->iTx ) << 8 ) / h3;
		tyAdd3 = ( ( aV3->iTy - aV1->iTy ) << 8 ) / h3;
		}

	TInt mul = ( aV2->iY - aV1->iY );

	TInt midX =  ( aV1->iX << 0 )  + ( ( xAdd3 * mul )  >> KShift  );
	TInt midTx = ( aV1->iTx << 8 )  + ( ( txAdd3 * mul ) >> 0  );
	TInt midTy = ( aV1->iTy << 8 )  + ( ( tyAdd3 * mul ) >> 0 );

	TInt w = ( aV2->iX << 0 ) - midX;

	TInt txa = ( aV2->iTx << 8 ) - midTx;
	TInt tya = ( aV2->iTy << 8 )  - midTy;
	
	if( w )
		{
		txa /= w;
		tya /= w;
		}

	// Draw triangle in two parts
	// first upper half and then lower
	// split by mid point
	// Also choose parameters depending which side of triangle
	// has the midpoint


	if( midX < aV2->iX ) // if long side left
		{
		if( h1 ) DrawTexSlice(	aV1->iX, aV1->iX, 
								xAdd3, xAdd1, 
								aV1->iY, aV2->iY,
								aV1->iTx << 8, aV1->iTy << 8,
								txa, tya,
								txAdd3, tyAdd3 );

		if( h2 ) DrawTexSlice(  midX, aV2->iX,
								xAdd3, xAdd2, 
								aV2->iY, aV3->iY, 
								midTx, midTy, 
								txa, tya, 
								txAdd3, tyAdd3 );
		}
	else			 // if long side right
		{
		if( h1 ) DrawTexSlice(  aV1->iX, aV1->iX, 
								xAdd1, xAdd3, 
								aV1->iY, aV2->iY, 
								aV1->iTx << 8, aV1->iTy << 8, 
								txa, tya, 
								txAdd1, tyAdd1 );

		if( h2 ) DrawTexSlice(	aV2->iX, midX, 
								xAdd2, xAdd3, 
								aV2->iY, aV3->iY, 
								aV2->iTx << 8, aV2->iTy << 8, 
								txa, tya, 
								txAdd2, tyAdd2 );		
		}

		
	}
	// enable warning of local variable may be used without initialized
#pragma warning( default : 4701 )


inline void CPolygonObject::DrawTexSlice( TInt aX1, TInt aX2, TInt aX1Add, TInt aX2Add, 
										  TInt aY1, TInt aY2, TInt aTx1, TInt aTy1, 
										  TInt aTxAddX, TInt aTyAddX, TInt aTxAddY, TInt aTyAddY )
	{
	// This function is a bit optimized so the reading might be hard

	TInt tp = aY1 * iScreen.iSize.iWidth;
	tp <<= 1;
	tp += (TInt)iScreen.iData;	// calculate screen address by starting
								// y-position

	TInt h = aY2 - aY1;

	TInt x1 = aX1 << KShift;	// calculate starting x-positions
	TInt x2 = aX2 << KShift;

	// here is combined adders for texture x and y coordinates 
	// to only one integer, high half has the X
	TInt otxa = ( ( aTxAddX & 0xffff ) << 16 ) + ( aTyAddX & 0xffff );
	
	// scan all lines from up to down
	// and fill area from x1 to x2 with texture
	// updates x1 and x2 positions after every line

	for( TInt y=h; y>0; y-- )
		{
		
#ifdef __WINS__

		TUint32 txa = otxa;
		TUint32 tx = ( aTx1 << 16 ) + ( aTy1 & 0xffff );
		TInt w = ( x2-x1 + ( 1 << ( KShift-1 ) ) ) >> KShift;
		TInt sp = (TInt)iTexture;
		TUint16* p = (TUint16*)( tp + ( ( x1 >> KShift ) << 1 ) );
		TInt x;
		
#else
		// compiler has difficulties to optimize right the rendering loop
		// these are helpers to keep all parameters in registers
		// which speeds up the drawing a lot
		// next phase would be writing straight assembler
		// but you can check the code this generates with "ABLD LISTING"
		// -command in "\group" -folder

		register TUint32 txa asm("r0");
		register TInt w asm("r1");
		register TUint32 tx asm("r2");
		register TInt sp asm("r3");
		register TInt x asm("r4");
		
		txa = otxa;
		w = ( x2-x1 ) >> KShift;
		tx = ( aTx1 << 16 ) + ( aTy1 & 0xffff );
		sp = (TInt)iTexture ;
		TUint16* p = (TUint16*)( tp + ( ( x1 >> KShift ) << 1 ) );
#endif
		
		for( x=w; x>=0; x-- )
			{
			TInt cp = ( tx >> 24 ) + ( tx & 0xff00 );
			*p++ = ((TUint16*)sp)[cp];
			tx += txa;
			}
		
		x1 += aX1Add;
		x2 += aX2Add;
		
		aTx1 += aTxAddY;
		aTy1 += aTyAddY;
		
		tp += iScreen.iSize.iWidth*2;
		}

	}





⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -