~ubuntu-branches/debian/sid/ember/sid

« back to all changes in this revision

Viewing changes to src/components/ogre/AvatarCamera.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michael Koch
  • Date: 2009-07-23 07:46:40 UTC
  • Revision ID: james.westby@ubuntu.com-20090723074640-wh0ukzis0kda36qv
Tags: upstream-0.5.6
ImportĀ upstreamĀ versionĀ 0.5.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (C) 2004  Erik Hjortsberg
 
3
 
 
4
    This program is free software; you can redistribute it and/or modify
 
5
    it under the terms of the GNU General Public License as published by
 
6
    the Free Software Foundation; either version 2 of the License, or
 
7
    (at your option) any later version.
 
8
 
 
9
    This program is distributed in the hope that it will be useful,
 
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
    GNU General Public License for more details.
 
13
 
 
14
    You should have received a copy of the GNU General Public License
 
15
    along with this program; if not, write to the Free Software
 
16
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
17
*/
 
18
#ifdef HAVE_CONFIG_H
 
19
#include "config.h"
 
20
#endif
 
21
#include "AvatarCamera.h"
 
22
#include "AvatarTerrainCursor.h"
 
23
#include "Avatar.h"
 
24
#include "EmberOgre.h"
 
25
#include "EmberEntity.h"
 
26
// #include "WorldEmberEntity.h"
 
27
#include "MathConverter.h"
 
28
 
 
29
 
 
30
#include "services/EmberServices.h"
 
31
#include "services/config/ConfigService.h"
 
32
#include "services/time/TimeService.h"
 
33
#ifndef WIN32
 
34
#include "services/sound/SoundService.h"
 
35
#endif
 
36
 
 
37
#include "MousePicker.h"
 
38
// #include "jesus/JesusPickerObject.h"
 
39
 
 
40
#include "SceneManagers/EmberPagingSceneManager/include/OgrePagingLandScapeRaySceneQuery.h"
 
41
#include "framework/Tokeniser.h"
 
42
#include "framework/ConsoleBackend.h"
 
43
 
 
44
#include "GUIManager.h"
 
45
#include "services/input/Input.h"
 
46
 
 
47
#include "IWorldPickListener.h"
 
48
 
 
49
#include "framework/osdir.h"
 
50
 
 
51
#ifdef __WIN32__
 
52
#include <windows.h>
 
53
#include <direct.h>
 
54
#endif
 
55
 
 
56
using namespace Ember;
 
