Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9219 was 9219, checked in by scmoritz, 12 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
RevLine 
[1505]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
[1454]4 *
[1505]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 *
[1454]22 *   Author:
23 *      Felix Schulthess
24 *   Co-authors:
[1590]25 *      Reto Grieder
[7801]26 *      Oliver Scheuss
[9016]27 *      Matthias Spalinger
[1454]28 *
29 */
[1393]30
[1601]31#include "HUDNavigation.h"
[1410]32
[6417]33#include <OgreCamera.h>
[7163]34#include <OgreFontManager.h>
[1393]35#include <OgreOverlayManager.h>
[1614]36#include <OgreTextAreaOverlayElement.h>
37#include <OgrePanelOverlayElement.h>
[9159]38#include <OgreEntity.h>
[1410]39
[1614]40#include "util/Math.h"
[1616]41#include "util/Convert.h"
42#include "core/CoreIncludes.h"
43#include "core/XMLPort.h"
[6417]44#include "CameraManager.h"
[5929]45#include "Scene.h"
[5735]46#include "Radar.h"
[6417]47#include "graphics/Camera.h"
[9177]48#include "graphics/Model.h"
49#include "worldentities/MovableEntity.h"
[6417]50#include "controllers/HumanController.h"
51#include "worldentities/pawns/Pawn.h"
[7163]52#include "worldentities/WorldEntity.h"
53#include "core/ConfigValueIncludes.h"
54#include "tools/TextureGenerator.h"
55// #include <boost/bind/bind_template.hpp>
[1393]56
[7163]57
[1393]58namespace orxonox
59{
[7163]60bool compareDistance ( std::pair<RadarViewable*, unsigned int > a, std::pair<RadarViewable*, unsigned int > b )
61{
62    return a.second<b.second;
[1590]63
[7163]64}
[2087]65
[7163]66void HUDNavigation::setConfigValues()
67{
68  SetConfigValue(markerLimit_, 3);
[9016]69  SetConfigValue(showDistance, false);
[7163]70}
[2087]71
[7163]72CreateFactory ( HUDNavigation );
[2087]73
[7163]74HUDNavigation::HUDNavigation ( BaseObject* creator )
75        : OrxonoxOverlay ( creator )
76{
77    RegisterObject ( HUDNavigation );
78    this->setConfigValues();
[2087]79
[7163]80    // Set default values
[9016]81    this->setFont ( "Monofur" );
82    this->setTextSize ( 0.05f );
83    this->setNavMarkerSize ( 0.05f );
84    this->setDetectionLimit( 10000.0f ); 
[9159]85
[9177]86    //Ogre::Entity* ent = this->getScene()->getSceneManager()->createEntity("Arrow3D", "Arrow3D.mesh");
87
88    Model* arrow = new Model(this);
[9219]89    this->arrowEntity = new MovableEntity(this);
[9177]90    arrow->setMeshSource("Arrow3D.mesh");
[9219]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_);
[9177]98    //this->add3DMesh(arrowEntity);
99
[9219]100    //this->overlay3d_->setPosition(0, 0, 0);
101    //this->overlay3d_->setVisible(false, true);
102    this->overlay_->setZOrder(0);
103    this->overlay_->show();
104    hideArrow3D();
[7163]105}
[2087]106
[7163]107HUDNavigation::~HUDNavigation()
108{
109    if ( this->isInitialized() )
110    {
111        for ( ObjectMap::iterator it = activeObjectList_.begin(); it != activeObjectList_.end(); )
112            removeObject ( ( it++ )->first );
[2087]113
[1393]114    }
115
[7163]116    sortedObjectList_.clear();
117}
[1564]118
[7401]119void HUDNavigation::XMLPort ( Element& xmlelement, XMLPort::Mode mode )
[7163]120{
[7401]121    SUPER ( HUDNavigation, XMLPort, xmlelement, mode );
[1394]122
[9016]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 ); 
[7163]127}
[1393]128
[7163]129void HUDNavigation::setFont ( const std::string& font )
130{
131    const Ogre::ResourcePtr& fontPtr = Ogre::FontManager::getSingleton().getByName ( font );
132    if ( fontPtr.isNull() )
[1590]133    {
[8858]134        orxout(internal_warning) << "HUDNavigation: Font '" << font << "' not found" << endl;
[7163]135        return;
[1590]136    }
[7163]137    fontName_ = font;
138    for ( ObjectMap::iterator it = activeObjectList_.begin(); it != activeObjectList_.end(); ++it )
[1590]139    {
[7163]140        if ( it->second.text_ != NULL )
141            it->second.text_->setFontName ( fontName_ );
[1590]142    }
[7163]143}
[1590]144
[7163]145const std::string& HUDNavigation::getFont() const
146{
147    return fontName_;
148}
149
150void HUDNavigation::setTextSize ( float size )
151{
152    if ( size <= 0.0f )
[1590]153    {
[8858]154        orxout(internal_warning) << "HUDNavigation: Negative font size not allowed" << endl;
[7163]155        return;
[1590]156    }
[7163]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}
[1590]164
[7163]165float HUDNavigation::getTextSize() const
166{
167    return textSize_;
168}
169
[9016]170float HUDNavigation::getArrowSizeX(int dist)
171{   
172    if (dist < 600) 
173        dist = 600;
174    return this->getActualSize().x * 900 * navMarkerSize_ / dist;
175}
[7163]176
[9016]177float HUDNavigation::getArrowSizeY(int dist)
178{   
179    if (dist < 600)
180        dist = 600;   
181    return this->getActualSize().y * 900 * navMarkerSize_ / dist;
182}
[7163]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 )
[1590]195    {
[7163]196        listIt->second = ( int ) ( ( listIt->first->getRVWorldPosition() - HumanController::getLocalControllerSingleton()->getControllableEntity()->getWorldPosition() ).length() + 0.5f );
[1590]197    }
198
[7163]199    sortedObjectList_.sort ( compareDistance );
200
201    unsigned int markerCount_ = 0;
[8891]202    bool closeEnough_ = false; //only display objects that are close enough to be relevant for the player
[9016]203
[9177]204    //for the first element of sortedObjectList_ / the closest waypoint show the Arrow3D
[9219]205    //set the direction of the arrow to the closest waypoint
[9177]206    if(!sortedObjectList_.empty())
207    {
208        showArrow3D();
209                sortedList::iterator firstIt = sortedObjectList_.begin();
[9219]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);
[9177]217    }
[9219]218    else{hideArrow3D();}
[9177]219
220
[7163]221//         for (ObjectMap::iterator it = activeObjectList_.begin(); it != activeObjectList_.end(); ++it)
222    for ( sortedList::iterator listIt = sortedObjectList_.begin(); listIt != sortedObjectList_.end(); ++markerCount_, ++listIt )
[1590]223    {
[7163]224        ObjectMap::iterator it = activeObjectList_.find ( listIt->first );
[8891]225        closeEnough_ = listIt->second < detectionLimit_ ;
[9016]226        // display radarviewables on HUD if the marker limit and max-distance is not exceeded
227        if ( markerCount_ < markerLimit_ && (closeEnough_ ||  detectionLimit_ < 0) ) 
[1613]228        {
[1400]229
[1399]230
[7163]231            // Get Distance to HumanController and save it in the TextAreaOverlayElement.
232            int dist = listIt->second;
[9016]233            float textLength = 0.0f;
234
235            //display distance next to cursor
236            if (showDistance){
[7163]237            it->second.text_->setCaption ( multi_cast<std::string> ( dist ) );
[9016]238            textLength = multi_cast<std::string> ( dist ).size() * it->second.text_->getCharHeight() * 0.3f;
239            }
[1564]240
[9016]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
[7163]247            // Transform to screen coordinates
248            Vector3 pos = camTransform * it->first->getRVWorldPosition();
[1399]249
[7163]250            bool outOfView = true;
251            if ( pos.z > 1.0 )
[1580]252            {
[7163]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;
[1411]259            }
[7163]260            else
261                outOfView = pos.x < -1.0 || pos.x > 1.0 || pos.y < -1.0 || pos.y > 1.0;
[1590]262
[7163]263            if ( outOfView )
[1580]264            {
[7163]265                // Object is not in view
266
267                // Change material only if outOfView changed
268                if ( !it->second.wasOutOfView_ )
[1580]269                {
[7368]270                    it->second.panel_->setMaterialName( TextureGenerator::getMaterialName( "arrows.png", it->first->getRadarObjectColour()) );
[7163]271                    it->second.wasOutOfView_ = true;
[1399]272                }
[7163]273
[9016]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
[7163]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
[1580]303                else
304                {
[7163]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                    }
[1411]324                }
325            }
[1590]326            else
[1580]327            {
[7163]328                // Object is in view
329
330                // Change material only if outOfView changed
331                if ( it->second.wasOutOfView_ )
[1580]332                {
[7163]333                  //it->second.panel_->setMaterialName ( "Orxonox/NavTDC" );
[7368]334                    it->second.panel_->setMaterialName( TextureGenerator::getMaterialName( "tdc.png", it->first->getRadarObjectColour()) );
[9016]335                    it->second.panel_->setDimensions ( navMarkerSize_ * this->getActualSize().x, navMarkerSize_ * this->getActualSize().y );
[7163]336                    it->second.wasOutOfView_ = false;
[1399]337                }
[7163]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 );
[1393]347            }
[7163]348
349            // Make sure the overlays are shown
350            it->second.panel_->show();
351            it->second.text_->show();
[1393]352        }
[9016]353        else // do not display on HUD
[1580]354        {
[7163]355            it->second.panel_->hide();
356            it->second.text_->hide();
357        }
[1590]358
[7163]359    }
360}
[1566]361
[7163]362
363/** Overridden method of OrxonoxOverlay.
364@details
365    Usually the entire overlay scales with scale().
366    Here we obviously have to adjust this.
[2087]367*/
[7163]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 );
[1410]380    }
[7163]381}
[1394]382
[7163]383void HUDNavigation::addObject ( RadarViewable* object )
384{
[9016]385    if( showObject(object)==false )
[7163]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" );
[7368]405    panel->setMaterialName( TextureGenerator::getMaterialName( "tdc.png", object->getRadarObjectColour()) );
[7163]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
[8706]418    ObjectInfo tempStruct = {panel, text, false /*, TODO: initialize wasOutOfView_ */};
[7163]419    activeObjectList_[object] = tempStruct;
420
421    this->background_->addChild ( panel );
422    this->background_->addChild ( text );
423
[9219]424    Ogre::Vector3 temp = object->getWorldEntity()->getPosition();
425    unsigned int distance = sqrt(temp.x*temp.x+temp.y*temp.y+temp.z*temp.z);
[7163]426
427
[9219]428
429    sortedObjectList_.push_front ( std::make_pair ( object, distance ) );
430
431
[7163]432}
433
434void HUDNavigation::removeObject ( RadarViewable* viewable )
435{
436    ObjectMap::iterator it = activeObjectList_.find ( viewable );
437
438    if ( activeObjectList_.find ( viewable ) != activeObjectList_.end() )
[1580]439    {
[7163]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
[1410]450    }
[1590]451
[7163]452    for ( sortedList::iterator listIt = sortedObjectList_.begin(); listIt != sortedObjectList_.end(); ++listIt )
[1590]453    {
[7163]454        if ( (listIt->first) == viewable )
455        {
456            sortedObjectList_.erase ( listIt );
457            break;
458        }
459
[1590]460    }
[7163]461
[1393]462}
[7163]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() );
[9016]477    if ( rv->getWorldEntity()->isVisible()==false || rv->getRadarVisibility()==false )
[7163]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}
[9177]492void HUDNavigation::showArrow3D()
493                { this->overlay3d_->setVisible(true, true);}
494void HUDNavigation::hideArrow3D()
495                { this->overlay3d_->setVisible(false, true);}
[7801]496
[9177]497
[7163]498}
Note: See TracBrowser for help on using the repository browser.