📄 gameengine.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 + -