Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7014 was 7014, checked in by scheusso, 14 years ago

small fix in hudnavigation (making sure we don't remove the players spaceship (which is not in the list))

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