Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/objecthierarchy2/src/orxonox/overlays/OrxonoxOverlay.cc @ 2576

Last change on this file since 2576 was 2369, checked in by landauf, 16 years ago
  • Added a health bar
  • Some changes in CameraManager to handle the case when no camera exists after removing the last one, but this is still somehow buggy (freezes and later crashes reproducible but inexplicable after a few respawns)
  • Added PawnManager to handle destruction of Pawns without using delete within tick()
  • Property svn:eol-style set to native
File size: 11.1 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 *      Reto Grieder
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30@file
31@brief Definition of the OrxonoxOverlay class.
32*/
33
34#include "OrxonoxStableHeaders.h"
35#include "OrxonoxOverlay.h"
36
37#include <cmath>
38#include <OgreOverlay.h>
39#include <OgreOverlayManager.h>
40#include <OgrePanelOverlayElement.h>
41#include "util/Convert.h"
42#include "util/Exception.h"
43#include "util/String.h"
44#include "core/Core.h"
45#include "core/CoreIncludes.h"
46#include "core/XMLPort.h"
47#include "core/ConsoleCommand.h"
48
49namespace orxonox
50{
51    unsigned int OrxonoxOverlay::hudOverlayCounter_s = 0;
52    std::map<std::string, OrxonoxOverlay*> OrxonoxOverlay::overlays_s;
53
54    SetConsoleCommand(OrxonoxOverlay, scaleOverlay, false).accessLevel(AccessLevel::User);
55    SetConsoleCommand(OrxonoxOverlay, scrollOverlay, false).accessLevel(AccessLevel::User);
56    SetConsoleCommand(OrxonoxOverlay, rotateOverlay, false).accessLevel(AccessLevel::User);
57
58    OrxonoxOverlay::OrxonoxOverlay(BaseObject* creator)
59        : BaseObject(creator)
60    {
61        RegisterObject(OrxonoxOverlay);
62
63        this->owner_ = 0;
64        this->group_ = 0;
65
66        if (!Core::showsGraphics())
67            ThrowException(NoGraphics, "Can't create OrxonoxOverlay, graphics engine not initialized");
68
69        // create the Ogre::Overlay
70        overlay_ = Ogre::OverlayManager::getSingleton().create("OrxonoxOverlay_overlay_"
71            + convertToString(hudOverlayCounter_s++));
72
73        // create background panel (can be used to show any picture)
74        this->background_ = static_cast<Ogre::PanelOverlayElement*>(
75            Ogre::OverlayManager::getSingleton().createOverlayElement("Panel",
76            "OrxonoxOverlay_background_" + convertToString(hudOverlayCounter_s++)));
77        this->overlay_->add2D(this->background_);
78
79        // We'll have to set the aspect ratio to a default value first.
80        // GSGraphics gets informed about our construction here and can update us in the next tick.
81        this->windowAspectRatio_ = 1.0;
82        this->sizeCorrectionChanged();
83
84        this->changedVisibility();
85
86        setSize(Vector2(1.0f, 1.0f));
87        setPickPoint(Vector2(0.0f, 0.0f));
88        setPosition(Vector2(0.0f, 0.0f));
89        setRotation(Degree(0.0));
90        setAspectCorrection(true);
91        setBackgroundMaterial("");
92    }
93
94    /**
95    @brief
96        Make sure everything gets removed/destroyed.
97    @remark
98        We assume that the Ogre::OverlayManager exists (there is an assert in Ogre for that!)
99    */
100    OrxonoxOverlay::~OrxonoxOverlay()
101    {
102        if (this->isInitialized())
103        {
104            // erase ourself from the map with all overlays
105            std::map<std::string, OrxonoxOverlay*>::iterator it = overlays_s.find(this->getName());
106            if (it != overlays_s.end())
107                overlays_s.erase(it);
108
109            Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->background_);
110            Ogre::OverlayManager::getSingleton().destroy(this->overlay_);
111        }
112    }
113
114    /**
115    @brief
116        Loads the OrxonoxOverlay.
117
118        This has to be called before usage, otherwise strange behaviour is
119        guaranteed! (there should be no segfaults however).
120    @copydoc
121        BaseObject::XMLPort()
122    */
123    void OrxonoxOverlay::XMLPort(Element& xmlElement, XMLPort::Mode mode)
124    {
125        SUPER(OrxonoxOverlay, XMLPort, xmlElement, mode);
126
127        XMLPortParam(OrxonoxOverlay, "size",      setSize,      getSize,      xmlElement, mode);
128        XMLPortParam(OrxonoxOverlay, "pickpoint", setPickPoint, getPickPoint, xmlElement, mode);
129        XMLPortParam(OrxonoxOverlay, "position",  setPosition,  getPosition,  xmlElement, mode);
130        XMLPortParam(OrxonoxOverlay, "rotation",  setRotation,  getRotation,  xmlElement, mode);
131        XMLPortParam(OrxonoxOverlay, "correctaspect", setAspectCorrection,   getAspectCorrection,   xmlElement, mode);
132        XMLPortParam(OrxonoxOverlay, "background",    setBackgroundMaterial, getBackgroundMaterial, xmlElement, mode);
133    }
134
135    void OrxonoxOverlay::changedName()
136    {
137        SUPER(OrxonoxOverlay, changedName);
138
139        OrxonoxOverlay::overlays_s.erase(this->getOldName());
140
141        if (OrxonoxOverlay::overlays_s.find(this->getName()) != OrxonoxOverlay::overlays_s.end())
142            COUT(1) << "Overlay names should be unique or you cannnot access them via console. Name: \"" << this->getName() << "\"" << std::endl;
143
144        OrxonoxOverlay::overlays_s[this->getName()] = this;
145    }
146
147    //! Only sets the background material name if not ""
148    void OrxonoxOverlay::setBackgroundMaterial(const std::string& material)
149    {
150        if (this->background_ && material != "")
151            this->background_->setMaterialName(material);
152    }
153
154    //! Returns the the material name of the background
155    const std::string& OrxonoxOverlay::getBackgroundMaterial() const
156    {
157        if (this->background_)
158            return this->background_->getMaterialName();
159        else
160            return BLANKSTRING;
161    }
162
163    //! Called by BaseObject when visibility has changed.
164    void OrxonoxOverlay::changedVisibility()
165    {
166        if (!this->overlay_)
167            return;
168
169        if (this->isVisible())
170            this->overlay_->show();
171        else
172            this->overlay_->hide();
173    }
174
175    /**
176    @brief
177        Called by the GraphicsEngine whenever the window size changes.
178        Calculates the aspect ratio only.
179    */
180    void OrxonoxOverlay::windowResized(int newWidth, int newHeight)
181    {
182        this->windowAspectRatio_ = newWidth/(float)newHeight;
183        this->sizeCorrectionChanged();
184    }
185
186    /**
187    @brief
188        Called whenever the rotation angle has changed.
189    */
190    void OrxonoxOverlay::angleChanged()
191    {
192        if (!this->overlay_)
193            return;
194
195        this->overlay_->setRotate(this->angle_);
196        this->sizeCorrectionChanged();
197    }
198
199    /**
200    @brief
201        Called whenever the aspect ratio or the angle has changed.
202        The method calculates a correction factor for the size to compensate
203        for aspect distortion if desired.
204    @remarks
205        This only works when the angle is about 0 or 90 degrees.
206    */
207    void OrxonoxOverlay::sizeCorrectionChanged()
208    {
209        if (this->bCorrectAspect_)
210        {
211            float angle = this->angle_.valueDegrees();
212            if (angle < 0.0)
213                angle = -angle;
214            angle -= 180.0 * (int)(angle / 180.0);
215
216            // take the reverse if angle is about 90 degrees
217            float tempAspect;
218            if (angle > 89.0 && angle < 91.0)
219            {
220                tempAspect = 1.0 / this->windowAspectRatio_;
221                rotState_ = Vertical;
222            }
223            else if (angle > 179 || angle < 1)
224            {
225                tempAspect = this->windowAspectRatio_;
226                rotState_ = Horizontal;
227            }
228            else
229            {
230                tempAspect = 1.0;
231                rotState_ = Inbetween;
232            }
233
234            // note: this is only an approximation that is mostly valid when the
235            // magnitude of the width is about the magnitude of the height.
236            // Correctly we would have to take the square root of width*height
237            this->sizeCorrection_.x = 2.0 / (tempAspect + 1.0);
238            this->sizeCorrection_.y = tempAspect * this->sizeCorrection_.x;
239        }
240        else
241        {
242            this->sizeCorrection_ = Vector2::UNIT_SCALE;
243        }
244
245        this->sizeChanged();
246    }
247
248    /**
249    @brief
250        Sets the overlay size using the actual corrected size.
251    */
252    void OrxonoxOverlay::sizeChanged()
253    {
254        if (!this->overlay_)
255            return;
256
257        this->overlay_->setScale(size_.x * sizeCorrection_.x, size_.y * sizeCorrection_.y);
258        positionChanged();
259    }
260
261    /**
262    @brief
263        Determines the position of the overlay.
264        This works also well when a rotation angle is applied. The overlay always
265        gets aligned correctly as well as possible.
266    */
267    void OrxonoxOverlay::positionChanged()
268    {
269        if (!this->overlay_)
270            return;
271
272        // transform the angle to a range of 0 - pi/2 first.
273        float angle = this->angle_.valueRadians();
274        if (angle < 0.0)
275            angle = -angle;
276        angle -= Ogre::Math::PI * (int)(angle / (Ogre::Math::PI));
277        if (angle > Ogre::Math::PI * 0.5)
278            angle = Ogre::Math::PI - angle;
279
280        // do some mathematical fiddling for a bounding box
281        Vector2 actualSize = size_ * sizeCorrection_;
282        float radius = actualSize.length();
283        float phi = atan(actualSize.y / actualSize.x);
284        Vector2 boundingBox(radius * cos(angle - phi), radius * sin(angle + phi));
285
286        // calculate the scrolling offset
287        Vector2 scroll = (position_ - 0.5 - boundingBox * (pickPoint_ - 0.5)) * 2.0;
288        this->overlay_->setScroll(scroll.x, -scroll.y);
289    }
290
291
292    //########### Console commands ############
293
294    /**
295    @brief
296        Scales an overlay by its name.
297    @param name
298        The name of the overlay defined BaseObject::setName() (usually done with the "name"
299        attribute in the xml file).
300    */
301    /*static*/ void OrxonoxOverlay::scaleOverlay(const std::string& name, float scale)
302    {
303        std::map<std::string, OrxonoxOverlay*>::const_iterator it = overlays_s.find(name);
304        if (it != overlays_s.end())
305            (*it).second->scale(Vector2(scale, scale));
306    }
307
308    /**
309    @brief
310        Scrolls an overlay by its name.
311    @param name
312        The name of the overlay defined BaseObject::setName() (usually done with the "name"
313        attribute in the xml file).
314    */
315    /*static*/ void OrxonoxOverlay::scrollOverlay(const std::string& name, const Vector2& scroll)
316    {
317        std::map<std::string, OrxonoxOverlay*>::const_iterator it = overlays_s.find(name);
318        if (it != overlays_s.end())
319            (*it).second->scroll(scroll);
320    }
321
322    /**
323    @brief
324        Rotates an overlay by its name.
325    @param name
326        The name of the overlay defined BaseObject::setName() (usually done with the "name"
327        attribute in the xml file).
328    */
329    /*static*/ void OrxonoxOverlay::rotateOverlay(const std::string& name, const Degree& angle)
330    {
331        std::map<std::string, OrxonoxOverlay*>::const_iterator it = overlays_s.find(name);
332        if (it != overlays_s.end())
333            (*it).second->rotate(angle);
334    }
335}
Note: See TracBrowser for help on using the repository browser.