Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9443 was 9443, checked in by mottetb, 12 years ago

was fuer einen Fortschritt heute!

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