57
namespace EmberOgre {
 
58
 
 
59
Recorder::Recorder(): mSequence(0), mAccruedTime(0.0f), mFramesPerSecond(20.0f)
 
60
{
 
61
}
 
62
 
 
63
void Recorder::startRecording()
 
64
{
 
65
        Ogre::Root::getSingleton().addFrameListener(this);
 
66
}
 
67
void Recorder::stopRecording()
 
68
{
 
69
        Ogre::Root::getSingleton().removeFrameListener(this);
 
70
}
 
71
 
 
72
bool Recorder::frameStarted(const Ogre::FrameEvent& event)
 
73
{
 
74
        mAccruedTime += event.timeSinceLastFrame;
 
75
        if (mAccruedTime >= (1.0f / mFramesPerSecond)) {
 
76
                mAccruedTime = 0.0f;
 
77
                std::stringstream filename;
 
78
                filename << "screenshot_" << mSequence++ << ".tga";
 
79
                const std::string dir = Ember::EmberServices::getSingletonPtr()->getConfigService()->getHomeDirectory() + "/recordings/";
 
80
                try {
 
81
                        //make sure the directory exists
 
82
                        
 
83
                        struct stat tagStat;
 
84
                        int ret;
 
85
                        ret = stat( dir.c_str(), &tagStat );
 
86
                        if (ret == -1) {
 
87
                        #ifdef __WIN32__
 
88
                                mkdir(dir.c_str());
 
89
                        #else
 
90
                                mkdir(dir.c_str(), S_IRWXU);
 
91
                        #endif
 
92
                        }
 
93
                } catch (const std::exception& ex) {
 
94
                        S_LOG_FAILURE("Error when creating directory for screenshots. Message: " << std::string(ex.what()));
 
95
                        stopRecording();
 
96
                        return true;
 
97
                }
 
98
                try {
 
99
                        // take screenshot
 
100
                        EmberOgre::getSingleton().getRenderWindow()->writeContentsToFile(dir + filename.str());
 
101
                } catch (const Ogre::Exception& ex) {
 
102
                        S_LOG_FAILURE("Could not write screenshot to disc. Message: "<< ex.getFullDescription());
 
103
                        stopRecording();
 
104
                        return true;
 
105
                }
 
106
        }
 
107
        return true;
 
108
}
 
109
 
 
110
 
 
111
 
 
112
AvatarCamera::AvatarCamera(Ogre::SceneNode* avatarNode, Ogre::SceneManager& sceneManager, Ogre::RenderWindow& window, Input& input, Ogre::Camera& camera) :
 
113
        SetCameraDistance("setcameradistance", this, "Set the distance of the camera."),
 
114
        ToggleRendermode("toggle_rendermode", this, "Toggle between wireframe and solid render modes."),
 
115
        ToggleFullscreen("toggle_fullscreen", this, "Switch between windowed and full screen mode."),
 
116
        Screenshot("screenshot", this, "Take a screenshot and write to disk."),
 
117
        Record("+record", this, "Record to disk."),
 
118
        mInvertCamera(false),
 
119
        mCamera(camera),
 
120
        mAvatarNode(0),
 
121
        mSceneManager(sceneManager),
 
122
        mDegreeOfPitchPerSecond(50),
 
123
        mDegreeOfYawPerSecond(50),
 
124
        degreePitch(0),
 
125
        degreeYaw(0),
 
126
        mWindow(window),
 
127
        mViewPort(0),
 
128
        mClosestPickingDistance(10000),
 
129
        mLastPosition(Ogre::Vector3::ZERO),
 
130
        mAdjustTerrainRaySceneQuery(0),
 
131
        mCameraRaySceneQuery(0),
 
132
        mIsAdjustedToTerrain(true),
 
133
        mAvatarTerrainCursor(new AvatarTerrainCursor(*this))
 
134
//      mLastOrientationOfTheCamera(avatar->getOrientation())
 
135
{
 
136
        createNodesForCamera();
 
137
        createViewPort();
 
138
        setAvatarNode(avatarNode);
 
139
        
 
140
        /// Register this as a frame listener
 
141
        Ogre::Root::getSingleton().addFrameListener(this);
 
142
        
 
143
        input.EventMouseMoved.connect(sigc::mem_fun(*this, &AvatarCamera::Input_MouseMoved));
 
144
 
 
145
        Ember::EmberServices::getSingletonPtr()->getConfigService()->EventChangedConfigItem.connect(sigc::mem_fun(*this, &AvatarCamera::ConfigService_EventChangedConfigItem));
 
146
        
 
147
        updateValuesFromConfig();
 
148
        createRayQueries();
 
149
}
 
150
 
 
151
AvatarCamera::~AvatarCamera()
 
152
{
 
153
        Ogre::Root::getSingleton().removeFrameListener(this);
 
154
        EmberOgre::getSingleton().getSceneManager()->destroyQuery(mAdjustTerrainRaySceneQuery);
 
155
        EmberOgre::getSingleton().getSceneManager()->destroyQuery(mCameraRaySceneQuery);
 
156
}
 
157
 
 
158
void AvatarCamera::createRayQueries()
 
159
{
 
160
    // attempt to create a query to get back terrain coords
 
161
        mAdjustTerrainRaySceneQuery = EmberOgre::getSingletonPtr()->getSceneManager()->createRayQuery(mAdjustTerrainRay, Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK);
 
162
        ///only test for terrain
 
163
        mAdjustTerrainRaySceneQuery->setWorldFragmentType(Ogre::SceneQuery::WFT_SINGLE_INTERSECTION);
 
164
        mAdjustTerrainRaySceneQuery->setSortByDistance(true);
 
165
        mAdjustTerrainRaySceneQuery->setQueryTypeMask(Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK);
 
166
        
 
167
        
 
168
        unsigned long queryMask = Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK;
 
169
        queryMask |= MousePicker::CM_AVATAR;
 
170
        queryMask |= MousePicker::CM_ENTITY;
 
171
        queryMask |= MousePicker::CM_NATURE;
 
172
        queryMask |= MousePicker::CM_UNDEFINED;
 
173
//      queryMask |= Ogre::RSQ_FirstTerrain;
 
174
        
 
175
        mCameraRaySceneQuery = mSceneManager.createRayQuery( Ogre::Ray(), queryMask); 
 
176
        mCameraRaySceneQuery->setWorldFragmentType(Ogre::SceneQuery::WFT_SINGLE_INTERSECTION);
 
177
        mCameraRaySceneQuery->setSortByDistance(true);
 
178
 
 
179
}
 
180
 
 
181
 
 
182
void AvatarCamera::createNodesForCamera()
 
183
{
 
184
        mAvatarCameraRootNode = mSceneManager.createSceneNode("AvatarCameraRootNode");
 
185
        //we need to adjust for the height of the avatar mesh
 
186
        mAvatarCameraRootNode->setPosition(Ogre::Vector3(0,2,0));
 
187
        //rotate to sync with WF world
 
188
    mAvatarCameraRootNode->rotate(Ogre::Vector3::UNIT_Y,(Ogre::Degree)-90);
 
189
 
 
190
        mAvatarCameraPitchNode = mAvatarCameraRootNode->createChildSceneNode("AvatarCameraPitchNode");
 
191
        mAvatarCameraPitchNode->setPosition(Ogre::Vector3(0,0,0));
 
192
        mAvatarCameraNode = mAvatarCameraPitchNode->createChildSceneNode("AvatarCameraNode");
 
193
        setCameraDistance(10);
 
194
        
 
195
//      mCamera = mSceneManager.createCamera("AvatarCamera");
 
196
        mAvatarCameraNode->attachObject(&mCamera);
 
197
        // Look to the Avatar's head
 
198
        //mAvatar3pCamera->setAutoTracking(true, mAvatar1pCameraNode);
 
199
        mCamera.setNearClipDistance(0.5);
 
200
        
 
201
        ///set the far clip distance high to make sure that the sky is completely shown
 
202
        if (Ogre::Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_INFINITE_FAR_PLANE))
 
203
        {
 
204
/*              //NOTE: this won't currently work with the sky
 
205
                mCamera.setFarClipDistance(0);*/
 
206
                
 
207
                mCamera.setFarClipDistance(10000);
 
208
        } else {
 
209
                mCamera.setFarClipDistance(10000);
 
210
        }
 
211
        
 
212
        //create the nodes for the camera
 
213
        setMode(MODE_THIRD_PERSON);
 
214
//      createViewPort();
 
215
}
 
