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

📄 gameengine.cpp

📁 这个是symbian下的一个蛮庞大的3D游戏源代码!对于学习3D开发的人有很大的帮助!
💻 CPP
字号:
////////////////////////////////////////////////////////////////////////
//
// GameEngine.cpp
//
// Copyright (c) 2006 Nokia Corporation. All rights reserved.
//
////////////////////////////////////////////////////////////////////////

#include "GameEngine.h"

//System includes
#include <e32math.h>
#include <eikenv.h>
#include <eikapp.h>
#include <eikappui.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include <lang/GlobalStorage.h>
#include "dprintf.h"

//User includes
#include "DoublebufferedArea.h"
#include "GameTimer.h"

#ifdef __SERIES60_3X__
#include <cdsb.h>
#include "RenderAO.h"
#endif

#include "App.h"
#include "Context.h"
#include "dprintf.h"
#include <config.h>

const int BUFFER_SIZE = 352 * 416 * 2;  // max required buffer size (2Bpp) in double resolution.
const int SOUND_BUFFER_SIZE = 1024 * 4;


App* init();

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

CGameEngine* CGameEngine::NewLC(RWsSession& aClient, CWsScreenDevice& aScreenDevice, RWindow& aWindow, const TSize& aSize)
	{
	CGameEngine* self = new (ELeave) CGameEngine(aClient, aScreenDevice, aWindow, aSize);
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

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

CGameEngine* CGameEngine::NewL(RWsSession& aClient, CWsScreenDevice& aScreenDevice, RWindow& aWindow, const TSize& aSize)
	{
	CGameEngine* self = CGameEngine::NewLC(aClient, aScreenDevice, aWindow, aSize);
	CleanupStack::Pop();
	return self;
	}

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

CGameEngine::CGameEngine(RWsSession& aClient, CWsScreenDevice& aScreenDevice, RWindow& aWindow, const TSize& aSize) :
	m_context( 0 ),
	m_app( 0 ),
	m_buffer( 0 ),
	m_conv4Kto64K( 0 ),
	m_conv4Kto256K( 0 ),
	iClient(aClient),
	iScreenDevice(aScreenDevice),
	iWindow(aWindow),
	iSize(aSize),
	iDropRenderFrames(ETrue), // Set to "EFalse" to demonstrate ViewSrv 11 problem
	iFrameCounter(0),
	iBuffer(0)
	{
#ifndef SOUNDS_DISABLED
		iStream = 0;
#endif
		lang::GlobalStorage* gs = &lang::GlobalStorage::get();
		memset( gs, 0, sizeof(lang::GlobalStorage) );
	}

////////////////////////////////////////////////////////////////////////
	
void CGameEngine::ConstructL()
	{
	User::CompressAllHeaps();

	iPlaying = EFalse;

	iGameTimer = CGameTimer::NewL(*this);

	assert( CEikonEnv::Static() != 0 );
	assert( CEikonEnv::Static()->ScreenDevice() != 0 );
	TDisplayMode displaymode = CEikonEnv::Static()->ScreenDevice()->DisplayMode();
	TDisplayMode backbuffermode = EColor4K;
	if ( displaymode == EColor64K )
		backbuffermode = EColor64K;

	// Direct screen access
	iDirectScreenAccess = CDirectScreenAccess::NewL(iClient, iScreenDevice, iWindow, *this);
	iDoubleBufferedArea = CDoubleBufferedArea::NewL(iSize, backbuffermode);
	iOffscreenContext = &(iDoubleBufferedArea->GetDoubleBufferedAreaContext());
	
	// For S60 3rd Ed, use CDSB for faster drawing
	// (this could also be taken into use on later 2nd Ed devices)
#ifdef __SERIES60_3X__
	iDSBitmap = CDirectScreenBitmap::NewL();
	iRenderAo = new (ELeave) CRenderActive;
#endif

	iRedraw.Set(TRawEvent::ERedraw);

	// print time
	iTickCount = 0;
	time_t t;
	time( &t );
	dprintf( "Game Demo %s\n", ctime(&t) );

	// app allocation
	m_app = init();

	// app data path
	char apppath[KMaxFileName] = {0};
	TBuf<KMaxFileName> appname = CEikonEnv::Static()->EikAppUi()->Application()->AppFullName();
	int pos = 0;
	const unsigned short* p = appname.Ptr();
	while ( pos < appname.Length() ) 
		apppath[pos++] = (char)p[pos];
	apppath[pos] = 0;
	
#ifdef __SERIES60_3X__
	
	apppath[2] = 0; // store the drive and append our \private path on S60 3rd Ed
	strcat( apppath, "\\private\\e01fd192\\");
	
#else
	
	char* tp1 = strrchr( apppath, '/' );
	char* tp2 = strrchr( apppath, '\\' );
	char* tp = tp1 ? (tp1 > tp2 ? tp1 : tp2) : tp2;
	if ( tp )
		tp[1] = 0;
		
#endif

	strcpy( m_app->path, apppath );
	dprintf( "Application path is %s", m_app->path );

	InitSounds();

	m_buffer = new uint16_t[ BUFFER_SIZE ];
	memset( m_buffer, 0, BUFFER_SIZE * 2 );
	m_context = new Context;
	
	// init App
	m_app->init( m_context, this );
	}

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

CGameEngine::~CGameEngine()
	{
	delete[] m_conv4Kto64K;
	delete[] m_conv4Kto256K;
	delete m_context;
	delete[] m_buffer;
	delete m_app;

#ifndef SOUNDS_DISABLED
	delete iStream;
#endif

	delete iBuffer;
	delete iGameTimer;
	
#ifdef __SERIES60_3X__
	delete iDSBitmap;
	iRenderAo->Cancel();
	delete iRenderAo;
#endif

	delete iDirectScreenAccess;
	delete iDoubleBufferedArea;
	
	}

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

void CGameEngine::Render() 
	{
	//
	// NB: we must lock the offscreen bitmap with TBitmapUtil::Begin() to
	// prevent it being moved during the rendering process.
	//
	CFbsBitmap* bitmap = &(iDoubleBufferedArea->GetDoubleBufferedAreaBitmap());
	TBitmapUtil dummyUtil(bitmap);
	dummyUtil.Begin(TPoint(0,0));

	// Note assumption of screen format as 16 bpp:
	TSize size = bitmap->SizeInPixels();
	int width = size.iWidth;
	int height = size.iHeight;
	TUint16* buffer = (TUint16 *)bitmap->DataAddress();
	TDisplayMode displaymode = bitmap->DisplayMode();
	int pitch = CFbsBitmap::ScanLineLength( width, displaymode );
	m_context->set( m_buffer, pitch, width, height );
		
	int ticks = User::TickCount();
	if ( 0 == iTickCount || ticks-iTickCount > 32 )
		iTickCount = ticks;

	while ( iTickCount+2 < ticks )
	{
		if ( !m_app->update( Fix(8), m_context ) )
		{
			StopGame();
		}
		iTickCount += 2;
	}

	int dstSize = pitch * height;
	assert( dstSize < BUFFER_SIZE );
	
	uint16_t* s = (uint16_t*) m_buffer;
	uint16_t* d = (uint16_t*) buffer;
	switch ( displaymode )
	{
	case EColor4K:
		memcpy( d, s, dstSize );
		break;
	case EColor64K:
		if ( 0 == m_conv4Kto64K )
		{
			// create color conversion table
			m_conv4Kto64K = new uint16_t[4096];
			for ( int i = 0 ; i < 4096 ; ++i )
			{
				int r = (i >> 8) & 0xF;
				int g = (i >> 4) & 0xF;
				int b = (i) & 0xF;
				r = ((r*31) / 15)&0x1F;
				g = ((g*63) / 15)&0x3F;
				b = ((b*31) / 15)&0x1F;
				m_conv4Kto64K[i] = uint16_t( (r<<11) + (g<<5) + b );
			}
		}
		dstSize >>= 1;
		for ( int i = 0 ; i < dstSize; ++i )
			d[i] = m_conv4Kto64K[(s[i] & 0xFFF)];
		break;
	default:
		break;
	}
	//bitmap->UnlockHeap();
	dummyUtil.End();
	}
	
#ifdef __SERIES60_3X__

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

void CGameEngine::DirectRender()
	{
	// skip this frame if previous is not yet done
	if(iRenderAo->IsActive())
		return;
		
	int width = iSize.iWidth;
	int height = iSize.iHeight;
	
	int pitch = CFbsBitmap::ScanLineLength( width, EColor4K );
	m_context->set( m_buffer, pitch, width, height );
		
	int ticks = User::TickCount();
	if ( 0 == iTickCount || ticks-iTickCount > 32 )
		iTickCount = ticks;

	while ( iTickCount+2 < ticks )
	    {
		if ( !m_app->update( Fix(8), m_context ) )
    		{
    		StopGame();
    		}
		iTickCount += 2;
	    }

	const int dstPixCount = width * height;
	uint16_t* s = (uint16_t*) m_buffer;
		
	if ( 0 == m_conv4Kto256K )
		{
		// create color conversion table (RGB444) -> (RGB666)
		m_conv4Kto256K = new TUint32[4096];
		for ( int i = 0 ; i < 4096 ; ++i )
			{
			int r = (i >> 8) & 0xF;
			int g = (i >> 4) & 0xF;
			int b = (i) & 0xF;
			r = ((r*63) / 15)&0x3F;
			g = ((g*63) / 15)&0x3F;
			b = ((b*63) / 15)&0x3F;
			m_conv4Kto256K[i] = TUint32( (r<<18) + (g<<10) + (b<<2) );
			}
		}
		
	TAcceleratedBitmapInfo info;
    iDSBitmap->BeginUpdate(info);        
    TUint32* framebuf = (TUint32*)info.iAddress;
  
    for ( int i = 0 ; i < dstPixCount; ++i )
			framebuf[i] = m_conv4Kto256K[(s[i] & 0xFFF)];

    iDSBitmap->EndUpdate(*(iRenderAo->Status()));
	iRenderAo->Activate();	    
  }

#endif // __SERIES60_3X__
		

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

void CGameEngine::SetupDirectScreenAccessL()
	{

	// Initialise DSA
	iDirectScreenAccess->StartL();
				
	// Get graphics context for it
	iGc = iDirectScreenAccess->Gc();

	// Get region that DSA can draw in
	iRegion = iDirectScreenAccess->DrawingRegion();

	// Set the display to clip to this region
	iGc->SetClippingRegion(iRegion);
	
#ifdef __SERIES60_3X__

	iDSBitmap->Create(iRegion->BoundingRect(), CDirectScreenBitmap::EDoubleBuffer);

#endif
	}

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

void CGameEngine::StartFirstGameL()
	{
	StartGameL();
	// We only want to play the game if we have the whole screen available so 
	// on first start we record the region available for comparision later (in restart)
	iGameDawingArea = iRegion->BoundingRect();
	}

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

void CGameEngine::StartGameL()
	{
	iTickCount = User::TickCount();
	iPaused = EFalse;
	if(!iPlaying)
		{
		SetupDirectScreenAccessL();
		iGameTimer->Restart();
		}
	iPlaying = ETrue;
	}

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

void CGameEngine::StopGame()
	{
	iPlaying = EFalse;
	iPaused = ETrue;
	iGameTimer->CancelTimer();
	iDirectScreenAccess->Cancel();
	
#ifdef __SERIES60_3X__
	iDSBitmap->Close();
#endif
	}

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

TInt CGameEngine::DoGameFrame()
	{
	if(iPaused)
		{
		PauseFrame();
		}
	else
		{
			
#ifdef __SERIES60_3X__

		// Drop 1 render frame in every 128, to avoid ViewSrv 11 problems:
		if (iDropRenderFrames & ((iFrameCounter & 0x007f) != 0x007f))
			{
			DirectRender();
			}

#else

		// Force backlight to remain on:
		UserSvr::AddEvent(iRedraw);

		// Force screen update:
		iDirectScreenAccess->ScreenDevice()->Update();

		// Drop 1 render frame in every 128, to avoid ViewSrv 11 problems:
		if (iDropRenderFrames & ((iFrameCounter & 0x007f) != 0x007f))
			{
			Render();
			}
		
		// Draw from offscreen bitmap
		iGc->BitBlt(TPoint(0,0), &(iDoubleBufferedArea->GetDoubleBufferedAreaBitmap()));
		
#endif

		iFrameCounter++;

		}
	return CGameTimer::TickAgain;
	}

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

void CGameEngine::Restart(RDirectScreenAccess::TTerminationReasons /*aReason*/)
	{
	// Restart display
	// Note that this will result in the clipping region being updated
	// so that menus, overlaying dialogs, etc. will not be drawn over

	if(iPaused)
		{
		SetupDirectScreenAccessL();
		if(iGameDawingArea == iRegion->BoundingRect())
			{
			iPaused = EFalse;	
			if(!iGameTimer->IsActive())
				{
				iGameTimer->Restart();
				}
			}
		else
			{
			PauseFrame();
			}
		}
	else
		{
		if(!iGameTimer->IsActive())
			{
			iGameTimer->Restart();
			}
		}
	}

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

void CGameEngine::AbortNow(RDirectScreenAccess::TTerminationReasons /*aReason*/)
	{
	// Cancel timer and display
	iDirectScreenAccess->Cancel();
	iPaused = ETrue;
	
#ifdef __SERIES60_3X__
	iDSBitmap->Close();
#endif
	}

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

void CGameEngine::PauseFrame()
	{
	if ( iBuffer )
		memset( SoundBuffer(), 0, SOUND_BUFFER_SIZE );

	// Force backlight to remain on:
	UserSvr::AddEvent(iRedraw);

	// Force screen update: this is required for WINS, but may
	// not be for all hardware:
	iDirectScreenAccess->ScreenDevice()->Update();
	}

////////////////////////////////////////////////////////////////////////
void* CGameEngine::SoundBuffer()
{
	ASSERT( iBuffer );
	return (void*)iBuffer->Ptr();
}

void CGameEngine::InitSounds()
{
	iBuffer = HBufC8::NewMaxL( SOUND_BUFFER_SIZE );

#ifndef SOUNDS_DISABLED
	memset( SoundBuffer(), 0, SOUND_BUFFER_SIZE );

	iStream = CMdaAudioOutputStream::NewL( *this );
	iStream->Open( &iSettings );
#endif
}

void CGameEngine::StartSoundPlayback()
{
	ASSERT( iBuffer );

#ifndef SOUNDS_DISABLED
	iStream->WriteL( *iBuffer ); 
#endif
}

void CGameEngine::MaoscOpenComplete( TInt aError )
{
#ifndef SOUNDS_DISABLED
	if ( KErrNone == aError )
	{
		ASSERT( iStream );

		iStream->SetAudioPropertiesL( 
			TMdaAudioDataSettings::ESampleRate16000Hz,
			TMdaAudioDataSettings::EChannelsMono );

		iStream->SetVolume( iStream->MaxVolume() );
		iStream->SetPriority( EPriorityMuchMore, EMdaPriorityPreferenceNone );      
	}
	else 
	{
		_LIT( KPanic, "audio" );
		User::Panic( KPanic, 1 );
	}

	StartSoundPlayback(); 
#endif
}

void CGameEngine::MaoscBufferCopied( TInt aError, const TDesC8& /*aBuffer*/ )
{
#ifndef SOUNDS_DISABLED
	if ( KErrNone == aError )
	{
		ASSERT( iStream );
		ASSERT( iBuffer );

		int16_t* buf = (int16_t*)SoundBuffer();
		const int size = SOUND_BUFFER_SIZE >> 1;
		mix( buf, size );

		iStream->WriteL( *iBuffer ); 
	} 
#endif
}

void CGameEngine::MaoscPlayComplete( TInt aError )
{
#ifndef SOUNDS_DISABLED
	if ( KErrUnderflow == aError ) 
	{
		iStream->Stop();
		iStream->SetAudioPropertiesL( 
			TMdaAudioDataSettings::ESampleRate16000Hz, 
			TMdaAudioDataSettings::EChannelsMono );
		
		int16_t* buf = (int16_t*)SoundBuffer();
		const int size = SOUND_BUFFER_SIZE >> 1;
		mix( buf, size );

		iStream->WriteL( *iBuffer ); 
	}
#endif
}

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

// End of File

⌨️ 快捷键说明

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