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

📄 camera.cpp

📁 手机 GAME c++ 版
💻 CPP
字号:
////////////////////////////////////////////////////////////////////////
//
// Camera.cpp
//
// Copyright (c) 2003 Nokia Mobile Phones Ltd.  All rights reserved.
//
////////////////////////////////////////////////////////////////////////

#include "Camera.h"
#include "Face.h"

////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

void TCamera::SetFieldOfView(const TReal &aAngle,const TReal &aPixelSize)
	{
	// Calculate the screen depth that would give us exactly the desired FOV,
	// and then round this off to an integer value:
	TReal degreesToRadians = 3.141592 / 180.0;

	TReal tanHalfAngle;
	Math::Tan(tanHalfAngle, (aAngle * 0.5 * degreesToRadians));

	TReal idealScreenDepth = aPixelSize / tanHalfAngle;

	TInt32 screenDepthAsInt;
	Math::Int(screenDepthAsInt, idealScreenDepth);
	iScreenDepth = screenDepthAsInt;

	// Generate lookup table for perspective transform:
	TReal screenDepth = screenDepthAsInt * ratioUnity;
	TInt depth;

	for ( depth = depthTableSize - 1 ; depth > 0 ; depth-- )
		{
		TReal depthRatio = screenDepth / ( depth + 0.5 );
		TInt32 depthRatioAsInt;

		Math::Int(depthRatioAsInt, depthRatio);

		if ( depthRatioAsInt > maxRatio )
			{
			break;
			}

		iDepthRatio[ depth ] = ( TInt16 )depthRatioAsInt;
		}

	iMinDepth = depth + 1;
	}

////////////////////////////////////////////////////////////////////////

void TCamera::SetBounds
	(
	TInt aLeftX, 
	TInt aTopY, 
	TInt aRightX, 
	TInt aBottomY, 
	TInt aCenterX, 
	TInt aCenterY
	)
	{
	//
	// Adjust coords to leave half-pixel safety margin.
	// (Note that we are in effect using a fixed-point 
	// representation with a unity value of 2.)
	//
	TInt leftX		= ( aLeftX			<< 1 ) + 1;
	TInt topY		= ( aTopY			<< 1 ) + 1;
	TInt rightX		= ( aRightX			<< 1 ) + 1;
	TInt bottomY	= ( aBottomY		<< 1 ) + 1;

	TInt screenZ	= iScreenDepth << 1;
	TInt centerX	= aCenterX << 1;
	TInt centerY	= aCenterY << 1;

	// Map center and bounds into screen coords:
	iCenterX = aCenterX	<< Geometry3D::screenCoordUnityLog;
	iCenterY = aCenterY	<< Geometry3D::screenCoordUnityLog;

	iLeftX	 = ( aLeftX		<< Geometry3D::screenCoordUnityLog ) + Geometry3D::screenCoordBias;
	iTopY	 = ( aTopY		<< Geometry3D::screenCoordUnityLog ) + Geometry3D::screenCoordBias;
	iRightX	 = ( aRightX	<< Geometry3D::screenCoordUnityLog ) + Geometry3D::screenCoordBias;
	iBottomY = ( aBottomY	<< Geometry3D::screenCoordUnityLog ) + Geometry3D::screenCoordBias;


	// Map screen bounds into space coords:
	TInt screenXL = leftX	- centerX;
	TInt screenXR = rightX	- centerX;
	TInt screenYT = topY	- centerY;
	TInt screenYB = bottomY	- centerY;

	// Take vertices of screen frustrum (in camera space coords):
	TVector3 origin( 0, 0, 0 );

	TVector3 screenTL(screenXL, screenYT, screenZ);
	TVector3 screenTR(screenXR, screenYT, screenZ);
	TVector3 screenBR(screenXR, screenYB, screenZ);
	TVector3 screenBL(screenXL, screenYB, screenZ);
	
	// Use these vertices to define clipping planes for the view volume:
	iClipPlane[Geometry3D::leftBound]	= TPlane(origin, screenTL, screenBL);
	iClipPlane[Geometry3D::topBound]	= TPlane(origin, screenTR, screenTL);
	iClipPlane[Geometry3D::rightBound]	= TPlane(origin, screenBR, screenTR);
	iClipPlane[Geometry3D::bottomBound]	= TPlane(origin, screenBL, screenBR);
	}