216
 
 
217
void AvatarCamera::setMode(Mode mode)
 
218
{
 
219
        mMode = mode;
 
220
/*      if (mMode == MODE_THIRD_PERSON) {
 
221
                mCamera.setAutoTracking(true, mAvatarCameraRootNode);
 
222
        } else {
 
223
                mCamera.setAutoTracking(false);
 
224
        }*/
 
225
        
 
226
        
 
227
}
 
228
 
 
229
const Ogre::Quaternion& AvatarCamera::getOrientation(bool onlyHorizontal) const {
 
230
        if (!onlyHorizontal) {
 
231
                return getCamera().getDerivedOrientation();
 
232
        } else {
 
233
                static Ogre::Quaternion quat;
 
234
                quat = getCamera().getDerivedOrientation();
 
235
                quat.x = 0;
 
236
                quat.z = 0;
 
237
                return quat;
 
238
        }
 
239
}
 
240
 
 
241
const Ogre::Vector3& AvatarCamera::getPosition() const
 
242
{
 
243
        return mCamera.getDerivedPosition();
 
244
}
 
245
 
 
246
void AvatarCamera::attach(Ogre::SceneNode* toNode) {
 
247
        mIsAttached = true;
 
248
        assert(mAvatarCameraRootNode);
 
249
        if (mAvatarCameraRootNode->getParent()) {
 
250
                mAvatarCameraRootNode->getParent()->removeChild(mAvatarCameraRootNode->getName());
 
251
        }
 
252
        toNode->addChild(mAvatarCameraRootNode);
 
253
        
 
254
        setCameraDistance(10);
 
255
        mAvatarCameraNode->setOrientation(Ogre::Quaternion::IDENTITY);
 
256
        mAvatarCameraNode->_update(true, true);
 
257
        std::stringstream ss;
 
258
        ss << "Attached camera to node: " << toNode->getName() <<". New position: " << mCamera.getDerivedPosition() << " New orientation: " << mCamera.getDerivedOrientation();
 
259
        S_LOG_VERBOSE(ss.str());
 
260
}
 
261
 
 
262
 
 
263
void AvatarCamera::enableCompositor(const std::string& compositorName, bool enable)
 
