Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9468 was 9468, checked in by mottetb, 11 years ago

shortcuts don't work

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