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

📄 cpolygonobject.cpp

📁 S60 3D游戏引擎开发案例 S60 3D游戏引擎开发案例
💻 CPP
字号:
   /*
============================================================================
    * Name : CPolygonObject.cpp
    * Part of : Example3D
    * Description : Definition of CPolygonObject
    * Copyright (c) 2007 Nokia Corporation
============================================================================
    */

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

// CONSTANTS
const TUint KInvalidTextureObject = 0xffffffff;

// 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;
	delete[] iGlVerts;
	delete[] iGlTexCoords;
	delete[] iGlTris;
	if( iTextureObject != KInvalidTextureObject )
		{
		glDeleteTextures( 1, &iTextureObject );
		}
	}

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 ];

	// OpenGl texture object handle
	// valid texture handle is '0'
	// so set the handle as KInvalidTextureObject here.
	iTextureObject = KInvalidTextureObject;
	}

void CPolygonObject::Draw( const TBitmap& aScreen, TMatrix* aRotateMatrix )
	{
	// Here the drawing is done with OpenGl ES
	// We are using Z-buffered draw with opengl
	// so we don't need to sort the polygons

	const TInt glShift = 16;

	// shift adjustor
	// OpenGl uses 16-bit decimals
	// and this example uses KShift-bit decimals
	// this is the difference to convert values to same decimal depth
	const TInt shift = glShift - KShift;
	const TInt mul = 1 << shift;

    glMatrixMode    (GL_MODELVIEW);
	
	// Generate rotate matrix for OpenGl from example's rotate matrix
	GLfixed mat[4*4]={ (*aRotateMatrix)[0]*mul, -(*aRotateMatrix)[4]*mul, -(*aRotateMatrix)[ 8]*mul, 0,
					   (*aRotateMatrix)[1]*mul, -(*aRotateMatrix)[5]*mul, -(*aRotateMatrix)[ 9]*mul, 0,
					   (*aRotateMatrix)[2]*mul, -(*aRotateMatrix)[6]*mul, -(*aRotateMatrix)[10]*mul, 0,
					   (*aRotateMatrix)[3]*mul, -(*aRotateMatrix)[7]*mul, -(*aRotateMatrix)[11]*mul, 1 << glShift };
    
	// Init OpenGl for drawing
	glLoadMatrixx( mat );
	
	glEnableClientState( GL_VERTEX_ARRAY );
	glVertexPointer( 3, GL_FIXED, 0, iGlVerts );
	
	if( iTextureObject != KInvalidTextureObject )
		{
		glBindTexture( GL_TEXTURE_2D, iTextureObject );
		glEnable( GL_TEXTURE_2D );
		glEnableClientState( GL_TEXTURE_COORD_ARRAY );
		glTexCoordPointer( 2, GL_FIXED, 0, iGlTexCoords );
		}
	else
		{
		glDisable( GL_TEXTURE_2D );
		glDisableClientState ( GL_TEXTURE_COORD_ARRAY );
		}
	glColor4x( 1<<glShift, 1<<glShift, 1<<glShift, 1<<glShift );
	glDrawElements( GL_TRIANGLES, iGlTriCount, GL_UNSIGNED_SHORT, iGlTris );

	// This isn't really accurate number of polygons drawn
	// but number of polygons feeded to OpenGL drawing pipeline
	// some of the polygons are backface culled off etc.
	i3DBase->AddPolygonCount( iGlTriCount );
	}

// OpenGl uses it's own texture handles
void CPolygonObject::SetTexture( TInt aTextureObjectHandle )
	{
	iTextureObject = aTextureObjectHandle;
	}