264
{
 
265
        if (std::find(mLoadedCompositors.begin(), mLoadedCompositors.end(), compositorName) == mLoadedCompositors.end()) {
 
266
                Ogre::CompositorManager::getSingleton().addCompositor(mWindow.getViewport(0), compositorName);
 
267
        }
 
268
        Ogre::CompositorManager::getSingleton().setCompositorEnabled(mWindow.getViewport(0), compositorName, enable);
 
269
}
 
270
 
 
271
void AvatarCamera::createViewPort()
 
272
{
 
273
 
 
274
//      Ogre::CompositorManager::getSingleton().addCompositor(mWindow.getViewport(0), "Bloom");
 
275
//      Ogre::CompositorManager::getSingleton().setCompositorEnabled(mWindow.getViewport(0), "Bloom", true);
 
276
 
 
277
//      assert(mCamera);
 
278
//      assert(!mViewPort);
 
279
//     // Create 1st person viewport, entire window
 
280
//     mViewPort = mWindow.addViewport(mCamera);
 
281
//     mViewPort->setBackgroundColour(Ogre::ColourValue(0,0,0));
 
282
//     mCamera.setAspectRatio(
 
283
//              Ogre::Real(mViewPort->getActualWidth()) / Ogre::Real(mViewPort->getActualHeight()));
 
284
 
 
285
        
 
286
}
 
287
                
 
288
                
 
289
void AvatarCamera::toggleRenderMode()
 
290
{
 
291
        S_LOG_INFO("Switching render mode.");
 
292
        if (mCamera.getPolygonMode() == Ogre::PM_SOLID) {
 
293
                mCamera.setPolygonMode(Ogre::PM_WIREFRAME);
 
294
        } else {
 
295
                mCamera.setPolygonMode(Ogre::PM_SOLID);
 
296
        }
 
297
}
 
298
 
 
299
void AvatarCamera::setAvatarNode(Ogre::SceneNode* sceneNode)
 
300
{
 
301
        mAvatarNode = sceneNode;
 
302
        attach(mAvatarNode);
 
303
}
 
304
 
 
305
void AvatarCamera::setCameraDistance(Ogre::Real distance)
 
306
{
 
307
        mWantedCameraDistance = distance;
 
308
        _setCameraDistance(distance);
 
309
}
 
310
 
 
311
void AvatarCamera::_setCameraDistance(Ogre::Real distance)
 
312
{
 
313
        mCurrentCameraDistance = distance;
 
314
        Ogre::Vector3 pos(0,0,distance);
 
315
        mAvatarCameraNode->setPosition(pos);
 
316
        markCameraNodeAsDirty();
 
317
        EventChangedCameraDistance.emit(distance);
 
318
}
 
319
 
 
320
void AvatarCamera::pitch(Ogre::Degree degrees)
 
321
{
 
322
        if (mInvertCamera) {
 
323
                degrees -= degrees * 2;
 
324
        }
 
325
        
 
326
        Ogre::SceneNode* node(mMode == MODE_THIRD_PERSON ? mAvatarCameraPitchNode : mAvatarCameraNode);
 
327
        
 
328
        ///prevent the camera from being turned upside down
 
329
        const Ogre::Quaternion& orientation(node->getOrientation());
 
330
        Ogre::Degree pitch(orientation.getPitch());
 
331
        if ((pitch.valueDegrees() + degrees.valueDegrees()) > 0) {
 
332
                degrees = std::min<float>(degrees.valueDegrees(), 90 - pitch.valueDegrees());
 
333
        } else {
 
334
                degrees = std::max<float>(degrees.valueDegrees(), -90 - pitch.valueDegrees());
 
335
        }
 
336
        
 
337
        if (mMode == MODE_THIRD_PERSON) {
 
338
                degreePitch += degrees;
 
339
                node->pitch(degrees);
 
340
        } else {
 
341
                node->pitch(degrees);
 
342
        }
 
343
        ///We need to manually update the node here to make sure that the derived orientation and position of the camera is updated.
 
344
        node->_update(true, false);
 
345
        markCameraNodeAsDirty();
 
346
}
 
347
void AvatarCamera::yaw(Ogre::Degree degrees)
 
348
{
 
349
        if (mMode == MODE_THIRD_PERSON) {
 
350
                degreeYaw += degrees;
 
351
                mAvatarCameraRootNode->yaw(degrees);
 
352
                
 
353
                ///We need to manually update the node here to make sure that the derived orientation and position of the camera is updated.
 
354
                mAvatarCameraRootNode->_update(true, false);
 
355
        } else {
 
356
                mAvatarCameraNode->yaw(degrees);
 
357
                ///We need to manually update the node here to make sure that the derived orientation and position of the camera is updated.
 
358
                mAvatarCameraNode->_update(true, false);
 
359
        }
 
360
        markCameraNodeAsDirty();
 
361
}
 
