Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation3/src/modules/overlays/hud/HUDNavigation.cc @ 6957

Last change on this file since 6957 was 6947, checked in by scheusso, 15 years ago

fixed a bug which caused a segfault when shooting a rocket

  • Property svn:eol-style set to native
File size: 12.5 KB
RevLine 
[1505]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
[1454]4 *
[1505]5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
[1454]22 *   Author:
23 *      Felix Schulthess
24 *   Co-authors:
[1590]25 *      Reto Grieder
[1454]26 *
27 */
[1393]28
[1601]29#include "HUDNavigation.h"
[1410]30
[6417]31#include <OgreCamera.h>
[6942]32#include <OgreFontManager.h>
[1393]33#include <OgreOverlayManager.h>
[1614]34#include <OgreTextAreaOverlayElement.h>
35#include <OgrePanelOverlayElement.h>
[1410]36
[1614]37#include "util/Math.h"
[1616]38#include "util/Convert.h"
39#include "core/CoreIncludes.h"
40#include "core/XMLPort.h"
[6417]41#include "CameraManager.h"
[5929]42#include "Scene.h"
[5735]43#include "Radar.h"
[6417]44#include "graphics/Camera.h"
45#include "controllers/HumanController.h"
46#include "worldentities/pawns/Pawn.h"
[6942]47#include "worldentities/WorldEntity.h"
48#include "interfaces/RadarViewable.h"
[1393]49
50namespace orxonox
51{
[1601]52    CreateFactory(HUDNavigation);
[1590]53
[2087]54    HUDNavigation::HUDNavigation(BaseObject* creator)
55        : OrxonoxOverlay(creator)
[1580]56    {
[1601]57        RegisterObject(HUDNavigation);
[2087]58
[6942]59        // Set default values
[2087]60        setFont("Monofur");
61        setTextSize(0.05f);
62        setNavMarkerSize(0.05f);
[1393]63    }
64
[1601]65    HUDNavigation::~HUDNavigation()
[1564]66    {
[2087]67        if (this->isInitialized())
68        {
[6942]69            for (ObjectMap::iterator it = activeObjectList_.begin(); it != activeObjectList_.end();)
70                removeObject((it++)->first);
[2087]71        }
[1564]72    }
73
[1601]74    void HUDNavigation::XMLPort(Element& xmlElement, XMLPort::Mode mode)
[1580]75    {
[1747]76        SUPER(HUDNavigation, XMLPort, xmlElement, mode);
[1394]77
[6942]78        XMLPortParam(HUDNavigation, "font",          setFont,          getFont,          xmlElement, mode);
79        XMLPortParam(HUDNavigation, "textSize",      setTextSize,      getTextSize,      xmlElement, mode);
[2087]80        XMLPortParam(HUDNavigation, "navMarkerSize", setNavMarkerSize, getNavMarkerSize, xmlElement, mode);
[1410]81    }
[1393]82
[1601]83    void HUDNavigation::setFont(const std::string& font)
[1590]84    {
[6942]85        const Ogre::ResourcePtr& fontPtr = Ogre::FontManager::getSingleton().getByName(font);
86        if (fontPtr.isNull())
87        {
88            COUT(2) << "Warning: HUDNavigation: Font '" << font << "' not found" << std::endl;
89            return;
90        }
91        fontName_ = font;
92        for (ObjectMap::iterator it = activeObjectList_.begin(); it != activeObjectList_.end(); ++it)
93        {
94            if (it->second.text_ != NULL)
95                it->second.text_->setFontName(fontName_);
96        }
[1590]97    }
98
[1615]99    const std::string& HUDNavigation::getFont() const
[1590]100    {
[6942]101        return fontName_;
[1590]102    }
103
[1601]104    void HUDNavigation::setTextSize(float size)
[1590]105    {
[6942]106        if (size <= 0.0f)
107        {
108            COUT(2) << "Warning: HUDNavigation: Negative font size not allowed" << std::endl;
109            return;
110        }
111        textSize_ = size;
112        for (ObjectMap::iterator it = activeObjectList_.begin(); it!=activeObjectList_.end(); ++it)
113        {
114            if (it->second.text_)
115                it->second.text_->setCharHeight(size);
116        }
[1590]117    }
118
[1601]119    float HUDNavigation::getTextSize() const
[1590]120    {
[6942]121        return textSize_;
[1590]122    }
123
[1601]124    void HUDNavigation::tick(float dt)
[1590]125    {
[2662]126        SUPER(HUDNavigation, tick, dt);
127
[6942]128        Camera* cam = CameraManager::getInstance().getActiveCamera();
129        if (cam == NULL)
[1564]130            return;
[6942]131        const Matrix4& camTransform = cam->getOgreCamera()->getProjectionMatrix() * cam->getOgreCamera()->getViewMatrix();
[1400]132
[6942]133        for (ObjectMap::iterator it = activeObjectList_.begin(); it != activeObjectList_.end(); ++it)
[1590]134        {
[6942]135            // Get Distance to HumanController and save it in the TextAreaOverlayElement.
[6947]136            int dist = (int)((it->first->getRVWorldPosition() - HumanController::getLocalControllerSingleton()->getControllableEntity()->getWorldPosition()).length() + 0.5f);
[6942]137            it->second.text_->setCaption(multi_cast<std::string>(dist));
138            float textLength = multi_cast<std::string>(dist).size() * it->second.text_->getCharHeight() * 0.3f;
[1399]139
[6942]140            // Transform to screen coordinates
141            Vector3 pos = camTransform * it->first->getRVWorldPosition();
[1411]142
[6942]143            bool outOfView = true;
144            if (pos.z > 1.0)
[1580]145            {
[6942]146                // z > 1.0 means that the object is behind the camera
147                outOfView = true;
148                // we have to switch all coordinates (if you don't know why,
149                // try linear algebra lectures, because I can't explain..)
150                pos.x = -pos.x;
151                pos.y = -pos.y;
[1411]152            }
[6942]153            else
154                outOfView = pos.x < -1.0 || pos.x > 1.0 || pos.y < -1.0 || pos.y > 1.0;
[1590]155
[6942]156            if (outOfView)
[1580]157            {
[6942]158                // Object is not in view
159
160                // Change material only if outOfView changed
161                if (!it->second.wasOutOfView_)
[1580]162                {
[6942]163                    it->second.panel_->setMaterialName("Orxonox/NavArrows");
164                    it->second.wasOutOfView_ = true;
[1399]165                }
[6942]166
167                // Switch between top, bottom, left and right position of the arrow at the screen border
168                if (pos.x < pos.y)
169                {
170                    if (pos.y > -pos.x)
171                    {
172                        // Top
173                        float position = pos.x / pos.y + 1.0f;
174                        it->second.panel_->setPosition((position - it->second.panel_->getWidth()) * 0.5f, 0.0f);
175                        it->second.panel_->setUV(0.5f, 0.0f, 1.0f, 0.5f);
176                        it->second.text_->setLeft((position - textLength) * 0.5f);
177                        it->second.text_->setTop(it->second.panel_->getHeight());
178                    }
179                    else
180                    {
181                        // Left
182                        float position = pos.y / pos.x + 1.0f;
183                        it->second.panel_->setPosition(0.0f, (position - it->second.panel_->getWidth()) * 0.5f);
184                        it->second.panel_->setUV(0.0f, 0.0f, 0.5f, 0.5f);
185                        it->second.text_->setLeft(it->second.panel_->getWidth() + 0.01f);
186                        it->second.text_->setTop((position - it->second.text_->getCharHeight()) * 0.5f);
187                    }
188                }
[1580]189                else
190                {
[6942]191
192                    if (pos.y < -pos.x)
193                    {
194                        // Bottom
195                        float position = -pos.x / pos.y + 1.0f;
196                        it->second.panel_->setPosition((position - it->second.panel_->getWidth()) * 0.5f, 1.0f - it->second.panel_->getHeight());
197                        it->second.panel_->setUV(0.0f, 0.5f, 0.5f, 1.0f);
198                        it->second.text_->setLeft((position - textLength) * 0.5f);
199                        it->second.text_->setTop(1.0f - it->second.panel_->getHeight() - it->second.text_->getCharHeight());
200                    }
201                    else
202                    {
203                        // Right
204                        float position = -pos.y / pos.x + 1.0f;
205                        it->second.panel_->setPosition(1.0f - it->second.panel_->getWidth(), (position - it->second.panel_->getHeight()) * 0.5f);
206                        it->second.panel_->setUV(0.5f, 0.5f, 1.0f, 1.0f);
207                        it->second.text_->setLeft(1.0f - it->second.panel_->getWidth() - textLength - 0.01f);
208                        it->second.text_->setTop((position - it->second.text_->getCharHeight()) * 0.5f);
209                    }
[1411]210                }
211            }
[1590]212            else
[1580]213            {
[6942]214                // Object is in view
215
216                // Change material only if outOfView changed
217                if (it->second.wasOutOfView_)
[1580]218                {
[6942]219                    it->second.panel_->setMaterialName("Orxonox/NavTDC");
220                    it->second.wasOutOfView_ = false;
[1399]221                }
[6942]222
223                // Position marker
224                it->second.panel_->setUV(0.0f, 0.0f, 1.0f, 1.0f);
225                it->second.panel_->setLeft((pos.x + 1.0f - it->second.panel_->getWidth()) * 0.5f);
226                it->second.panel_->setTop((-pos.y + 1.0f - it->second.panel_->getHeight()) * 0.5f);
227
228                // Position text
229                it->second.text_->setLeft((pos.x + 1.0f + it->second.panel_->getWidth()) * 0.5f);
230                it->second.text_->setTop((-pos.y + 1.0f + it->second.panel_->getHeight()) * 0.5f);
[1393]231            }
[6942]232
233            // Make sure the overlays are shown
234            it->second.panel_->show();
235            it->second.text_->show();
[1393]236        }
[6942]237    }
[1590]238
[1566]239
[6942]240    /** Overridden method of OrxonoxOverlay.
241    @details
242        Usually the entire overlay scales with scale().
243        Here we obviously have to adjust this.
244    */
245    void HUDNavigation::sizeChanged()
246    {
247        // Use size to compensate for aspect ratio if enabled.
248        float xScale = this->getActualSize().x;
249        float yScale = this->getActualSize().y;
250
251        for (ObjectMap::iterator it = activeObjectList_.begin(); it!=activeObjectList_.end(); ++it)
252        {
253            if (it->second.panel_ != NULL)
254                it->second.panel_->setDimensions(navMarkerSize_ * xScale, navMarkerSize_ * yScale);
255            if (it->second.text_ != NULL)
256                it->second.text_->setCharHeight(it->second.text_->getCharHeight() * yScale);
[1393]257        }
[1410]258    }
[1394]259
[6942]260    void HUDNavigation::addObject(RadarViewable* object)
[1580]261    {
[6942]262        if (object == NULL)
263            return;
264
265        // Don't display our own ship
266        if (object == dynamic_cast<RadarViewable*>(this->getOwner()))
267            return;
268
269        // Object hasn't been added yet (we know that)
270        assert(this->activeObjectList_.find(object) == this->activeObjectList_.end());
271
272        // Scales used for dimensions and text size
273        float xScale = this->getActualSize().x;
274        float yScale = this->getActualSize().y;
275
276        // Create everything needed to display the object on the radar and add it to the map
277
278        // Create arrow/marker
279        Ogre::PanelOverlayElement* panel = static_cast<Ogre::PanelOverlayElement*>(Ogre::OverlayManager::getSingleton()
280            .createOverlayElement("Panel", "HUDNavigation_navMarker_" + getUniqueNumberString()));
281        panel->setMaterialName("Orxonox/NavTDC");
282        panel->setDimensions(navMarkerSize_ * xScale, navMarkerSize_ * yScale);
283
284        Ogre::TextAreaOverlayElement* text = static_cast<Ogre::TextAreaOverlayElement*>(Ogre::OverlayManager::getSingleton()
285            .createOverlayElement("TextArea", "HUDNavigation_navText_" + getUniqueNumberString()));
286        text->setFontName(this->fontName_);
287        text->setCharHeight(text->getCharHeight() * yScale);
288
289        ObjectInfo tempStruct = {panel, text, false};
290        activeObjectList_[object] = tempStruct;
291
292        this->background_->addChild(panel);
293        this->background_->addChild(text);
294    }
295
296    void HUDNavigation::removeObject(RadarViewable* viewable)
297    {
298        ObjectMap::iterator it = activeObjectList_.find(viewable);
299
300        if (activeObjectList_.find(viewable) != activeObjectList_.end())
301        {
302            // Detach overlays
303            this->background_->removeChild(it->second.panel_->getName());
304            this->background_->removeChild(it->second.text_->getName());
305            // Properly destroy the overlay elements (do not use delete!)
306            Ogre::OverlayManager::getSingleton().destroyOverlayElement(it->second.panel_);
307            Ogre::OverlayManager::getSingleton().destroyOverlayElement(it->second.text_);
308            // Remove from the list
309            activeObjectList_.erase(viewable);
310        }
[1580]311        else
[6942]312            COUT(2) << "Warning, HUDNavigation: Attempting to remove non-existent object" << std::endl;
[1410]313    }
[1590]314
[6942]315    void HUDNavigation::changedOwner()
[1590]316    {
[6942]317        // TODO: Delete old objects?
318        const std::set<RadarViewable*>& respawnObjects = this->getOwner()->getScene()->getRadar()->getRadarObjects();
319        for (std::set<RadarViewable*>::const_iterator it = respawnObjects.begin(); it != respawnObjects.end(); ++it)
320        {
321            if (!(*it)->isHumanShip_)
322                this->addObject(*it);
323        }
[1590]324    }
[1393]325}
Note: See TracBrowser for help on using the repository browser.