Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ai2/src/modules/overlays/hud/HUDNavigation.cc @ 8874

Last change on this file since 8874 was 8874, checked in by jo, 13 years ago

Radar & Navigation tweaks: Radar is now hiding 'radar invisible' objects in the same way as the navigation markers are hidden. New 'feature': objects that are too far away are not displayed.

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