📄 cengine.cpp
字号:
/*
============================================================================
* Name : CEngine.cpp
* Part of : Example3D
* Description : Definition of CEngine
* Copyright (c) 2005 Nokia Corporation
============================================================================
*/
// INCLUDES
#include "CEngine.h"
#include "CGameTimer.h"
#include "CGame.h"
#include "CPictureLoader.h"
#include <eikenv.h>
#include <eikappui.h>
// CONSTANTS
const TInt KUpdateInterval = 1000000 / 64; // 64 times per second "Move" update
const TInt KMaxNumUpdates = 10;
// MEMBER FUNCTIONS
CEngine* CEngine::NewL( CWindowGc& aGc, RWindow& aWindow,
TDisplayMode aDisplayMode )
{
CEngine* self = new( ELeave )CEngine( aGc, aWindow, aDisplayMode );
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop( self );
return self;
}
CEngine::~CEngine()
{
iFile.Close();
iFs.Close();
delete iFbsBitmapBuffer;
delete iTimer;
delete iGame;
delete iFbsScreenDevice;
delete iBitmapUtil;
#ifdef GLES
eglMakeCurrent( iGldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
eglDestroyContext( iGldisplay, iGlcontext );
eglDestroySurface( iGldisplay, iGlsurface );
eglTerminate( iGldisplay );
#endif
}
void CEngine::ConstructL()
{
iFs.Connect();
iFile.Replace( iFs, _L("c:\\debug.txt"), EFileWrite );
iPaused = ETrue;
#ifdef GLES
// Define properties for the preferred EGLSurface, try to match with window depth
EGLint attribList[ ] = { EGL_BUFFER_SIZE, 0,
EGL_DEPTH_SIZE, 15,
EGL_NONE };
switch( iWindow.DisplayMode() )
{
case( EColor4K ) : { attribList[1] = 12; break; }
case( EColor64K ): { attribList[1] = 16; break; }
case( EColor16M ): { attribList[1] = 24; break; }
default: attribList[1] = 32; // for EColor16MU
}
EGLint numConfigs;
EGLint majorVersion;
EGLint minorVersion;
iGldisplay = eglGetDisplay( EGL_DEFAULT_DISPLAY );
if( iGldisplay == EGL_NO_DISPLAY )
{
User::Panic( _L("GL No Display"),0 );
}
if( !eglInitialize( iGldisplay, &majorVersion, &minorVersion ) )
{
User::Panic( _L("GL Init"), 0 );
}
if( !eglChooseConfig( iGldisplay, attribList, &iGlconfig, 1, &numConfigs ) )
{
User::Panic(_L("GL Config"), 0 );
}
iGlcontext = eglCreateContext( iGldisplay, iGlconfig, NULL, NULL );
if( iGlcontext==0 )
{
User::Panic( _L("GL Context"), 0 );
}
iGlsurface = eglCreateWindowSurface( iGldisplay, iGlconfig, &iWindow, NULL );
if( iGlsurface==0 )
{
User::Panic( _L("GL Surface"), 0 );
}
eglMakeCurrent( iGldisplay, iGlsurface, iGlsurface, iGlcontext );
#else
// create screen device for direct screen access
iFbsScreenDevice = CFbsScreenDevice::NewL( _L(""), iDisplayMode, NULL );
iFbsBitmapBuffer = new( ELeave )CFbsBitmap();
iBitmapUtil = new( ELeave )TBitmapUtil( iFbsBitmapBuffer );
#ifndef __WINS__
TScreenInfoV01 screenInfo;
TPckg<TScreenInfoV01> sInfo(screenInfo);
UserSvr::ScreenInfo(sInfo);
TUint16* screenAddr = screenInfo.iScreenAddressValid ? (TUint16*)screenInfo.iScreenAddress : 0;
User::LeaveIfNull( screenAddr );
// skip the palette data in the beginning of frame buffer (16 entries in 12bit mode)
screenAddr += 16;
iScreen.iData = screenAddr;
iScreen.iSize = screenInfo.iScreenSize;
#endif
#endif
iGame = CGame::NewL( iDisplayMode );
iTimer = CGameTimer::NewL( *this );
iTime.HomeTime();
// Some devices have difficulties to multitask with
// this application using idle time.
// This should help it a little
RProcess().SetPriority( EPriorityLow );
}
void CEngine::InitScreen( const TRect& aRect )
{
iDrawRect = aRect;
#ifdef GLES
#else
iFbsBitmapBuffer->Reset();
iFbsBitmapBuffer->Create( iDrawRect.Size(), iDisplayMode );
iBuffer.iData = iFbsBitmapBuffer->DataAddress();
#endif
iBuffer.iSize = iDrawRect.Size();
iBuffer.iMode = iDisplayMode;
}
CEngine::CEngine( CWindowGc& aGc, RWindow& aWindow,
TDisplayMode aDisplayMode )
: iGc( aGc )
, iWindow( aWindow )
, iDisplayMode( aDisplayMode )
{
}
TInt CEngine::DoGameFrameL()
{
if( iPaused )
{
// stop gametimer
return EFalse;
}
TPoint pos = iWindow.Position();
TSize size = iWindow.Size();
if( size != iDrawRect.Size() || pos != iDrawRect.iTl )
{
TRect rect( pos, size );
InitScreen( rect );
return ETrue;
}
//
// Calculate number of updates that should happen since last game frame
//
TTime time;
time.HomeTime();
TInt updates = time.MicroSecondsFrom( iTime ).Int64().Low();
iUpdates += updates;
updates = iUpdates / KUpdateInterval;
iTime = time.Int64();
TInt i;
for( i=0; i<updates; i++ )
{
iGame->Move( iKey );
}
iUpdates -= updates * KUpdateInterval;
#ifdef GLES
// Draw with OpenGL
eglMakeCurrent( iGldisplay, iGlsurface, iGlsurface, iGlcontext );
// GL double buffer swap
eglSwapBuffers( iGldisplay, iGlsurface);
iGame->Draw( iBuffer );
RRegion drawRegion;
drawRegion.AddRect( iDrawRect );
drawRegion.Clear();
#else
// Draw with software renderer
// Lock the bitmap we are drawing to
iBitmapUtil->Begin( TPoint( 0,0 ) );
// CFbsBitmap data address can change
iBuffer.iData = iFbsBitmapBuffer->DataAddress();
iBuffer.iMode = iDisplayMode;
iGame->Draw( iBuffer );
//
// During the direct screen draw we don't want any interruptions
// So adjust priority high at this time
//
RProcess().SetPriority( EPriorityHigh );
iWindow.Invalidate();
RRegion drawRegion;
iWindow.GetInvalidRegion( drawRegion );
iGc.Activate( iWindow );
iWindow.BeginRedraw();
TDrawBuffer drawBuffer = EBitmapCopy;
#ifdef __WINS__
drawBuffer = EBitmapCopy;
#else
// check if draw area is free to draw
// only then use directly screen memory to draw
// ( with doublebuffer to prevent display artifacts )
/*
if( drawRegion.Count() == 0 )
{
drawBuffer = ENoScreen;
}
else
{
TRect rect = ( drawRegion.RectangleList()[ 0 ] );
TPoint windowPos = iWindow.Position();
rect.iTl.iX += windowPos.iX;
rect.iBr.iX += windowPos.iX;
rect.iTl.iY += windowPos.iY;
rect.iBr.iY += windowPos.iY;
if( iDrawRect.iTl.iX >= rect.iTl.iX &&
iDrawRect.iTl.iY >= rect.iTl.iY &&
iDrawRect.iBr.iX <= rect.iBr.iX &&
iDrawRect.iBr.iY <= rect.iBr.iY )
{
drawBuffer = EDoubleBuffered;
}
}
*/
#endif
drawBuffer = EBitmapCopy;
switch( drawBuffer )
{
case EBitmapCopy:
{
// Blit to top left corner of our window
// this doesn't have to be top left corner of the screen
iGc.BitBlt( TPoint( 0,0 ), iFbsBitmapBuffer );
break;
}
case EDoubleBuffered:
{
// Since draw rect can be different from actual screen size
// this copy has to be done line-by-line
TUint16* sourceAddress = ( TUint16* )iBuffer.iData;
TUint16* targetAddress = ( TUint16* )iScreen.iData;
// add offset from drawing rect
targetAddress += iDrawRect.iTl.iX;
targetAddress += iDrawRect.iTl.iY * iScreen.iSize.iWidth;
// bytes to copy per line
TInt numBytes = iDrawRect.Width() * 2; // 16 bit pixels
for( TInt y=0; y<iBuffer.iSize.iHeight; y++ )
{
Mem::Copy( targetAddress, sourceAddress, numBytes );
sourceAddress += iBuffer.iSize.iWidth;
targetAddress += iScreen.iSize.iWidth;
}
break;
}
}
drawRegion.Clear();
drawRegion.AddRect( iDrawRect );
iFbsScreenDevice->Update( drawRegion );
// RRegion leaks memory if Clear isn't called
drawRegion.Clear();
iWindow.EndRedraw();
iGc.Deactivate();
// Unlock the bitmap we are drawing to
iBitmapUtil->End();
//
// Set priority back to normal
//
RProcess().SetPriority( EPriorityLow );
#endif
// continue gametimer
return ETrue;
}
void CEngine::KeyEvent( const TKeyEvent& aKeyEvent,TEventCode aType )
{
switch( aType )
{
case EEventKeyDown:
{
iKey[ aKeyEvent.iScanCode ] = 1;
break;
}
case EEventKeyUp:
{
iKey[ aKeyEvent.iScanCode ] = 0;
break;
}
default:
{
break;
}
}
}
void CEngine::Start()
{
if( !iPaused ) return;
iPaused = EFalse;
iTimer->Start();
}
void CEngine::Stop()
{
if( iPaused ) return;
iPaused = ETrue;
iTimer->Cancel();
}
void CEngine::Command( TInt aCommand )
{
if( iGame )
{
iGame->Command( aCommand );
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -