Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8920 was 8920, checked in by mspaling, 13 years ago

Arrow in HUD now changes its size according to distance

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