thread method which is created by the dll using the native WIN32 API call (CreateThread).
Code: Select all
void threadFunc( LPVOID *lpvData )
{
logMessage( "gseEngine threadFunc, start run ... \n" );
while ( gseEngine ) {
if ( !gseEngine->isPaused() && !gseEngine->isShuttingDown() )
if ( gseEngine->getCamera() )
gseEngine->Render();
}
logMessage( "gseEngine threadFunc, end run ... %d\n", nOpenGSE );
}
of the engine is available at any given time.
Code: Select all
//! \class COpenGSE
//! \brief This class is exported from the OpenGSE.dll and provides the main
//! interface to the OpenGSE game/simulation engine. Note that it is
//! a multi-threaded dll and if using with a .NET application compile
//! the .NET application with /clr compiler switch.
// : public OpenGSE::gseSingleton<OpenGSE::COpenGSE>
class OPENGSE_API COpenGSE : public OpenGSE::gseSingleton<OpenGSE::COpenGSE>
{
protected:
private:
irr::IrrlichtDevice *mDevice; // Device pointer to Irrlicht rendering device, D3D8/9 or OGL interface.
irr::scene::ISceneManager *sceneMgr; // Scene manager from Irrlicht.
irr::gui::IGUIEnvironment *envMgr; // GUI manager from Irrlicht.
irr::gui::IGUIFont *defaultFont;
IrrPhysx::IPhysxManager *physxMgr; // PhysX interface.
IrrPhysx::SSceneDesc sceneDesc; // PhysX scene description.
IrrAI::IAIManager *aiMgr; // AI interface.
irr::scene::ISceneNode *rootNode; // root scene node.
gseDataSerializer *dataSerializer; // data serializer input/output of custom scene data.
gseEventReceiver *eventReceiver; // event receiver.
HWND m_hWindow; // Window that Irrlicht is running in.
WNDPROC wndProc; // Old window message handler.
irr::scene::ICameraSceneNode *cameraNode; // Current camera in use.
#if defined( USE_INTEL_TERRAIN )
gseTerrainManager *terrainMgr;
#endif
#if defined( USE_SHIFT_TERRAIN )
gseTerrain *terrainMgr;
#endif
#if defined( USE_PAGED_TERRAIN )
CTerrainPager *terrainMgr;
#endif
irr::core::map<irr::core::stringc, gseObjectArray> objectArray;
// thread for gseEngine tasks.
gseThread *gseEngineThread;
gseScriptEngine *scriptEngine;
bool ioOperation; // OpenGSE is loading or saving a file. Display a static image for now.
bool paused;
bool shutdown;
bool picknplaceMode;
public:
//! COpenGSE constructor, pass a Windows handle to the control that you
//! wish to use as a 'rendering context' for OpenGSE, this can be any
//! windows control.
COpenGSE ( HWND hWindow );
// irr::s32 readConfig ( const irr::core::stringc filePathName );
// irr::s32 writeConfig ( const irr::core::stringc filePathName );
irr::scene::ISceneManager *getSceneManager ( void ) { if ( !this ) return( NULL ); else return( sceneMgr ); };
#if defined( USE_INTEL_TERRAIN )
gseTerrainManager *getTerrainManager ( void ) { if ( !this ) return( NULL ); else return( terrainMgr ); };
#endif
#if defined( USE_SHIFT_TERRAIN )
gseTerrain *getTerrainManager ( void ) { if ( !this ) return( NULL ); else return( terrainMgr ); };
#endif
#if defined( USE_PAGED_TERRAIN )
CTerrainPager *getTerrainManager ( void ) { if ( !this ) return( NULL ); else return( terrainMgr ); };
#endif
//! Returns true/false on whether the engine is in pick and place mode or normal render mode.
// The difference is that that object can be picked and moved, for example by an editor when
// in pick and place mode (true).
bool getEngineMode ( void ) { return( picknplaceMode ); };
void setPauseState ( bool flag )
{
paused = flag;
};
//! Destructor for OpenGSE, cleans up Irrlicht, OpenGSE and removes itself from
//! the associated windows control that OpenGSE was using as a rendering context.
virtual ~COpenGSE ( void );
irr::scene::ICameraSceneNode *getCamera ( void )
{
if ( !cameraNode )
return( NULL );
return( cameraNode );
};
virtual irr::s32 loadSceneFromFile ( const irr::core::stringc filePathName );
virtual irr::s32 saveSceneToFile ( const irr::core::stringc filePathName );
virtual irr::s32 importIrrlichtScene ( const irr::core::stringc filePathName );
virtual irr::s32 exportIrrlichtScene ( const irr::core::stringc filePathName );
//! Returns the current device from Irrlicht that is being used by OpenGSE.
irr::IrrlichtDevice *getDevice ( void ) { return( mDevice ); };
//! Returns the current Windows handle (HWND) for the window, or control, that is
//! being used by OpenGSE to display the contents of the scene from the current
//! camera.
HWND getWindowHandle ( void ) { return( m_hWindow ); };
//! Handle the Windows message loop.
LRESULT CALLBACK WndProc ( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
//! Render the contents of the current OpenGSE 'scene'.
void Render ( void );
//! Returns a status flag indicating whether OpenGSE is shutting down or not.
bool isShuttingDown ( void ) { if ( !this ) return( true ); else return( shutdown ); };
//! Returns a status flag indicating whether OpenGSE is paused or not.
bool isPaused ( void ) { if ( !this ) return( true ); else return( paused ); };
// Add methods, these add existing objects into the engine.
// Create methods, these create new objects and add them into the engine.
//! Create a triangle meta selector for objects in the scene node, and it's children, for the
//! given camera.
void createCameraCollisionResponse ( const irr::scene::ICameraSceneNode *camera, const irr::scene::ISceneNode *root );
//! Creates an object and inserts it into the current scene that is in use by OpenGSE.
gseObject *createObject ( irr::core::stringc objectType, irr::scene::ISceneNode *parent = NULL, irr::s32 id = -1,
const irr::core::vector3df &position = irr::core::vector3df( 0, 0, 0 ),
const irr::core::vector3df &rotation = irr::core::vector3df( 0, 0, 0 ),
const irr::core::vector3df &scale = irr::core::vector3df( 1.0, 1.0, 1.0 ) );
// Remove methods, these remove an object, or objects from the engine.
// void removeObject ( const irr::core::stringc object_name );
// void removeObject ( const irr::u32 object_ident );
// void removeAllObjects ( void );
#if defined( _DEBUG ) && !defined( NDEBUG )
irr::s32 constructDebugScene ( irr::s32 sceneId = -1 );
#endif
};
which can be anything from a button, panel or full window.
Code: Select all
// This is the constructor of a class that has been exported, see OpenGSE.h for the class definition
// Based on the handle of the control passed to it start initialising the internal properties for
// OpenGSE along with making sure that Irrlicht (and friends) are also initialised, this method
// also associates a custom windows message handler with the passed control to allow for OpenGSE
// to be able to respond to any appropriate windows messages, including custom ones.
COpenGSE::COpenGSE( HWND hWindow )
{
logMessage( "COpenGSE construction taking place ... \n" );
cameraNode = NULL;
paused = true;
shutdown = false;
#if defined( _USE_INTEL_TERRAIN )
terrainMgr = NULL;
#endif
#if defined( USE_SHIFT_TERRAIN )
terrainMgr = NULL;
#endif
#if defined( USE_PAGED_TERRAIN )
terrainMgr = NULL;
#endif
if ( !gseEngine )
gseEngine = this;
if ( !hWindow ) {
gseEngine = NULL;
logMessage( "Bad window handle supplied to COpenGSE constructor. Create fullscreen window to compensate.\n" );
ErrorExit( (LPTSTR)L"COpenGSE, bad window handle given to OpenGSE.", 1 );
}
// Initialise Irrlicht to use the window handle provided.
RECT rc;
GetWindowRect( hWindow, &rc );
m_hWindow = hWindow;
// Associate this instance of OpenGSE with the window handle that has been passed to it.
SetWindowLongPtr( m_hWindow, GWLP_USERDATA, (LONG)this );
// Construct the event receiver and data serialiazer that are used when dealing with Irrlicht.
logMessage( "Constructing event receiver ... " );
eventReceiver = new gseEventReceiver;
if ( eventReceiver )
logMessage( "OK.\n" );
else
logMessage( "FAILED.\n" );
logMessage( "Constructing data serializer ... " );
dataSerializer = new gseDataSerializer;
if ( dataSerializer )
logMessage( "OK.\n" );
else
logMessage( "FAILED.\n" );
irr::SIrrlichtCreationParameters createParams;
// Construct the Irrlicht device to use the supplied window control and resize to fit it.
memset( (void*)&createParams, 0, sizeof( irr::SIrrlichtCreationParameters ) );
createParams.WindowId = reinterpret_cast<void*>(hWindow);
createParams.DriverType = irr::video::EDT_DIRECT3D9;
createParams.WindowSize = irr::core::dimension2d<irr::s32>(rc.right, rc.bottom);
createParams.EventReceiver = eventReceiver;
createParams.Vsync = true;
logMessage( "Constructing Irrlicht device ... " );
mDevice = irr::createDeviceEx( (const irr::SIrrlichtCreationParameters)createParams );
if ( !mDevice ) {
logMessage( "FAILED.\n" );
ErrorExit( (LPTSTR)L"COpenGSE, unable to construct Irrlicht device.", 2 );
} else
logMessage( "OK.\n" );
// Store a copy of the device being used by Irrlicht and also store a copy of the pointers
// to the current gui and scene manager. Also tell the scene manager that we are using our
// own version of the event receiver class to deal with messages passing through Irrlicht.
mDevice->setEventReceiver( eventReceiver );
mDevice->setResizeAble( true );
envMgr = mDevice->getGUIEnvironment();
sceneMgr = mDevice->getSceneManager();
envMgr->setUserEventReceiver( eventReceiver );
defaultFont = envMgr->getBuiltInFont();
// Save the original window proc.
wndProc = (WNDPROC)GetWindowLongPtr( m_hWindow, GWLP_WNDPROC );
// Take over the operations of the window message handler.
SetWindowLongPtr( m_hWindow, GWLP_WNDPROC, (LONG)(gseWndProc) );
// Construct the associated PhysX and AI modules to the engine.
memset( (void*)&sceneDesc, 0, sizeof( IrrPhysx::SSceneDesc ) );
physxMgr = IrrPhysx::createPhysxManager( mDevice, (const IrrPhysx::SSceneDesc)sceneDesc );
aiMgr = IrrAI::createAIManager( mDevice );
// Here would be construct any local threads for OpenGSE and set them to work.
logMessage( "Constructing engine thread ... " );
gseEngineThread = new gseThread( (LPVOID)&threadFunc, (LPVOID)this, false );
if ( gseEngineThread )
logMessage( "OK.\n" );
else
logMessage( "FAILED.\n" );
// Broadcast a message to the parent window control to show itself and then
// to the control itself to paint itself.
SendMessage( GetParent( m_hWindow ), SW_SHOW, NULL, NULL );
SendMessage( m_hWindow, WM_PAINT, NULL, NULL );
// DONT USE THE SCRIPT ENGINE AT PRESENT IT HAS NO WAY OF DOING OVERLAPPED I/O ON
// THE CONSOLE AND THIS DOESNT ALLOW OPENGSE TO FUNCTION CORRECTLY.
scriptEngine = NULL;
// Set the internal variable to say we are not paused and everything should render/run.
// This must be done last.
paused = false;
logMessage( "COpenGSE finished.\n" );
}
Code: Select all
// This does the rendering, perhaps this should be in it's own thread of sorts.
// Promoted to threading behaviour, the method (above) threadFunc does nothing
// more than call this method, repeatedly as part of a thread.
// + display the frame rate.
void COpenGSE::Render( void )
{
static int lastFPS = -1;
irr::core::stringw str;// = L"OpenGSE [ ";
str = L"OpenGSE [ ";
str += mDevice->getVideoDriver()->getName();
str += " ] ";
if ( paused ) {
str += "PAUSED";
}
if ( shutdown ) {
str += "SHUTDOWN";
}
if ( !paused && !shutdown ) {
physxMgr->simulate( 1.0f / 60 );
physxMgr->fetchResults();
aiMgr->update( (irr::s32)(1.0f / 60) );
str += " ] FPS:";
str += mDevice->getVideoDriver()->getFPS();
}
if ( mDevice && !paused ) {
mDevice->getTimer()->tick();
mDevice->getVideoDriver()->beginScene();
try {
if ( sceneMgr && cameraNode )
sceneMgr->drawAll(); // 3d stuffs
}
catch (...) {
logMessage( "Exception during rendering.\n" );
}
envMgr->drawAll(); // 2d gui stuffs.
if ( defaultFont ) { // 2d hud/debug info.
defaultFont->draw( (const wchar_t*)str.c_str(), core::rect<s32>(0,0,342,224), video::SColor(255,255,255,255), false, false );
defaultFont->draw( (const wchar_t*)L"Testing the frame rates for OpenGSE.", irr::core::rect<s32>(0,10,150,40), irr::video::SColor(127,127,255,255) );
}
#if defined( USE_INTEL_TERRAIN )
if ( terrainMgr )
terrainMgr->Render(cameraNode->getAbsoluteTransformation());
#endif
#if defined( USE_SHIFT_TERRAIN )
if ( terrainMgr )
terrainMgr->render();
#endif
#if defined( USE_PAGED_TERRAIN )
// if ( terrainMgr )
// terrainMgr->render();
#endif
mDevice->getVideoDriver()->endScene();
}
}
http://www.flickr.com/photos/56603839@N07/5226983623/
Extra info,
The engine also takes over control of handling the windows messages from the application that
are directed towards that control, ie COpenGSE has it's own windows messaging handler.
No I am *NOT* using the device->run() method rather the tick() method each render loop and
making sure the framerate is synched to the current modes refresh rate.
Have fun, and may the source be with you.