Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/gui/src/orxonox/overlays/OrxonoxOverlay.cc @ 2802

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

Move graphic related content of GSGraphics to GraphicsManager which originally was GraphisEngine (but since we don't have an engine of our own, I renamed it).
Reduced OgreWindowEventUtilities.h dependency from GraphisManager.h (includes windows.h).

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