Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Oct 29th, works pretty well!

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