362
 
 
363
void AvatarCamera::markCameraNodeAsDirty()
 
364
{
 
365
        if (mCamera.getParentNode()) {
 
366
                ///We need to mark the parent node of the camera as dirty. The update of the derived orientation and position of the node should normally occur when the scene tree is traversed, but in some instances we need to access the derived position or orientataion of the camera before the traversal occurs, and if we don't mark the node as dirty it won't be updated
 
367
                mCamera.getParentNode()->needUpdate(true);
 
368
        }
 
369
}
 
370
 
 
371
void AvatarCamera::Input_MouseMoved(const MouseMotion& motion, Input::InputMode mode)
 
372
/*(int xPosition, int yPosition, Ogre::Real xRelativeMovement, Ogre::Real yRelativeMovement, Ogre::Real timeSinceLastMovement)*/
 
373
{
 
374
        if (mode == Input::IM_MOVEMENT) {
 
375
                Ogre::Degree diffX(mDegreeOfYawPerSecond * motion.xRelativeMovement);
 
376
                Ogre::Degree diffY(mDegreeOfPitchPerSecond * motion.yRelativeMovement);
 
377
        
 
378
                if (diffX.valueDegrees()) {
 
379
                        this->yaw(diffX);
 
380
        //              this->yaw(diffX * e->timeSinceLastFrame);
 
381
                }
 
382
                if (diffY.valueDegrees()) {
 
383
                        this->pitch(diffY);
 
384
        //              this->pitch(diffY * e->timeSinceLastFrame);
 
385
                }
 
386
                
 
387
                if (diffY.valueDegrees() || diffX.valueDegrees()) {
 
388
                        MovedCamera.emit(mCamera);
 
389
                }
 
390
        } 
 
391
        
 
392
        
 
393
}
 
394
 
 
395
 
 
396
 
 
397
 
 
398
void AvatarCamera::pickInWorld(Ogre::Real mouseX, Ogre::Real mouseY, const MousePickerArgs& mousePickerArgs)
 
399
{
 
400
        S_LOG_INFO("Trying to pick an entity at mouse coords: "  << Ogre::StringConverter::toString(mouseX) << ":" << Ogre::StringConverter::toString(mouseY) << ".");
 
401
 
 
402
        // get the terrain vector for mouse coords when a pick event happens
 
403
//      mAvatarTerrainCursor->getTerrainCursorPosition();
 
404
        
 
405
        /// Start a new ray query 
 
406
        Ogre::Ray cameraRay = getCamera().getCameraToViewportRay( mouseX, mouseY ); 
 
407
 
 
408
        mCameraRaySceneQuery->setRay(cameraRay);
 
409
        mCameraRaySceneQuery->execute(); 
 
410
        
 
411
        
 
412
        ///now check the entity picking
 
413
        Ogre::RaySceneQueryResult& queryResult = mCameraRaySceneQuery->getLastResults(); 
 
414
        bool continuePicking = true;
 
415
                        
 
416
        for (WorldPickListenersStore::iterator I = mPickListeners.begin(); I != mPickListeners.end(); ++I) {
 
417
                (*I)->initializePickingContext();
 
418
        }
 
419
                        
 
420
                        
 
421
        Ogre::RaySceneQueryResult::iterator rayIterator = queryResult.begin( ); 
 
422
        Ogre::RaySceneQueryResult::iterator rayIterator_end = queryResult.end( );
 
423
        if (rayIterator != rayIterator_end) {
 
424
                for ( ; rayIterator != rayIterator_end && continuePicking; rayIterator++ ) {
 
425
                        for (WorldPickListenersStore::iterator I = mPickListeners.begin(); I != mPickListeners.end(); ++I) {
 
426
                                (*I)->processPickResult(continuePicking, *rayIterator, cameraRay, mousePickerArgs);
 
427
                                if (!continuePicking) {
 
428
                                        break;
 
429
                                }
 
430
                        }
 
431
                }
 
432
        }
 
433
        
 
434
        for (WorldPickListenersStore::iterator I = mPickListeners.begin(); I != mPickListeners.end(); ++I) {
 
435
                (*I)->endPickingContext(mousePickerArgs);
 
436
        }
 
437
}
 
