Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core4/src/orxonox/overlays/OrxonoxOverlay.cc @ 4006

Last change on this file since 4006 was 3291, checked in by rgrieder, 15 years ago

Added window size as static variable to the WindowEventListener interface.
This resolves several hacks and inconveniences in Mouse, InputManager, InGameConsole, GSGraphics and OrxonoxOverlay.

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