Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

first checkin

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