Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6952 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
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 *
27 */
28
29#include "HUDNavigation.h"
30
31#include <OgreCamera.h>
32#include <OgreFontManager.h>
33#include <OgreOverlayManager.h>
34#include <OgreTextAreaOverlayElement.h>
35#include <OgrePanelOverlayElement.h>
36
37#include "util/Math.h"
38#include "util/Convert.h"
39#include "core/CoreIncludes.h"
40#include "core/XMLPort.h"
41#include "CameraManager.h"
42#include "Scene.h"
43#include "Radar.h"
44#include "graphics/Camera.h"
45#include "controllers/HumanController.h"
46#include "worldentities/pawns/Pawn.h"
47#include "worldentities/WorldEntity.h"
48#include "interfaces/RadarViewable.h"
49
50namespace orxonox
51{
52    CreateFactory(HUDNavigation);
53
54    HUDNavigation::HUDNavigation(BaseObject* creator)
55        : OrxonoxOverlay(creator)
56    {
57        RegisterObject(HUDNavigation);
58
59        // Set default values
60        setFont("Monofur");
61        setTextSize(0.05f);
62        setNavMarkerSize(0.05f);
63    }
64
65    HUDNavigation::~HUDNavigation()
66    {
67        if (this->isInitialized())
68        {
69            for (ObjectMap::iterator it = activeObjectList_.begin(); it != activeObjectList_.end();)
70                removeObject((it++)->first);
71        }
72    }
73
74    void HUDNavigation::XMLPort(Element& xmlElement, XMLPort::Mode mode)
75    {
76        SUPER(HUDNavigation, XMLPort, xmlElement, mode);
77
78        XMLPortParam(HUDNavigation, "font",          setFont,          getFont,          xmlElement, mode);
79        XMLPortParam(HUDNavigation, "textSize",      setTextSize,      getTextSize,      xmlElement, mode);
80        XMLPortParam(HUDNavigation, "navMarkerSize", setNavMarkerSize, getNavMarkerSize, xmlElement, mode);
81    }
82
83    void HUDNavigation::setFont(const std::string& font)
84    {
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        }
97    }
98
99    const std::string& HUDNavigation::getFont() const
100    {
101        return fontName_;
102    }
103
104    void HUDNavigation::setTextSize(float size)
105    {
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        }
117    }
118
119    float HUDNavigation::getTextSize() const
120    {
121        return textSize_;
122    }
123
124    void HUDNavigation::tick(float dt)
125    {
126        SUPER(HUDNavigation, tick, dt);
127
128        Camera* cam = CameraManager::getInstance().getActiveCamera();
129        if (cam == NULL)
130            return;
131        const Matrix4& camTransform = cam->getOgreCamera()->getProjectionMatrix() * cam->getOgreCamera()->getViewMatrix();
132
133        for (ObjectMap::iterator it = activeObjectList_.begin(); it != activeObjectList_.end(); ++it)
134        {
135            // Get Distance to HumanController and save it in the TextAreaOverlayElement.
136            int dist = (int)((it->first->getRVWorldPosition() - HumanController::getLocalControllerSingleton()->getControllableEntity()->getWorldPosition()).length() + 0.5f);
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;
139
140            // Transform to screen coordinates
141            Vector3 pos = camTransform * it->first->getRVWorldPosition();
142
143            bool outOfView = true;
144            if (pos.z > 1.0)
145            {
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;
152            }
153            else
154                outOfView = pos.x < -1.0 || pos.x > 1.0 || pos.y < -1.0 || pos.y > 1.0;
155
156            if (outOfView)
157            {
158                // Object is not in view
159
160                // Change material only if outOfView changed
161                if (!it->second.wasOutOfView_)
162                {
163                    it->second.panel_->setMaterialName("Orxonox/NavArrows");
164                    it->second.wasOutOfView_ = true;
165                }
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                }
189                else
190                {
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                    }
210                }
211            }
212            else
213            {
214                // Object is in view
215
216                // Change material only if outOfView changed
217                if (it->second.wasOutOfView_)
218                {
219                    it->second.panel_->setMaterialName("Orxonox/NavTDC");
220                    it->second.wasOutOfView_ = false;
221                }
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);
231            }
232
233            // Make sure the overlays are shown
234            it->second.panel_->show();
235            it->second.text_->show();
236        }
237    }
238
239
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);
257        }
258    }
259
260    void HUDNavigation::addObject(RadarViewable* object)
261    {
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        }
311        else
312            COUT(2) << "Warning, HUDNavigation: Attempting to remove non-existent object" << std::endl;
313    }
314
315    void HUDNavigation::changedOwner()
316    {
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        }
324    }
325}
Note: See TracBrowser for help on using the repository browser.