Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

getTeam doesn't work, have to find sth else

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