438
 
 
439
        bool AvatarCamera::worldToScreen(const Ogre::Vector3& worldPos, Ogre::Vector2& screenPos) 
 
440
        {
 
441
                
 
442
                Ogre::Vector3 hcsPosition = mCamera.getProjectionMatrix() * (mCamera.getViewMatrix() * worldPos); 
 
443
        
 
444
                if ((hcsPosition.x < -1.0f) || 
 
445
                (hcsPosition.x > 1.0f) || 
 
446
                (hcsPosition.y < -1.0f) || 
 
447
                (hcsPosition.y > 1.0f)) 
 
448
                return false; 
 
449
        
 
450
        
 
451
                screenPos.x = (hcsPosition.x + 1) * 0.5; 
 
452
                screenPos.y = (-hcsPosition.y + 1) * 0.5; 
 
453
        
 
454
                return true; 
 
455
        }
 
456
 
 
457
//      void AvatarCamera::setClosestPickingDistance(Ogre::Real distance)
 
458
//      {
 
459
//              mClosestPickingDistance = distance; 
 
460
//      }
 
461
//      
 
462
//      Ogre::Real AvatarCamera::getClosestPickingDistance() 
 
463
//      { 
 
464
//              return mClosestPickingDistance; 
 
465
//      }
 
466
        
 
467
        bool AvatarCamera::adjustForTerrain()
 
468
        {
 
469
                /// We will shoot a ray from the camera base node to the camera. If it hits anything on the way we know that there's something between the camera and the avatar and we'll position the camera closer to the avatar. Thus we'll avoid having the camera dip below the terrain
 
470
                ///For now we'll only check against the terrain
 
471
                const Ogre::Vector3 direction(-mCamera.getDerivedDirection());
 
472
                ///If the direction if pointing straight upwards we'll end up in an infinite loop in the ray query
 
473
                if (direction.z != 0) {
 
474
                
 
475
                        mAdjustTerrainRay.setDirection(direction);
 
476
                        mAdjustTerrainRay.setOrigin(mAvatarCameraRootNode->_getDerivedPosition());
 
477
                        
 
478
                        mAdjustTerrainRaySceneQuery->setRay(mAdjustTerrainRay);
 
479
                        
 
480
                        mAdjustTerrainRaySceneQuery->execute(); 
 
481
                        
 
482
                        Ogre::RaySceneQueryResult queryResult = mAdjustTerrainRaySceneQuery->getLastResults(); 
 
483
                        Ogre::RaySceneQueryResult::iterator rayIterator = queryResult.begin( );
 
484
                        for ( ; rayIterator != queryResult.end(); ++rayIterator ) {
 
485
                                Ogre::RaySceneQueryResultEntry& entry = *rayIterator;
 
486
                                
 
487
                                if (entry.worldFragment) {
 
488
                                        Ogre::Vector3 position = entry.worldFragment->singleIntersection;
 
489
                                        Ogre::Real distance = mAvatarCameraRootNode->_getDerivedPosition().distance(position);
 
490
                                        if (distance < mWantedCameraDistance) {
 
491
                                                _setCameraDistance(distance - 0.1);
 
492
                                                return true;
 
493
                                        } else {
 
494
                                                ///we hit some terrain beyond the max distance of the camera, so set it to the "default" distance
 
495
                                                if (mWantedCameraDistance != mCurrentCameraDistance) {
 
496
                                                        _setCameraDistance(mWantedCameraDistance);
 
497
                                                }
 
498
                                                return false;
 
499
                                        }
 
500
                                }
 
501
                        }
 
502
                }
 
503
                return false;
 
504
                
 
505
/*              Ogre::RaySceneQuery *raySceneQueryHeight = EmberOgre::getSingletonPtr()->getSceneManager()->createRayQuery( Ogre::Ray(mCamera.getDerivedPosition(), Ogre::Vector3::NEGATIVE_UNIT_Y), Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK); 
 
506
                
 
507
                
 
508
                raySceneQueryHeight->execute(); 
 
509
                
 
510
                //first check the terrain picking
 
511
                Ogre::RaySceneQueryResult queryResult = raySceneQueryHeight->getLastResults(); 
 
512
                
 
513
                if (queryResult.begin( ) != queryResult.end()) {
 
514
                        Ogre::Vector3 position = queryResult.begin()->worldFragment->singleIntersection;
 
515
                        Ogre::Real terrainHeight = position.y;
 
516
                        //pad it a little
 
517
                        //terrainHeight += 0.4;
 
518
                        Ogre::Real cameraHeight = mCamera.getDerivedPosition().y;
 
519
                        Ogre::Real cameraNodeHeight = mAvatarCameraNode->getWorldPosition().y;
 
520
                        if (terrainHeight > cameraHeight) {
 
521
                                mCamera.move(mCamera.getDerivedOrientation().Inverse() * Ogre::Vector3(0,terrainHeight - cameraHeight,0));
 
522
//                              mCamera.lookAt(mAvatarCameraRootNode->getPosition());
 
523
                                
 
524
                        } else if (cameraHeight != cameraNodeHeight) {
 
525
                                Ogre::Real newHeight = std::max<Ogre::Real>(terrainHeight, cameraNodeHeight);
 
526
                                mCamera.move(Ogre::Vector3(0,newHeight - cameraHeight,0));
 
527
                                mCamera.lookAt(mAvatarCameraRootNode->getWorldPosition());
 
528
                                
 
529
                        }
 
530
                        
 
531
                }*/
 
532
        
 
533
        }
 