void CPolygonObject::Reset( TInt aNumVertices, TInt aNumFaces )
	{
	iMaxNumVertices = aNumVertices;
	iMaxNumFaces = aNumFaces;

	delete[] iFace;
	iFace = new( ELeave )TFace[ iMaxNumFaces ];
	iNumFaces = 0;
	
	delete[] iVertex;
	iVertex = new( ELeave )TVertex[ iMaxNumVertices ];
	
	delete[] iRVertex;
	iRVertex = new( ELeave )TVertex[ iMaxNumVertices ];
	iNumVertices = 0;

	delete[] iFaceN;
	iFaceN = new( ELeave )TInt[ iMaxNumFaces ];

	delete[] iFaceZ;
	iFaceZ = new( ELeave )TInt[ iMaxNumFaces ];

	delete[] iDrawList;
	iDrawList = new( ELeave )TDrawFace[ iMaxNumFaces ];
	}

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;

	// if using OpenGL ES, convert vertices and faces
	// to opengl world

	delete[] iGlVerts;
	delete[] iGlTexCoords;
	delete[] iGlTris;
	
	iGlTriCount = iNumFaces*3;
	iGlVerts=new GLfixed[ iGlTriCount*3];
	iGlTexCoords=new GLfixed[ iGlTriCount*2 ];
	iGlTris=new GLushort[ iGlTriCount ];

	TInt ic=0;
	TInt vc=0;

	const TInt textureSize = 256;
	const TInt GlShift = 16;
	const TInt shift = GlShift - KShift;

	for (i=0;i<iNumFaces;i++)
		{
		int a,b,c;
		a=iFace[i].iV1;
		b=iFace[i].iV2;
		c=iFace[i].iV3;

		iGlVerts[vc*3] = iVertex[a].iX << shift;
		iGlVerts[vc*3+1] = iVertex[a].iY << shift;
		iGlVerts[vc*3+2] = iVertex[a].iZ << shift;

		iGlTexCoords[vc*2] = ( iFace[i].iTx1 << GlShift ) / textureSize;
		iGlTexCoords[vc*2+1] = ( iFace[i].iTy1 << GlShift ) / textureSize;
		iGlTris[ic] = (GLushort)vc;
		ic++;	
		vc++;

		iGlVerts[vc*3] = iVertex[b].iX << shift;
		iGlVerts[vc*3+1] = iVertex[b].iY << shift;
		iGlVerts[vc*3+2] = iVertex[b].iZ << shift;
		iGlTexCoords[vc*2] = ( iFace[i].iTx2 << GlShift ) / textureSize;
		iGlTexCoords[vc*2+1] = ( iFace[i].iTy2 << GlShift ) / textureSize;
		iGlTris[ic] = (GLushort)vc;
		ic++;
		vc++;

		iGlVerts[vc*3] = iVertex[c].iX << shift;
		iGlVerts[vc*3+1] = iVertex[c].iY << shift;
		iGlVerts[vc*3+2] = iVertex[c].iZ << shift;
		iGlTexCoords[vc*2] = ( iFace[i].iTx3 << GlShift) / textureSize;
		iGlTexCoords[vc*2+1] = ( iFace[i].iTy3 << GlShift) / textureSize;
		iGlTris[ic] = (GLushort)vc;
		ic++;
		vc++;		
		}
	}

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 )
	{
	const TInt mul = 512;
	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 = f.iV1.iX * mul / f.iV1.iZ + mx;
		f.iV1.iY = f.iV1.iY * mul / f.iV1.iZ + my;
		f.iV2.iX = f.iV2.iX * mul / f.iV2.iZ + mx;
		f.iV2.iY = f.iV2.iY * mul / f.iV2.iZ + my;
		f.iV3.iX = f.iV3.iX * mul / f.iV3.iZ + mx;
		f.iV3.iY = f.iV3.iY * mul / f.iV3.iZ + my;		
		}
	}

