source: GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrainApplication.cpp @ 866

Revision 866, 20.2 KB checked in by mattausch, 18 years ago (diff)

added support for iv scenes

Line 
1#include <OgreNoMemoryMacros.h>
2#include <CEGUI/CEGUI.h>
3#include <../CEGUIRenderer/include/OgreCEGUIRenderer.h>
4#include <../CEGUIRenderer/include/OgreCEGUIResourceProvider.h>
5#include <../CEGUIRenderer/include/OgreCEGUITexture.h>
6#include <OgreMemoryMacros.h>
7
8#include <Ogre.h>
9#include <direct.h> // for getcwd
10//#include "OgreReferenceAppLayer.h"
11//#include "OgreRefAppWorld.h"
12#include "TestCullingTerrainApplication.h"
13#include "TerrainFrameListener.h"
14
15#include "IVReader.h"
16
17#define WIN32_LEAN_AND_MEAN
18#include <windows.h>
19
20
21bool TestCullingTerrainApplication::msShowHillyTerrain = false;
22
23/******************************************************/
24/*             EntityState implementation             */
25/******************************************************/
26
27
28Vector3 EntityState::msMinPos = Vector3::ZERO;
29Vector3 EntityState::msMaxPos = Vector3::ZERO;
30
31EntityState::EntityState(Entity *ent, State entityState, Real speed):
32mEntity(ent), mState(entityState), mAnimationSpeed(speed)
33{
34        switch(entityState)
35        {
36        case MOVING:
37                mAnimationState = mEntity->getAnimationState("Walk");
38                break;
39        case WAITING:
40                mAnimationState = mEntity->getAnimationState("Idle");
41                break;
42        case STOP:
43                mAnimationState = NULL;
44                break;
45        default:
46                break;
47        }
48        // enable animation state
49        if (mAnimationState)
50        {
51                mAnimationState->setLoop(true);
52                mAnimationState->setEnabled(true);
53        }
54        mTimeElapsed = Math::RangeRandom(1, 5);
55}
56//-----------------------------------------------------------------------
57EntityState::~EntityState()
58{
59        mAnimationState = NULL;
60        mEntity = NULL;
61}
62//-----------------------------------------------------------------------
63Entity *EntityState::GetEntity()
64{
65        return mEntity;
66}
67//-----------------------------------------------------------------------
68EntityState::State EntityState::GetState()
69{
70        return mState;
71}
72//-----------------------------------------------------------------------
73void EntityState::update(Real timeSinceLastFrame)
74{
75        mTimeElapsed -= timeSinceLastFrame * mAnimationSpeed;
76
77        if (!mEntity || !mAnimationState)
78                return;
79       
80        if (mState == MOVING) // toggle between moving (longer) and waiting (short)
81        {
82                SceneNode *parent = mEntity->getParentSceneNode();
83               
84                if (!parent)
85                        return;
86
87                if (mTimeElapsed <= 0) // toggle animation state
88                {
89                        if (mAnimationState->getAnimationName() == "Idle")
90                        {
91                                SetAnimationState("Walk", true);
92                               
93                                mTimeElapsed = walk_duration; // walk for mTimeElapsed units
94
95                                // choose random rotation
96                                Radian rnd = Radian(Math::UnitRandom() * Math::PI * rotate_factor);
97
98                                //mEntity->getParentSceneNode()->rotate();
99                                parent->yaw(rnd);                                               
100                        }
101                        else
102                        {
103                                SetAnimationState("Idle", true);
104                                mTimeElapsed = wait_duration; // wait for mTimeElapsed seconds
105                        }
106                }
107
108                if (mAnimationState->getAnimationName() == "Walk") // move forward
109                {
110                        // store old position, just in case we get out of bounds
111                        Vector3 oldPos = parent->getPosition();
112                        parent->translate(parent->getLocalAxes(), Vector3(move_factor * mAnimationSpeed, 0, 0));
113
114                        // HACK: if out of bounds => reset to old position and set animationstate to idle
115                        if (OutOfBounds(parent))
116                        {
117                                parent->setPosition(oldPos);
118                                SetAnimationState("Idle", true);
119                               
120                                mTimeElapsed = wait_duration;
121                        }
122                }
123        }
124               
125        // add time to drive animation
126        mAnimationState->addTime(timeSinceLastFrame * mAnimationSpeed);
127}
128//-----------------------------------------------------------------------
129void EntityState::SetAnimationState(String stateStr, bool loop)
130{
131        if (!mEntity)
132                return;
133
134        mAnimationState = mEntity->getAnimationState(stateStr);
135        mAnimationState->setLoop(loop);
136        mAnimationState->setEnabled(true);
137}
138//-----------------------------------------------------------------------
139bool EntityState::OutOfBounds(SceneNode *node)
140{
141        Vector3 pos = node->getPosition();
142
143        if ((pos > msMinPos) && (pos < msMaxPos))
144                return false;
145
146        return true;
147}
148
149
150
151/*********************************************************/
152/*      TestCullingTerrainApplication implementation     */
153/*********************************************************/
154
155
156TestCullingTerrainApplication::TestCullingTerrainApplication():
157mTerrainContentGenerator(NULL), mRayQueryExecutor(NULL)
158{
159}
160//-----------------------------------------------------------------------
161TestCullingTerrainApplication::~TestCullingTerrainApplication()
162{
163        OGRE_DELETE(mTerrainContentGenerator);
164        OGRE_DELETE(mRayQueryExecutor);
165        OGRE_DELETE(mIVReader);
166
167        deleteEntityStates();   
168}
169//-----------------------------------------------------------------------
170void TestCullingTerrainApplication::deleteEntityStates()
171{
172        for (int i = 0; i < (int)mEntityStates.size(); ++i)
173        {
174                OGRE_DELETE(mEntityStates[i]);
175        }
176
177        mEntityStates.clear();
178}
179//-----------------------------------------------------------------------
180void TestCullingTerrainApplication::createCamera()
181{
182        // create the camera
183        mCamera = mSceneMgr->createCamera("PlayerCam");
184       
185        /** set a nice viewpoint
186        *       we use a camera node here and apply all transformations on it instead
187        *       of applying all transformations directly to the camera
188        *       because then the camera is displayed correctly in the visualization
189        */
190        if (msShowHillyTerrain)
191        {
192                mCamNode = mSceneMgr->getRootSceneNode()->
193                createChildSceneNode("CamNode1", Vector3(707, 5000, 528));
194        }
195        else
196        {
197                mCamNode = mSceneMgr->getRootSceneNode()->
198                        createChildSceneNode("CamNode1", Vector3(0, -100, -200));
199        }
200
201        mCamNode->setOrientation(Quaternion(-0.3486, 0.0122, 0.9365, 0.0329));
202        mCamNode->attachObject(mCamera);
203
204        //-- create visualization camera
205        mVizCamera = mSceneMgr->createCamera("VizCam");
206        mVizCamera->setPosition(mCamNode->getPosition());
207
208        mVizCamera->setNearClipDistance(1);
209        mCamera->setNearClipDistance(1);
210
211        // infinite far plane?
212        if (mRoot->getRenderSystem()->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE))
213        {
214                mVizCamera->setFarClipDistance(0);
215                mCamera->setFarClipDistance(0);
216        }
217        else
218        {
219                 mVizCamera->setFarClipDistance(20000);
220                 mCamera->setFarClipDistance(20000);
221        }       
222}
223
224//-----------------------------------------------------------------------
225bool TestCullingTerrainApplication::setup()
226{
227        bool carryOn = ExampleApplication::setup();
228
229        if (carryOn)
230                createRenderTargetListener();
231
232        return carryOn;
233}
234//-----------------------------------------------------------------------
235void TestCullingTerrainApplication::createRenderTargetListener()
236{
237        mWindow->addListener(new VisualizationRenderTargetListener(mSceneMgr));
238}
239//-----------------------------------------------------------------------
240void TestCullingTerrainApplication::LoadWorldGeometry()
241{
242        mIVReader = new IVReader();
243
244        // _MAX_PATH is the maximum length allowed for a path
245        char currentPath[_MAX_PATH];
246        // use the function to get the path
247        getcwd(currentPath, _MAX_PATH);
248        std::stringstream d;
249        d << "current path: " << currentPath;
250//E:\ogre_versions\ogre-win32-v1-0-3p1\ogrenew\Samples\Common\bin\Release
251        Ogre::LogManager::getSingleton().logMessage(d.str());
252        //String path = "E:/svn/gametools/trunk/VUT/Ogre/resources/";
253        String path = "E:/svn/gametools/OGRE/trunk/resources/";
254       
255        SceneNode *node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("Node1");
256        SceneNode *node2 = mSceneMgr->getRootSceneNode()->createChildSceneNode("Node2");
257        SceneNode *node3 = mSceneMgr->getRootSceneNode()->createChildSceneNode("Node3");
258        SceneNode *node4 = mSceneMgr->getRootSceneNode()->createChildSceneNode("Node4");
259        SceneNode *node5 = mSceneMgr->getRootSceneNode()->createChildSceneNode("Node5");
260        SceneNode *node6 = mSceneMgr->getRootSceneNode()->createChildSceneNode("Node6");
261        SceneNode *node7 = mSceneMgr->getRootSceneNode()->createChildSceneNode("Node7");
262        SceneNode *node8 = mSceneMgr->getRootSceneNode()->createChildSceneNode("Node8");
263        SceneNode *node9 = mSceneMgr->getRootSceneNode()->createChildSceneNode("Node9");
264
265
266        node1->translate(Vector3(-500, 0, 750));
267        node2->translate(Vector3(-400, 0, 750));
268        node3->scale(Vector3(100, 100 ,100));
269        node3->pitch(Radian(3 * Math::HALF_PI));
270        node4->translate(Vector3(-100, 0, 0));
271        node5->translate(Vector3(0, 300, 0));
272       
273        node6->scale(Vector3(100, 100 ,100));
274        node6->pitch(Radian(3 * Math::HALF_PI));
275        node6->roll(Radian(Math::HALF_PI));
276        node6->translate(Vector3(0, -100, 0));
277
278        node7->scale(Vector3(100, 100 ,100));
279        node7->pitch(Radian(3 * Math::HALF_PI));
280        node7->roll(Radian(Math::HALF_PI));
281        node7->translate(Vector3(100, 0, 0));
282       
283        node8->translate(Vector3(-300, -300, 0));
284
285        Log *log = LogManager::getSingleton().createLog("IVLog.log");
286        mIVReader->setLog(log);
287#if 1
288        String fileName = path + "media\\house_test1.iv";
289
290        if (mIVReader->loadFile(fileName.c_str()))
291        {
292                mIVReader->buildTree(mSceneMgr, node1);
293                mIVReader->buildTree(mSceneMgr, node2);
294        }
295
296        /*if (mIVReader->loadFile("media\\anhk.wrl"))
297        {
298                mIVReader->buildTree(mSceneMgr, node3);
299        }
300        if (mIVReader->loadFile("media\\ant.wrl"))
301        {
302                mIVReader->buildTree(mSceneMgr, node4);
303        }
304        if (mIVReader->loadFile("media\\zepplin0.wrl"))
305        {
306                mIVReader->buildTree(mSceneMgr, node5);
307        }
308        if (mIVReader->loadFile("media\\warbird.wrl"))
309        {
310                mIVReader->buildTree(mSceneMgr, node6);
311        }
312        if (mIVReader->loadFile("media\\z_wing.wrl"))
313        {
314                mIVReader->buildTree(mSceneMgr, node7);
315        }*/
316#else
317       
318        String fileName = path + "media\\city1500_flat_1.iv";
319       
320        if (mIVReader->loadFile(fileName.c_str()))
321        {
322                mIVReader->buildTree(mSceneMgr, node8);
323        }
324
325        fileName = path + "media\\roofs_1500.iv";
326        if (mIVReader->loadFile(fileName.c_str()))
327        {
328                mIVReader->buildTree(mSceneMgr, node8);
329        }
330
331        fileName = path + "media\\CityRoads60.iv";
332        if (mIVReader->loadFile(fileName.c_str()))
333        {
334                mIVReader->buildTree(mSceneMgr, node8);
335        }
336
337        fileName = path + "media\\CityPlane60.iv";
338    if (mIVReader->loadFile(fileName.c_str()))
339        {
340                mIVReader->buildTree(mSceneMgr, node8);
341        }
342       
343        fileName = path + "media\\test.iv";
344        if (mIVReader->loadFile(fileName.c_str()))
345        {
346                mIVReader->buildTree(mSceneMgr, node9);
347        }
348#endif
349        mIVReader->collapse();
350}
351
352//-----------------------------------------------------------------------
353void TestCullingTerrainApplication::createScene()
354{
355        if (!msShowHillyTerrain)
356                LoadWorldGeometry();
357
358        // Set ambient light
359        mAmbientLight = ColourValue(0.5, 0.5, 0.5);
360        mSceneMgr->setAmbientLight(mAmbientLight);
361       
362        //-- create light
363        mSunLight = mSceneMgr->createLight("SunLight");
364        mSunLight->setType(Light::LT_DIRECTIONAL);
365        //mSunLight->setType(Light::LT_SPOTLIGHT);
366        //mSunLight->setSpotlightRange(Degree(30), Degree(50));
367
368    mSunLight->setPosition(707, 2000, 500);
369        mSunLight->setCastShadows(true);
370
371        // set light angle not too small over the surface, otherwise shadows textures will be broken
372        Vector3 dir(0.5, 1, 0.5);
373        dir.normalise();
374        mSunLight->setDirection(dir);
375        //mSunLight->setDirection(Vector3::NEGATIVE_UNIT_Y);
376        mSunLight->setDiffuseColour(1, 1, 1);
377        mSunLight->setSpecularColour(1, 1, 1);
378
379        // -- Fog
380        // NB it's VERY important to set this before calling setWorldGeometry
381        // because the vertex program picked will be different
382        ColourValue fadeColour(0.93, 0.86, 0.76);
383        mWindow->getViewport(0)->setBackgroundColour(fadeColour);
384        //mSceneMgr->setFog( FOG_LINEAR, fadeColour, .001, 500, 1000);
385       
386        // Create a skybox
387        mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox", 5000, true);
388       
389        if (msShowHillyTerrain)
390        {
391                std::string terrain_cfg("terrain.cfg");
392#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
393                terrain_cfg = mResourcePath + terrain_cfg;
394#endif
395                mSceneMgr->setWorldGeometry(terrain_cfg);
396        }
397       
398
399        //-- CEGUI setup
400        setupGui();
401
402        /* // occluder plane to test visibility
403        Plane plane; plane.normal = Vector3::UNIT_Y;    plane.d = -60;
404        MeshManager::getSingleton().createPlane("Myplane",
405                ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,
406                5000,5000,100,100,true,1,5,5,Vector3::UNIT_Z);
407        Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
408        pPlaneEnt->setMaterialName("Examples/Rockwall");
409        pPlaneEnt->setCastShadows(true);
410        mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt); */
411
412        // Warning: In GL since we can't go higher than the window res
413        mSceneMgr->setShadowTextureSettings(1024, 2);
414
415        mSceneMgr->setShadowColour(ColourValue(0.5, 0.5, 0.5));
416   
417
418        //-- terrain content setup
419
420        // HACK: necessary to call once before the content creation for
421        // terrain initialisation
422        mSceneMgr->_renderScene(mCamera, mWindow->getViewport(0), true);
423
424        // ray query executor: needed to clamp to terrain
425        mRayQueryExecutor = new RayQueryExecutor(mSceneMgr);
426
427        mTerrainMinPos = EntityState::msMinPos = Vector3(0, 0, 0);
428        mTerrainMaxPos = EntityState::msMaxPos = Vector3(5000, 5000, 5000);
429
430        mTerrainContentGenerator = new TerrainContentGenerator(mSceneMgr);
431       
432       
433        // if no objects in file, we generate new objects
434        if (msShowHillyTerrain && !mTerrainContentGenerator->LoadObjects("objects.out"))
435        {
436                // the objects are generated randomly distributed over the terrain
437                if (1) generateScene(500, 0); // create robots
438                if (0) generateScene(100, 1); // create trees
439                if (0) generateScene(100, 2); // create ninjas
440        }
441}
442//-----------------------------------------------------------------------
443void  TestCullingTerrainApplication::generateScene(int num, int objectType)
444{
445        float val = TerrainFrameListener::msObjectScales[objectType];
446        Vector3 scale(val, val, val);
447        const float maxHeight = 75;
448       
449        // In order to provide much occlusion,
450        // height is restricted to maxHeight => no objects are created on peaks
451        mTerrainContentGenerator->SetMinPos(Vector3(mTerrainMinPos));
452        mTerrainContentGenerator->SetMaxPos(Vector3(mTerrainMaxPos.x, maxHeight, mTerrainMaxPos.z));
453       
454        //std::stringstream d; d << "objscale: " << scale[0];
455        //Ogre::LogManager::getSingleton().logMessage(d.str());
456       
457        mTerrainContentGenerator->SetScale(scale);
458        mTerrainContentGenerator->SetOffset(TerrainFrameListener::msObjectTerrainOffsets[objectType]);
459        mTerrainContentGenerator->GenerateScene(num, TerrainFrameListener::msObjectCaptions[objectType]);
460
461        if (objectType != 0) // from our objects, only robot has animation phases
462                return;
463
464        EntityList *entList = mTerrainContentGenerator->GetGeneratedEntities();
465
466        //-- add animation state for new robots (located at the end of the list)
467        for (int i = (int)entList->size() - num; i < (int)entList->size(); ++i)
468        {
469                mEntityStates.push_back(new EntityState((*entList)[i],
470                        EntityState::WAITING, Math::RangeRandom(0.5, 1.5)));
471        }
472
473        // release limitations on height => it is possible for the user to put single
474        // objects on peaks of the terrain (will be only few, not relevant for occlusion)
475        mTerrainContentGenerator->SetMaxPos(mTerrainMaxPos);
476}
477//-----------------------------------------------------------------------
478void TestCullingTerrainApplication::updateAnimations(Real timeSinceLastFrame)
479{
480        for (int i = 0; i < (int)mEntityStates.size(); ++i)
481        {
482                SceneNode *sn = mEntityStates[i]->GetEntity()->getParentSceneNode();
483
484                mEntityStates[i]->update(timeSinceLastFrame);
485
486                if (mEntityStates[i]->GetState() == EntityState::MOVING)
487                {
488                        Clamp2Terrain(sn, 0); //sn->setNodeVisible(false);
489                }
490        }
491}
492//-----------------------------------------------------------------------
493EntityStates  &TestCullingTerrainApplication::getEntityStates()
494{
495        return mEntityStates;
496}
497//-----------------------------------------------------------------------
498void TestCullingTerrainApplication::setupGui()
499{
500         mGUIRenderer = new CEGUI::OgreCEGUIRenderer(mWindow, Ogre::RENDER_QUEUE_OVERLAY,
501                 false, 3000, ST_EXTERIOR_CLOSE);
502     mGUISystem = new CEGUI::System(mGUIRenderer);
503
504         // Mouse
505     CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"TaharezLook.scheme");
506     CEGUI::MouseCursor::getSingleton().setImage("TaharezLook", "MouseArrow");
507         mGUISystem->setDefaultMouseCursor((CEGUI::utf8*)"TaharezLook",
508                                                                           (CEGUI::utf8*)"MouseArrow");
509
510         CEGUI::MouseCursor::getSingleton().hide();
511}
512//-----------------------------------------------------------------------
513void TestCullingTerrainApplication::createFrameListener()
514{
515        mTerrainFrameListener = new TerrainFrameListener(mWindow, mCamera, mSceneMgr,
516                mGUIRenderer, mTerrainContentGenerator, mVizCamera, mCamNode, mSunLight, this);
517       
518        mRoot->addFrameListener(mTerrainFrameListener);
519}
520//-----------------------------------------------------------------------
521void TestCullingTerrainApplication::chooseSceneManager()
522{
523        if (msShowHillyTerrain)
524        {
525                // Terrain scene manager
526                mSceneMgr = mRoot->getSceneManager(ST_EXTERIOR_CLOSE);
527        }
528        else
529        {       // octree scene manager
530                mSceneMgr = mRoot->getSceneManager(ST_GENERIC);
531        }
532}
533//-----------------------------------------------------------------------
534bool TestCullingTerrainApplication::Clamp2Terrain(SceneNode *node, int terrainOffs)
535{
536        // clamp scene node to terrain
537        Vector3 pos = node->getPosition();
538        Vector3 queryResult;
539
540        if (mRayQueryExecutor->executeRayQuery(&queryResult,
541                        Vector3(pos.x, MAX_HEIGHT, pos.z), Vector3::NEGATIVE_UNIT_Y))
542        {
543        node->setPosition(pos.x, queryResult.y + terrainOffs, pos.z);
544                return true;
545        }
546
547        return false;
548}
549
550//-----------------------------------------------------------------------
551bool TestCullingTerrainApplication::Clamp2FloorPlane()
552{
553    // clamp to floor plane
554        RaySceneQuery *raySceneQuery = mSceneMgr->createRayQuery(
555                Ray(mCamNode->getPosition(), Vector3::NEGATIVE_UNIT_Y));
556
557        RaySceneQueryResult& qryResult = raySceneQuery->execute();
558   
559        RaySceneQueryResult::iterator rit = qryResult.begin();
560 
561        while (rit != qryResult.end() && rit->movable)
562        {
563                if (rit->movable->getName() != "PlayerCam")
564                {
565                        mCamNode->setPosition(mCamNode->getPosition().x,
566                                rit->movable->getWorldBoundingBox().getCenter().y + 2,
567                                mCamNode->getPosition().z);
568       
569                        /*std::stringstream d;
570                        d << "World: " << it->movable->getWorldBoundingBox().getCenter().y <<
571                        ", Object: " << it->movable->getBoundingBox().getCenter().y <<
572                        ", Camera: " << mCamera->getDerivedPosition();
573
574                        LogManager::getSingleton().logMessage(d.str());*/
575
576                        return true;
577                }
578
579                ++ rit;
580        }
581   
582        OGRE_DELETE(raySceneQuery);
583        return false;
584}
585
586
587
588/**********************************************************************/
589/*            VisualizationRenderTargetListener implementation        */
590/**********************************************************************/
591
592
593//-----------------------------------------------------------------------
594VisualizationRenderTargetListener::VisualizationRenderTargetListener(SceneManager *sceneMgr)
595:RenderTargetListener(), mSceneMgr(sceneMgr)
596{
597}
598//-----------------------------------------------------------------------
599void VisualizationRenderTargetListener::preViewportUpdate(const RenderTargetViewportEvent &evt)
600{
601        // visualization viewport
602        const bool showViz = evt.source->getZOrder() == VIZ_VIEWPORT_Z_ORDER;
603        const bool nShowViz = !showViz;
604
605        mSavedShadowTechnique = mSceneMgr->getShadowTechnique();
606        mSavedAmbientLight = mSceneMgr->getAmbientLight();
607
608        // -- ambient light must be full for visualization, shadows disabled
609    if (showViz)
610        {
611                mSceneMgr->setAmbientLight(ColourValue(1, 1, 1));
612                mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE);
613        }
614       
615    mSceneMgr->setOption("PrepareVisualization", &showViz);
616        mSceneMgr->setOption("SkyBoxEnabled", &nShowViz);
617        //mSceneMgr->setOption("SkyPlaneEnabled", &showViz);
618       
619        RenderTargetListener::preViewportUpdate(evt);
620}
621//-----------------------------------------------------------------------
622void VisualizationRenderTargetListener::postRenderTargetUpdate(const RenderTargetEvent &evt)
623{
624        // reset values
625        mSceneMgr->setShadowTechnique(mSavedShadowTechnique);
626        mSceneMgr->setAmbientLight(mSavedAmbientLight);
627       
628        RenderTargetListener::postRenderTargetUpdate(evt);
629}
630//-----------------------------------------------------------------------
631INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
632{
633    // Create application object
634    TestCullingTerrainApplication app;
635
636        try
637        {
638        app.go();
639    }
640        catch( Ogre::Exception& e )
641        {
642        MessageBox( NULL, e.getFullDescription().c_str(),
643                        "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
644    }   
645
646    return 0;
647}
Note: See TracBrowser for help on using the repository browser.