534
        
 
535
void AvatarCamera::runCommand(const std::string &command, const std::string &args)
 
536
{
 
537
        if(Screenshot == command) {
 
538
                //just take a screen shot
 
539
                takeScreenshot();
 
540
        } else if(SetCameraDistance == command)
 
541
        {
 
542
                Ember::Tokeniser tokeniser;
 
543
                tokeniser.initTokens(args);
 
544
                std::string distance = tokeniser.nextToken();
 
545
                if (distance != "") {
 
546
                        float fDistance = Ogre::StringConverter::parseReal(distance);
 
547
                        setCameraDistance(fDistance);
 
548
                }
 
549
        } else if (ToggleFullscreen == command){
 
550
                SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
 
551
                
 
552
        } else if (ToggleRendermode == command) {
 
553
                toggleRenderMode();
 
554
        } else if (Record == command) {
 
555
                mRecorder.startRecording();
 
556
        } else if (Record.getInverseCommand() == command) {
 
557
                mRecorder.stopRecording();
 
558
        }
 
559
}
 
560
        
 
561
void AvatarCamera::updateValuesFromConfig()
 
562
{
 
563
        if (Ember::EmberServices::getSingletonPtr()->getConfigService()->itemExists("input", "invertcamera")) {
 
564
                mInvertCamera = static_cast<bool>(Ember::EmberServices::getSingletonPtr()->getConfigService()->getValue("input", "invertcamera"));
 
565
        }
 
566
        if (Ember::EmberServices::getSingletonPtr()->getConfigService()->itemExists("input", "cameradegreespersecond")) {
 
567
                mDegreeOfPitchPerSecond = mDegreeOfYawPerSecond = (double)Ember::EmberServices::getSingletonPtr()->getConfigService()->getValue("input", "cameradegreespersecond");
 
568
        }
 
569
        if (Ember::EmberServices::getSingletonPtr()->getConfigService()->itemExists("input", "adjusttoterrain")) {
 
570
                mIsAdjustedToTerrain = static_cast<bool>(Ember::EmberServices::getSingletonPtr()->getConfigService()->getValue("input", "adjusttoterrain"));
 
571
        }       
 
572
}
 
573
        
 
574
void AvatarCamera::ConfigService_EventChangedConfigItem(const std::string& section, const std::string& key)
 
575
{
 
576
        if (section == "input") {
 
577
                if (key == "invertcamera" || key == "cameradegreespersecond" || key == "adjusttoterrain") {
 
578
                        updateValuesFromConfig();
 
579
                }
 
580
        }
 
581
}
 
582
 
 
583
bool AvatarCamera::frameStarted(const Ogre::FrameEvent& event)
 
584
{
 
585
        if (mIsAdjustedToTerrain && mAvatarNode) {
 
586
                if (mCamera.getDerivedPosition() != mLastPosition) {
 
587
                        adjustForTerrain();
 
588
                        mLastPosition = mCamera.getDerivedPosition();
 
589
                }
 
590
        }
 
591
        
 
592
        /// Update avatar entity position in sound service
 
593
        Ember::EmberServices::getSingleton().getSoundService()->updateListenerPosition(Ogre2Atlas(mCamera.getDerivedPosition()), Ogre2Atlas_Vector3(mCamera.getDirection()), Ogre2Atlas_Vector3(mCamera.getUp()));
 
594
 
 
595
        return true;
 
596
}
 
