Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/archive/waypoints/src/modules/overlays/hud/HUDNavigation.cc @ 10422

Last change on this file since 10422 was 9219, checked in by scmoritz, 13 years ago

3D arrow added. Spinns around like crazy. the partyarrow needs a fix :)

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