Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/objecthierarchy/src/orxonox/overlays/OrxonoxOverlay.cc @ 2046

Last change on this file since 2046 was 2046, checked in by rgrieder, 16 years ago

Changed initialisation of overlay classes to the new convention.
The default values of the XML parameters are set in the constructor with the setter functions!

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