597
 
 
598
void AvatarCamera::pushWorldPickListener(IWorldPickListener* worldPickListener)
 
599
{
 
600
        mPickListeners.push_front(worldPickListener);
 
601
}
 
602
 
 
603
void AvatarCamera::removeWorldPickListener(IWorldPickListener* worldPickListener)
 
604
{
 
605
        if (worldPickListener) {
 
606
                WorldPickListenersStore::iterator I = std::find(mPickListeners.begin(), mPickListeners.end(), worldPickListener);
 
607
                if (I != mPickListeners.end()) {
 
608
                        mPickListeners.erase(I);
 
609
                }
 
610
        }
 
611
}
 
612
 
 
613
 
 
614
const std::string AvatarCamera::_takeScreenshot() 
 
615
{
 
616
        // retrieve current time
 
617
        time_t rawtime;
 
618
        struct tm* timeinfo;
 
619
        time(&rawtime);
 
620
        timeinfo = localtime(&rawtime);
 
621
        
 
622
        // construct filename string
 
623
        // padding with 0 for single-digit values
 
624
        std::stringstream filename;
 
625
        filename << "screenshot_" << ((*timeinfo).tm_year + 1900); // 1900 is year "0"
 
626
        int month = ((*timeinfo).tm_mon + 1); // January is month "0"
 
627
        if(month <= 9) 
 
628
        {
 
629
                filename << "0";        
 
630
        }
 
631
        filename << month;
 
632
        int day = (*timeinfo).tm_mday;
 
633
        if(day <= 9) 
 
634
        {
 
635
                filename << "0";        
 
636
        }
 
637
        filename << day << "_";
 
638
        int hour = (*timeinfo).tm_hour;
 
639
        if(hour <= 9) 
 
640
        {
 
641
                filename << "0"; 
 
642
        }
 
643
        filename << hour;
 
644
        int min = (*timeinfo).tm_min;
 
645
        if(min <= 9) 
 
646
        {
 
647
                filename << "0";         
 
648
        }
 
649
        filename << min;
 
650
        int sec = (*timeinfo).tm_sec;
 
651
        if(sec <= 9) 
 
652
        {
 
653
                filename << "0";
 
654
        } 
 
655
        filename << sec << ".jpg";
 
656
 
 
657
        const std::string dir = Ember::EmberServices::getSingletonPtr()->getConfigService()->getHomeDirectory() + "/screenshots/";
 
658
        try {
 
659
                //make sure the directory exists
 
660
                
 
661
                oslink::directory osdir(dir);
 
662
 
 
663
                if (!osdir.isExisting()) {
 
664
#ifdef __WIN32__
 
665
                        mkdir(dir.c_str());
 
666
#else
 
667
                        mkdir(dir.c_str(), S_IRWXU);
 
668
#endif
 
669
                }
 
670
        } catch (const std::exception& ex) {
 
671
                S_LOG_FAILURE("Error when creating directory for screenshots. Message: " << std::string(ex.what()));
 
672
                throw Ember::Exception("Error when saving screenshot. Message: " + std::string(ex.what()));
 
673
        }
 
674
        
 
675
        try {
 
676
                // take screenshot
 
677
                mWindow.writeContentsToFile(dir + filename.str());
 
678
        } catch (const Ogre::Exception& ex) {
 
679
                S_LOG_FAILURE("Could not write screenshot to disc. Message: "<< ex.getFullDescription());
 
680
                throw Ember::Exception("Error when saving screenshot. Message: " + ex.getDescription());
 
681
        }
 
682
        return dir + filename.str();
 
683
}
 
684
 
 
685
void AvatarCamera::takeScreenshot()
 
686
{
 
687
        try {
 
688
                const std::string& result = _takeScreenshot();
 
689
                S_LOG_INFO(result);
 
690
                Ember::ConsoleBackend::getSingletonPtr()->pushMessage("Wrote image: " + result);
 
691
        } catch (const std::exception& ex) {
 
692
                Ember::ConsoleBackend::getSingletonPtr()->pushMessage(std::string("Error when saving screenshot: ") + ex.what());
 
693
        } catch (...) {
 
694
                Ember::ConsoleBackend::getSingletonPtr()->pushMessage("Unknown error when saving screenshot.");
 
695
        }
 
696
}
 
697
 
 
698
}
 
699
 
 
700
 
 
701
 
 
702
 
 
703