Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation3/src/modules/overlays/hud/HUDNavigation.cc @ 7050

Last change on this file since 7050 was 7050, checked in by sfluecki, 14 years ago

Added a ConfigValue to limit the amount of marked entities

  • Property svn:eol-style set to native
File size: 13.9 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Felix Schulthess
24 *   Co-authors:
25 *      Reto Grieder
26 *
27 */
28
29#include "HUDNavigation.h"
30
31#include <OgreCamera.h>
32#include <OgreFontManager.h>
33#include <OgreOverlayManager.h>
34#include <OgreTextAreaOverlayElement.h>
35#include <OgrePanelOverlayElement.h>
36
37#include "util/Math.h"
38#include "util/Convert.h"
39#include "core/CoreIncludes.h"
40#include "core/XMLPort.h"
41#include "CameraManager.h"
42#include "Scene.h"
43#include "Radar.h"
44#include "graphics/Camera.h"
45#include "controllers/HumanController.h"
46#include "worldentities/pawns/Pawn.h"
47#include "worldentities/WorldEntity.h"
48#include "core/ConfigValueIncludes.h"
49// #include <boost/bind/bind_template.hpp>
50
51
52namespace orxonox
53{
54bool compareDistance ( std::pair<RadarViewable*, unsigned int > a, std::pair<RadarViewable*, unsigned int > b )
55{
56    return a.second<b.second;
57
58}
59
60void HUDNavigation::setConfigValues()
61{
62  SetConfigValue(markerLimit_, 3);
63}
64
65CreateFactory ( HUDNavigation );
66
67HUDNavigation::HUDNavigation ( BaseObject* creator )
68        : OrxonoxOverlay ( creator )
69{
70    RegisterObject ( HUDNavigation );
71    this->setConfigValues();
72
73    // Set default values
74    setFont ( "Monofur" );
75    setTextSize ( 0.05f );
76    setNavMarkerSize ( 0.05f );
77}
78
79HUDNavigation::~HUDNavigation()
80{
81    if ( this->isInitialized() )
82    {
83        for ( ObjectMap::iterator it = activeObjectList_.begin(); it != activeObjectList_.end(); )
84            removeObject ( ( it++ )->first );
85
86    }
87
88    sortedObjectList_.clear();
89}
90
91void HUDNavigation::XMLPort ( Element& xmlElement, XMLPort::Mode mode )
92{
93    SUPER ( HUDNavigation, XMLPort, xmlElement, mode );
94
95    XMLPortParam ( HUDNavigation, "font",          setFont,          getFont,          xmlElement, mode );
96    XMLPortParam ( HUDNavigation, "textSize",      setTextSize,      getTextSize,      xmlElement, mode );
97    XMLPortParam ( HUDNavigation, "navMarkerSize", setNavMarkerSize, getNavMarkerSize, xmlElement, mode );
98}
99
100void HUDNavigation::setFont ( const std::string& font )
101{
102    const Ogre::ResourcePtr& fontPtr = Ogre::FontManager::getSingleton().getByName ( font );
103    if ( fontPtr.isNull() )
104    {
105        COUT ( 2 ) << "Warning: HUDNavigation: Font '" << font << "' not found" << std::endl;
106        return;
107    }
108    fontName_ = font;
109    for ( ObjectMap::iterator it = activeObjectList_.begin(); it != activeObjectList_.end(); ++it )
110    {
111        if ( it->second.text_ != NULL )
112            it->second.text_->setFontName ( fontName_ );
113    }
114}
115
116const std::string& HUDNavigation::getFont() const
117{
118    return fontName_;
119}
120
121void HUDNavigation::setTextSize ( float size )
122{
123    if ( size <= 0.0f )
124    {
125        COUT ( 2 ) << "Warning: HUDNavigation: Negative font size not allowed" << std::endl;
126        return;
127    }
128    textSize_ = size;
129    for ( ObjectMap::iterator it = activeObjectList_.begin(); it!=activeObjectList_.end(); ++it )
130    {
131        if ( it->second.text_ )
132            it->second.text_->setCharHeight ( size );
133    }
134}
135
136float HUDNavigation::getTextSize() const
137{
138    return textSize_;
139}
140
141
142
143void HUDNavigation::tick ( float dt )
144{
145    SUPER ( HUDNavigation, tick, dt );
146
147    Camera* cam = CameraManager::getInstance().getActiveCamera();
148    if ( cam == NULL )
149        return;
150    const Matrix4& camTransform = cam->getOgreCamera()->getProjectionMatrix() * cam->getOgreCamera()->getViewMatrix();
151
152
153    for ( sortedList::iterator listIt = sortedObjectList_.begin(); listIt != sortedObjectList_.end(); ++listIt )
154    {
155        listIt->second = ( int ) ( ( listIt->first->getRVWorldPosition() - HumanController::getLocalControllerSingleton()->getControllableEntity()->getWorldPosition() ).length() + 0.5f );
156    }
157
158    sortedObjectList_.sort ( compareDistance );
159
160    unsigned int markerCount_ = 0;
161
162//         for (ObjectMap::iterator it = activeObjectList_.begin(); it != activeObjectList_.end(); ++it)
163    for ( sortedList::iterator listIt = sortedObjectList_.begin(); listIt != sortedObjectList_.end(); ++markerCount_, ++listIt )
164    {
165        ObjectMap::iterator it = activeObjectList_.find ( listIt->first );
166
167        if ( markerCount_ < markerLimit_ )
168        {
169
170
171            // Get Distance to HumanController and save it in the TextAreaOverlayElement.
172            int dist = listIt->second;
173            it->second.text_->setCaption ( multi_cast<std::string> ( dist ) );
174            float textLength = multi_cast<std::string> ( dist ).size() * it->second.text_->getCharHeight() * 0.3f;
175
176            // Transform to screen coordinates
177            Vector3 pos = camTransform * it->first->getRVWorldPosition();
178
179            bool outOfView = true;
180            if ( pos.z > 1.0 )
181            {
182                // z > 1.0 means that the object is behind the camera
183                outOfView = true;
184                // we have to switch all coordinates (if you don't know why,
185                // try linear algebra lectures, because I can't explain..)
186                pos.x = -pos.x;
187                pos.y = -pos.y;
188            }
189            else
190                outOfView = pos.x < -1.0 || pos.x > 1.0 || pos.y < -1.0 || pos.y > 1.0;
191            // Get Distance to HumanController and save it in the TextAreaOverlayElement.
192            it->second.text_->setCaption ( multi_cast<std::string> ( dist ) );
193
194            if ( outOfView )
195            {
196                // Object is not in view
197
198                // Change material only if outOfView changed
199                if ( !it->second.wasOutOfView_ )
200                {
201                    it->second.panel_->setMaterialName ( "Orxonox/NavArrows" );
202                    it->second.wasOutOfView_ = true;
203                }
204
205                // Switch between top, bottom, left and right position of the arrow at the screen border
206                if ( pos.x < pos.y )
207                {
208                    if ( pos.y > -pos.x )
209                    {
210                        // Top
211                        float position = pos.x / pos.y + 1.0f;
212                        it->second.panel_->setPosition ( ( position - it->second.panel_->getWidth() ) * 0.5f, 0.0f );
213                        it->second.panel_->setUV ( 0.5f, 0.0f, 1.0f, 0.5f );
214                        it->second.text_->setLeft ( ( position - textLength ) * 0.5f );
215                        it->second.text_->setTop ( it->second.panel_->getHeight() );
216                    }
217                    else
218                    {
219                        // Left
220                        float position = pos.y / pos.x + 1.0f;
221                        it->second.panel_->setPosition ( 0.0f, ( position - it->second.panel_->getWidth() ) * 0.5f );
222                        it->second.panel_->setUV ( 0.0f, 0.0f, 0.5f, 0.5f );
223                        it->second.text_->setLeft ( it->second.panel_->getWidth() + 0.01f );
224                        it->second.text_->setTop ( ( position - it->second.text_->getCharHeight() ) * 0.5f );
225                    }
226                }
227
228                else
229                {
230
231                    if ( pos.y < -pos.x )
232                    {
233                        // Bottom
234                        float position = -pos.x / pos.y + 1.0f;
235                        it->second.panel_->setPosition ( ( position - it->second.panel_->getWidth() ) * 0.5f, 1.0f - it->second.panel_->getHeight() );
236                        it->second.panel_->setUV ( 0.0f, 0.5f, 0.5f, 1.0f );
237                        it->second.text_->setLeft ( ( position - textLength ) * 0.5f );
238                        it->second.text_->setTop ( 1.0f - it->second.panel_->getHeight() - it->second.text_->getCharHeight() );
239                    }
240                    else
241                    {
242                        // Right
243                        float position = -pos.y / pos.x + 1.0f;
244                        it->second.panel_->setPosition ( 1.0f - it->second.panel_->getWidth(), ( position - it->second.panel_->getHeight() ) * 0.5f );
245                        it->second.panel_->setUV ( 0.5f, 0.5f, 1.0f, 1.0f );
246                        it->second.text_->setLeft ( 1.0f - it->second.panel_->getWidth() - textLength - 0.01f );
247                        it->second.text_->setTop ( ( position - it->second.text_->getCharHeight() ) * 0.5f );
248                    }
249                }
250            }
251            else
252            {
253                // Object is in view
254
255                // Change material only if outOfView changed
256                if ( it->second.wasOutOfView_ )
257                {
258                    it->second.panel_->setMaterialName ( "Orxonox/NavTDC" );
259                    it->second.wasOutOfView_ = false;
260                }
261
262                // Position marker
263                it->second.panel_->setUV ( 0.0f, 0.0f, 1.0f, 1.0f );
264                it->second.panel_->setLeft ( ( pos.x + 1.0f - it->second.panel_->getWidth() ) * 0.5f );
265                it->second.panel_->setTop ( ( -pos.y + 1.0f - it->second.panel_->getHeight() ) * 0.5f );
266
267                // Position text
268                it->second.text_->setLeft ( ( pos.x + 1.0f + it->second.panel_->getWidth() ) * 0.5f );
269                it->second.text_->setTop ( ( -pos.y + 1.0f + it->second.panel_->getHeight() ) * 0.5f );
270            }
271
272            // Make sure the overlays are shown
273            it->second.panel_->show();
274            it->second.text_->show();
275        }
276        else
277        {
278            it->second.panel_->hide();
279            it->second.text_->hide();
280        }
281
282    }
283}
284
285
286/** Overridden method of OrxonoxOverlay.
287@details
288    Usually the entire overlay scales with scale().
289    Here we obviously have to adjust this.
290*/
291void HUDNavigation::sizeChanged()
292{
293    // Use size to compensate for aspect ratio if enabled.
294    float xScale = this->getActualSize().x;
295    float yScale = this->getActualSize().y;
296
297    for ( ObjectMap::iterator it = activeObjectList_.begin(); it!=activeObjectList_.end(); ++it )
298    {
299        if ( it->second.panel_ != NULL )
300            it->second.panel_->setDimensions ( navMarkerSize_ * xScale, navMarkerSize_ * yScale );
301        if ( it->second.text_ != NULL )
302            it->second.text_->setCharHeight ( it->second.text_->getCharHeight() * yScale );
303    }
304}
305
306void HUDNavigation::addObject ( RadarViewable* object )
307{
308
309    if ( activeObjectList_.size() >= markerLimit_ )
310        if ( object == NULL )
311            return;
312
313    // Don't display our own ship
314    if ( object == dynamic_cast<RadarViewable*> ( this->getOwner() ) )
315        return;
316
317    // Object hasn't been added yet (we know that)
318    assert ( this->activeObjectList_.find ( object ) == this->activeObjectList_.end() );
319
320    // Scales used for dimensions and text size
321    float xScale = this->getActualSize().x;
322    float yScale = this->getActualSize().y;
323
324    // Create everything needed to display the object on the radar and add it to the map
325
326    // Create arrow/marker
327    Ogre::PanelOverlayElement* panel = static_cast<Ogre::PanelOverlayElement*> ( Ogre::OverlayManager::getSingleton()
328                                       .createOverlayElement ( "Panel", "HUDNavigation_navMarker_" + getUniqueNumberString() ) );
329    panel->setMaterialName ( "Orxonox/NavTDC" );
330    panel->setDimensions ( navMarkerSize_ * xScale, navMarkerSize_ * yScale );
331
332    Ogre::TextAreaOverlayElement* text = static_cast<Ogre::TextAreaOverlayElement*> ( Ogre::OverlayManager::getSingleton()
333                                         .createOverlayElement ( "TextArea", "HUDNavigation_navText_" + getUniqueNumberString() ) );
334    text->setFontName ( this->fontName_ );
335    text->setCharHeight ( text->getCharHeight() * yScale );
336
337    panel->hide();
338    text->hide();
339
340    ObjectInfo tempStruct = {panel, text, false};
341    activeObjectList_[object] = tempStruct;
342
343    this->background_->addChild ( panel );
344    this->background_->addChild ( text );
345
346    sortedObjectList_.push_front ( std::make_pair ( object, ( unsigned int ) 0 ) );
347
348
349}
350
351void HUDNavigation::removeObject ( RadarViewable* viewable )
352{
353    if ( viewable == dynamic_cast<RadarViewable*> ( this->getOwner() ) )
354        return;
355
356    ObjectMap::iterator it = activeObjectList_.find ( viewable );
357
358    if ( activeObjectList_.find ( viewable ) != activeObjectList_.end() )
359    {
360        // Detach overlays
361        this->background_->removeChild ( it->second.panel_->getName() );
362        this->background_->removeChild ( it->second.text_->getName() );
363        // Properly destroy the overlay elements (do not use delete!)
364        Ogre::OverlayManager::getSingleton().destroyOverlayElement ( it->second.panel_ );
365        Ogre::OverlayManager::getSingleton().destroyOverlayElement ( it->second.text_ );
366        // Remove from the list
367        activeObjectList_.erase ( viewable );
368
369
370    }
371
372
373    else
374        COUT ( 2 ) << "Warning, HUDNavigation: Attempting to remove non-existent object" << std::endl;
375
376    for ( sortedList::iterator listIt = sortedObjectList_.begin(); listIt != sortedObjectList_.end(); ++listIt )
377    {
378        if ( (listIt->first) == viewable )
379        {
380            sortedObjectList_.erase ( listIt );
381            break;
382        }
383
384    }
385
386}
387
388void HUDNavigation::changedOwner()
389{
390   
391    const std::set<RadarViewable*>& respawnObjects = this->getOwner()->getScene()->getRadar()->getRadarObjects();
392    for ( std::set<RadarViewable*>::const_iterator it = respawnObjects.begin(); it != respawnObjects.end(); ++it )
393    {
394        if ( ! ( *it )->isHumanShip_ )
395            this->addObject ( *it );
396    }
397}
398}
Note: See TracBrowser for help on using the repository browser.