////////////////////////////////////////////////////////////////////////

void TCamera::SetAffine(TAffineTransform &aAffine)
	{
	iAffine = aAffine;
	}

////////////////////////////////////////////////////////////////////////

void TCamera::TransformVerts
	(
	TInt aNumVerts, 
	const TVector3 * aSrcVertPtr, 
	TAffineTransform &aAffine, 
	TScreenVertex * aDestVertPtr, 
	TVector3 &aCameraInModelSpace 
	)
	{
	// Get affine transform to map model into camera space:
	TAffineTransform modelToCameraAff;
	modelToCameraAff.MakeCompound(aAffine, iAffine);

	// Use this to transform model:
	const TVector3 * srcPtr = aSrcVertPtr;
	TScreenVertex * destPtr = aDestVertPtr;

	for (TInt v = 0 ; v < aNumVerts ; v++)
		{
		modelToCameraAff.Transform(*srcPtr, destPtr->iSpacePos);

		PrepareForScreen(*destPtr, 0);

		srcPtr++;
		destPtr++;
		}

	// Find position of camera in model space (for facing tests):
	modelToCameraAff.GetInverseVector(aCameraInModelSpace);
	}

////////////////////////////////////////////////////////////////////////

void TCamera::ClipAndRender
	( 
	TClipFace &aFaceA, 
	TClipFace &aFaceB, 
	TMathLookup &aMath, 
	TScanConverter &aScanConverter 
	)
	{
	TClipFace * validFacePtr = &aFaceA;
	TClipFace * invalidFacePtr = &aFaceB;

	for ( TInt b = 0 ; b < Geometry3D::numBounds ; b++ )
		{
		validFacePtr->ClipSelf(*invalidFacePtr, iClipPlane[b], b, *this, aMath);

		TClipFace * tempFacePtr = validFacePtr;
		validFacePtr = invalidFacePtr;
		invalidFacePtr = tempFacePtr;

		if ( !validFacePtr->IsDrawable() )
			{
			return;
			}
		}

	validFacePtr->RenderUnclipped(aScanConverter, aMath);
	}

////////////////////////////////////////////////////////////////////////

void TCamera::PrepareForScreen(TScreenVertex &aVertex, TInt aBoundIndex)
	{
	aVertex.iOutcodes = 0;

	for ( TInt b = aBoundIndex ; b < Geometry3D::numBounds ; b++ )
		{
		if ( iClipPlane[b].PointIsOutside(aVertex.iSpacePos) )
			{
			aVertex.iOutcodes |= 1 << b;
			}
		}

	if ( aVertex.iOutcodes == 0 )
		{
		aVertex.iScreenX = iCenterX + PerspectiveTransform(aVertex.iSpacePos.iX, aVertex.iSpacePos.iZ);
		aVertex.iScreenY = iCenterY + PerspectiveTransform(aVertex.iSpacePos.iY, aVertex.iSpacePos.iZ);

		if ( aVertex.iScreenX < iLeftX )
			{
			aVertex.iScreenX = iLeftX;
			}
		else if ( aVertex.iScreenX > iRightX )
			{
			aVertex.iScreenX = iRightX;
			}

		if ( aVertex.iScreenY < iTopY )
			{
			aVertex.iScreenY = iTopY;
			}
		else if ( aVertex.iScreenY > iBottomY )
			{
			aVertex.iScreenY = iBottomY;
			}
		}
	}

////////////////////////////////////////////////////////////////////////

TInt TCamera::PerspectiveTransform(TInt &aInput, TInt &aDepth)
	{
	TInt input = aInput;
	TInt depth = aDepth;

	TInt shift = resultDownshift;

	if ( depth <= 0 )
		{
		return 0;
		}

	while ( depth >= depthTableSize )
		{
		depth >>= 1;
		//
		// Downshifting input here would discard precision, so instead we will
		// fold the operation into the downshifting of the result.
		//
		shift++;
		}

	while ( depth < iMinDepth )
		{
		depth <<= 1;
		shift--;
		}

	TInt ratio = iDepthRatio[ depth ];
	TInt result = ( input * ratio ) >> shift;

	return result;	
	}

////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

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