inline void CPolygonObject::Swap( TAny* aV1, TAny* aV2 )
	{
	TUint32 temp = *(TUint32*)aV1;
	*(TUint32*)aV1 = *(TUint32*)aV2;
	*(TUint32*)aV2 = temp;
	}

	// 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 )
	{
	TInt d = ( aV1->iX - aV3->iX ) * ( aV2->iY - aV3->iY ) -
			 ( aV2->iX - aV3->iX ) * ( aV1->iY - aV3->iY );
	
	if( d <= 0 ) return;

	TInt id = ( 1 << 24 ) / d;

	TInt dudx = ( ( aV1->iTx - aV3->iTx ) * ( aV2->iY - aV3->iY ) -
				  ( aV2->iTx - aV3->iTx ) * ( aV1->iY - aV3->iY ) ) * id / ( 1 << 16 );

	TInt dvdx = ( ( aV1->iTy - aV3->iTy ) * ( aV2->iY - aV3->iY ) -
				  ( aV2->iTy - aV3->iTy ) * ( aV1->iY - aV3->iY ) ) * id / ( 1 << 16 );
	
	if( aV1->iY > aV2->iY ) { Swap( &aV1, &aV2 ); d = -d; }
	if( aV2->iY > aV3->iY ) { Swap( &aV2, &aV3 ); d = -d; }
	if( aV1->iY > aV2->iY ) { Swap( &aV1, &aV2 ); d = -d; }
	
	TInt h1 = ( aV2->iY - aV1->iY );
	TInt h2 = ( aV3->iY - aV2->iY );
	TInt h3 = ( aV3->iY - aV1->iY );

	if( h3 == 0 ) return;

	TInt h1i = 0;
	if( h1 ) h1i = 65536 / h1; 
	TInt h2i = 0;
	if( h2 ) h2i = 65536 / h2; 
	TInt h3i = 65536 / h3;

	TInt y = aV1->iY;

	TInt x1, x2;
	TInt x1a, x2a;
	TInt txya;
	TInt tyya;
	TInt otx;
	TInt oty;
	
	for( ;; )
		{

		//
		// First half:
		//
		if( y==aV1->iY )
			{
			x1 = 256 * aV1->iX;
			x2 = x1;
			if( d > 0 ) // long side left
				{
				x1a = h3i * ( aV3->iX - aV1->iX ) >> 8;
				x2a = h1i * ( aV2->iX - aV1->iX ) >> 8;

				txya = h3i * ( aV3->iTx - aV1->iTx ) >> 8;
				tyya = h3i * ( aV3->iTy - aV1->iTy ) >> 8;
				otx = aV1->iTx << 8;
				oty = aV1->iTy << 8;
				}
			else		// long side right
				{
				x1a = h1i * ( aV2->iX - aV1->iX ) >> 8;
				x2a = h3i * ( aV3->iX - aV1->iX ) >> 8;
				txya = h1i * ( aV2->iTx - aV1->iTx ) >> 8;
				tyya = h1i * ( aV2->iTy - aV1->iTy ) >> 8;
				otx = aV1->iTx << 8;
				oty = aV1->iTy << 8;
				}

			}

		//
		// Second half:
		//
		if( y==aV2->iY )
			{
			if( d > 0 )	// long side left
				{
				x1a = h3i * ( aV3->iX - aV1->iX ) >> 8;
				x2a = h2i * ( aV3->iX - aV2->iX ) >> 8;
				x1 = 256 * aV1->iX + x1a * h1;
				x2 = 256 * aV2->iX;

				txya = h3i * ( aV3->iTx - aV1->iTx ) >> 8;
				tyya = h3i * ( aV3->iTy - aV1->iTy ) >> 8;
				otx = 256 * aV1->iTx + txya * h1;
				oty = 256 * aV1->iTy + tyya * h1;
				}
			else		// long side right
				{
				x1a = h2i * ( aV3->iX - aV2->iX ) >> 8;
				x2a = h3i * ( aV3->iX - aV1->iX ) >> 8;
				x1 = 256 * aV2->iX;
				x2 = 256 * aV1->iX + x2a * h1;

				txya = h2i * ( aV3->iTx - aV2->iTx ) >> 8;
				tyya = h2i * ( aV3->iTy - aV2->iTy ) >> 8;
				otx = 256 * aV2->iTx;
				oty = 256 * aV2->iTy;
				}
			}

		//
		// End of polygon
		//
		if( y==aV3->iY )
			{
			break;
			}
		
		// Left edge pointer
		TUint16* p = (TUint16*)iScreen.iData + y * iScreen.iSize.iWidth;

		// Right edge pointer
		TUint16* p2 = p + ( x2 >> 8 );
		p += x1 >> 8;

		TInt tx = otx;
		TInt ty = oty;
		
		// scanline filler
		register TUint16* sp = iTexture;
		register TInt txa = dudx;
		register TInt tya = dvdx;
		while( p <= p2 )
			{
			*p++ = sp[ ( tx >> 8 ) + ( ty & 0xff00 ) ];
			tx += txa;
			ty += tya;
			}

		x1 += x1a;
		x2 += x2a;
		otx += txya;
		oty += tyya;
		y++;
		}
	}

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

⌨️ 快捷键说明

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